我正在尝试用Rfc2898DerivedBytes替换PasswordDerivedBytes,但是在获取unicode编码结果时遇到后者问题。
以此代码为例:
[TestMethod]
public void DerivedBytesTest()
{
string encrypted = "y4Ijqo9Ga/mHlFbLHDdDUkYZlyu7CHF4PVXGLnb8by7FAVtCgPLhFSiA9Et6hDac";
string key = "{00B3403A-3C29-4f26-A9CC-14C411EA8547}";
string salt = "gT5M07XB9hHl3l1s";
string expected = "4552065703414505";
string decrypted;
decrypted = Decrypt(encrypted, key, salt, true);
Assert.IsTrue(decrypted == expected); // Works
decrypted = Decrypt(encrypted, key, salt, false);
Assert.IsTrue(decrypted == expected); // Doesn't work, get wrong unicode characters in 24 character string
}
private string Decrypt(string encrypted, string key, string salt, bool legacy = false)
{
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] encryptedDataBytes = Convert.FromBase64String(encrypted);
byte[] saltBytes = encoding.GetBytes(salt);
RijndaelManaged encryption = new RijndaelManaged();
DeriveBytes secretKey;
if (legacy)
{
secretKey = new PasswordDeriveBytes(key, saltBytes) {IterationCount = 100};
encryption.Padding = PaddingMode.PKCS7;
}
else
{
secretKey = new Rfc2898DeriveBytes(key, saltBytes, 100);
encryption.Padding = PaddingMode.Zeros; // This is the only one that doesn't throw the "Padding is invalid and cannot be removed" exception, but gives me a non-ASCII result
}
ICryptoTransform decryptor = encryption.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));
string decryptedText = "";
using (MemoryStream memoryStream = new MemoryStream(encryptedDataBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
byte[] bytes = new byte[encryptedDataBytes.Length];
int decryptedCount = cryptoStream.Read(bytes, 0, bytes.Length);
decryptedText = encoding.GetString(bytes, 0, decryptedCount);
if (!legacy)
{
// Something more to do with result?
}
}
}
return decryptedText;
}
我想知道是否有人可以告诉我哪里出错了?
答案 0 :(得分:1)
PasswordDeriveBytes
是PBKDF1的一个严格实现的扩展,而Rfc2898DeriveBytes
是PBKDF2的实现。两者都从密码派生密钥,但它们是两种不同的算法,因此它们得出两种不同的结果。由于他们在下面使用加密安全哈希,因此无法将其转换为另一个。
如果您可以节省几个字节的存储空间,您仍然可以使用PKBDF1派生密钥,然后使用PBKDF2的结果加密该密钥。如果输出大小相同,你甚至可以使用XOR加密(一次性填充),但AES当然也可以工作。那么解密就变成:计算PBKDF2结果,解密数据密钥,使用数据密钥解密密文。
否则,您必须解密然后重新加密结果。
如果要比较解密结果,则比较生成的字节;不要先将其转换为字符串。强烈建议使用经过身份验证的加密或MAC,以便可以验证身份验证标记。通过使用零填充忽略填充异常是不可取的。这些填充错误发生在,因为密钥错误。
通用说明:
PasswordDeriveBytes
应该不用于任何数量的字节> PBKDF1的Mickeysoft扩展20字节是非常不安全的,甚至在输出中重复字节(!)。如果你对PBKDF2做同样的事情,那么任何对手都必须完成你必须做的工作的一半,这也不是一个好主意。
问题中的迭代计数非常低,但是您似乎使用高度随机的UID而不是密码应该没问题。