+27
packages/crypto/src/decrypt.test.ts
+27
packages/crypto/src/decrypt.test.ts
···
2
2
import { generateKeys } from "./keys.ts";
3
3
import { encryptText } from "./encrypt.ts";
4
4
import { decryptText } from "./decrypt.ts";
5
+
import { sha3_512 } from "@noble/hashes/sha3.js";
5
6
6
7
Deno.test({
7
8
name: "decrypts an encrypted value",
···
14
15
expect(decrypted).toEqual(text);
15
16
},
16
17
});
18
+
19
+
Deno.test({
20
+
name: "errors when provided an incorrect hash",
21
+
fn() {
22
+
const keys = generateKeys();
23
+
const text = "Hello, world!";
24
+
const encrypted = encryptText(keys.publicKey, text);
25
+
26
+
encrypted.hash = sha3_512(new Uint8Array(24)).toBase64();
27
+
28
+
expect(() => decryptText(keys.secretKey, encrypted)).toThrow();
29
+
},
30
+
});
31
+
32
+
Deno.test({
33
+
name: "errors when provided an incorrect content length",
34
+
fn() {
35
+
const keys = generateKeys();
36
+
const text = "Hello, world!";
37
+
const encrypted = encryptText(keys.publicKey, text);
38
+
39
+
encrypted.length = Math.round(Math.random() * 1000);
40
+
41
+
expect(() => decryptText(keys.secretKey, encrypted)).toThrow();
42
+
},
43
+
});
+12
packages/crypto/src/decrypt.ts
+12
packages/crypto/src/decrypt.ts
···
1
1
import { XWing } from "@noble/post-quantum/hybrid.js";
2
2
import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
3
+
import { sha3_512 } from "@noble/hashes/sha3.js";
3
4
import type { EncryptedPayload } from "./types.ts";
4
5
5
6
export function decryptText(
···
12
13
const sharedSecret = XWing.decapsulate(cipherText, secretKey);
13
14
const cipher = xchacha20poly1305(sharedSecret, nonce);
14
15
const decrypted = cipher.decrypt(content);
16
+
const hash = sha3_512(decrypted);
17
+
18
+
if (decrypted.byteLength !== payload.length) {
19
+
throw new Error(
20
+
`content lengths do not match: got ${decrypted.byteLength}, expected ${payload.length}`,
21
+
);
22
+
} else if (hash.toBase64() !== payload.hash) {
23
+
throw new Error(
24
+
`hashes do not match: got ${hash.toBase64()}, expected ${payload.hash}`,
25
+
);
26
+
}
15
27
16
28
return new TextDecoder().decode(decrypted);
17
29
}
+7
-6
packages/crypto/src/encrypt.test.ts
+7
-6
packages/crypto/src/encrypt.test.ts
···
3
3
import { encryptText } from "./encrypt.ts";
4
4
5
5
Deno.test({
6
-
name: "generates non-empty encrypted payload",
6
+
name: "generates an encrypted payload",
7
7
fn() {
8
8
const keys = generateKeys();
9
9
const text = "Hello, world!";
10
10
const result = encryptText(keys.publicKey, text);
11
-
const entries = Array.from(Object.values(result));
12
11
13
-
expect(entries).toHaveLength(4);
12
+
expect(Object.entries(result)).toHaveLength(5);
14
13
15
-
for (const [key, val] of entries) {
16
-
expect(val.length, `${key} is empty`).toBeGreaterThan(0);
17
-
}
14
+
expect(result.cipherText.length).toBeGreaterThan(0);
15
+
expect(result.content.length).toBeGreaterThan(0);
16
+
expect(result.hash.length).toBeGreaterThan(0);
17
+
expect(result.nonce.length).toBeGreaterThan(0);
18
+
expect(result.length).toBeGreaterThan(0);
18
19
},
19
20
});
+3
-2
packages/crypto/src/encrypt.ts
+3
-2
packages/crypto/src/encrypt.ts
···
1
1
import { XWing } from "@noble/post-quantum/hybrid.js";
2
-
import { sha256 } from "@noble/hashes/sha2.js";
3
2
import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
4
3
import { randomBytes } from "@noble/hashes/utils.js";
4
+
import { sha3_512 } from "@noble/hashes/sha3.js";
5
5
import type { EncryptedPayload } from "./types.ts";
6
6
7
7
export function encryptText(
···
13
13
const contentBytes = new TextEncoder().encode(text);
14
14
const cipher = xchacha20poly1305(sharedSecret, nonce);
15
15
const content = cipher.encrypt(contentBytes);
16
-
const hash = sha256(content);
16
+
const hash = sha3_512(contentBytes);
17
17
18
18
return {
19
19
cipherText: cipherText.toBase64(),
20
20
content: content.toBase64(),
21
21
nonce: nonce.toBase64(),
22
22
hash: hash.toBase64(),
23
+
length: contentBytes.byteLength,
23
24
};
24
25
}