1import { describe, expect, it } from "vitest";23import { decrypt, encrypt } from "./aes";4import { deriveKey, generateSalt } from "../crypto/argon2";56describe("background aes", () => {7 it("encrypt then decrypt round-trips the plaintext", async () => {8 const key = await deriveKey("correct-pass-12345", generateSalt());910 const encrypted = await encrypt(key, "hello peach");11 const plaintext = await decrypt(12 key,13 encrypted.nonce,14 encrypted.ciphertext,15 encrypted.tag16 );1718 expect(plaintext).toBe("hello peach");19 });2021 it("decrypt with the wrong key throws", async () => {22 const salt = generateSalt();23 const rightKey = await deriveKey("correct-pass-12345", salt);24 const wrongKey = await deriveKey("wrong-pass-67890", salt);25 const encrypted = await encrypt(rightKey, "secret");2627 await expect(28 decrypt(wrongKey, encrypted.nonce, encrypted.ciphertext, encrypted.tag)29 ).rejects.toThrow();30 });3132 it("decrypt with tampered ciphertext throws", async () => {33 const key = await deriveKey("correct-pass-12345", generateSalt());34 const encrypted = await encrypt(key, "secret");35 const lastByte = Number.parseInt(encrypted.ciphertext.slice(-2), 16);36 const tamperedByte = (lastByte ^ 0xff).toString(16).padStart(2, "0");37 const tamperedCiphertext = `${encrypted.ciphertext.slice(0, -2)}${tamperedByte}`;3839 await expect(40 decrypt(key, encrypted.nonce, tamperedCiphertext, encrypted.tag)41 ).rejects.toThrow();42 });4344 it("encrypt uses a fresh nonce each time", async () => {45 const key = await deriveKey("correct-pass-12345", generateSalt());4647 const first = await encrypt(key, "same plaintext");48 const second = await encrypt(key, "same plaintext");4950 expect(first.nonce).not.toBe(second.nonce);51 expect(first.ciphertext).not.toBe(second.ciphertext);52 });5354 it("encrypt output includes the 16-byte auth tag overhead", async () => {55 const key = await deriveKey("correct-pass-12345", generateSalt());56 const plaintext = "hello";5758 const encrypted = await encrypt(key, plaintext);5960 expect(encrypted.tag).toHaveLength(32);61 expect(encrypted.ciphertext.length / 2).toBe(new TextEncoder().encode(plaintext).length);62 });63});