Fixed bug in channel hash calculation and decryption

This commit is contained in:
2026-03-14 19:26:53 +01:00
parent 38b7ea7517
commit 0feb4868e4
5 changed files with 146 additions and 88 deletions

View File

@@ -112,18 +112,12 @@ describe("PrivateKey", () => {
});
describe("SharedSecret", () => {
const secret = randomBytes(32);
const secret = randomBytes(16);
it("constructs from 32 bytes", () => {
it("constructs from 16 bytes", () => {
const ss = new SharedSecret(secret);
expect(ss.toBytes()).toEqual(secret);
});
it("pads if 16 bytes", () => {
const short = randomBytes(16);
const ss = new SharedSecret(short);
expect(ss.toBytes().length).toBe(32);
expect(Array.from(ss.toBytes()).slice(16)).toEqual(Array.from(short));
expect(ss.toBytes().length).toBe(16);
expect(bytesToHex(ss.toBytes())).toBe(bytesToHex(secret));
});
it("throws on invalid length", () => {
@@ -163,6 +157,9 @@ describe("SharedSecret", () => {
it('fromName "Public"', () => {
const ss = SharedSecret.fromName("Public");
expect(ss).toBeInstanceOf(SharedSecret);
const hash = ss.toHash();
expect(typeof hash).toBe("number");
expect(hash).toBe(0x11);
});
it("fromName with #group", () => {

View File

@@ -1,5 +1,5 @@
import { describe, it, expect, beforeEach } from "vitest";
import { bytesToHex } from "@hamradio/packet";
import { bytesToHex, hexToBytes } from "@hamradio/packet";
import { Identity, LocalIdentity, Contact, Group, Contacts, parseNodeHash } from "../src/identity";
import { PrivateKey, PublicKey, SharedSecret } from "../src/crypto";
import { DecryptedGroupText, DecryptedGroupData } from "../src/packet.types";
@@ -230,6 +230,18 @@ describe("Group", () => {
it("decryptData throws on short ciphertext", () => {
expect(() => group.decryptData(randomBytes(16), Uint8Array.of(1, 2, 3))).toThrow();
});
it("hash is consistent with test vectors", () => {
const testVectors = [
{ name: "Public", hash: 0x11 },
{ name: "#test", hash: 0xd9 }
];
testVectors.forEach(({ name, hash }) => {
const g = new Group(name);
expect(`${name}:${g.hash()}`).toBe(`${name}:${hash}`);
});
});
});
describe("Contacts", () => {
@@ -501,4 +513,23 @@ describe("Contacts", () => {
const res2 = contacts.decrypt(contactB.identity.hash(), localA.publicKey.key[0], hmac, ciphertext);
expect(res2.decrypted).toEqual(msg);
});
it("decryptGroupText on well known channels with test vectors", () => {
const testVectors = [
{
name: "#test",
channelHash: 0xd9,
cipherMAC: hexToBytes("570D"),
cipherText: hexToBytes("E397F0560B2B61396F7E236811FC70B70038E956045347D7F6B9976A46727427"),
message: "corrauder 🏕️: Testing "
}
];
testVectors.forEach(({ name, channelHash, cipherMAC, cipherText, message }) => {
const group = new Group(name);
expect(group.hash()).toBe(channelHash);
const decrypted = group.decryptText(cipherMAC, cipherText);
expect(decrypted.message).toBe(message);
});
});
});