在 browser/CryptoJS 中解密 openssl AES 256 CBC

Decrypt openssl AES 256 CBC in browser/CryptoJS

我想在服务器上解密一个用openssl加密过的字符串,像这样:

openssl enc -e -aes-256-cbc -pbkdf2 -a -S 0123456789ABCDEF -A -k mypassword

请注意,这仅提供盐和密码即可完成,openssl 应自动处理密钥和 IV。当浏览器解密时也会发生这种情况,我是不是太乐观了?如果可能的话,我想只使用那些加密设置,或者增加复杂性的最低限度。在浏览器中,我正在尝试像这样使用 CryptoJS 解密:

import * as CryptoJS from 'crypto-js'

const encrypted = <ENCRYPTED_STRING_FROM_SERVER>
const password = 'mypassword'
const salt = '0123456789ABCDEF'
const key = CryptoJS.PBKDF2(password, salt) // Generate key

const bytes = CryptoJS.AES.decrypt(encrypted, key)
const decrypted = bytes.toString(CryptoJS.enc.Utf8)
console.log(decrypted)

但是 CryptoJS.AES.decrypt 的调用错误 Cannot read property '0' of undefinedcrypto-js/cipher-core.js:371。 CryptoJS.AES.decrypt 的文档非常薄,我知道在调用该 func 时更改的任何设置似乎都会出现相同的错误。感谢任何能发光的人!

OpenSSL语句中没有指定迭代次数和摘要,所以使用默认值10000和SHA256。这是相关的,因为 CryptoJS 使用不同的默认值(1 和 SHA1)。

CryptoJS对密文应用OpenSSL格式,即加密数据以Salted__的ASCII编码开头,后跟通过盐然后是密文。因此Base64编码密文的开头总是以U2FsdGVkX1.

开头

CryptoJS 使用 WordArray 数据类型,它封装了一个单词数组。一个字由4个字节组成。

解密时,首先要将密文和salt分开。然后,必须使用 PBKDF2 确定密钥和 IV。由于默认值不同,必须明确指定迭代次数和摘要。终于可以解密了:

// 1. Separate ciphertext and salt
var encrypted = "U2FsdGVkX18BI0VniavN78vlhR6fryIan0VvUrdIr+YeLkDYhO2xyA+/oVXJj/c35swVVkCqHPh9VdRbNQG6NQ=="
var encryptedWA = CryptoJS.enc.Base64.parse(encrypted);
var prefixWA = CryptoJS.lib.WordArray.create(encryptedWA.words.slice(0, 8/4));                             // Salted__ prefix
var saltWA = CryptoJS.lib.WordArray.create(encryptedWA.words.slice(8/4, 16/4));                            // 8 bytes salt: 0x0123456789ABCDEF
var ciphertextWA = CryptoJS.lib.WordArray.create(encryptedWA.words.slice(16/4, encryptedWA.words.length)); // ciphertext        

// 2. Determine key and IV using PBKDF2
var password = 'mypassword'
var keyIvWA = CryptoJS.PBKDF2(
    password, 
    saltWA, 
    {
        keySize: (32+16)/4,          // key and IV
        iterations: 10000,
        hasher: CryptoJS.algo.SHA256
    }
);
var keyWA = CryptoJS.lib.WordArray.create(keyIvWA.words.slice(0, 32/4));
var ivWA = CryptoJS.lib.WordArray.create(keyIvWA.words.slice(32/4, (32+16)/4));

// 3. Decrypt
var decryptedWA = CryptoJS.AES.decrypt(
    {ciphertext: ciphertextWA}, 
    keyWA, 
    {iv: ivWA}
);
var decrypted = decryptedWA.toString(CryptoJS.enc.Utf8)
console.log(decrypted)
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

可以在 CryptoJS documentation 中找到更多详细信息。

在浏览器中试试这个库 https://www.npmjs.com/package/cryptojs2 可以在文档中找到更多详细信息。