noise.reject-zero-dh.test.ts

2.4 KB · raw

1// PCH-02-009 regression tests — every Noise NK DH must reject an all-zero2// shared secret (low-order / identity peer point) instead of feeding it into3// the key schedule.45import { describe, expect, it } from "vitest";6import { generateKeyPair } from "@stablelib/x25519";7import { noiseNKInitiator, noiseNKResponder } from "./noise-js";89const ZERO_POINT = new Uint8Array(32);1011function queuePair() {12  const makeQueue = () => {13    const items: Uint8Array[] = [];14    const waiters: Array<(m: Uint8Array) => void> = [];15    return {16      push(m: Uint8Array) {17        const w = waiters.shift();18        if (w) w(m);19        else items.push(m);20      },21      pull(): Promise<Uint8Array> {22        const m = items.shift();23        return m ? Promise.resolve(m) : new Promise((r) => waiters.push(r));24      },25    };26  };27  const aToB = makeQueue();28  const bToA = makeQueue();29  return {30    a: { send: async (m: Uint8Array) => aToB.push(m), receive: () => bToA.pull() },31    b: { send: async (m: Uint8Array) => bToA.push(m), receive: () => aToB.pull() },32  };33}3435const deadTransport = {36  send: async () => undefined,37  receive: () => new Promise<Uint8Array>(() => undefined),38};3940describe("PCH-02-009 — reject zero X25519 DH outputs", () => {41  it("NK initiator aborts against an all-zero responder static key", async () => {42    await expect(43      noiseNKInitiator(ZERO_POINT, deadTransport.send, deadTransport.receive),44    ).rejects.toThrow(/diffie|dh/i);45  });4647  it("NK responder aborts on an all-zero msg-1 ephemeral", async () => {48    const ourStatic = generateKeyPair();49    const msg1 = new Uint8Array(48);50    await expect(51      noiseNKResponder(52        ourStatic.secretKey,53        ourStatic.publicKey,54        deadTransport.send,55        async () => msg1,56      ),57    ).rejects.toThrow(/diffie|dh/i);58  });5960  it("honest NK handshake still completes and transports a frame (regression)", async () => {61    const responderStatic = generateKeyPair();62    const { a, b } = queuePair();6364    const [initiator, responder] = await Promise.all([65      noiseNKInitiator(responderStatic.publicKey, a.send, a.receive),66      noiseNKResponder(responderStatic.secretKey, responderStatic.publicKey, b.send, b.receive),67    ]);6869    const frame = new TextEncoder().encode("peach-nk-frame");70    expect(responder.decrypt(initiator.encrypt(frame))).toEqual(frame);71    expect(initiator.handshakeHash).toEqual(responder.handshakeHash);72  });7374});