127 lines
2.6 KiB
JavaScript
127 lines
2.6 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { loadModule } from "./test-helpers.mjs";
|
|
|
|
const crypto = await loadModule("app/utils/crypto.ts");
|
|
const id = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
|
|
const key = crypto.generateKey();
|
|
const wrongKey = crypto.generateKey();
|
|
const nonce = crypto.generateNoncePrefix();
|
|
|
|
test("AES-GCM manifest and chunk round trips preserve plaintext", async () => {
|
|
const plain = new TextEncoder().encode("hello chunk");
|
|
const cipher = await crypto.encryptChunk(
|
|
plain,
|
|
key,
|
|
id,
|
|
nonce,
|
|
0,
|
|
8 * 1024 * 1024,
|
|
1,
|
|
);
|
|
assert.deepEqual(
|
|
[
|
|
...(await crypto.decryptChunk(
|
|
cipher,
|
|
key,
|
|
id,
|
|
nonce,
|
|
0,
|
|
plain.byteLength,
|
|
8 * 1024 * 1024,
|
|
1,
|
|
)),
|
|
],
|
|
[...plain],
|
|
);
|
|
const manifest = {
|
|
version: 2,
|
|
name: "hello.txt",
|
|
type: "text/plain",
|
|
size: plain.byteLength,
|
|
lastModified: 1,
|
|
chunkSize: 8 * 1024 * 1024,
|
|
chunkCount: 1,
|
|
};
|
|
const encrypted = await crypto.encryptManifest(manifest, key, id, nonce);
|
|
assert.deepEqual(
|
|
await crypto.decryptManifest(
|
|
encrypted,
|
|
key,
|
|
id,
|
|
nonce,
|
|
manifest.chunkSize,
|
|
manifest.chunkCount,
|
|
),
|
|
manifest,
|
|
);
|
|
});
|
|
|
|
test("empty chunks are authenticated and round-trip", async () => {
|
|
const cipher = await crypto.encryptChunk(
|
|
new Uint8Array(),
|
|
key,
|
|
id,
|
|
nonce,
|
|
0,
|
|
8 * 1024 * 1024,
|
|
1,
|
|
);
|
|
assert.equal(cipher.byteLength, 16);
|
|
assert.equal(
|
|
(
|
|
await crypto.decryptChunk(
|
|
cipher,
|
|
key,
|
|
id,
|
|
nonce,
|
|
0,
|
|
0,
|
|
8 * 1024 * 1024,
|
|
1,
|
|
)
|
|
).byteLength,
|
|
0,
|
|
);
|
|
});
|
|
|
|
test("tampering and wrong key or AAD fail integrity", async () => {
|
|
const cipher = await crypto.encryptChunk(
|
|
new Uint8Array([1, 2, 3]),
|
|
key,
|
|
id,
|
|
nonce,
|
|
0,
|
|
8 * 1024 * 1024,
|
|
1,
|
|
);
|
|
const tampered = new Uint8Array(cipher);
|
|
tampered[0] ^= 1;
|
|
await assert.rejects(
|
|
crypto.decryptChunk(tampered, key, id, nonce, 0, 3, 8 * 1024 * 1024, 1),
|
|
/integrity/,
|
|
);
|
|
await assert.rejects(
|
|
crypto.decryptChunk(cipher, wrongKey, id, nonce, 0, 3, 8 * 1024 * 1024, 1),
|
|
/integrity/,
|
|
);
|
|
await assert.rejects(
|
|
crypto.decryptChunk(cipher, key, id, nonce, 1, 3, 8 * 1024 * 1024, 1),
|
|
/integrity/,
|
|
);
|
|
});
|
|
|
|
test("tag-only manifests are rejected before decryption", async () => {
|
|
await assert.rejects(
|
|
crypto.decryptManifest(
|
|
new Uint8Array(16),
|
|
key,
|
|
id,
|
|
nonce,
|
|
8 * 1024 * 1024,
|
|
1,
|
|
),
|
|
/empty/,
|
|
);
|
|
});
|