fuzzyworld

north-star / main_old / files / src / core / crypto.ts

Branch main_old · default branch · all branches

crypto.ts

Blame: the commit that last changed each line · file · history

36d64b37 2026-03-15 Pavel Safronov1const AES_PARAMS = { name: 'AES-GCM', length: 256 };
2const IV_BYTES = 12;
3
4export const generateRoomKey = () =>
5 crypto.subtle.generateKey(AES_PARAMS, true, ['encrypt', 'decrypt']);
6
b4e7f682 2026-03-16 Pavel Safronov7export const exportRoomKey = async (key: CryptoKey) => {
36d64b37 2026-03-15 Pavel Safronov8 const raw = await crypto.subtle.exportKey('raw', key);
9 return btoa(String.fromCharCode(...new Uint8Array(raw)))
10 .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
11};
12
b4e7f682 2026-03-16 Pavel Safronov13export const importRoomKey = async (base64url: string) => {
36d64b37 2026-03-15 Pavel Safronov14 const b64 = base64url.replace(/-/g, '+').replace(/_/g, '/');
15 const padded = b64 + '='.repeat((4 - (b64.length % 4)) % 4);
16 const raw = Uint8Array.from(atob(padded), (c) => c.charCodeAt(0));
17 return crypto.subtle.importKey('raw', raw, AES_PARAMS, false, ['encrypt', 'decrypt']);
18};
19
b4e7f682 2026-03-16 Pavel Safronov20export const encryptJson = async (key: CryptoKey, value: unknown) => {
36d64b37 2026-03-15 Pavel Safronov21 const iv = crypto.getRandomValues(new Uint8Array(IV_BYTES));
22 const plaintext = new TextEncoder().encode(JSON.stringify(value));
23 const ciphertext = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, plaintext);
24 const ivB64 = btoa(String.fromCharCode(...iv));
25 const ctB64 = btoa(String.fromCharCode(...new Uint8Array(ciphertext)));
26 return `${ivB64}:${ctB64}`;
27};
28
b4e7f682 2026-03-16 Pavel Safronov29export const decryptJson = async (key: CryptoKey, encryptedValue: string) => {
36d64b37 2026-03-15 Pavel Safronov30 const [ivB64, ctB64] = encryptedValue.split(':');
31 const iv = Uint8Array.from(atob(ivB64), (c) => c.charCodeAt(0));
32 const ciphertext = Uint8Array.from(atob(ctB64), (c) => c.charCodeAt(0));
33 const plaintext = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ciphertext);
34 return JSON.parse(new TextDecoder().decode(plaintext));
35};