feat: release authentication laboratories 0.3.0
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { utf8ToBytes } from "../../src/crypto/encoding";
|
||||
import { exportEncryptedPskc, importEncryptedPskc } from "../../src/otp/pskc";
|
||||
import type { OtpProfile } from "../../src/otp/profile";
|
||||
|
||||
const profiles: OtpProfile[] = [
|
||||
{
|
||||
kind: "totp",
|
||||
account: "alice@example.test",
|
||||
issuer: "Example & Sons",
|
||||
secret: utf8ToBytes("12345678901234567890"),
|
||||
algorithm: "SHA-256",
|
||||
digits: 8,
|
||||
period: 45,
|
||||
epoch: 10,
|
||||
counter: 0n,
|
||||
extensions: new Map(),
|
||||
},
|
||||
{
|
||||
kind: "hotp",
|
||||
account: "hardware token",
|
||||
issuer: "Example",
|
||||
secret: utf8ToBytes("abcdefghijklmnopqrst"),
|
||||
algorithm: "SHA-1",
|
||||
digits: 6,
|
||||
period: 30,
|
||||
counter: 1042n,
|
||||
extensions: new Map(),
|
||||
},
|
||||
];
|
||||
|
||||
describe("encrypted PSKC", () => {
|
||||
it("round-trips authenticated password-encrypted collections", async () => {
|
||||
const exported = await exportEncryptedPskc(
|
||||
profiles,
|
||||
"correct horse battery staple",
|
||||
{ iterations: 100_000 },
|
||||
);
|
||||
expect(exported).toContain("PBKDF2-params");
|
||||
expect(exported).toContain(
|
||||
'Algorithm="http://www.rsasecurity.com/rsalabs/pkcs/schemas/pkcs-5v2-0#pbkdf2"',
|
||||
);
|
||||
expect(exported).toContain("<pskc:MACKey><xenc:EncryptionMethod");
|
||||
expect(exported).toContain('<pskc:EncryptedValue Id="ED-1">');
|
||||
expect(exported).not.toContain("12345678901234567890");
|
||||
const result = await importEncryptedPskc(
|
||||
exported,
|
||||
"correct horse battery staple",
|
||||
);
|
||||
expect(result.profiles).toHaveLength(2);
|
||||
expect(result.profiles[0]).toMatchObject({
|
||||
kind: "totp",
|
||||
account: "alice@example.test",
|
||||
issuer: "Example & Sons",
|
||||
algorithm: "SHA-256",
|
||||
digits: 8,
|
||||
period: 45,
|
||||
epoch: 10,
|
||||
});
|
||||
expect(result.profiles[1]).toMatchObject({
|
||||
kind: "hotp",
|
||||
counter: 1042n,
|
||||
});
|
||||
expect([...result.profiles[0]!.secret]).toEqual([...profiles[0]!.secret]);
|
||||
});
|
||||
|
||||
it("rejects wrong passwords and unauthenticated changes", async () => {
|
||||
const exported = await exportEncryptedPskc(
|
||||
profiles.slice(0, 1),
|
||||
"correct horse battery staple",
|
||||
{ iterations: 100_000 },
|
||||
);
|
||||
await expect(
|
||||
importEncryptedPskc(exported, "incorrect password"),
|
||||
).rejects.toThrow(/incorrect|damaged/u);
|
||||
const tampered = exported.replace(
|
||||
/<pskc:ValueMAC>([^<])/u,
|
||||
(_match, first: string) => `<pskc:ValueMAC>${first === "A" ? "B" : "A"}`,
|
||||
);
|
||||
await expect(
|
||||
importEncryptedPskc(tampered, "correct horse battery staple"),
|
||||
).rejects.toThrow(/ValueMAC/u);
|
||||
});
|
||||
|
||||
it("rejects XML entity declarations", async () => {
|
||||
await expect(
|
||||
importEncryptedPskc(
|
||||
'<!DOCTYPE x [<!ENTITY e SYSTEM "file:///etc/passwd">]><x/>',
|
||||
"password",
|
||||
),
|
||||
).rejects.toThrow(/entity/u);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user