refactor: SHA256 as parameter

This commit is contained in:
Richard Ramos 2023-11-20 14:34:08 -04:00 committed by richΛrd
parent 31510dac38
commit 5d54dc28be
5 changed files with 31 additions and 21 deletions

View File

@ -1,6 +1,7 @@
import { ChaCha20Poly1305, TAG_LENGTH } from "@stablelib/chacha20poly1305";
import { Hash } from "@stablelib/hash";
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 { concat as uint8ArrayConcat } from "uint8arrays/concat";
@ -43,9 +44,15 @@ export function intoCurve25519Key(s: Uint8Array): bytes32 {
* @param numKeys number of keys to generate
* @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 okm = new hkdf(SHA256, ikm, ck).expand(numBytes);
const okm = new hkdf(hash, ikm, ck).expand(numBytes);
const result = [];
for (let i = 0; i < numBytes; 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
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 code = bn.mod(new BN(100_000_000)).toString().padStart(8, "0");
return code.toString();

View File

@ -31,19 +31,14 @@ export class HandshakeState {
re?: bytes32;
ss: SymmetricState;
initiator: boolean;
handshakePattern: HandshakePattern;
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
// Will be set to true when the user associated to the handshake state starts an handshake
this.initiator = false;
this.handshakePattern = hsPattern;
this.psk = psk;
this.ss = new SymmetricState(hsPattern);
this.ss = new SymmetricState(handshakePattern);
this.msgPatternIdx = 0;
}
@ -101,14 +96,14 @@ export class HandshakeState {
}
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 };
}
// 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
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);
}

View File

@ -216,11 +216,10 @@ export class SymmetricState {
h: bytes32; // handshake hash
private ck: bytes32; // chaining key
constructor(private readonly hsPattern: HandshakePattern) {
this.h = hashProtocol(hsPattern.name);
constructor(private readonly handshakePattern: HandshakePattern) {
this.h = hashProtocol(handshakePattern.name);
this.ck = this.h;
this.cs = new CipherState();
this.hsPattern = hsPattern;
}
/**
@ -233,7 +232,7 @@ export class SymmetricState {
this.cs.equals(other.cs) &&
uint8ArrayEquals(this.ck, other.ck) &&
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
*/
clone(): SymmetricState {
const ss = new SymmetricState(this.hsPattern);
const ss = new SymmetricState(this.handshakePattern);
ss.cs = this.cs.clone();
ss.ck = new Uint8Array(this.ck);
ss.h = new Uint8Array(this.h);
@ -256,7 +255,7 @@ export class SymmetricState {
*/
mixKey(inputKeyMaterial: Uint8Array): void {
// 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
this.cs = new CipherState(tempK);
this.ck = ck;
@ -281,7 +280,7 @@ export class SymmetricState {
*/
mixKeyAndHash(inputKeyMaterial: Uint8Array): void {
// 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
this.ck = tmpKey0;
// Updates the handshake hash value
@ -334,7 +333,7 @@ export class SymmetricState {
*/
split(): { cs1: CipherState; cs2: CipherState } {
// 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
return {
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
* as in http://www.noiseprotocol.org/noise.html#handshake-pattern-basics
@ -70,6 +73,7 @@ export class MessagePattern {
export class HandshakePattern {
constructor(
public readonly name: string,
public readonly hash: new () => Hash,
public readonly preMessagePatterns: Array<PreMessagePattern>,
public readonly messagePatterns: Array<MessagePattern>
) {}
@ -100,6 +104,7 @@ export class HandshakePattern {
export const NoiseHandshakePatterns = {
K1K1: new HandshakePattern(
"Noise_K1K1_25519_ChaChaPoly_SHA256",
SHA256,
[
new PreMessagePattern(MessageDirection.r, [NoiseTokens.s]),
new PreMessagePattern(MessageDirection.l, [NoiseTokens.s]),
@ -112,6 +117,7 @@ export const NoiseHandshakePatterns = {
),
XK1: new HandshakePattern(
"Noise_XK1_25519_ChaChaPoly_SHA256",
SHA256,
[new PreMessagePattern(MessageDirection.l, [NoiseTokens.s])],
[
new MessagePattern(MessageDirection.r, [NoiseTokens.e]),
@ -121,6 +127,7 @@ export const NoiseHandshakePatterns = {
),
XX: new HandshakePattern(
"Noise_XX_25519_ChaChaPoly_SHA256",
SHA256,
[],
[
new MessagePattern(MessageDirection.r, [NoiseTokens.e]),
@ -130,6 +137,7 @@ export const NoiseHandshakePatterns = {
),
XXpsk0: new HandshakePattern(
"Noise_XXpsk0_25519_ChaChaPoly_SHA256",
SHA256,
[],
[
new MessagePattern(MessageDirection.r, [NoiseTokens.psk, NoiseTokens.e]),
@ -139,6 +147,7 @@ export const NoiseHandshakePatterns = {
),
WakuPairing: new HandshakePattern(
"Noise_WakuPairing_25519_ChaChaPoly_SHA256",
SHA256,
[new PreMessagePattern(MessageDirection.l, [NoiseTokens.e])],
[
new MessagePattern(MessageDirection.r, [NoiseTokens.e, NoiseTokens.ee]),