diff --git a/example/src/tests/ecdh/ecdh_tests.ts b/example/src/tests/ecdh/ecdh_tests.ts index 884891fb..75902fe8 100644 --- a/example/src/tests/ecdh/ecdh_tests.ts +++ b/example/src/tests/ecdh/ecdh_tests.ts @@ -132,6 +132,44 @@ test(SUITE, 'should set private key and compute secret for secp256k1', () => { assert.strictEqual(secret1.toString('hex'), secret2.toString('hex')); }); +test(SUITE, 'should compute secret with sliced public key buffer', () => { + const alice = crypto.createECDH('secp256k1'); + alice.generateKeys(); + + const bob = crypto.createECDH('secp256k1'); + bob.generateKeys(); + + const bobPub = bob.getPublicKey() as Buffer; + assert.isTrue(Buffer.isBuffer(bobPub), 'public key should be a Buffer'); + + // Force non-zero byteOffset by slicing from a larger packet. + const packet = Buffer.concat([ + Buffer.from([0xaa, 0xbb]), + bobPub, + Buffer.from([0xcc]), + ]); + const bobPubSlice = packet.slice(2, 2 + bobPub.length); + assert.strictEqual( + bobPubSlice.length, + bobPub.length, + 'slice length should match key length', + ); + assert.isAbove( + bobPubSlice.byteOffset, + 0, + 'slice should have non-zero byteOffset', + ); + + const secretFromOriginal = alice.computeSecret(bobPub); + const secretFromSlice = alice.computeSecret(bobPubSlice); + + assert.strictEqual( + secretFromSlice.toString('hex'), + secretFromOriginal.toString('hex'), + 'sliced public key should derive the same shared secret', + ); +}); + test(SUITE, 'getCurves - should return array of supported curves', () => { const curves = getCurves(); assert.isArray(curves); diff --git a/packages/react-native-quick-crypto/src/diffie-hellman.ts b/packages/react-native-quick-crypto/src/diffie-hellman.ts index 84ea8e68..308f6071 100644 --- a/packages/react-native-quick-crypto/src/diffie-hellman.ts +++ b/packages/react-native-quick-crypto/src/diffie-hellman.ts @@ -2,6 +2,7 @@ import { NitroModules } from 'react-native-nitro-modules'; import type { DiffieHellman as DiffieHellmanInterface } from './specs/diffie-hellman.nitro'; import { Buffer } from '@craftzdog/react-native-buffer'; import { DH_GROUPS } from './dh-groups'; +import { toArrayBuffer } from './utils/conversion'; export class DiffieHellman { private _hybrid: DiffieHellmanInterface; @@ -36,10 +37,7 @@ export class DiffieHellman { genBuf = Buffer.from(generator, encoding as BufferEncoding); } - this._hybrid.init( - primeBuf.buffer as ArrayBuffer, - genBuf.buffer as ArrayBuffer, - ); + this._hybrid.init(toArrayBuffer(primeBuf), toArrayBuffer(genBuf)); } } @@ -62,7 +60,7 @@ export class DiffieHellman { } const secret = Buffer.from( - this._hybrid.computeSecret(keyBuf.buffer as ArrayBuffer), + this._hybrid.computeSecret(toArrayBuffer(keyBuf)), ); if (outputEncoding) return secret.toString(outputEncoding); return secret; @@ -99,7 +97,7 @@ export class DiffieHellman { } else { keyBuf = Buffer.from(publicKey, encoding); } - this._hybrid.setPublicKey(keyBuf.buffer as ArrayBuffer); + this._hybrid.setPublicKey(toArrayBuffer(keyBuf)); } setPrivateKey(privateKey: Buffer | string, encoding?: BufferEncoding): void { @@ -109,7 +107,7 @@ export class DiffieHellman { } else { keyBuf = Buffer.from(privateKey, encoding); } - this._hybrid.setPrivateKey(keyBuf.buffer as ArrayBuffer); + this._hybrid.setPrivateKey(toArrayBuffer(keyBuf)); } get verifyError(): number { diff --git a/packages/react-native-quick-crypto/src/ecdh.ts b/packages/react-native-quick-crypto/src/ecdh.ts index 677d38a5..5136a3be 100644 --- a/packages/react-native-quick-crypto/src/ecdh.ts +++ b/packages/react-native-quick-crypto/src/ecdh.ts @@ -1,6 +1,7 @@ import { NitroModules } from 'react-native-nitro-modules'; import type { ECDH as ECDHInterface } from './specs/ecdh.nitro'; import { Buffer } from '@craftzdog/react-native-buffer'; +import { toArrayBuffer } from './utils/conversion'; const POINT_CONVERSION_COMPRESSED = 2; const POINT_CONVERSION_UNCOMPRESSED = 4; @@ -43,7 +44,7 @@ export class ECDH { } // ECDH.computeSecret in Node.js returns Buffer - const secret = this._hybrid.computeSecret(keyBuf.buffer as ArrayBuffer); + const secret = this._hybrid.computeSecret(toArrayBuffer(keyBuf)); return Buffer.from(secret); } @@ -58,7 +59,7 @@ export class ECDH { } else { keyBuf = Buffer.from(privateKey, encoding); } - this._hybrid.setPrivateKey(keyBuf.buffer as ArrayBuffer); + this._hybrid.setPrivateKey(toArrayBuffer(keyBuf)); } getPublicKey(encoding?: BufferEncoding): Buffer | string { @@ -80,7 +81,7 @@ export class ECDH { } else { keyBuf = Buffer.from(publicKey, encoding); } - this._hybrid.setPublicKey(keyBuf.buffer as ArrayBuffer); + this._hybrid.setPublicKey(toArrayBuffer(keyBuf)); } static convertKey( @@ -116,11 +117,7 @@ export class ECDH { } const result = Buffer.from( - ECDH.convertKeyHybrid.convertKey( - keyBuf.buffer as ArrayBuffer, - curve, - formatNum, - ), + ECDH.convertKeyHybrid.convertKey(toArrayBuffer(keyBuf), curve, formatNum), ); if (outputEncoding) {