Skip to content

Commit 3ea9f33

Browse files
authored
chore: update protons and peer collections (#172)
* chore: update protons and peer collections * update it-pb-stream and it-length-prefixed * stop slicing data during encryption * remove slicing * remove unused deps
1 parent 7ffb5bd commit 3ea9f33

File tree

11 files changed

+47
-55
lines changed

11 files changed

+47
-55
lines changed

package.json

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,25 +77,23 @@
7777
"@stablelib/hkdf": "^1.0.1",
7878
"@stablelib/sha256": "^1.0.1",
7979
"@stablelib/x25519": "^1.0.1",
80-
"it-length-prefixed": "^7.0.1",
80+
"it-length-prefixed": "^8.0.2",
8181
"it-pair": "^2.0.2",
82-
"it-pb-stream": "^1.0.2",
82+
"it-pb-stream": "^2.0.1",
8383
"it-pipe": "^2.0.3",
84-
"protons-runtime": "^1.0.3",
85-
"uint8arraylist": "^1.4.0",
84+
"it-stream-types": "^1.0.4",
85+
"protons-runtime": "^2.0.1",
86+
"uint8arraylist": "^2.0.0",
8687
"uint8arrays": "^3.0.0"
8788
},
8889
"devDependencies": {
8990
"@libp2p/interface-connection-encrypter-compliance-tests": "^1.0.1",
9091
"@libp2p/peer-id-factory": "^1.0.8",
9192
"aegir": "^37.3.0",
9293
"benchmark": "^2.1.4",
93-
"events": "^3.3.0",
94-
"microtime": "^3.0.0",
9594
"mkdirp": "^1.0.4",
96-
"protons": "^3.0.3",
97-
"sinon": "^14.0.0",
98-
"util": "^0.12.4"
95+
"protons": "^4.0.0",
96+
"sinon": "^14.0.0"
9997
},
10098
"browser": {
10199
"./dist/src/alloc-unsafe.js": "./dist/src/alloc-unsafe-browser.js",

src/crypto/stablelib.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ export const stablelib: ICryptoInterface = {
1717
const okmU8Array = hkdf.expand(96)
1818
const okm = okmU8Array
1919

20-
const k1 = okm.slice(0, 32)
21-
const k2 = okm.slice(32, 64)
22-
const k3 = okm.slice(64, 96)
20+
const k1 = okm.subarray(0, 32)
21+
const k2 = okm.subarray(32, 64)
22+
const k3 = okm.subarray(64, 96)
2323

2424
return [k1, k2, k3]
2525
},

src/crypto/streaming.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Transform } from 'it-stream-types'
2+
import type { Uint8ArrayList } from 'uint8arraylist'
23
import type { IHandshake } from '../@types/handshake-interface.js'
34
import { NOISE_MSG_MAX_LENGTH_BYTES, NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG } from '../constants.js'
45

@@ -12,15 +13,15 @@ export function encryptStream (handshake: IHandshake): Transform<Uint8Array> {
1213
end = chunk.length
1314
}
1415

15-
const data = handshake.encrypt(chunk.slice(i, end), handshake.session)
16+
const data = handshake.encrypt(chunk.subarray(i, end), handshake.session)
1617
yield data
1718
}
1819
}
1920
}
2021
}
2122

2223
// Decrypt received payload to the user
23-
export function decryptStream (handshake: IHandshake): Transform<Uint8Array> {
24+
export function decryptStream (handshake: IHandshake): Transform<Uint8Array|Uint8ArrayList> {
2425
return async function * (source) {
2526
for await (const chunk of source) {
2627
for (let i = 0; i < chunk.length; i += NOISE_MSG_MAX_LENGTH_BYTES) {
@@ -29,7 +30,7 @@ export function decryptStream (handshake: IHandshake): Transform<Uint8Array> {
2930
end = chunk.length
3031
}
3132

32-
const { plaintext: decrypted, valid } = await handshake.decrypt(chunk.slice(i, end), handshake.session)
33+
const { plaintext: decrypted, valid } = await handshake.decrypt(chunk.subarray(i, end), handshake.session)
3334
if (!valid) {
3435
throw new Error('Failed to validate decrypted chunk')
3536
}

src/encoder.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
22
import type { Uint8ArrayList } from 'uint8arraylist'
33
import type { bytes } from './@types/basic.js'
44
import type { MessageBuffer } from './@types/handshake.js'
5+
import type { LengthDecoderFunction, LengthEncoderFunction } from 'it-length-prefixed'
56

67
const allocUnsafe = (len: number): Uint8Array => {
78
if (globalThis.Buffer) {
@@ -11,14 +12,14 @@ const allocUnsafe = (len: number): Uint8Array => {
1112
return new Uint8Array(len)
1213
}
1314

14-
export const uint16BEEncode = (value: number, target?: Uint8Array, offset?: number): Uint8Array => {
15-
target = target ?? allocUnsafe(2)
16-
new DataView(target.buffer, target.byteOffset, target.byteLength).setUint16(offset ?? 0, value, false)
15+
export const uint16BEEncode: LengthEncoderFunction = (value: number) => {
16+
const target = allocUnsafe(2)
17+
new DataView(target.buffer, target.byteOffset, target.byteLength).setUint16(0, value, false)
1718
return target
1819
}
1920
uint16BEEncode.bytes = 2
2021

21-
export const uint16BEDecode = (data: Uint8Array | Uint8ArrayList): number => {
22+
export const uint16BEDecode: LengthDecoderFunction = (data: Uint8Array | Uint8ArrayList): number => {
2223
if (data.length < 2) throw RangeError('Could not decode int16BE')
2324

2425
if (data instanceof Uint8Array) {
@@ -49,8 +50,8 @@ export function decode0 (input: bytes): MessageBuffer {
4950
}
5051

5152
return {
52-
ne: input.slice(0, 32),
53-
ciphertext: input.slice(32, input.length),
53+
ne: input.subarray(0, 32),
54+
ciphertext: input.subarray(32, input.length),
5455
ns: new Uint8Array(0)
5556
}
5657
}
@@ -61,9 +62,9 @@ export function decode1 (input: bytes): MessageBuffer {
6162
}
6263

6364
return {
64-
ne: input.slice(0, 32),
65-
ns: input.slice(32, 80),
66-
ciphertext: input.slice(80, input.length)
65+
ne: input.subarray(0, 32),
66+
ns: input.subarray(32, 80),
67+
ciphertext: input.subarray(80, input.length)
6768
}
6869
}
6970

@@ -74,7 +75,7 @@ export function decode2 (input: bytes): MessageBuffer {
7475

7576
return {
7677
ne: new Uint8Array(0),
77-
ns: input.slice(0, 48),
78-
ciphertext: input.slice(48, input.length)
78+
ns: input.subarray(0, 48),
79+
ciphertext: input.subarray(48, input.length)
7980
}
8081
}

src/handshake-ik.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export class IKHandshake implements IHandshake {
8383
const err = e as Error
8484
logger('Responder breaking up with IK handshake in stage 0.')
8585

86-
throw new FailedIKError(receivedMsg, `Error occurred while verifying initiator's signed payload: ${err.message}`)
86+
throw new FailedIKError(receivedMsg.slice(), `Error occurred while verifying initiator's signed payload: ${err.message}`)
8787
}
8888
}
8989
}

src/handshake-xx.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export class XXHandshake implements IHandshake {
6969
logLocalEphemeralKeys(this.session.hs.e)
7070
} else {
7171
logger('Stage 0 - Responder waiting to receive first message...')
72-
const receivedMessageBuffer = decode0((await this.connection.readLP()).slice())
72+
const receivedMessageBuffer = decode0((await this.connection.readLP()).subarray())
7373
const { valid } = this.xx.recvMessage(this.session, receivedMessageBuffer)
7474
if (!valid) {
7575
throw new InvalidCryptoExchangeError('xx handshake stage 0 validation fail')
@@ -83,7 +83,7 @@ export class XXHandshake implements IHandshake {
8383
public async exchange (): Promise<void> {
8484
if (this.isInitiator) {
8585
logger('Stage 1 - Initiator waiting to receive first message from responder...')
86-
const receivedMessageBuffer = decode1((await this.connection.readLP()).slice())
86+
const receivedMessageBuffer = decode1((await this.connection.readLP()).subarray())
8787
const { plaintext, valid } = this.xx.recvMessage(this.session, receivedMessageBuffer)
8888
if (!valid) {
8989
throw new InvalidCryptoExchangeError('xx handshake stage 1 validation fail')
@@ -121,7 +121,7 @@ export class XXHandshake implements IHandshake {
121121
logger('Stage 2 - Initiator sent message with signed payload.')
122122
} else {
123123
logger('Stage 2 - Responder waiting for third handshake message...')
124-
const receivedMessageBuffer = decode2((await this.connection.readLP()).slice())
124+
const receivedMessageBuffer = decode2((await this.connection.readLP()).subarray())
125125
const { plaintext, valid } = this.xx.recvMessage(this.session, receivedMessageBuffer)
126126
if (!valid) {
127127
throw new InvalidCryptoExchangeError('xx handshake stage 2 validation fail')

src/handshakes/abstract-handshake.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export abstract class AbstractHandshake {
9898
return derivedU8
9999
}
100100

101-
return derivedU8.slice(0, 32)
101+
return derivedU8.subarray(0, 32)
102102
} catch (e) {
103103
const err = e as Error
104104
logger(err.message)

src/proto/payload.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import { encodeMessage, decodeMessage, message, bytes } from 'protons-runtime'
55
import type { Codec } from 'protons-runtime'
6+
import type { Uint8ArrayList } from 'uint8arraylist'
67

78
export namespace pb {
89
export interface NoiseHandshakePayload {
@@ -20,11 +21,11 @@ export namespace pb {
2021
})
2122
}
2223

23-
export const encode = (obj: NoiseHandshakePayload): Uint8Array => {
24+
export const encode = (obj: NoiseHandshakePayload): Uint8ArrayList => {
2425
return encodeMessage(obj, NoiseHandshakePayload.codec())
2526
}
2627

27-
export const decode = (buf: Uint8Array): NoiseHandshakePayload => {
28+
export const decode = (buf: Uint8Array | Uint8ArrayList): NoiseHandshakePayload => {
2829
return decodeMessage(buf, NoiseHandshakePayload.codec())
2930
}
3031
}

src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export function createHandshakePayload (
3636
identityKey: libp2pPublicKey,
3737
identitySig: signedPayload,
3838
data: earlyData ?? new Uint8Array(0)
39-
})
39+
}).subarray()
4040
}
4141

4242
export async function signPayload (peerId: PeerId, payload: bytes): Promise<bytes> {

test/noise.spec.ts

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { duplexPair } from 'it-pair/duplex'
66
import { pbStream } from 'it-pb-stream'
77
import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
88
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
9-
import { Uint8ArrayList } from 'uint8arraylist'
9+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
1010
import sinon from 'sinon'
1111
import { NOISE_MSG_MAX_LENGTH_BYTES } from '../src/constants.js'
1212
import { stablelib } from '../src/crypto/stablelib.js'
@@ -95,23 +95,15 @@ describe('Noise', () => {
9595
})()
9696
])
9797

98-
try {
99-
const wrappedOutbound = pbStream(outbound.conn)
100-
wrappedOutbound.write(new Uint8ArrayList(Buffer.from('test')))
101-
102-
// Check that noise message is prefixed with 16-bit big-endian unsigned integer
103-
const receivedEncryptedPayload = (await wrapped.read()).slice()
104-
const view = new DataView(receivedEncryptedPayload.buffer, receivedEncryptedPayload.byteOffset, receivedEncryptedPayload.byteLength)
105-
const dataLength = view.getInt16(0)
106-
const data = receivedEncryptedPayload.slice(2, dataLength + 2)
107-
const { plaintext: decrypted, valid } = handshake.decrypt(data, handshake.session)
108-
// Decrypted data should match
109-
assert(uint8ArrayEquals(decrypted, Buffer.from('test')))
110-
assert(valid)
111-
} catch (e) {
112-
const err = e as Error
113-
assert(false, err.message)
114-
}
98+
const wrappedOutbound = pbStream(outbound.conn)
99+
wrappedOutbound.write(uint8ArrayFromString('test'))
100+
101+
// Check that noise message is prefixed with 16-bit big-endian unsigned integer
102+
const data = await (await wrapped.readLP()).slice()
103+
const { plaintext: decrypted, valid } = handshake.decrypt(data, handshake.session)
104+
// Decrypted data should match
105+
expect(uint8ArrayEquals(decrypted, uint8ArrayFromString('test'))).to.be.true()
106+
expect(valid).to.be.true()
115107
})
116108

117109
it('should test large payloads', async function () {

0 commit comments

Comments
 (0)