如何在 openssl 中解密使用 CryptoJs3+ 库加密的文件,该文件具有自定义迭代和密钥大小



我有一个由cryptojs加密的文本文件(也许还有一些自定义js函数来迭代密码的哈希),我想通过openssl在窗口中解密它.exe而不是浏览器(当我提供密码时,它可以完美地工作)。 看起来 cryptojs 使用了一些自定义的东西,例如使用 sha512 派生密钥并将其迭代 11512 次,如您在下面的 js 解密器中看到的那样,然后使用EVPKDF 迭代 484 次(我不知道这是什么意思)。从 cryptojs 解密文件的代码片段如下,我需要openssl exe -cli 参数来执行此操作,而无需在浏览器中使用该 js 库。

function hex2a(t) { //hex to ascii
for (var e = t.toString(), i = "", n = 0; n < e.length && "00" !== e.substr(n, 2); n += 2) i += String.fromCharCode(parseInt(e.substr(n, 2), 16));
return i; }
function decoder(secret, passwrd) {
for (var i = CryptoJS.SHA512(passwrd), n = 0; n < 11512; n++) 
i = CryptoJS.SHA512(i);
(CryptoJS.algo.AES.keySize = 32), 
(CryptoJS.algo.EvpKDF.cfg.iterations = 1e4), 
(CryptoJS.algo.EvpKDF.cfg.keySize = 32);
var r = CryptoJS.AES.decrypt(secret, i.toString());
return (out = hex2a(r)), out;
}

这是它调用函数并在成功解密时返回文件的时间。

var msg="base64 of the salted encrypted file via cryptojs"
function proceed() {
var pass=document.getElementById('textfield2').value;
a=decoder(msg, pass);
if (a.search('{version')>-1) {
document.getElementById('status').innerHTML="SUCCESS";
download("result.json",a);
}   else {
document.getElementById('status').innerHTML="FAILED";
}

我已经尝试过这个(Windows openssl.exe cli 1.1)并收到有关 -iter 和其他参数的错误。 不知道如何给它密钥大小 32 和迭代和 evpkdf 和 js 文件解密的仇恨。

OpenSSL.exe enc -aes-256-cbc -md md5 -d -pass pass:"simpletext" -in "tiny.bin" -out "result.txt"

使用OpenSSL解密基本上是不可能的,原因如下:

  • 指定的密钥大小AES.keySize = 32定义一个 128 字节的密钥(不直接在此处传递,而是从密码派生)。据推测,32字节的密钥是有意的,但CryptoJS以单词的形式指定密钥大小,其中单词由4个字节组成。
    AES 仅针对 16/24/32 字节密钥定义,即不针对使用的 128 字节密钥。尽管该密钥对 AES 无效,但由于错误(问题 #293),CryptoJS 会处理此密钥。
    从密钥大小直接派生整数,此处得出 38(源代码)。但是,AES 仅针对整数 10 (AES-128)、12 (AES-192) 和 14 (AES-256)(AES、安全性)定义。因此,生成的密文与AES不兼容,即使用符合AES的工具(特别是OpenSSL)进行解密通常是不可能的。
    为了可以使用OpenSSL进行解密,AES.keySize需要具有值4/6/8之一,该值对应于允许的整数10/12/14或AES-128/192/256。因此,配置AES.keySize = 32是所有符合AES的工具(如OpenSSL)的KO标准。

  • CryptoJS使用OpenSSL函数EVP_BytesToKey()进行密钥派生。但是,OpenSSL 不支持指定的迭代计数EvpKDF.cfg.iterations = 1e4用于使用EVP_BytesToKey()的密钥派生,只有值1(此处为最后一部分)。
    更现代的OpenSSL版本(从1.1.1开始)有-iter选项,但这只能与密钥派生PBKDF2一起使用,即如果指定了-iter,则会自动使用PBKDF2而不是EVP_BytesToKey(),这与CryptoJS不兼容。
    要使用OpenSSL进行解密,EvpKDF.cfg.iterations需要具有值1。因此,配置EvpKDF.cfg.iterations = 1e4是OpenSSL的KO标准。

  • 传递给 CryptoJS 的密码是通过使用 SHA512 进行多次哈希处理从原始密码派生出来的。正如Artjom B.的评论中所解释的那样,这不能单独使用OpenSSL来实现,但至少可以作为脚本的一部分。

  • EvpKDF.cfg.keySize参数对加密/解密没有影响,可以忽略。

如果在发布的代码中使用兼容值而不是不兼容的值,例如CryptoJS.algo.AES.keySize = 8CryptoJS.algo.EvpKDF.cfg.iterations = 1,使用OpenSSL解密是可能的。以下示例使用具有兼容值的已发布代码,并执行加密和解密。密文可以使用OpenSSL解密:

//
// Your code
//
function hex2a(t) {
for (var e = t.toString(), i = "", n = 0; n < e.length && "00" !== e.substr(n, 2); n += 2) i += String.fromCharCode(parseInt(e.substr(n, 2), 16));
return i; 
}
function decoder(secret, passwrd) {
for (var i = CryptoJS.SHA512(passwrd), n = 0; n < 11512; n++) i = CryptoJS.SHA512(i);
CryptoJS.algo.AES.keySize = 8;            // compatible with OpenSSL: 4/6/8, corresponds to AES-128/192/265
CryptoJS.algo.EvpKDF.cfg.iterations = 1;  // compatible with OpenSSL: 1
CryptoJS.algo.EvpKDF.cfg.keySize = 123;   // ignored
var r = CryptoJS.AES.decrypt(secret, i.toString());
return (out = hex2a(r)), out;
}
// 
// The encryption counterpart
//
function encrypt(secret, passwrd) {
for (var i = CryptoJS.SHA512(passwrd), n = 0; n < 11512; n++) i = CryptoJS.SHA512(i);
CryptoJS.algo.AES.keySize = 8;
CryptoJS.algo.EvpKDF.cfg.iterations = 1;
CryptoJS.algo.EvpKDF.cfg.keySize = 456;
console.log("CryptoJS input passphrase:n", i.toString().replace(/(.{56})/g,'$1n'));  
var ciphertext = CryptoJS.AES.encrypt(secret, i.toString());
return ciphertext;
}
// 
// Encryption, decryption
//
var ciphertext = encrypt('The quick brown fox jumps over the lazy dog', 'my initial passphrase');
var decryptedData = decoder(ciphertext, 'my initial passphrase');
console.log("Ciphertext:n", ciphertext.toString().replace(/(.{56})/g,'$1n'));  
console.log("Plaintext:n", decryptedData.replace(/(.{56})/g,'$1n'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

具有可能的输出:

CryptoJS input passphrase: 7bff3331f9dcfbb2e1c5b6cb4170689db91fe5b12258d59672fe0e9ce61780c61f3e6dc324e58cc2170c6a8010083aafe07930708ee63c0022a7e9bce784c4c5
Ciphertext: U2FsdGVkX1/3SLTOsvc6CoWfg53rR+l//pHiWstJibl5D5OopIFWVmhUDhEpj7zBZRjA1vQiIoU2F5qR1v8NEw==
Plaintext: The quick brown fox jumps over the lazy dog

密文可以使用以下 OpenSSL 语句解密(直接使用派生的密码):

openssl enc -aes-256-cbc -d -a -A -in <path to ciphertext file> -md md5 -pass pass:7bff3331f9dcfbb2e1c5b6cb4170689db91fe5b12258d59672fe0e9ce61780c61f3e6dc324e58cc2170c6a8010083aafe07930708ee63c0022a7e9bce784c4c5 

当使用与这些参数不同的参数时(例如AES.keySize = 32EvpKDF.cfg.iterations = 1e4),解密通常失败并导致解密错误(即使使用-iter 10000)。

最新更新