Skip to content

Commit d61a8e9

Browse files
tp26610boorad
andauthored
fix: handle sliced Buffer byte ranges in ECDH/DH native bridge (#973)
Co-authored-by: Brad Anderson <brad@sankatygroup.com>
1 parent ca27455 commit d61a8e9

4 files changed

Lines changed: 50 additions & 16 deletions

File tree

example/src/tests/ecdh/ecdh_tests.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,44 @@ test(SUITE, 'should set private key and compute secret for secp256k1', () => {
132132
assert.strictEqual(secret1.toString('hex'), secret2.toString('hex'));
133133
});
134134

135+
test(SUITE, 'should compute secret with sliced public key buffer', () => {
136+
const alice = crypto.createECDH('secp256k1');
137+
alice.generateKeys();
138+
139+
const bob = crypto.createECDH('secp256k1');
140+
bob.generateKeys();
141+
142+
const bobPub = bob.getPublicKey() as Buffer;
143+
assert.isTrue(Buffer.isBuffer(bobPub), 'public key should be a Buffer');
144+
145+
// Force non-zero byteOffset by slicing from a larger packet.
146+
const packet = Buffer.concat([
147+
Buffer.from([0xaa, 0xbb]),
148+
bobPub,
149+
Buffer.from([0xcc]),
150+
]);
151+
const bobPubSlice = packet.slice(2, 2 + bobPub.length);
152+
assert.strictEqual(
153+
bobPubSlice.length,
154+
bobPub.length,
155+
'slice length should match key length',
156+
);
157+
assert.isAbove(
158+
bobPubSlice.byteOffset,
159+
0,
160+
'slice should have non-zero byteOffset',
161+
);
162+
163+
const secretFromOriginal = alice.computeSecret(bobPub);
164+
const secretFromSlice = alice.computeSecret(bobPubSlice);
165+
166+
assert.strictEqual(
167+
secretFromSlice.toString('hex'),
168+
secretFromOriginal.toString('hex'),
169+
'sliced public key should derive the same shared secret',
170+
);
171+
});
172+
135173
test(SUITE, 'getCurves - should return array of supported curves', () => {
136174
const curves = getCurves();
137175
assert.isArray(curves);

packages/react-native-quick-crypto/src/blake3.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Buffer } from '@craftzdog/react-native-buffer';
33
import type { Blake3 as NativeBlake3 } from './specs/blake3.nitro';
44
import type { BinaryLike, Encoding } from './utils';
55
import { binaryLikeToArrayBuffer, ab2str } from './utils';
6+
import { toArrayBuffer } from './utils/conversion';
67

78
const BLAKE3_KEY_LEN = 32;
89
const BLAKE3_OUT_LEN = 32;
@@ -34,7 +35,7 @@ export class Blake3 {
3435
}
3536
this.mode = 'keyed';
3637
this.keyData = opts.key;
37-
this.native.initKeyed(opts.key.buffer as ArrayBuffer);
38+
this.native.initKeyed(toArrayBuffer(opts.key));
3839
} else if (opts?.context !== undefined) {
3940
if (typeof opts.context !== 'string' || opts.context.length === 0) {
4041
throw new Error('BLAKE3: context must be a non-empty string');

packages/react-native-quick-crypto/src/diffie-hellman.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { NitroModules } from 'react-native-nitro-modules';
22
import type { DiffieHellman as DiffieHellmanInterface } from './specs/diffie-hellman.nitro';
33
import { Buffer } from '@craftzdog/react-native-buffer';
44
import { DH_GROUPS } from './dh-groups';
5+
import { toArrayBuffer } from './utils/conversion';
56

67
export class DiffieHellman {
78
private _hybrid: DiffieHellmanInterface;
@@ -36,10 +37,7 @@ export class DiffieHellman {
3637
genBuf = Buffer.from(generator, encoding as BufferEncoding);
3738
}
3839

39-
this._hybrid.init(
40-
primeBuf.buffer as ArrayBuffer,
41-
genBuf.buffer as ArrayBuffer,
42-
);
40+
this._hybrid.init(toArrayBuffer(primeBuf), toArrayBuffer(genBuf));
4341
}
4442
}
4543

@@ -62,7 +60,7 @@ export class DiffieHellman {
6260
}
6361

6462
const secret = Buffer.from(
65-
this._hybrid.computeSecret(keyBuf.buffer as ArrayBuffer),
63+
this._hybrid.computeSecret(toArrayBuffer(keyBuf)),
6664
);
6765
if (outputEncoding) return secret.toString(outputEncoding);
6866
return secret;
@@ -99,7 +97,7 @@ export class DiffieHellman {
9997
} else {
10098
keyBuf = Buffer.from(publicKey, encoding);
10199
}
102-
this._hybrid.setPublicKey(keyBuf.buffer as ArrayBuffer);
100+
this._hybrid.setPublicKey(toArrayBuffer(keyBuf));
103101
}
104102

105103
setPrivateKey(privateKey: Buffer | string, encoding?: BufferEncoding): void {
@@ -109,7 +107,7 @@ export class DiffieHellman {
109107
} else {
110108
keyBuf = Buffer.from(privateKey, encoding);
111109
}
112-
this._hybrid.setPrivateKey(keyBuf.buffer as ArrayBuffer);
110+
this._hybrid.setPrivateKey(toArrayBuffer(keyBuf));
113111
}
114112

115113
get verifyError(): number {

packages/react-native-quick-crypto/src/ecdh.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { NitroModules } from 'react-native-nitro-modules';
22
import type { ECDH as ECDHInterface } from './specs/ecdh.nitro';
33
import { Buffer } from '@craftzdog/react-native-buffer';
4+
import { toArrayBuffer } from './utils/conversion';
45

56
const POINT_CONVERSION_COMPRESSED = 2;
67
const POINT_CONVERSION_UNCOMPRESSED = 4;
@@ -43,7 +44,7 @@ export class ECDH {
4344
}
4445

4546
// ECDH.computeSecret in Node.js returns Buffer
46-
const secret = this._hybrid.computeSecret(keyBuf.buffer as ArrayBuffer);
47+
const secret = this._hybrid.computeSecret(toArrayBuffer(keyBuf));
4748
return Buffer.from(secret);
4849
}
4950

@@ -58,7 +59,7 @@ export class ECDH {
5859
} else {
5960
keyBuf = Buffer.from(privateKey, encoding);
6061
}
61-
this._hybrid.setPrivateKey(keyBuf.buffer as ArrayBuffer);
62+
this._hybrid.setPrivateKey(toArrayBuffer(keyBuf));
6263
}
6364

6465
getPublicKey(encoding?: BufferEncoding): Buffer | string {
@@ -80,7 +81,7 @@ export class ECDH {
8081
} else {
8182
keyBuf = Buffer.from(publicKey, encoding);
8283
}
83-
this._hybrid.setPublicKey(keyBuf.buffer as ArrayBuffer);
84+
this._hybrid.setPublicKey(toArrayBuffer(keyBuf));
8485
}
8586

8687
static convertKey(
@@ -116,11 +117,7 @@ export class ECDH {
116117
}
117118

118119
const result = Buffer.from(
119-
ECDH.convertKeyHybrid.convertKey(
120-
keyBuf.buffer as ArrayBuffer,
121-
curve,
122-
formatNum,
123-
),
120+
ECDH.convertKeyHybrid.convertKey(toArrayBuffer(keyBuf), curve, formatNum),
124121
);
125122

126123
if (outputEncoding) {

0 commit comments

Comments
 (0)