我正在尝试在服务器上加密jpeg并在浏览器上将其解密,如下所示,但是在步骤3中失败了。
我尝试了以下操作,但无济于事。
服务器上的加密
public byte[] Encrypt(byte[] bytes, string password, string vector)
{
AesManaged aes = new AesManaged();
aes.KeySize = _keySize;
aes.BlockSize = _blockSize;
aes.Mode = CipherMode.CBC;
aes.IV = Encoding.UTF8.GetBytes(vector);
aes.Key = Encoding.UTF8.GetBytes(password);
aes.Padding = PaddingMode.PKCS7;
byte[] encrypted = aes.CreateEncryptor().TransformFinalBlock(bytes, 0, bytes.Length);
return encrypted;
}
客户端解密
// These values are same as above
var encrypted = ... // byte[]
var vector = ... // string
var password = ... // string
var cipherParams = CryptoJS.lib.CipherParams.create({
iv: CryptoJS.enc.Utf8.parse(vector),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
var cipherText = CryptoJS.lib.WordArray.create(encrypted);
var passwordWordArray = CryptoJS.enc.Utf8.parse(password);
var decrypted = CryptoJS.AES.decrypt(cipherText, passwordWordArray, cipherParams);
// decrypted.words is empty here
请告知。
我在Windows 10上使用.Net Core MVC 2.1,Crypto-JS 3.1.9-1和Chrome74.0.3729.169。
此问题已解决
正如Topaco提到的那样,javascript中存在一个缺陷。更正后的代码如下。
var encrypted = ... // byte[]
var vector = ... // string
var password = ... // string
var cipherParams = CryptoJS.lib.CipherParams.create({
iv: CryptoJS.enc.Utf8.parse(vector),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
var cipherText = CryptoJS.lib.WordArray.create(encrypted);
var cipherTextParam = CryptoJS.lib.CipherParams.create({
ciphertext: cipherText
});
var passwordWordArray = CryptoJS.enc.Utf8.parse(password);
var decrypted = CryptoJS.AES.decrypt(cipherTextParam, passwordWordArray, cipherParams);
谢谢您的帮助。
答案 0 :(得分:1)
JavaScript代码中有两个缺陷,可以纠正如下:
在JavaScript代码行中:
var cipherText = CryptoJS.lib.WordArray.create(encrypted);
必须替换为:
var cipherText = byteArrayToWordArray(encrypted);
在这里,使用功能byteArrayToWordArray
:
function byteArrayToWordArray(ba) {
var wa = [], i;
for (i = 0; i < ba.length; i++)
wa[(i / 4) | 0] |= ba[i] << (24 - 8 * i);
return CryptoJS.lib.WordArray.create(wa, ba.length);
}
此函数通过从字节数组的4个字节生成一个字(4个字节)来从字节数组生成一个字数组。在旧的代码中,每个字节生成一个具有相同值的单词,即两个数组具有相同数量的元素,这是错误的。
或者:
var cipherTextHex = bytesToHex(encrypted);
var cipherText = CryptoJS.enc.Hex.parse(cipherTextHex);
也可以使用。在这里,使用功能bytesToHex
:
function bytesToHex(bytes) {
for (var hex = [], i = 0; i < bytes.length; i++) {
var current = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];
hex.push((current >>> 4).toString(16));
hex.push((current & 0xF).toString(16));
}
return hex.join("");
}
该函数从字节数组生成一个十六进制字符串。由此,使用适当的encoder得出单词数组。
在JavaScript代码中,以下行:
var decrypted = CryptoJS.AES.decrypt(cipherText, passwordWordArray, cipherParams);
必须替换为:
var cipherParamsCipherText = CryptoJS.lib.CipherParams.create({
ciphertext: cipherText
});
var decrypted = CryptoJS.AES.decrypt(cipherParamsCipherText, passwordWordArray, cipherParams);
因为decrypted
函数期望CipherParams
对象代替WordArray
作为第一个参数。
或者,也可以传递Base64编码的字符串:
var cipherTextB64Enc = CryptoJS.enc.Base64.stringify(cipherText);
var decrypted = CryptoJS.AES.decrypt(cipherTextB64Enc, passwordWordArray, cipherParams);
测试:C#代码提供以下输入:
byte[] bytes = Encoding.UTF8.GetBytes("The quick brown fox jumps over the lazy dog");
string password = "0123456789012345"; // 16 byte -> AES-128
string vector = "5432109876543210"; // 16 byte
以下字节数组为密文:
170, 27, 161, 209, 42, 247, 234, 191, 38, 167, 22, 74, 34, 139, 115, 0, 75, 207, 119, 161, 97, 142, 179, 93, 41, 12, 177, 128, 52, 151, 75, 231, 76, 157, 14, 197, 59, 111, 63, 206, 136, 218, 189, 244, 116, 43, 25, 20
如果修改后的JavaScript代码已与这些数据一起测试:
var encrypted = [170,27,161,209,42,247,234,191,38,167,22,74,34,139,115,0,75,207,119,161,97,142,179,93,41,12,177,128,52,151,75,231,76,157,14,197,59,111,63,206,136,218,189,244,116,43,25,20]; // byte[]
var vector = "5432109876543210" // string
var password = "0123456789012345"; // string
它已正确解密。
在测试中,使用了AES-128。只需使用32字节密钥而不是16字节密钥即可将其切换为AES-256。