(encryptedValue: string, keyBase64: string)
| 208 | * Decrypts a value encrypted with encryptWithSymmetricKey. |
| 209 | */ |
| 210 | export function decryptWithSymmetricKey(encryptedValue: string, keyBase64: string): string { |
| 211 | if (!keyBase64) { |
| 212 | throw new EncryptionConfigurationError('Encryption key is required'); |
| 213 | } |
| 214 | |
| 215 | const parts = encryptedValue.split(':'); |
| 216 | if (parts.length !== 3) { |
| 217 | throw new EncryptionFormatError( |
| 218 | 'Invalid encrypted value format: expected iv:authTag:encrypted' |
| 219 | ); |
| 220 | } |
| 221 | const [ivBase64, authTagBase64, encrypted] = parts; |
| 222 | |
| 223 | const iv = Buffer.from(ivBase64, 'base64'); |
| 224 | const authTag = Buffer.from(authTagBase64, 'base64'); |
| 225 | const key = Buffer.from(keyBase64, 'base64'); |
| 226 | |
| 227 | if (key.length !== 32) { |
| 228 | throw new EncryptionConfigurationError('Encryption key must be exactly 32 bytes (256 bits)'); |
| 229 | } |
| 230 | |
| 231 | const decipher = createDecipheriv('aes-256-gcm', key, iv); |
| 232 | decipher.setAuthTag(authTag); |
| 233 | |
| 234 | let decrypted = decipher.update(encrypted, 'base64', 'utf8'); |
| 235 | decrypted += decipher.final('utf8'); |
| 236 | |
| 237 | return decrypted; |
| 238 | } |
| 239 | |
| 240 | // ---- Helpers for batch decryption ---- |
| 241 |
no test coverage detected