| 83 | // --- AES-256-GCM encryption --- |
| 84 | |
| 85 | export function encryptWithDataKey(data: unknown, dataKey: Uint8Array): Uint8Array { |
| 86 | const nonce = getRandomBytes(12); |
| 87 | const cipher = createCipheriv('aes-256-gcm', dataKey, nonce); |
| 88 | const plaintext = new TextEncoder().encode(JSON.stringify(data)); |
| 89 | const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]); |
| 90 | const authTag = cipher.getAuthTag(); |
| 91 | |
| 92 | // Bundle: version(1) + nonce(12) + ciphertext + authTag(16) |
| 93 | const bundle = new Uint8Array(1 + 12 + encrypted.length + 16); |
| 94 | bundle[0] = 0; // version |
| 95 | bundle.set(nonce, 1); |
| 96 | bundle.set(new Uint8Array(encrypted), 13); |
| 97 | bundle.set(new Uint8Array(authTag), 13 + encrypted.length); |
| 98 | return bundle; |
| 99 | } |
| 100 | |
| 101 | export function decryptWithDataKey(bundle: Uint8Array, dataKey: Uint8Array): unknown | null { |
| 102 | if (bundle.length < 1 + 12 + 16) return null; // minimum: version + nonce + authTag |