mirror of https://github.com/waku-org/js-noise.git
refactor: key type as parameter
This commit is contained in:
parent
d9b8fdc98e
commit
6baa061f0e
107
src/crypto.ts
107
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<PreMessagePattern>,
|
||||
public readonly messagePatterns: Array<MessagePattern>
|
||||
) {}
|
||||
) {
|
||||
this.dhKey = new dhKeyType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check HandshakePattern equality
|
||||
|
@ -106,6 +114,7 @@ export class HandshakePattern {
|
|||
export const NoiseHandshakePatterns: Record<string, HandshakePattern> = {
|
||||
Noise_K1K1_25519_ChaChaPoly_SHA256: new HandshakePattern(
|
||||
"Noise_K1K1_25519_ChaChaPoly_SHA256",
|
||||
DH25519,
|
||||
SHA256,
|
||||
ChaChaPolyTagLen,
|
||||
[
|
||||
|
@ -120,6 +129,7 @@ export const NoiseHandshakePatterns: Record<string, HandshakePattern> = {
|
|||
),
|
||||
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<string, HandshakePattern> = {
|
|||
),
|
||||
Noise_XX_25519_ChaChaPoly_SHA256: new HandshakePattern(
|
||||
"Noise_XX_25519_ChaChaPoly_SHA256",
|
||||
DH25519,
|
||||
SHA256,
|
||||
ChaChaPolyTagLen,
|
||||
[],
|
||||
|
@ -142,6 +153,7 @@ export const NoiseHandshakePatterns: Record<string, HandshakePattern> = {
|
|||
),
|
||||
Noise_XXpsk0_25519_ChaChaPoly_SHA256: new HandshakePattern(
|
||||
"Noise_XXpsk0_25519_ChaChaPoly_SHA256",
|
||||
DH25519,
|
||||
SHA256,
|
||||
ChaChaPolyTagLen,
|
||||
[],
|
||||
|
@ -153,6 +165,7 @@ export const NoiseHandshakePatterns: Record<string, HandshakePattern> = {
|
|||
),
|
||||
Noise_WakuPairing_25519_ChaChaPoly_SHA256: new HandshakePattern(
|
||||
"Noise_WakuPairing_25519_ChaChaPoly_SHA256",
|
||||
DH25519,
|
||||
SHA256,
|
||||
ChaChaPolyTagLen,
|
||||
[new PreMessagePattern(MessageDirection.l, [NoiseTokens.e])],
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue