From 128aba164d096fb86c608029480d14016ca22203 Mon Sep 17 00:00:00 2001 From: Belma Gutlic Date: Tue, 24 Dec 2019 13:46:50 +0100 Subject: [PATCH 1/6] Encrypt stream in chunks --- src/crypto.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/crypto.ts b/src/crypto.ts index 5d583d2..81b1121 100644 --- a/src/crypto.ts +++ b/src/crypto.ts @@ -1,22 +1,35 @@ -import { Handshake } from "./handshake"; import { Buffer } from "buffer"; +import { Handshake } from "./handshake"; interface ReturnEncryptionWrapper { (source: Iterable): AsyncIterableIterator; } +const maxPlaintextLength = 65519; + + // Returns generator that encrypts payload from the user export function encryptStream(handshake: Handshake): ReturnEncryptionWrapper { return async function * (source) { for await (const chunk of source) { const chunkBuffer = Buffer.from(chunk); - const data = await handshake.encrypt(chunkBuffer, handshake.session); - yield data; + + + for (let i = 0; i < chunkBuffer.length; i += maxPlaintextLength) { + let end = i + maxPlaintextLength; + if (end > chunkBuffer.length) { + end = chunkBuffer.length; + } + + const data = handshake.encrypt(chunkBuffer.slice(i, end), handshake.session); + yield data; + } } } } + // Decrypt received payload to the user export function decryptStream(handshake: Handshake): ReturnEncryptionWrapper { return async function * (source) { From 4a04e955dda43cf728ab9c7a86b95d4786f9c9fe Mon Sep 17 00:00:00 2001 From: Belma Gutlic Date: Tue, 24 Dec 2019 16:25:49 +0100 Subject: [PATCH 2/6] Create test for large payload --- test/noise.test.ts | 28 +++++++++++++++++++++++++++- test/utils.ts | 13 +++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/test/noise.test.ts b/test/noise.test.ts index 6d42cd5..ddc285e 100644 --- a/test/noise.test.ts +++ b/test/noise.test.ts @@ -14,7 +14,7 @@ import { import { decodeMessageBuffer, encodeMessageBuffer } from "../src/encoder"; import {XXHandshake} from "../src/xx"; import {Buffer} from "buffer"; -import {getKeyPairFromPeerId} from "./utils"; +import {getKeyPairFromPeerId, getRandomBuffer} from "./utils"; describe("Noise", () => { let remotePeer, localPeer; @@ -96,4 +96,30 @@ describe("Noise", () => { assert(false, e.message); } }) + + + it("should test large payloads", async() => { + try { + const { privateKey: libp2pInitPrivKey } = getKeyPairFromPeerId(localPeer); + const { privateKey: libp2pRespPrivKey } = getKeyPairFromPeerId(remotePeer); + const noiseInit = new Noise(libp2pInitPrivKey); + const noiseResp = new Noise(libp2pRespPrivKey); + + const [inboundConnection, outboundConnection] = DuplexPair(); + const [outbound, inbound] = await Promise.all([ + noiseInit.secureOutbound(localPeer, outboundConnection, remotePeer), + noiseResp.secureInbound(remotePeer, inboundConnection, localPeer), + ]); + const wrappedInbound = Wrap(inbound.conn); + const wrappedOutbound = Wrap(outbound.conn); + + const largePlaintext = getRandomBuffer(100000); + wrappedOutbound.writeLP(largePlaintext); + const response = await wrappedInbound.readLP(); + expect(response.equals(largePlaintext)).to.be.true; + } catch (e) { + console.error(e); + assert(false, e.message); + } + }); }); diff --git a/test/utils.ts b/test/utils.ts index 2ac5b7b..7f68b0d 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -1,5 +1,6 @@ import * as crypto from 'libp2p-crypto'; import {KeyPair, PeerId} from "../src/@types/libp2p"; +import {bytes} from "../src/@types/basic"; export async function generateEd25519Keys() { return await crypto.keys.generateKeyPair('ed25519'); @@ -11,3 +12,15 @@ export function getKeyPairFromPeerId(peerId: PeerId): KeyPair { publicKey: peerId.marshalPubKey(), } } + +export function getRandomBuffer(size: number) : bytes { + size = Math.max(1, size<<0); + + const buf = Buffer.alloc(size); + let i = 0; + for (; i < size; ++i) { + buf[i] = (Math.random() * 0xFF) << 0; + } + + return buf; +} From a5ec8efd2802a596e459d3c4265a814c3533da15 Mon Sep 17 00:00:00 2001 From: Belma Gutlic Date: Tue, 24 Dec 2019 17:27:55 +0100 Subject: [PATCH 3/6] Fix encoding uint --- src/encoder.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/encoder.ts b/src/encoder.ts index ea946ef..6c4cf75 100644 --- a/src/encoder.ts +++ b/src/encoder.ts @@ -4,13 +4,13 @@ import {MessageBuffer} from "./xx"; export const int16BEEncode = (value, target, offset) => { target = target || Buffer.allocUnsafe(2); - return target.writeInt16BE(value, offset); + return target.writeUInt16BE(value, offset); }; int16BEEncode.bytes = 2; export const int16BEDecode = data => { if (data.length < 2) throw RangeError('Could not decode int16BE'); - return data.readInt16BE(0); + return data.readUInt16BE(0); }; int16BEDecode.bytes = 2; From 4b2091be9f095a85696d574fcade644e626150da Mon Sep 17 00:00:00 2001 From: Belma Gutlic Date: Tue, 24 Dec 2019 20:36:16 +0100 Subject: [PATCH 4/6] Read large payload --- src/crypto.ts | 13 +++++++++++-- test/noise.test.ts | 3 ++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/crypto.ts b/src/crypto.ts index 81b1121..44088dd 100644 --- a/src/crypto.ts +++ b/src/crypto.ts @@ -35,8 +35,17 @@ export function decryptStream(handshake: Handshake): ReturnEncryptionWrapper { return async function * (source) { for await (const chunk of source) { const chunkBuffer = Buffer.from(chunk); - const decrypted = await handshake.decrypt(chunkBuffer, handshake.session); - yield decrypted + + for (let i = 0; i < chunkBuffer.length; i += maxPlaintextLength) { + let end = i + maxPlaintextLength; + if (end > chunkBuffer.length) { + end = chunkBuffer.length; + } + + const chunk = chunkBuffer.slice(i, end); + const decrypted = await handshake.decrypt(chunk, handshake.session); + yield decrypted; + } } } } diff --git a/test/noise.test.ts b/test/noise.test.ts index ddc285e..5d68098 100644 --- a/test/noise.test.ts +++ b/test/noise.test.ts @@ -116,7 +116,8 @@ describe("Noise", () => { const largePlaintext = getRandomBuffer(100000); wrappedOutbound.writeLP(largePlaintext); const response = await wrappedInbound.readLP(); - expect(response.equals(largePlaintext)).to.be.true; + + expect(response.length).equals(largePlaintext.length); } catch (e) { console.error(e); assert(false, e.message); From 36a66c59da27e35da444c10d132b348fbe132e97 Mon Sep 17 00:00:00 2001 From: Belma Gutlic Date: Tue, 24 Dec 2019 20:38:34 +0100 Subject: [PATCH 5/6] Remove empty lines --- src/crypto.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/crypto.ts b/src/crypto.ts index 44088dd..4f4a0b0 100644 --- a/src/crypto.ts +++ b/src/crypto.ts @@ -7,14 +7,12 @@ interface ReturnEncryptionWrapper { const maxPlaintextLength = 65519; - // Returns generator that encrypts payload from the user export function encryptStream(handshake: Handshake): ReturnEncryptionWrapper { return async function * (source) { for await (const chunk of source) { const chunkBuffer = Buffer.from(chunk); - for (let i = 0; i < chunkBuffer.length; i += maxPlaintextLength) { let end = i + maxPlaintextLength; if (end > chunkBuffer.length) { @@ -29,7 +27,6 @@ export function encryptStream(handshake: Handshake): ReturnEncryptionWrapper { } - // Decrypt received payload to the user export function decryptStream(handshake: Handshake): ReturnEncryptionWrapper { return async function * (source) { From 5c1a50bd8e4cf6f11c68a8a6d1e39feac70b2801 Mon Sep 17 00:00:00 2001 From: Belma Gutlic Date: Fri, 27 Dec 2019 13:15:06 +0100 Subject: [PATCH 6/6] Address PR comments --- src/crypto.ts | 4 ++-- test/noise.test.ts | 5 +++-- test/utils.ts | 12 ------------ 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/crypto.ts b/src/crypto.ts index 4f4a0b0..34f8c06 100644 --- a/src/crypto.ts +++ b/src/crypto.ts @@ -11,7 +11,7 @@ const maxPlaintextLength = 65519; export function encryptStream(handshake: Handshake): ReturnEncryptionWrapper { return async function * (source) { for await (const chunk of source) { - const chunkBuffer = Buffer.from(chunk); + const chunkBuffer = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.length); for (let i = 0; i < chunkBuffer.length; i += maxPlaintextLength) { let end = i + maxPlaintextLength; @@ -31,7 +31,7 @@ export function encryptStream(handshake: Handshake): ReturnEncryptionWrapper { export function decryptStream(handshake: Handshake): ReturnEncryptionWrapper { return async function * (source) { for await (const chunk of source) { - const chunkBuffer = Buffer.from(chunk); + const chunkBuffer = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.length); for (let i = 0; i < chunkBuffer.length; i += maxPlaintextLength) { let end = i + maxPlaintextLength; diff --git a/test/noise.test.ts b/test/noise.test.ts index 5d68098..d6a8dd2 100644 --- a/test/noise.test.ts +++ b/test/noise.test.ts @@ -4,6 +4,7 @@ import DuplexPair from 'it-pair/duplex'; import { Noise } from "../src"; import {createPeerIdsFromFixtures} from "./fixtures/peer"; import Wrap from "it-pb-rpc"; +import { random } from "bcrypto"; import {Handshake} from "../src/handshake"; import { createHandshakePayload, @@ -14,7 +15,7 @@ import { import { decodeMessageBuffer, encodeMessageBuffer } from "../src/encoder"; import {XXHandshake} from "../src/xx"; import {Buffer} from "buffer"; -import {getKeyPairFromPeerId, getRandomBuffer} from "./utils"; +import {getKeyPairFromPeerId} from "./utils"; describe("Noise", () => { let remotePeer, localPeer; @@ -113,7 +114,7 @@ describe("Noise", () => { const wrappedInbound = Wrap(inbound.conn); const wrappedOutbound = Wrap(outbound.conn); - const largePlaintext = getRandomBuffer(100000); + const largePlaintext = random.randomBytes(100000); wrappedOutbound.writeLP(largePlaintext); const response = await wrappedInbound.readLP(); diff --git a/test/utils.ts b/test/utils.ts index 7f68b0d..5e8b430 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -12,15 +12,3 @@ export function getKeyPairFromPeerId(peerId: PeerId): KeyPair { publicKey: peerId.marshalPubKey(), } } - -export function getRandomBuffer(size: number) : bytes { - size = Math.max(1, size<<0); - - const buf = Buffer.alloc(size); - let i = 0; - for (; i < size; ++i) { - buf[i] = (Math.random() * 0xFF) << 0; - } - - return buf; -}