Files
cobble/src/utils/crypt.ts
T

54 lines
1.5 KiB
TypeScript

const key = process.env.ENCRYPTION_KEY;
const salt = process.env.ENCRYPTION_SALT;
async function getKey() {
const material = await crypto.subtle.importKey(
"raw",
new TextEncoder().encode(key),
"PBKDF2",
false,
["deriveKey"],
);
return crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: new TextEncoder().encode(salt),
iterations: 100000,
hash: "SHA-256",
},
material,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"],
);
}
export async function encrypt(text: string): Promise<string> {
const derivedKey = await getKey();
const iv = crypto.getRandomValues(new Uint8Array(12));
const ciphertext = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
derivedKey,
new TextEncoder().encode(text),
);
const combined = new Uint8Array(
iv.length + new Uint8Array(ciphertext).length,
);
combined.set(iv);
combined.set(new Uint8Array(ciphertext), iv.length);
return btoa(String.fromCharCode(...combined));
}
export async function decrypt(encoded: string): Promise<string> {
const derivedKey = await getKey();
const combined = Uint8Array.from(atob(encoded), (c) => c.charCodeAt(0));
const iv = combined.slice(0, 12);
const ciphertext = combined.slice(12);
const decrypted = await crypto.subtle.decrypt(
{ name: "AES-GCM", iv },
derivedKey,
ciphertext,
);
return new TextDecoder().decode(decrypted);
}