|
1 |
| -import AES from 'crypto-js/aes' |
2 |
| -import Utf8 from 'crypto-js/enc-utf8' |
| 1 | +import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'crypto' |
3 | 2 | import { getConfig } from '../../config'
|
4 |
| - |
5 | 3 | const { encryptionKey } = getConfig()
|
6 | 4 |
|
7 | 5 | /**
|
8 |
| - * Decrypts a text with the configured encryption key via ENCRYPTION_KEY env |
9 |
| - * @param ciphertext |
10 |
| - */ |
| 6 | + * Generate CryptoJs.AES key from passphrase |
| 7 | + * https://github.com/brix/crypto-js/issues/468 |
| 8 | + * */ |
| 9 | +function convertPassphraseToAesKeyBuffer(key: string, salt: Buffer): Buffer { |
| 10 | + const password = Buffer.concat([Buffer.from(key, 'binary'), salt]) |
| 11 | + const hash: Buffer[] = [] |
| 12 | + let digest = password |
| 13 | + for (let i = 0; i < 3; i++) { |
| 14 | + hash[i] = createHash('md5').update(digest).digest() |
| 15 | + digest = Buffer.concat([hash[i]!, password]) |
| 16 | + } |
| 17 | + return Buffer.concat(hash) |
| 18 | +} |
| 19 | + |
| 20 | +/** |
| 21 | + * Replicate CryptoJs.AES.decrypt method |
| 22 | + * */ |
11 | 23 | export function decrypt(ciphertext: string): string {
|
12 |
| - return AES.decrypt(ciphertext, encryptionKey).toString(Utf8) |
| 24 | + try { |
| 25 | + const cipherBuffer = Buffer.from(ciphertext, 'base64') |
| 26 | + const salt = cipherBuffer.subarray(8, 16) |
| 27 | + const keyDerivation = convertPassphraseToAesKeyBuffer(encryptionKey, salt) |
| 28 | + const [key, iv] = [keyDerivation.subarray(0, 32), keyDerivation.subarray(32)] |
| 29 | + const contents = cipherBuffer.subarray(16) |
| 30 | + const decipher = createDecipheriv('aes-256-cbc', key, iv) |
| 31 | + const decrypted = Buffer.concat([decipher.update(contents), decipher.final()]) |
| 32 | + return decrypted.toString('utf8') |
| 33 | + } catch (e) { |
| 34 | + throw e |
| 35 | + } |
13 | 36 | }
|
14 | 37 |
|
15 | 38 | /**
|
16 |
| - * Encrypts a text with the configured encryption key via ENCRYPTION_KEY env |
17 |
| - * @param plaintext |
18 |
| - */ |
| 39 | + * Replicate CryptoJs.AES.encrypt method |
| 40 | + * */ |
19 | 41 | export function encrypt(plaintext: string): string {
|
20 |
| - return AES.encrypt(plaintext, encryptionKey).toString() |
| 42 | + try { |
| 43 | + const salt = randomBytes(8) |
| 44 | + const keyDerivation = convertPassphraseToAesKeyBuffer(encryptionKey, salt) |
| 45 | + const [key, iv] = [keyDerivation.subarray(0, 32), keyDerivation.subarray(32)] |
| 46 | + const cipher = createCipheriv('aes-256-cbc', key, iv) |
| 47 | + const contents = Buffer.concat([cipher.update(plaintext), cipher.final()]) |
| 48 | + const encrypted = Buffer.concat([Buffer.from('Salted__', 'utf8'), salt, contents]) |
| 49 | + return encrypted.toString('base64') |
| 50 | + } catch (e) { |
| 51 | + throw e |
| 52 | + } |
21 | 53 | }
|
0 commit comments