C# & JS 加密方式 return 不同的结果
C# & JS encryption methods return different results
我在 C# 中有旧的加密代码,现在我必须在 JavaScript 中进行相同的加密。
我做了一些研究并尝试了 3 个不同的库,但无法获得相同的结果。我使用的最后一个库是 CryptoJS,我必须弄清楚为什么我会得到不同的结果。
以下是两个代码片段:
C#代码:
text = "chocolate";
PasswordHash = "hashhash";
SaltKey = "saltsaltsaltsa";
VIKey = "iviviviviviviviv";
byte[] plainTextBytes = Encoding.UTF8.GetBytes(text);
byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.Zeros };
var encryptor = symmetricKey.CreateEncryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));
byte[] cipherTextBytes;
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
cipherTextBytes = memoryStream.ToArray();
cryptoStream.Close();
}
memoryStream.Close();
}
var result = Convert.ToBase64String(cipherTextBytes);
结果==>“8AbNsyyqHHfi/PEF/bbiew==”
JavaScript代码:
pass = 'chocolate';
//Creating the Vector Key
var iv = CryptoJS.enc.Utf8.parse('iviviviviviviviv');
//Encoding the Password in from UTF8 to byte array
var passHash = CryptoJS.enc.Utf8.parse('hashhash');
//Encoding the Salt in from UTF8 to byte array
var Salt = CryptoJS.enc.Utf8.parse("saltsaltsaltsa");
//Creating the key in PBKDF2 format to be used during the encryption
var key128Bits1000Iterations = CryptoJS.PBKDF2(passHash, Salt, { keySize: 256 / 8, iterations: 1000 });
//Encrypting the string contained in cipherParams using the PBKDF2 key
var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(pass), key128Bits1000Iterations, { mode: CryptoJS.mode.CBC, iv: iv, padding: CryptoJS.pad.ZeroPadding });
var result = encrypted.ciphertext.toString(CryptoJS.enc.Base64);
result = "dpgTA41PDyrM8ef9C1c8iA==“
问题出在您的 PBKDF2 盐上。 CryptoJS 使用 WordArray
作为原语来存储盐。即,一个 32 位值的数组。 C# 使用 8 位值(显然,它是一个 byte
数组)。
请注意,在 JS 中:
var Salt = CryptoJS.lib.WordArray.create([1, 2]);
在 C# 中,等同于:
byte[] Salt = new byte[] { 0, 0, 0, 1, 0, 0, 0, 2 };
您可以通过在 JS 中输出以下内容来证明这一点:
var Salt = CryptoJS.lib.WordArray.create([1, 2]);
console.log(Salt.toString(CryptoJS.enc.Base64));
-> AAAAAQAAAAI=
CryptoJS 不喜欢将字符串用作盐。它一点都不喜欢。无论如何,您不应该使用字符串或短语作为盐,它应该随机生成并与密码哈希一起存储。
终于找到解决办法了。感谢 Luke Park 告诉我 CryptoJS 使用 4 字节(字)结构。
导致不同结果的问题是密钥大小(显然)不同。
在 C# 中,256/8 实际上是 32 字节长度,但是在 CryptoJS 中,由于使用 4 字节,256/8 实际上转换为 128 字节长度:(
一旦我将 JS 代码段中的密钥大小更改为 256/32 ((256/32)*4 = 32),它就可以完美运行并回显与 C# 加密方法相同的结果。
谢谢大家
尼尔
我在 C# 中有旧的加密代码,现在我必须在 JavaScript 中进行相同的加密。 我做了一些研究并尝试了 3 个不同的库,但无法获得相同的结果。我使用的最后一个库是 CryptoJS,我必须弄清楚为什么我会得到不同的结果。
以下是两个代码片段:
C#代码:
text = "chocolate";
PasswordHash = "hashhash";
SaltKey = "saltsaltsaltsa";
VIKey = "iviviviviviviviv";
byte[] plainTextBytes = Encoding.UTF8.GetBytes(text);
byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.Zeros };
var encryptor = symmetricKey.CreateEncryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));
byte[] cipherTextBytes;
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
cipherTextBytes = memoryStream.ToArray();
cryptoStream.Close();
}
memoryStream.Close();
}
var result = Convert.ToBase64String(cipherTextBytes);
结果==>“8AbNsyyqHHfi/PEF/bbiew==”
JavaScript代码:
pass = 'chocolate';
//Creating the Vector Key
var iv = CryptoJS.enc.Utf8.parse('iviviviviviviviv');
//Encoding the Password in from UTF8 to byte array
var passHash = CryptoJS.enc.Utf8.parse('hashhash');
//Encoding the Salt in from UTF8 to byte array
var Salt = CryptoJS.enc.Utf8.parse("saltsaltsaltsa");
//Creating the key in PBKDF2 format to be used during the encryption
var key128Bits1000Iterations = CryptoJS.PBKDF2(passHash, Salt, { keySize: 256 / 8, iterations: 1000 });
//Encrypting the string contained in cipherParams using the PBKDF2 key
var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(pass), key128Bits1000Iterations, { mode: CryptoJS.mode.CBC, iv: iv, padding: CryptoJS.pad.ZeroPadding });
var result = encrypted.ciphertext.toString(CryptoJS.enc.Base64);
result = "dpgTA41PDyrM8ef9C1c8iA==“
问题出在您的 PBKDF2 盐上。 CryptoJS 使用 WordArray
作为原语来存储盐。即,一个 32 位值的数组。 C# 使用 8 位值(显然,它是一个 byte
数组)。
请注意,在 JS 中:
var Salt = CryptoJS.lib.WordArray.create([1, 2]);
在 C# 中,等同于:
byte[] Salt = new byte[] { 0, 0, 0, 1, 0, 0, 0, 2 };
您可以通过在 JS 中输出以下内容来证明这一点:
var Salt = CryptoJS.lib.WordArray.create([1, 2]);
console.log(Salt.toString(CryptoJS.enc.Base64));
-> AAAAAQAAAAI=
CryptoJS 不喜欢将字符串用作盐。它一点都不喜欢。无论如何,您不应该使用字符串或短语作为盐,它应该随机生成并与密码哈希一起存储。
终于找到解决办法了。感谢 Luke Park 告诉我 CryptoJS 使用 4 字节(字)结构。
导致不同结果的问题是密钥大小(显然)不同。 在 C# 中,256/8 实际上是 32 字节长度,但是在 CryptoJS 中,由于使用 4 字节,256/8 实际上转换为 128 字节长度:(
一旦我将 JS 代码段中的密钥大小更改为 256/32 ((256/32)*4 = 32),它就可以完美运行并回显与 C# 加密方法相同的结果。
谢谢大家 尼尔