refactor: SHA256 as parameter

This commit is contained in:
Richard Ramos 2023-11-20 14:34:08 -04:00
parent 31510dac38
commit bf665a0222
No known key found for this signature in database
GPG Key ID: 1CE87DB518195760
5 changed files with 31 additions and 21 deletions

View File

@ -1,6 +1,7 @@
import { ChaCha20Poly1305, TAG_LENGTH } from "@stablelib/chacha20poly1305"; import { ChaCha20Poly1305, TAG_LENGTH } from "@stablelib/chacha20poly1305";
import { Hash } from "@stablelib/hash";
import { HKDF as hkdf } from "@stablelib/hkdf"; import { HKDF as hkdf } from "@stablelib/hkdf";
import { hash, SHA256 } from "@stablelib/sha256"; import { hash } from "@stablelib/sha256";
import * as x25519 from "@stablelib/x25519"; import * as x25519 from "@stablelib/x25519";
import { concat as uint8ArrayConcat } from "uint8arrays/concat"; import { concat as uint8ArrayConcat } from "uint8arrays/concat";
@ -43,9 +44,15 @@ export function intoCurve25519Key(s: Uint8Array): bytes32 {
* @param numKeys number of keys to generate * @param numKeys number of keys to generate
* @returns array of `numValues` length containing Uint8Array keys of a given byte `length` * @returns array of `numValues` length containing Uint8Array keys of a given byte `length`
*/ */
export function HKDF(ck: bytes32, ikm: Uint8Array, length: number, numKeys: number): Array<Uint8Array> { export function HKDF(
hash: new () => Hash,
ck: bytes32,
ikm: Uint8Array,
length: number,
numKeys: number
): Array<Uint8Array> {
const numBytes = length * numKeys; const numBytes = length * numKeys;
const okm = new hkdf(SHA256, ikm, ck).expand(numBytes); const okm = new hkdf(hash, ikm, ck).expand(numBytes);
const result = []; const result = [];
for (let i = 0; i < numBytes; i += length) { for (let i = 0; i < numBytes; i += length) {
const k = okm.subarray(i, i + length); const k = okm.subarray(i, i + length);

View File

@ -173,7 +173,7 @@ export class Handshake {
// Generates an 8 decimal digits authorization code using HKDF and the handshake state // Generates an 8 decimal digits authorization code using HKDF and the handshake state
genAuthcode(): string { genAuthcode(): string {
const [output0] = HKDF(this.hs.ss.h, new Uint8Array(), 8, 1); const [output0] = HKDF(this.hs.handshakePattern.hash, this.hs.ss.h, new Uint8Array(), 8, 1);
const bn = new BN(output0); const bn = new BN(output0);
const code = bn.mod(new BN(100_000_000)).toString().padStart(8, "0"); const code = bn.mod(new BN(100_000_000)).toString().padStart(8, "0");
return code.toString(); return code.toString();

View File

@ -31,19 +31,14 @@ export class HandshakeState {
re?: bytes32; re?: bytes32;
ss: SymmetricState; ss: SymmetricState;
initiator: boolean; initiator: boolean;
handshakePattern: HandshakePattern;
msgPatternIdx: number; msgPatternIdx: number;
psk: Uint8Array;
constructor(hsPattern: HandshakePattern, psk: Uint8Array) { constructor(public readonly handshakePattern: HandshakePattern, public psk: Uint8Array) {
// By default the Handshake State initiator flag is set to false // By default the Handshake State initiator flag is set to false
// Will be set to true when the user associated to the handshake state starts an handshake // Will be set to true when the user associated to the handshake state starts an handshake
this.initiator = false; this.initiator = false;
this.handshakePattern = hsPattern; this.ss = new SymmetricState(handshakePattern);
this.psk = psk;
this.ss = new SymmetricState(hsPattern);
this.msgPatternIdx = 0; this.msgPatternIdx = 0;
} }
@ -101,14 +96,14 @@ export class HandshakeState {
} }
genMessageNametagSecrets(): { nms1: Uint8Array; nms2: Uint8Array } { genMessageNametagSecrets(): { nms1: Uint8Array; nms2: Uint8Array } {
const [nms1, nms2] = HKDF(this.ss.h, new Uint8Array(), 2, 32); const [nms1, nms2] = HKDF(this.handshakePattern.hash, this.ss.h, new Uint8Array(), 2, 32);
return { nms1, nms2 }; return { nms1, nms2 };
} }
// Uses the cryptographic information stored in the input handshake state to generate a random message nametag // Uses the cryptographic information stored in the input handshake state to generate a random message nametag
// In current implementation the messageNametag = HKDF(handshake hash value), but other derivation mechanisms can be implemented // In current implementation the messageNametag = HKDF(handshake hash value), but other derivation mechanisms can be implemented
toMessageNametag(): MessageNametag { toMessageNametag(): MessageNametag {
const [output] = HKDF(this.ss.h, new Uint8Array(), 32, 1); const [output] = HKDF(this.handshakePattern.hash, this.ss.h, new Uint8Array(), 32, 1);
return output.subarray(0, MessageNametagLength); return output.subarray(0, MessageNametagLength);
} }

View File

@ -216,11 +216,10 @@ export class SymmetricState {
h: bytes32; // handshake hash h: bytes32; // handshake hash
private ck: bytes32; // chaining key private ck: bytes32; // chaining key
constructor(private readonly hsPattern: HandshakePattern) { constructor(private readonly handshakePattern: HandshakePattern) {
this.h = hashProtocol(hsPattern.name); this.h = hashProtocol(handshakePattern.name);
this.ck = this.h; this.ck = this.h;
this.cs = new CipherState(); this.cs = new CipherState();
this.hsPattern = hsPattern;
} }
/** /**
@ -233,7 +232,7 @@ export class SymmetricState {
this.cs.equals(other.cs) && this.cs.equals(other.cs) &&
uint8ArrayEquals(this.ck, other.ck) && uint8ArrayEquals(this.ck, other.ck) &&
uint8ArrayEquals(this.h, other.h) && uint8ArrayEquals(this.h, other.h) &&
this.hsPattern.equals(other.hsPattern) this.handshakePattern.equals(other.handshakePattern)
); );
} }
@ -242,7 +241,7 @@ export class SymmetricState {
* @returns a copy of the SymmetricState * @returns a copy of the SymmetricState
*/ */
clone(): SymmetricState { clone(): SymmetricState {
const ss = new SymmetricState(this.hsPattern); const ss = new SymmetricState(this.handshakePattern);
ss.cs = this.cs.clone(); ss.cs = this.cs.clone();
ss.ck = new Uint8Array(this.ck); ss.ck = new Uint8Array(this.ck);
ss.h = new Uint8Array(this.h); ss.h = new Uint8Array(this.h);
@ -256,7 +255,7 @@ export class SymmetricState {
*/ */
mixKey(inputKeyMaterial: Uint8Array): void { mixKey(inputKeyMaterial: Uint8Array): void {
// We derive two keys using HKDF // We derive two keys using HKDF
const [ck, tempK] = HKDF(this.ck, inputKeyMaterial, 32, 2); const [ck, tempK] = HKDF(this.handshakePattern.hash, this.ck, inputKeyMaterial, 32, 2);
// We update ck and the Cipher state's key k using the output of HDKF // We update ck and the Cipher state's key k using the output of HDKF
this.cs = new CipherState(tempK); this.cs = new CipherState(tempK);
this.ck = ck; this.ck = ck;
@ -281,7 +280,7 @@ export class SymmetricState {
*/ */
mixKeyAndHash(inputKeyMaterial: Uint8Array): void { mixKeyAndHash(inputKeyMaterial: Uint8Array): void {
// Derives 3 keys using HKDF, the chaining key and the input key material // Derives 3 keys using HKDF, the chaining key and the input key material
const [tmpKey0, tmpKey1, tmpKey2] = HKDF(this.ck, inputKeyMaterial, 32, 3); const [tmpKey0, tmpKey1, tmpKey2] = HKDF(this.handshakePattern.hash, this.ck, inputKeyMaterial, 32, 3);
// Sets the chaining key // Sets the chaining key
this.ck = tmpKey0; this.ck = tmpKey0;
// Updates the handshake hash value // Updates the handshake hash value
@ -334,7 +333,7 @@ export class SymmetricState {
*/ */
split(): { cs1: CipherState; cs2: CipherState } { split(): { cs1: CipherState; cs2: CipherState } {
// Derives 2 keys using HKDF and the chaining key // Derives 2 keys using HKDF and the chaining key
const [tmpKey1, tmpKey2] = HKDF(this.ck, new Uint8Array(0), 32, 2); const [tmpKey1, tmpKey2] = HKDF(this.handshakePattern.hash, this.ck, new Uint8Array(0), 32, 2);
// Returns a tuple of two Cipher States initialized with the derived keys // Returns a tuple of two Cipher States initialized with the derived keys
return { return {
cs1: new CipherState(tmpKey1), cs1: new CipherState(tmpKey1),

View File

@ -1,3 +1,6 @@
import { Hash } from "@stablelib/hash";
import { SHA256 } from "@stablelib/sha256";
/** /**
* The Noise tokens appearing in Noise (pre)message patterns * The Noise tokens appearing in Noise (pre)message patterns
* as in http://www.noiseprotocol.org/noise.html#handshake-pattern-basics * as in http://www.noiseprotocol.org/noise.html#handshake-pattern-basics
@ -70,6 +73,7 @@ export class MessagePattern {
export class HandshakePattern { export class HandshakePattern {
constructor( constructor(
public readonly name: string, public readonly name: string,
public readonly hash: new () => Hash,
public readonly preMessagePatterns: Array<PreMessagePattern>, public readonly preMessagePatterns: Array<PreMessagePattern>,
public readonly messagePatterns: Array<MessagePattern> public readonly messagePatterns: Array<MessagePattern>
) {} ) {}
@ -100,6 +104,7 @@ export class HandshakePattern {
export const NoiseHandshakePatterns = { export const NoiseHandshakePatterns = {
K1K1: new HandshakePattern( K1K1: new HandshakePattern(
"Noise_K1K1_25519_ChaChaPoly_SHA256", "Noise_K1K1_25519_ChaChaPoly_SHA256",
SHA256,
[ [
new PreMessagePattern(MessageDirection.r, [NoiseTokens.s]), new PreMessagePattern(MessageDirection.r, [NoiseTokens.s]),
new PreMessagePattern(MessageDirection.l, [NoiseTokens.s]), new PreMessagePattern(MessageDirection.l, [NoiseTokens.s]),
@ -112,6 +117,7 @@ export const NoiseHandshakePatterns = {
), ),
XK1: new HandshakePattern( XK1: new HandshakePattern(
"Noise_XK1_25519_ChaChaPoly_SHA256", "Noise_XK1_25519_ChaChaPoly_SHA256",
SHA256,
[new PreMessagePattern(MessageDirection.l, [NoiseTokens.s])], [new PreMessagePattern(MessageDirection.l, [NoiseTokens.s])],
[ [
new MessagePattern(MessageDirection.r, [NoiseTokens.e]), new MessagePattern(MessageDirection.r, [NoiseTokens.e]),
@ -121,6 +127,7 @@ export const NoiseHandshakePatterns = {
), ),
XX: new HandshakePattern( XX: new HandshakePattern(
"Noise_XX_25519_ChaChaPoly_SHA256", "Noise_XX_25519_ChaChaPoly_SHA256",
SHA256,
[], [],
[ [
new MessagePattern(MessageDirection.r, [NoiseTokens.e]), new MessagePattern(MessageDirection.r, [NoiseTokens.e]),
@ -130,6 +137,7 @@ export const NoiseHandshakePatterns = {
), ),
XXpsk0: new HandshakePattern( XXpsk0: new HandshakePattern(
"Noise_XXpsk0_25519_ChaChaPoly_SHA256", "Noise_XXpsk0_25519_ChaChaPoly_SHA256",
SHA256,
[], [],
[ [
new MessagePattern(MessageDirection.r, [NoiseTokens.psk, NoiseTokens.e]), new MessagePattern(MessageDirection.r, [NoiseTokens.psk, NoiseTokens.e]),
@ -139,6 +147,7 @@ export const NoiseHandshakePatterns = {
), ),
WakuPairing: new HandshakePattern( WakuPairing: new HandshakePattern(
"Noise_WakuPairing_25519_ChaChaPoly_SHA256", "Noise_WakuPairing_25519_ChaChaPoly_SHA256",
SHA256,
[new PreMessagePattern(MessageDirection.l, [NoiseTokens.e])], [new PreMessagePattern(MessageDirection.l, [NoiseTokens.e])],
[ [
new MessagePattern(MessageDirection.r, [NoiseTokens.e, NoiseTokens.ee]), new MessagePattern(MessageDirection.r, [NoiseTokens.e, NoiseTokens.ee]),