diff --git a/src/crypto.ts b/src/crypto.ts index 1bdb323..73ef192 100644 --- a/src/crypto.ts +++ b/src/crypto.ts @@ -1,15 +1,13 @@ import { ChaCha20Poly1305 } from "@stablelib/chacha20poly1305"; import { Hash } from "@stablelib/hash"; import { HKDF as hkdf } from "@stablelib/hkdf"; +import { RandomSource } from "@stablelib/random"; import { hash } from "@stablelib/sha256"; -import * as x25519 from "@stablelib/x25519"; import { concat as uint8ArrayConcat } from "uint8arrays/concat"; import type { bytes32 } from "./@types/basic.js"; import type { KeyPair } from "./@types/keypair.js"; -export const Curve25519KeySize = x25519.PUBLIC_KEY_LENGTH; - /** * Generate hash using SHA2-256 * @param data data to hash @@ -19,21 +17,6 @@ export function hashSHA256(data: Uint8Array): Uint8Array { return hash(data); } -/** - * Convert an Uint8Array into a 32-byte value. If the input data length is different - * from 32, throw an error. This is used mostly as a validation function to ensure - * that an Uint8Array represents a valid x25519 key - * @param s input data - * @return 32-byte key - */ -export function intoCurve25519Key(s: Uint8Array): bytes32 { - if (s.length != x25519.PUBLIC_KEY_LENGTH) { - throw new Error("invalid public key length"); - } - - return s; -} - /** * HKDF key derivation function using SHA256 * @param ck chaining key @@ -59,33 +42,6 @@ export function HKDF( return result; } -/** - * Generate a random keypair - * @returns Keypair - */ -export function generateX25519KeyPair(): KeyPair { - const keypair = x25519.generateKeyPair(); - - return { - publicKey: keypair.publicKey, - privateKey: keypair.secretKey, - }; -} - -/** - * Generate x25519 keypair using an input seed - * @param seed 32-byte secret - * @returns Keypair - */ -export function generateX25519KeyPairFromSeed(seed: bytes32): KeyPair { - const keypair = x25519.generateKeyPairFromSeed(seed); - - return { - publicKey: keypair.publicKey, - privateKey: keypair.secretKey, - }; -} - /** * Encrypt and authenticate data using ChaCha20-Poly1305 * @param plaintext data to encrypt @@ -123,27 +79,6 @@ export function chaCha20Poly1305Decrypt( return ctx.open(nonce, ciphertext, ad); } -/** - * Perform a Diffie–Hellman key exchange - * @param privateKey x25519 private key - * @param publicKey x25519 public key - * @returns shared secret - */ -export function dh(privateKey: bytes32, publicKey: bytes32): bytes32 { - try { - const derivedU8 = x25519.sharedKey(privateKey, publicKey); - - if (derivedU8.length === 32) { - return derivedU8; - } - - return derivedU8.subarray(0, 32); - } catch (e) { - console.error(e); - return new Uint8Array(32); - } -} - /** * Generates a random static key commitment using a public key pk for randomness r as H(pk || s) * @param publicKey x25519 public key @@ -153,3 +88,43 @@ export function dh(privateKey: bytes32, publicKey: bytes32): bytes32 { export function commitPublicKey(publicKey: bytes32, r: Uint8Array): bytes32 { return hashSHA256(uint8ArrayConcat([publicKey, r])); } + +/** + * Represents a key uses for Diffie–Hellman key exchange + */ +export interface DHKey { + /** + * Convert an Uint8Array into a 32-byte value. If the input data length is different + * from 32, throw an error. This is used mostly as a validation function to ensure + * that an Uint8Array represents a valid key + * @param s input data + * @return 32-byte key + */ + intoKey(s: Uint8Array): bytes32; + + /** + * Get key length + */ + DHLen(): number; + + /** + * Perform a Diffie–Hellman key exchange + * @param privateKey private key + * @param publicKey public key + * @returns shared secret + */ + DH(privateKey: bytes32, publicKey: bytes32): bytes32; + + /** + * Generate a random keypair + * @returns Keypair + */ + generateKeyPair(prng?: RandomSource): KeyPair; + + /** + * Generate keypair using an input seed + * @param seed 32-byte secret + * @returns Keypair + */ + generateKeyPairFromSeed(seed: bytes32): KeyPair; +} diff --git a/src/dh25519.ts b/src/dh25519.ts new file mode 100644 index 0000000..c698fa5 --- /dev/null +++ b/src/dh25519.ts @@ -0,0 +1,52 @@ +import * as x25519 from "@stablelib/x25519"; + +import type { bytes32 } from "./@types/basic.js"; +import type { KeyPair } from "./@types/keypair.js"; +import { DHKey } from "./crypto.js"; + +export class DH25519 implements DHKey { + intoKey(s: Uint8Array): bytes32 { + if (s.length != x25519.PUBLIC_KEY_LENGTH) { + throw new Error("invalid public key length"); + } + + return s; + } + + generateKeyPair(): KeyPair { + const keypair = x25519.generateKeyPair(); + + return { + publicKey: keypair.publicKey, + privateKey: keypair.secretKey, + }; + } + + generateKeyPairFromSeed(seed: bytes32): KeyPair { + const keypair = x25519.generateKeyPairFromSeed(seed); + + return { + publicKey: keypair.publicKey, + privateKey: keypair.secretKey, + }; + } + + DH(privateKey: bytes32, publicKey: bytes32): bytes32 { + try { + const derivedU8 = x25519.sharedKey(privateKey, publicKey); + + if (derivedU8.length === 32) { + return derivedU8; + } + + return derivedU8.subarray(0, 32); + } catch (e) { + console.error(e); + return new Uint8Array(32); + } + } + + DHLen(): number { + return x25519.PUBLIC_KEY_LENGTH; + } +} diff --git a/src/handshake_state.ts b/src/handshake_state.ts index 0f9f2e8..3b161ba 100644 --- a/src/handshake_state.ts +++ b/src/handshake_state.ts @@ -5,7 +5,7 @@ import { equals as uint8ArrayEquals } from "uint8arrays/equals"; import { bytes32 } from "./@types/basic.js"; import { MessageNametag } from "./@types/handshake.js"; import type { KeyPair } from "./@types/keypair.js"; -import { Curve25519KeySize, dh, generateX25519KeyPair, HKDF, intoCurve25519Key } from "./crypto.js"; +import { HKDF } from "./crypto.js"; import { MessageNametagLength } from "./messagenametag.js"; import { SymmetricState } from "./noise.js"; import { HandshakePattern, MessageDirection, NoiseTokens, PreMessagePattern } from "./patterns.js"; @@ -212,7 +212,7 @@ export class HandshakeState { // We check if current key is encrypted or not. We assume pre-message public keys are all unencrypted on users' end if (currPK.flag == 0) { // Sets re and calls MixHash(re.public_key). - this.re = intoCurve25519Key(currPK.pk); + this.re = this.handshakePattern.dhKey.intoKey(currPK.pk); this.ss.mixHash(this.re); } else { throw new Error("noise read e, incorrect encryption flag for pre-message public key"); @@ -223,7 +223,7 @@ export class HandshakeState { // When writing, the user is sending a public key, // We check that the public part corresponds to the set local key and we call MixHash(e.public_key). - if (this.e && uint8ArrayEquals(this.e.publicKey, intoCurve25519Key(currPK.pk))) { + if (this.e && uint8ArrayEquals(this.e.publicKey, this.handshakePattern.dhKey.intoKey(currPK.pk))) { this.ss.mixHash(this.e.publicKey); } else { throw new Error("noise pre-message e key doesn't correspond to locally set e key pair"); @@ -256,7 +256,7 @@ export class HandshakeState { // We check if current key is encrypted or not. We assume pre-message public keys are all unencrypted on users' end if (currPK.flag == 0) { // Sets re and calls MixHash(re.public_key). - this.rs = intoCurve25519Key(currPK.pk); + this.rs = this.handshakePattern.dhKey.intoKey(currPK.pk); this.ss.mixHash(this.rs); } else { throw new Error("noise read s, incorrect encryption flag for pre-message public key"); @@ -268,7 +268,7 @@ export class HandshakeState { // If writing, it means that the user is sending a public key, // We check that the public part corresponds to the set local key and we call MixHash(s.public_key). - if (this.s && uint8ArrayEquals(this.s.publicKey, intoCurve25519Key(currPK.pk))) { + if (this.s && uint8ArrayEquals(this.s.publicKey, this.handshakePattern.dhKey.intoKey(currPK.pk))) { this.ss.mixHash(this.s.publicKey); } else { throw new Error("noise pre-message s key doesn't correspond to locally set s key pair"); @@ -358,14 +358,14 @@ export class HandshakeState { if (currPK.flag == 0) { // Unencrypted Public Key // Sets re and calls MixHash(re.public_key). - this.re = intoCurve25519Key(currPK.pk); + this.re = this.handshakePattern.dhKey.intoKey(currPK.pk); this.ss.mixHash(this.re); // The following is out of specification: we call decryptAndHash for encrypted ephemeral keys, similarly as happens for (encrypted) static keys } else if (currPK.flag == 1) { // Encrypted public key // Decrypts re, sets re and calls MixHash(re.public_key). - this.re = intoCurve25519Key(this.ss.decryptAndHash(currPK.pk)); + this.re = this.handshakePattern.dhKey.intoKey(this.ss.decryptAndHash(currPK.pk)); } else { throw new Error("noise read e, incorrect encryption flag for public key"); } @@ -386,7 +386,7 @@ export class HandshakeState { log("noise write e"); // We generate a new ephemeral keypair - this.e = generateX25519KeyPair(); + this.e = this.handshakePattern.dhKey.generateKeyPair(); // We update the state this.ss.mixHash(this.e.publicKey); @@ -420,12 +420,12 @@ export class HandshakeState { if (currPK.flag == 0) { // Unencrypted Public Key // Sets re and calls MixHash(re.public_key). - this.rs = intoCurve25519Key(currPK.pk); + this.rs = this.handshakePattern.dhKey.intoKey(currPK.pk); this.ss.mixHash(this.rs); } else if (currPK.flag == 1) { // Encrypted public key // Decrypts rs, sets rs and calls MixHash(rs.public_key). - this.rs = intoCurve25519Key(this.ss.decryptAndHash(currPK.pk)); + this.rs = this.handshakePattern.dhKey.intoKey(this.ss.decryptAndHash(currPK.pk)); } else { throw new Error("noise read s, incorrect encryption flag for public key"); } @@ -449,7 +449,7 @@ export class HandshakeState { // We add the (encrypted) static public key to the Waku payload // Note that encS = (Enc(s) || tag) if encryption key is set, otherwise encS = s. // We distinguish these two cases by checking length of encryption and we set the proper encryption flag - if (encS.length > Curve25519KeySize) { + if (encS.length > this.handshakePattern.dhKey.DHLen()) { outHandshakeMessage.push(new NoisePublicKey(1, encS)); } else { outHandshakeMessage.push(new NoisePublicKey(0, encS)); @@ -478,7 +478,7 @@ export class HandshakeState { } // Calls MixKey(DH(e, re)). - this.ss.mixKey(dh(this.e.privateKey, this.re)); + this.ss.mixKey(this.handshakePattern.dhKey.DH(this.e.privateKey, this.re)); break; case NoiseTokens.es: @@ -493,13 +493,13 @@ export class HandshakeState { throw new Error("local or remote ephemeral/static key not set"); } - this.ss.mixKey(dh(this.e.privateKey, this.rs)); + this.ss.mixKey(this.handshakePattern.dhKey.DH(this.e.privateKey, this.rs)); } else { if (!this.re || !this.s) { throw new Error("local or remote ephemeral/static key not set"); } - this.ss.mixKey(dh(this.s.privateKey, this.re)); + this.ss.mixKey(this.handshakePattern.dhKey.DH(this.s.privateKey, this.re)); } break; @@ -515,13 +515,13 @@ export class HandshakeState { throw new Error("local or remote ephemeral/static key not set"); } - this.ss.mixKey(dh(this.s.privateKey, this.re)); + this.ss.mixKey(this.handshakePattern.dhKey.DH(this.s.privateKey, this.re)); } else { if (!this.rs || !this.e) { throw new Error("local or remote ephemeral/static key not set"); } - this.ss.mixKey(dh(this.e.privateKey, this.rs)); + this.ss.mixKey(this.handshakePattern.dhKey.DH(this.e.privateKey, this.rs)); } break; @@ -536,7 +536,7 @@ export class HandshakeState { } // Calls MixKey(DH(s, rs)). - this.ss.mixKey(dh(this.s.privateKey, this.rs)); + this.ss.mixKey(this.handshakePattern.dhKey.DH(this.s.privateKey, this.rs)); break; } } diff --git a/src/index.spec.ts b/src/index.spec.ts index c8fb8fd..39a62a2 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -3,7 +3,8 @@ import { randomBytes } from "@stablelib/random"; import { expect } from "chai"; import { equals as uint8ArrayEquals } from "uint8arrays/equals"; -import { chaCha20Poly1305Encrypt, dh, generateX25519KeyPair } from "./crypto"; +import { chaCha20Poly1305Encrypt } from "./crypto"; +import { DH25519 } from "./dh25519"; import { Handshake, HandshakeStepResult } from "./handshake"; import { MessageNametagBuffer, MessageNametagLength } from "./messagenametag"; import { CipherState, createEmptyKey, SymmetricState } from "./noise"; @@ -31,7 +32,8 @@ function randomChaChaPolyCipherState(rng: HMACDRBG): ChaChaPolyCipherState { } function randomNoisePublicKey(): NoisePublicKey { - const keypair = generateX25519KeyPair(); + const dhKey = new DH25519(); + const keypair = dhKey.generateKeyPair(); return new NoisePublicKey(0, keypair.publicKey); } @@ -138,13 +140,15 @@ describe("js-noise", () => { }); it("Noise State Machine: Diffie-Hellman operation", function () { - const aliceKey = generateX25519KeyPair(); - const bobKey = generateX25519KeyPair(); + const dhKey = new DH25519(); + + const aliceKey = dhKey.generateKeyPair(); + const bobKey = dhKey.generateKeyPair(); // A Diffie-Hellman operation between Alice's private key and Bob's public key must be equal to // a Diffie-hellman operation between Alice's public key and Bob's private key - const dh1 = dh(aliceKey.privateKey, bobKey.publicKey); - const dh2 = dh(bobKey.privateKey, aliceKey.publicKey); + const dh1 = dhKey.DH(aliceKey.privateKey, bobKey.publicKey); + const dh2 = dhKey.DH(bobKey.privateKey, aliceKey.publicKey); expect(uint8ArrayEquals(dh1, dh2)).to.be.true; }); @@ -355,13 +359,14 @@ describe("js-noise", () => { }); it("Noise XX Handshake and message encryption (extended test)", function () { + const dhKey = new DH25519(); const hsPattern = NoiseHandshakePatterns.Noise_XX_25519_ChaChaPoly_SHA256; // We initialize Alice's and Bob's Handshake State - const aliceStaticKey = generateX25519KeyPair(); + const aliceStaticKey = dhKey.generateKeyPair(); const aliceHS = new Handshake({ hsPattern, staticKey: aliceStaticKey, initiator: true }); - const bobStaticKey = generateX25519KeyPair(); + const bobStaticKey = dhKey.generateKeyPair(); const bobHS = new Handshake({ hsPattern, staticKey: bobStaticKey }); let sentTransportMessage: Uint8Array; @@ -466,16 +471,17 @@ describe("js-noise", () => { }); it("Noise XXpsk0 Handhshake and message encryption (short test)", function () { + const dhKey = new DH25519(); const hsPattern = NoiseHandshakePatterns.Noise_XXpsk0_25519_ChaChaPoly_SHA256; // We generate a random psk const psk = randomBytes(32, rng); // We initialize Alice's and Bob's Handshake State - const aliceStaticKey = generateX25519KeyPair(); + const aliceStaticKey = dhKey.generateKeyPair(); const aliceHS = new Handshake({ hsPattern, staticKey: aliceStaticKey, psk, initiator: true }); - const bobStaticKey = generateX25519KeyPair(); + const bobStaticKey = dhKey.generateKeyPair(); const bobHS = new Handshake({ hsPattern, staticKey: bobStaticKey, psk }); let sentTransportMessage: Uint8Array; @@ -561,12 +567,13 @@ describe("js-noise", () => { }); it("Noise K1K1 Handhshake and message encryption (short test)", function () { + const dhKey = new DH25519(); const hsPattern = NoiseHandshakePatterns.Noise_K1K1_25519_ChaChaPoly_SHA256; // We initialize Alice's and Bob's Handshake State - const aliceStaticKey = generateX25519KeyPair(); + const aliceStaticKey = dhKey.generateKeyPair(); - const bobStaticKey = generateX25519KeyPair(); + const bobStaticKey = dhKey.generateKeyPair(); // This handshake has the following pre-message pattern: // -> s @@ -663,11 +670,12 @@ describe("js-noise", () => { }); it("Noise XK1 Handhshake and message encryption (short test)", function () { + const dhKey = new DH25519(); const hsPattern = NoiseHandshakePatterns.Noise_XK1_25519_ChaChaPoly_SHA256; // We initialize Alice's and Bob's Handshake State - const aliceStaticKey = generateX25519KeyPair(); - const bobStaticKey = generateX25519KeyPair(); + const aliceStaticKey = dhKey.generateKeyPair(); + const bobStaticKey = dhKey.generateKeyPair(); // This handshake has the following pre-message pattern: // <- s diff --git a/src/index.ts b/src/index.ts index 10bde26..125764b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,7 +4,7 @@ import { NoiseSecureTransferDecoder, NoiseSecureTransferEncoder, } from "./codec.js"; -import { generateX25519KeyPair, generateX25519KeyPairFromSeed } from "./crypto.js"; +import { DH25519 } from "./dh25519.js"; import { Handshake, HandshakeParameters, @@ -35,7 +35,7 @@ export { MessageNametagError, StepHandshakeParameters, }; -export { generateX25519KeyPair, generateX25519KeyPairFromSeed }; +export { DH25519 as X25519DHKey }; export { HandshakePattern, MessageDirection, diff --git a/src/pairing.spec.ts b/src/pairing.spec.ts index e2d292a..3156565 100644 --- a/src/pairing.spec.ts +++ b/src/pairing.spec.ts @@ -7,7 +7,7 @@ import { pEvent } from "p-event"; import { equals as uint8ArrayEquals } from "uint8arrays/equals"; import { NoiseHandshakeMessage } from "./codec"; -import { generateX25519KeyPair } from "./crypto"; +import { DH25519 } from "./dh25519"; import { MessageNametagBufferSize } from "./messagenametag"; import { ResponderParameters, WakuPairing } from "./pairing"; @@ -66,8 +66,10 @@ describe("js-noise: pairing object", () => { // ================= it("should pair", async function () { - const bobStaticKey = generateX25519KeyPair(); - const aliceStaticKey = generateX25519KeyPair(); + const dhKey = new DH25519(); + + const bobStaticKey = dhKey.generateKeyPair(); + const aliceStaticKey = dhKey.generateKeyPair(); const recvParameters = new ResponderParameters(); const bobPairingObj = new WakuPairing(sender, responder, bobStaticKey, recvParameters); @@ -112,8 +114,9 @@ describe("js-noise: pairing object", () => { }); it("should timeout", async function () { - const bobPairingObj = new WakuPairing(sender, responder, generateX25519KeyPair(), new ResponderParameters()); - const alicePairingObj = new WakuPairing(sender, responder, generateX25519KeyPair(), bobPairingObj.getPairingInfo()); + const dhKey = new DH25519(); + const bobPairingObj = new WakuPairing(sender, responder, dhKey.generateKeyPair(), new ResponderParameters()); + const alicePairingObj = new WakuPairing(sender, responder, dhKey.generateKeyPair(), bobPairingObj.getPairingInfo()); const bobExecP1 = bobPairingObj.execute(1000); const aliceExecP1 = alicePairingObj.execute(1000); @@ -130,8 +133,9 @@ describe("js-noise: pairing object", () => { }); it("pairs and `meta` field is encoded", async function () { - const bobStaticKey = generateX25519KeyPair(); - const aliceStaticKey = generateX25519KeyPair(); + const dhKey = new DH25519(); + const bobStaticKey = dhKey.generateKeyPair(); + const aliceStaticKey = dhKey.generateKeyPair(); // Encode the length of the payload // Not a relevant real life example diff --git a/src/pairing.ts b/src/pairing.ts index 1579354..b39a7bf 100644 --- a/src/pairing.ts +++ b/src/pairing.ts @@ -14,7 +14,8 @@ import { NoiseSecureTransferDecoder, NoiseSecureTransferEncoder, } from "./codec.js"; -import { commitPublicKey, generateX25519KeyPair } from "./crypto.js"; +import { commitPublicKey } from "./crypto.js"; +import { DH25519 } from "./dh25519.js"; import { Handshake, HandshakeResult, HandshakeStepResult, MessageNametagError } from "./handshake.js"; import { MessageNametagLength } from "./messagenametag.js"; import { NoiseHandshakePatterns } from "./patterns.js"; @@ -94,7 +95,7 @@ export class WakuPairing { private responder: IReceiver, private myStaticKey: KeyPair, pairingParameters: InitiatorParameters | ResponderParameters, - private myEphemeralKey: KeyPair = generateX25519KeyPair(), + private myEphemeralKey: KeyPair = new DH25519().generateKeyPair(), private readonly encoderParameters: EncoderParameters = {} ) { this.randomFixLenVal = randomBytes(32, rng); diff --git a/src/patterns.ts b/src/patterns.ts index 4ce1db4..a28a1b9 100644 --- a/src/patterns.ts +++ b/src/patterns.ts @@ -2,6 +2,9 @@ import { TAG_LENGTH as ChaChaPolyTagLen } from "@stablelib/chacha20poly1305"; import { Hash } from "@stablelib/hash"; import { SHA256 } from "@stablelib/sha256"; +import { DHKey } from "./crypto"; +import { DH25519 } from "./dh25519"; + /** * The Noise tokens appearing in Noise (pre)message patterns * as in http://www.noiseprotocol.org/noise.html#handshake-pattern-basics @@ -72,13 +75,18 @@ export class MessagePattern { * handshake pre message patterns and the handshake message patterns */ export class HandshakePattern { + public readonly dhKey: DHKey; + constructor( public readonly name: string, + dhKeyType: new () => DHKey, public readonly hash: new () => Hash, public readonly tagLen: number, public readonly preMessagePatterns: Array, public readonly messagePatterns: Array - ) {} + ) { + this.dhKey = new dhKeyType(); + } /** * Check HandshakePattern equality @@ -106,6 +114,7 @@ export class HandshakePattern { export const NoiseHandshakePatterns: Record = { Noise_K1K1_25519_ChaChaPoly_SHA256: new HandshakePattern( "Noise_K1K1_25519_ChaChaPoly_SHA256", + DH25519, SHA256, ChaChaPolyTagLen, [ @@ -120,6 +129,7 @@ export const NoiseHandshakePatterns: Record = { ), Noise_XK1_25519_ChaChaPoly_SHA256: new HandshakePattern( "Noise_XK1_25519_ChaChaPoly_SHA256", + DH25519, SHA256, ChaChaPolyTagLen, [new PreMessagePattern(MessageDirection.l, [NoiseTokens.s])], @@ -131,6 +141,7 @@ export const NoiseHandshakePatterns: Record = { ), Noise_XX_25519_ChaChaPoly_SHA256: new HandshakePattern( "Noise_XX_25519_ChaChaPoly_SHA256", + DH25519, SHA256, ChaChaPolyTagLen, [], @@ -142,6 +153,7 @@ export const NoiseHandshakePatterns: Record = { ), Noise_XXpsk0_25519_ChaChaPoly_SHA256: new HandshakePattern( "Noise_XXpsk0_25519_ChaChaPoly_SHA256", + DH25519, SHA256, ChaChaPolyTagLen, [], @@ -153,6 +165,7 @@ export const NoiseHandshakePatterns: Record = { ), Noise_WakuPairing_25519_ChaChaPoly_SHA256: new HandshakePattern( "Noise_WakuPairing_25519_ChaChaPoly_SHA256", + DH25519, SHA256, ChaChaPolyTagLen, [new PreMessagePattern(MessageDirection.l, [NoiseTokens.e])], diff --git a/src/payload.ts b/src/payload.ts index 43bd0c1..8654ed1 100644 --- a/src/payload.ts +++ b/src/payload.ts @@ -2,7 +2,6 @@ import { concat as uint8ArrayConcat } from "uint8arrays/concat"; import { equals as uint8ArrayEquals } from "uint8arrays/equals"; import { MessageNametag } from "./@types/handshake.js"; -import { Curve25519KeySize } from "./crypto.js"; import { MessageNametagLength } from "./messagenametag.js"; import { NoiseHandshakePatterns, PayloadV2ProtocolIDs } from "./patterns.js"; import { NoisePublicKey } from "./publickey.js"; @@ -140,6 +139,7 @@ export class PayloadV2 { const pattern = NoiseHandshakePatterns[protocolName]; const tagLen = pattern ? pattern.tagLen : 0; + const keySize = pattern ? pattern.dhKey.DHLen() : 0; i++; @@ -163,13 +163,13 @@ export class PayloadV2 { const flag = payload[i]; // If the key is unencrypted, we only read the X coordinate of the EC public key and we deserialize into a Noise Public Key if (flag === 0) { - const pkLen = 1 + Curve25519KeySize; + const pkLen = 1 + keySize; handshakeMessage.push(NoisePublicKey.deserialize(payload.subarray(i, i + pkLen))); i += pkLen; written += pkLen; // If the key is encrypted, we only read the encrypted X coordinate and the authorization tag, and we deserialize into a Noise Public Key } else if (flag === 1) { - const pkLen = 1 + Curve25519KeySize + tagLen; + const pkLen = 1 + keySize + tagLen; handshakeMessage.push(NoisePublicKey.deserialize(payload.subarray(i, i + pkLen))); i += pkLen; written += pkLen; diff --git a/src/waku-noise-pairing.spec.ts b/src/waku-noise-pairing.spec.ts index c475fab..298ce4e 100644 --- a/src/waku-noise-pairing.spec.ts +++ b/src/waku-noise-pairing.spec.ts @@ -9,7 +9,8 @@ import { NoiseSecureTransferDecoder, NoiseSecureTransferEncoder, } from "./codec"; -import { commitPublicKey, generateX25519KeyPair } from "./crypto"; +import { commitPublicKey } from "./crypto"; +import { DH25519 } from "./dh25519"; import { Handshake } from "./handshake"; import { MessageNametagBufferSize, MessageNametagLength } from "./messagenametag"; import { NoiseHandshakePatterns } from "./patterns"; @@ -27,17 +28,19 @@ describe("Waku Noise Sessions", () => { // Pairing Phase // ========== + const dhKey = new DH25519(); + const hsPattern = NoiseHandshakePatterns.Noise_WakuPairing_25519_ChaChaPoly_SHA256; // Alice static/ephemeral key initialization and commitment - const aliceStaticKey = generateX25519KeyPair(); - const aliceEphemeralKey = generateX25519KeyPair(); + const aliceStaticKey = dhKey.generateKeyPair(); + const aliceEphemeralKey = dhKey.generateKeyPair(); const s = randomBytes(32, rng); const aliceCommittedStaticKey = commitPublicKey(aliceStaticKey.publicKey, s); // Bob static/ephemeral key initialization and commitment - const bobStaticKey = generateX25519KeyPair(); - const bobEphemeralKey = generateX25519KeyPair(); + const bobStaticKey = dhKey.generateKeyPair(); + const bobEphemeralKey = dhKey.generateKeyPair(); const r = randomBytes(32, rng); const bobCommittedStaticKey = commitPublicKey(bobStaticKey.publicKey, r);