1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
import { log } from "../logger.ts";
//! I am not a crypto expert at all! Please read carefully and report any issues to me.
export async function crypto_seeded_key(seed: string): Promise<CryptoKey> {
log("crypto", "importing seed…")
const seed_key = await window.crypto.subtle.importKey(
"raw",
new TextEncoder().encode(seed),
"PBKDF2",
false,
["deriveKey"]
)
//? TODO is it possible to use a unique seed per session here?
// const salt = window.crypto.getRandomValues(new Uint8Array(16));
const salt = base64_to_buf("thisisagoodsaltAAAAAAA==") // valid "unique" 16-byte base-64 string
log("crypto", "deriving key…")
const key = await window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt,
iterations: 250000,
hash: "SHA-256",
},
seed_key,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
)
console.log(key);
log("crypto", "ready")
return key
}
export async function crypto_encrypt(key: CryptoKey, data: string): Promise<string> {
const iv = window.crypto.getRandomValues(new Uint8Array(12));
const ciphertext = new Uint8Array(await window.crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
key,
new TextEncoder().encode(data)
));
const buf = new Uint8Array(iv.byteLength + ciphertext.byteLength);
buf.set(iv, 0);
buf.set(ciphertext, iv.byteLength);
const b64 = buf_to_base64(buf);
return b64;
}
export async function crypt_decrypt(key: CryptoKey, data: string): Promise<string> {
const buf = base64_to_buf(data);
const iv = buf.slice(0, 12);
const ciphertext = buf.slice(12);
const decryptedContent = await window.crypto.subtle.decrypt(
{ name: "AES-GCM", iv },
key,
ciphertext
);
const plain = new TextDecoder().decode(decryptedContent);
return plain
}
// const buf_to_base64 = (buf: Uint8Array) => btoa(String.fromCharCode.apply(null, buf));
// const base64_to_buf = (b64: string) => Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
export function base64_to_buf(data: string): Uint8Array {
const binary_string = globalThis.atob(data);
const bytes = new Uint8Array(binary_string.length);
for (let i = 0; i < binary_string.length; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes;
}
export function buf_to_base64(bytes: Uint8Array): string {
let binary = '';
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i]);
}
return globalThis.btoa(binary);
}
|