How to decrypt message with CryptoJS AES. I have a working Ruby example
我能够使用Ruby解密AES加密消息,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 | require 'openssl' require 'base64' data ="IYkyGxYaNgHpnZWgwILMalVFmLWFgTCHCZL9263NOcfSo5lBjAzOZAtF5bF++R0Bi+9c9E+p3VEr/xvj4oABtRWVJ2wlWzLbYC2rKFk5iapFhb7uZCUpO4w4Su3a5QFa2vInjYueziRoqySZd/DpstMJ8rsJ94VGizFFFZ1l0sw1ax+wfBAv5+wHs/hlnHi/ea66KBO3rgXKahvV28h+4bh5etc8RCrmiiNbfg6Oj0jQJDjdYIdW8T9YPOI9E1hih8lbfRnMWcOFJgYekfLpoy5LI525UGnlM46J1k6ekLqsn9FqvbiOOoLgqa4YqBm1i9P0ePyjkME+t+RiL8xXX+ItgOYr9G7kM64wlTJPCW8B/crmUdmGzQNC/hD/u/8wfHBS2f8u6OtQMG/+Kpk1oju8lcUZGI/4S8A6/OuktvQr2zgnbs2aADMrM37Oait/pJ3G73S7NwVT8EaK+X43c0C/fUvW2/bD/rqCNpAh9WQlz4Cj6JHwjbmwuind6aCimF1tHjXuR9FXu+g17sPT4ZkKZ6aeBG+m170XdCGn2hVM0wH1rh3VeCG2u/JFqfuGKGSoqeHeNY/icu9pEhtZDzHd7aPoaMXcWvXC9PjooBf7GM1EPacSdnon1kBobjtKSt1l15DjO5TMrJoX7VO7GotQwo+uI/u5Kop01hBXxyxyggl1/8N0ESohPJoqLDrIwvbGK5kW4B49FVPnx9CMvjZDdSsoxPAh+hx6SPe8Hj0Nx4bRs06cbtOkte/V8QSYIqjiJDleEqPrdiKlvgToZz9L29ZR/3Ln65qU1sq7q9c0SEYxIopV7TdTjFS7y76zDPFZkhzc3DjfLtJo/M1hdtt648APcZdmAIgWH6fh3eJZ0qbiPh8RStYH7I2COmnlMw4+t/B5mlhYVSgwPK2Ir736Mh+P9Bw0fF8r9Ghhs4AJzpU0RiK9d1tCsrLfK/hSRwTXhtsSB6eDWEGkO7oeEIz43mgn0sv3SrA9JNHzYkg=" key ="2e35f242a46d67eeb74aabc37d5e5d05" aes = OpenSSL::Cipher::Cipher.new('aes-128-cbc') aes.decrypt aes.key = key.scan(/../).collect{ |x| x.hex }.pack('c*') aes.iv = Base64.decode64(data)[0...16] puts aes.update(Base64.decode64(data)[16..-1]) + aes.final # => JSON data... |
作为CryptoJS的新手,我无法将其他替代方法结合在一起。到目前为止,这是我所做的:
1 2 3 4 5 6 7 8 | data ="IYkyGxYaNgHpnZWgwILMalVFmLWFgTCHCZL9263NOcfSo5lBjAzOZAtF5bF++R0Bi+9c9E+p3VEr/xvj4oABtRWVJ2wlWzLbYC2rKFk5iapFhb7uZCUpO4w4Su3a5QFa2vInjYueziRoqySZd/DpstMJ8rsJ94VGizFFFZ1l0sw1ax+wfBAv5+wHs/hlnHi/ea66KBO3rgXKahvV28h+4bh5etc8RCrmiiNbfg6Oj0jQJDjdYIdW8T9YPOI9E1hih8lbfRnMWcOFJgYekfLpoy5LI525UGnlM46J1k6ekLqsn9FqvbiOOoLgqa4YqBm1i9P0ePyjkME+t+RiL8xXX+ItgOYr9G7kM64wlTJPCW8B/crmUdmGzQNC/hD/u/8wfHBS2f8u6OtQMG/+Kpk1oju8lcUZGI/4S8A6/OuktvQr2zgnbs2aADMrM37Oait/pJ3G73S7NwVT8EaK+X43c0C/fUvW2/bD/rqCNpAh9WQlz4Cj6JHwjbmwuind6aCimF1tHjXuR9FXu+g17sPT4ZkKZ6aeBG+m170XdCGn2hVM0wH1rh3VeCG2u/JFqfuGKGSoqeHeNY/icu9pEhtZDzHd7aPoaMXcWvXC9PjooBf7GM1EPacSdnon1kBobjtKSt1l15DjO5TMrJoX7VO7GotQwo+uI/u5Kop01hBXxyxyggl1/8N0ESohPJoqLDrIwvbGK5kW4B49FVPnx9CMvjZDdSsoxPAh+hx6SPe8Hj0Nx4bRs06cbtOkte/V8QSYIqjiJDleEqPrdiKlvgToZz9L29ZR/3Ln65qU1sq7q9c0SEYxIopV7TdTjFS7y76zDPFZkhzc3DjfLtJo/M1hdtt648APcZdmAIgWH6fh3eJZ0qbiPh8RStYH7I2COmnlMw4+t/B5mlhYVSgwPK2Ir736Mh+P9Bw0fF8r9Ghhs4AJzpU0RiK9d1tCsrLfK/hSRwTXhtsSB6eDWEGkO7oeEIz43mgn0sv3SrA9JNHzYkg="; key ="2e35f242a46d67eeb74aabc37d5e5d05"; CryptoJS.AES.decrypt(atob(data).substring(16), key, { iv: atob(cipher).substring(0, 16), mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); |
CryptoJS是否以某种不同的方式期望数据,密钥和初始化向量?据我了解,IV是数据中的前16个字节。
这适用于使用javascript解密。
1 2 3 4 | <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/aes.js"> var key ="2e35f242a46d67eeb74aabc37d5e5d05"; var data = CryptoJS.AES.encrypt("Message", key); // Encryption Part var decrypted = CryptoJS.AES.decrypt(data, key).toString(CryptoJS.enc.Utf8); // Message |
猜猜我参加聚会有点晚了。
这似乎对我有用(将解码后的字符串写入控制台):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | data ="IYkyGxYaNgHpnZWgwILMalVFmLWFgTCHCZL9263NOcfSo5lBjAzOZAtF5bF++R0Bi+9c9E+p3VEr/xvj4oABtRWVJ2wlWzLbYC2rKFk5iapFhb7uZCUpO4w4Su3a5QFa2vInjYueziRoqySZd/DpstMJ8rsJ94VGizFFFZ1l0sw1ax+wfBAv5+wHs/hlnHi/ea66KBO3rgXKahvV28h+4bh5etc8RCrmiiNbfg6Oj0jQJDjdYIdW8T9YPOI9E1hih8lbfRnMWcOFJgYekfLpoy5LI525UGnlM46J1k6ekLqsn9FqvbiOOoLgqa4YqBm1i9P0ePyjkME+t+RiL8xXX+ItgOYr9G7kM64wlTJPCW8B/crmUdmGzQNC/hD/u/8wfHBS2f8u6OtQMG/+Kpk1oju8lcUZGI/4S8A6/OuktvQr2zgnbs2aADMrM37Oait/pJ3G73S7NwVT8EaK+X43c0C/fUvW2/bD/rqCNpAh9WQlz4Cj6JHwjbmwuind6aCimF1tHjXuR9FXu+g17sPT4ZkKZ6aeBG+m170XdCGn2hVM0wH1rh3VeCG2u/JFqfuGKGSoqeHeNY/icu9pEhtZDzHd7aPoaMXcWvXC9PjooBf7GM1EPacSdnon1kBobjtKSt1l15DjO5TMrJoX7VO7GotQwo+uI/u5Kop01hBXxyxyggl1/8N0ESohPJoqLDrIwvbGK5kW4B49FVPnx9CMvjZDdSsoxPAh+hx6SPe8Hj0Nx4bRs06cbtOkte/V8QSYIqjiJDleEqPrdiKlvgToZz9L29ZR/3Ln65qU1sq7q9c0SEYxIopV7TdTjFS7y76zDPFZkhzc3DjfLtJo/M1hdtt648APcZdmAIgWH6fh3eJZ0qbiPh8RStYH7I2COmnlMw4+t/B5mlhYVSgwPK2Ir736Mh+P9Bw0fF8r9Ghhs4AJzpU0RiK9d1tCsrLfK/hSRwTXhtsSB6eDWEGkO7oeEIz43mgn0sv3SrA9JNHzYkg="; key ="2e35f242a46d67eeb74aabc37d5e5d05"; // Decode the base64 data so we can separate iv and crypt text. var rawData = atob(data); var iv = btoa(rawData.substring(0,16)); var crypttext = btoa(rawData.substring(16)); // Decrypt... var plaintextArray = CryptoJS.AES.decrypt( { ciphertext: CryptoJS.enc.Base64.parse(crypttext), salt:"" }, CryptoJS.enc.Hex.parse(key), { iv: CryptoJS.enc.Base64.parse(iv) } ); // Convert hex string to ASCII. // See https://stackoverflow.com/questions/11889329/word-array-to-string function hex2a(hex) { var str = ''; for (var i = 0; i < hex.length; i += 2) str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); return str; } console.log(hex2a(plaintextArray.toString())); |
重要的一点是要在输入中不加salt,如jlvaquero所说,将键作为WordArray传递。可能需要提高一些效率,例如我猜想有一种将字符串转换为WordArray的方法,比返回base64和返回方法更简单,但至少可以成功解码。我将hex2a函数从StackOverflow问题单词数组提升为字符串。
编辑:我想出了如何使用CryptoJS将字符串转换为WordArrays,反之亦然,因此不需要额外的base64编码/解码和十六进制至ASCII函数。而且事实证明,无需指定salt属性。这更加紧凑和高效:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | data ="IYkyGxYaNgHpnZWgwILMalVFmLWFgTCHCZL9263NOcfSo5lBjAzOZAtF5bF++R0Bi+9c9E+p3VEr/xvj4oABtRWVJ2wlWzLbYC2rKFk5iapFhb7uZCUpO4w4Su3a5QFa2vInjYueziRoqySZd/DpstMJ8rsJ94VGizFFFZ1l0sw1ax+wfBAv5+wHs/hlnHi/ea66KBO3rgXKahvV28h+4bh5etc8RCrmiiNbfg6Oj0jQJDjdYIdW8T9YPOI9E1hih8lbfRnMWcOFJgYekfLpoy5LI525UGnlM46J1k6ekLqsn9FqvbiOOoLgqa4YqBm1i9P0ePyjkME+t+RiL8xXX+ItgOYr9G7kM64wlTJPCW8B/crmUdmGzQNC/hD/u/8wfHBS2f8u6OtQMG/+Kpk1oju8lcUZGI/4S8A6/OuktvQr2zgnbs2aADMrM37Oait/pJ3G73S7NwVT8EaK+X43c0C/fUvW2/bD/rqCNpAh9WQlz4Cj6JHwjbmwuind6aCimF1tHjXuR9FXu+g17sPT4ZkKZ6aeBG+m170XdCGn2hVM0wH1rh3VeCG2u/JFqfuGKGSoqeHeNY/icu9pEhtZDzHd7aPoaMXcWvXC9PjooBf7GM1EPacSdnon1kBobjtKSt1l15DjO5TMrJoX7VO7GotQwo+uI/u5Kop01hBXxyxyggl1/8N0ESohPJoqLDrIwvbGK5kW4B49FVPnx9CMvjZDdSsoxPAh+hx6SPe8Hj0Nx4bRs06cbtOkte/V8QSYIqjiJDleEqPrdiKlvgToZz9L29ZR/3Ln65qU1sq7q9c0SEYxIopV7TdTjFS7y76zDPFZkhzc3DjfLtJo/M1hdtt648APcZdmAIgWH6fh3eJZ0qbiPh8RStYH7I2COmnlMw4+t/B5mlhYVSgwPK2Ir736Mh+P9Bw0fF8r9Ghhs4AJzpU0RiK9d1tCsrLfK/hSRwTXhtsSB6eDWEGkO7oeEIz43mgn0sv3SrA9JNHzYkg="; key ="2e35f242a46d67eeb74aabc37d5e5d05"; // Decode the base64 data so we can separate iv and crypt text. var rawData = atob(data); var iv = rawData.substring(0,16); var crypttext = rawData.substring(16); // Decrypt... var plaintextArray = CryptoJS.AES.decrypt( { ciphertext: CryptoJS.enc.Latin1.parse(crypttext) }, CryptoJS.enc.Hex.parse(key), { iv: CryptoJS.enc.Latin1.parse(iv) } ); console.log(CryptoJS.enc.Latin1.stringify(plaintextArray)); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | encryptWithCryptoJS(plainText: string): string { const key = CryptoJS.enc.Utf8.parse("hf8685nfhfhjs9h8"); const iv1 = CryptoJS.enc.Utf8.parse("hf8685nfhfhjs9h8"); const encrypted = CryptoJS.AES.encrypt(plainText, key, { keySize: 16, iv: iv1, mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }); return encrypted +""; } decryptionWithCryptoJS(cipher: string): string { const key = CryptoJS.enc.Utf8.parse("hf8685nfhfhjs9h8"); const iv1 = CryptoJS.enc.Utf8.parse("hf8685nfhfhjs9h8"); const plainText = CryptoJS.AES.decrypt(cipher, key, { keySize: 16, iv: iv1, mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }); return plainText.toString(CryptoJS.enc.Utf8); } |
1 2 3 4 5 6 7 8 9 10 | var key = CryptoJS.enc.Utf8.parse('8080808080808080'); var iv = CryptoJS.enc.Utf8.parse('8080808080808080'); var _enid = CryptoJS.AES.decrypt(data, key, { keySize: 128 / 8, iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }).toString(CryptoJS.enc.Utf8); return _enid; |
对于另一个用户提供的hex2a,如果ASCII代码超过128(即文本包含中文等),则可能无法正常工作。
您可以使用以下代码返回正确的unicode
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function hex2a(hex) { var str = ''; for (var i = 0; i < hex.length; i += 2){ var dec = parseInt(hex.substr(i, 2), 16); character = String.fromCharCode(dec); if (dec > 127) character ="%"+hex.substr(i,2); str += character; } return decodeURI(str); } |