C# 中使用 MD5 和 SHA256 的 CryptoJS AES 加密未生成正确的值
CryptoJS AES encryption with MD5 and SHA256 in C# not generated proper value
我想使用 CryptoJS 和 C# 来加密密码。不幸的是,我的 C# 代码无法生成正确的值。这是我的代码
internal static byte[] ComputeSha256(this byte[] value)
{
using (SHA256 sha256Hash = SHA256.Create())
return sha256Hash.ComputeHash(value);
}
internal static byte[] ComputeSha256(this string value) => ComputeSha256(Encoding.UTF8.GetBytes(value));
internal static byte[] ComputeMD5(this byte[] value)
{
using (MD5 md5 = MD5.Create())
return md5.ComputeHash(value);
}
internal static byte[] ComputeMD5(this string value) => ComputeMD5(Encoding.UTF8.GetBytes(value));
internal static byte[] CombineByteArray(byte[] first, byte[] second)
{
byte[] bytes = new byte[first.Length + second.Length];
Buffer.BlockCopy(first, 0, bytes, 0, first.Length);
Buffer.BlockCopy(second, 0, bytes, first.Length, second.Length);
return bytes;
}
internal static string EncryptPassword()
{
using (AesManaged aes = new AesManaged())
{
//CLIENT SIDE PASSWORD HASH
/*
var password = '12345';
var passwordMd5 = CryptoJS.MD5(password);
var passwordKey = CryptoJS.SHA256(CryptoJS.SHA256(passwordMd5 + '12345678') + '01234567890123456');
var encryptedPassword = CryptoJS.AES.encrypt(passwordMd5, passwordKey, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding });
encryptedPassword = CryptoJS.enc.Base64.parse(encryptedPassword.toString()).toString(CryptoJS.enc.Hex);
//encryptedPassword result is c3de82e9e8a28a4caded8c2ef0d49c80
*/
var y1 = Encoding.UTF8.GetBytes("12345678");
var y2 = Encoding.UTF8.GetBytes("01234567890123456");
var password = "12345";
var passwordMd5 = ComputeMD5(password);
var xkey = CombineByteArray(ComputeSha256(CombineByteArray(passwordMd5, y1)), y2);
var passwordKey = ComputeSha256(xkey);
aes.Key = passwordKey;
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.None;
ICryptoTransform crypt = aes.CreateEncryptor();
byte[] cipher = crypt.TransformFinalBlock(passwordMd5, 0, passwordMd5.Length);
var encryptedPassword = BitConverter.ToString(cipher).Replace("-", "").ToLower();
return encryptedPassword; //e969b60e87339625c32f805f17e6f993
}
}
上述 C# 代码的结果是 e969b60e87339625c32f805f17e6f993
。它应该与 CryptoJS c3de82e9e8a28a4caded8c2ef0d49c80
相同。这里有什么问题?
在 CryptoJS 代码哈希(以 WordArray
s 的形式)和字符串添加在几个地方。因此 WordArray
被隐式编码为 toString()
为小写字母的十六进制字符串。 C# 代码中缺少此内容。
在 C# 代码中,添加是通过 CombineByteArray()
完成的,其中散列作为 byte[]
在参数 first
中传递。因此这个参数必须先转换为小写字母的十六进制编码字符串,然后再进行UTF8编码,例如:
internal static byte[] CombineByteArray(byte[] first, byte[] second)
{
// Hex encode (with lowercase letters) and Utf8 encode
string hex = ByteArrayToString(first).ToLower();
first = Encoding.UTF8.GetBytes(hex);
byte[] bytes = new byte[first.Length + second.Length];
Buffer.BlockCopy(first, 0, bytes, 0, first.Length);
Buffer.BlockCopy(second, 0, bytes, first.Length, second.Length);
return bytes;
}
其中 ByteArrayToString()
来自 here.
通过此更改,C# 代码给出与 CryptoJS 代码相同的结果。
我不太清楚 CryptoJS 代码的用途。通常明文和密钥是独立的,即不是从同一个密码派生的。
也许这应该实现自定义的基于密码的密钥派生功能。如果是这样,并且除非出于兼容性原因强制执行自定义实现,否则使用经过验证的算法(例如 Argon2 或 PBKDF2)会更安全。特别是缺少 salt/work 因素是不安全的。
我想使用 CryptoJS 和 C# 来加密密码。不幸的是,我的 C# 代码无法生成正确的值。这是我的代码
internal static byte[] ComputeSha256(this byte[] value)
{
using (SHA256 sha256Hash = SHA256.Create())
return sha256Hash.ComputeHash(value);
}
internal static byte[] ComputeSha256(this string value) => ComputeSha256(Encoding.UTF8.GetBytes(value));
internal static byte[] ComputeMD5(this byte[] value)
{
using (MD5 md5 = MD5.Create())
return md5.ComputeHash(value);
}
internal static byte[] ComputeMD5(this string value) => ComputeMD5(Encoding.UTF8.GetBytes(value));
internal static byte[] CombineByteArray(byte[] first, byte[] second)
{
byte[] bytes = new byte[first.Length + second.Length];
Buffer.BlockCopy(first, 0, bytes, 0, first.Length);
Buffer.BlockCopy(second, 0, bytes, first.Length, second.Length);
return bytes;
}
internal static string EncryptPassword()
{
using (AesManaged aes = new AesManaged())
{
//CLIENT SIDE PASSWORD HASH
/*
var password = '12345';
var passwordMd5 = CryptoJS.MD5(password);
var passwordKey = CryptoJS.SHA256(CryptoJS.SHA256(passwordMd5 + '12345678') + '01234567890123456');
var encryptedPassword = CryptoJS.AES.encrypt(passwordMd5, passwordKey, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding });
encryptedPassword = CryptoJS.enc.Base64.parse(encryptedPassword.toString()).toString(CryptoJS.enc.Hex);
//encryptedPassword result is c3de82e9e8a28a4caded8c2ef0d49c80
*/
var y1 = Encoding.UTF8.GetBytes("12345678");
var y2 = Encoding.UTF8.GetBytes("01234567890123456");
var password = "12345";
var passwordMd5 = ComputeMD5(password);
var xkey = CombineByteArray(ComputeSha256(CombineByteArray(passwordMd5, y1)), y2);
var passwordKey = ComputeSha256(xkey);
aes.Key = passwordKey;
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.None;
ICryptoTransform crypt = aes.CreateEncryptor();
byte[] cipher = crypt.TransformFinalBlock(passwordMd5, 0, passwordMd5.Length);
var encryptedPassword = BitConverter.ToString(cipher).Replace("-", "").ToLower();
return encryptedPassword; //e969b60e87339625c32f805f17e6f993
}
}
上述 C# 代码的结果是 e969b60e87339625c32f805f17e6f993
。它应该与 CryptoJS c3de82e9e8a28a4caded8c2ef0d49c80
相同。这里有什么问题?
在 CryptoJS 代码哈希(以 WordArray
s 的形式)和字符串添加在几个地方。因此 WordArray
被隐式编码为 toString()
为小写字母的十六进制字符串。 C# 代码中缺少此内容。
在 C# 代码中,添加是通过 CombineByteArray()
完成的,其中散列作为 byte[]
在参数 first
中传递。因此这个参数必须先转换为小写字母的十六进制编码字符串,然后再进行UTF8编码,例如:
internal static byte[] CombineByteArray(byte[] first, byte[] second)
{
// Hex encode (with lowercase letters) and Utf8 encode
string hex = ByteArrayToString(first).ToLower();
first = Encoding.UTF8.GetBytes(hex);
byte[] bytes = new byte[first.Length + second.Length];
Buffer.BlockCopy(first, 0, bytes, 0, first.Length);
Buffer.BlockCopy(second, 0, bytes, first.Length, second.Length);
return bytes;
}
其中 ByteArrayToString()
来自 here.
通过此更改,C# 代码给出与 CryptoJS 代码相同的结果。
我不太清楚 CryptoJS 代码的用途。通常明文和密钥是独立的,即不是从同一个密码派生的。
也许这应该实现自定义的基于密码的密钥派生功能。如果是这样,并且除非出于兼容性原因强制执行自定义实现,否则使用经过验证的算法(例如 Argon2 或 PBKDF2)会更安全。特别是缺少 salt/work 因素是不安全的。