Files
auth-tools/tests/otp/encrypted-backup.test.ts
T

57 lines
1.6 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { utf8ToBytes } from "../../src/crypto/encoding";
import {
decryptOtpBackup,
encryptOtpBackup,
} from "../../src/otp/encrypted-backup";
import type { OtpProfile } from "../../src/otp/profile";
const profile: OtpProfile = {
kind: "totp",
secret: utf8ToBytes("12345678901234567890"),
issuer: "Example",
account: "alice",
algorithm: "SHA-256",
digits: 8,
period: 45,
epoch: 12,
counter: 0n,
extensions: new Map([["image", "none"]]),
};
describe("encrypted OTP backups", () => {
it("round-trips profiles through authenticated encryption", async () => {
const encrypted = await encryptOtpBackup(
[profile],
"correct horse battery staple",
);
expect(encrypted).not.toContain("JBSWY");
const restored = await decryptOtpBackup(
encrypted,
"correct horse battery staple",
);
expect(restored[0]).toMatchObject({
issuer: "Example",
account: "alice",
epoch: 12,
counter: 0n,
});
expect([...restored[0]!.secret]).toEqual([...profile.secret]);
});
it("rejects a wrong password and tampering", async () => {
const encrypted = await encryptOtpBackup(
[profile],
"correct horse battery staple",
);
await expect(
decryptOtpBackup(encrypted, "different secure password"),
).rejects.toThrow(/authentication failed/iu);
const parsed = JSON.parse(encrypted) as { ciphertext: string };
parsed.ciphertext = `${parsed.ciphertext.slice(0, -2)}AA`;
await expect(
decryptOtpBackup(JSON.stringify(parsed), "correct horse battery staple"),
).rejects.toThrow(/authentication failed/iu);
});
});