使用ECB模式的CryptoJS AES加密在相同的参数下产生不同的结果

问题描述 投票:1回答:1

answer中所述,我可以使用ECB模式将转换后的值反向转换为纯文本,而不仅仅是将其与另一个哈希值进行比较。

但是,使用下面的代码段:

const x = CryptoJS.AES.encrypt('abc', '123', { mode: CryptoJS.mode.ECB }).toString()
const y = CryptoJS.AES.encrypt('abc', '123', { mode: CryptoJS.mode.ECB }).toString()

console.log(x, y, x === y)
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

我得到:

U2FsdGVkX19blKXDRXfdgXyviCrZtouB0cPcJPoR/cQ= U2FsdGVkX1+1AwWqKWntLVkh7DtiZxPDYCDNsjmc8LM= false

我做错什么了吗?有没有办法达到预期的结果?

javascript cryptojs
1个回答
0
投票

首先:对于相同的明文和相同的密钥,在ECB模式下始终生成相同的密文!

如果将WordArray用作第二个参数,则CryptoJS.AES.encrypt执行用密钥加密,并且所得密文与预期的[[相同(here):

function encryptWithKey(plaintext, key){ var encrypted = CryptoJS.AES.encrypt(plaintext, key, { mode: CryptoJS.mode.ECB }); console.log("Ciphertext (Base64): " + encrypted.toString()); // Ciphertext var decrypted = CryptoJS.AES.decrypt(encrypted.toString(), key, { mode: CryptoJS.mode.ECB }); console.log("Decrypted: " + decrypted.toString(CryptoJS.enc.Utf8)); // Plaintext } var key = CryptoJS.enc.Hex.parse('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'); encryptWithKey('abc', key); encryptWithKey('abc', key);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
但是如果将字符串用作第二个参数,则CryptoJS.AES.encrypt执行

使用密码加密,并且所得密文为不同

here)。不过,解密当然会返回原始的纯文本:

function encryptWithPassphrase(plaintext, passphrase){ var encrypted = CryptoJS.AES.encrypt(plaintext, passphrase, { mode: CryptoJS.mode.ECB }); console.log("Ciphertext (OpenSSL): " + encrypted.toString()); // Salt and actual ciphertext in OpenSSL format var decrypted = CryptoJS.AES.decrypt(encrypted.toString(), passphrase, { mode: CryptoJS.mode.ECB }); console.log("Decrypted: " + decrypted.toString(CryptoJS.enc.Utf8)); // Plaintext } encryptWithPassphrase('abc', '123'); encryptWithPassphrase('abc', '123');
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

说明:在使用密码短语进行加密的过程中,会生成random 8字节的盐,从中与密码短语一起生成实际的密钥(32字节,AES-256)。该盐旨在使彩虹表的使用不可行。 由于每次都会随机生成盐,因此生成的密钥不同,因此密文也不同。 CryptoJS.AES.encrypt返回一个CipherParams对象,该对象封装了盐和实际密文之类的相关参数。CipherParams转换该对象格式转换为OpenSSL格式,该格式由toString()的ASCII编码组成,后跟8个字节的盐,然后是实际的密文,均由Base64编码。因此,所有密文均以Salted__开头。

U2FsdGVkX1
function encryptWithPassphraseParams(plaintext, passphrase){
    var encrypted = CryptoJS.AES.encrypt(plaintext, passphrase, { mode: CryptoJS.mode.ECB });
    console.log("Salt (hex):           " + encrypted.salt);       // Salt (hex)
    console.log("Key (hex):            " + encrypted.key);        // Key (hex)
    console.log("Ciphertext (hex):     " + encrypted.ciphertext); // Actual ciphertext (hex)
    console.log("Ciphertext (OpenSSL): " + encrypted.toString()); // Salt and actual ciphertext, Base64 encoded, in OpenSSL format
    console.log("\n");
}

encryptWithPassphraseParams('abc', '123'); 
encryptWithPassphraseParams('abc', '123');

详细信息:

当导出密钥时,CryptoJS使用带有摘要MD5和1的迭代计数的OpenSSL功能<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>,这不是很安全。使用可靠的KDF(例如PBKDF2)以及随后使用生成的密钥进行的加密,会更加安全。除安全性外,应注意EVB_BytesToKey没有实现标准,因此必须首先在不可用的库中实现(或从Internet复制)此功能。

注意:

ECB是一种不安全的模式,不应使用(EVB_BytesToKey),最好是经过身份验证的加密,例如GCM。有关CryptoJS的更多详细信息,请参见其文档(EVB_BytesToKey)。
© www.soinside.com 2019 - 2024. All rights reserved.