我发现了这篇文章:link to msdn
我想做的事情:加密Byte()数组然后解密它。 它工作但解密的结果不等于原始数组。 我的代码:
Dim RMCrypto As New RijndaelManaged()
RMCrypto.Key = Key
RMCrypto.IV = IV
RMCrypto.Padding = PaddingMode.Zeros
Dim dataToDecrypt As Byte() = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
Dim encrypted As Byte() = Encrypt(dataToDecrypt, RMCrypto)
Dim roundtrip As Byte() = Decrypt(encrypted, RMCrypto)
其中
Private Function Encrypt(ByVal plainText As Byte(), RMCrypto As RijndaelManaged) As Byte()
Dim encrypted() As Byte
Using RMCrypto
' Create a decrytor to perform the stream transform.
Dim encryptor As ICryptoTransform = RMCrypto.CreateEncryptor(RMCrypto.Key, RMCrypto.IV)
' Create the streams used for encryption.
Using msEncrypt As New MemoryStream()
Using csEncrypt As New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
Using swEncrypt As New StreamWriter(csEncrypt)
'Write all data to the stream.
swEncrypt.Write(plainText)
End Using
encrypted = msEncrypt.ToArray()
End Using
End Using
End Using
' Return the encrypted bytes from the memory stream.
Return encrypted
End Function 'Encrypt
和
Private Function Decrypt(ByVal cipherText() As Byte, RMCrypto As RijndaelManaged) As Byte()
Dim plaintext As Byte()
Using RMCrypto
' Create a decrytor to perform the stream transform.
Dim decryptor As ICryptoTransform = RMCrypto.CreateDecryptor(RMCrypto.Key, RMCrypto.IV)
' Create the streams used for decryption.
Using msDecrypt As New MemoryStream(cipherText)
Using csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
Using srDecrypt As New StreamReader(csDecrypt)
' Read the decrypted bytes from the decrypting stream
' and place them in a string.
plaintext = Encoding.UTF8.GetBytes(srDecrypt.ReadToEnd())
End Using
End Using
End Using
End Using
Return plaintext
End Function 'Decrypt
工作原理:
Input: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
encrypted: 221 54 108 65 95 233 31 124 101 181 205 176 13 233 85 252
decrypted: 15 45 15 239 191 189 239 191 189 14 58 239 191 189 9 118 37 239 191 189 212 149 239 191 189 58
正如我们所看到的,加密似乎是正确的,但解密是完全错误的 - 它甚至还有其他数量的成员!
P.S。可能是由于在Decrypt
函数中从字符串到Byte()的错误转换?
还有一个有趣的时刻:decrypted
改变它的大小,每次都给出一个新的答案!
答案 0 :(得分:4)
好的,你的代码确实存在很多错误。
我的代码片段将在C#中,因为我已经超过15年没有编写VB了。虽然他们可以阅读类似的内容,但我并不想最终提供无效的语法。
using
处理对象,然后再次使用它。显然对于RijndaelManaged
这只是将它放回到"我从未使用状态",这导致下一次使用生成随机密钥和IV。这可能是你最大的问题。
因此,您的Encrypt和Decrypt方法应删除对称算法对象(当前名为using
)的RMCrypto
语句。通常,对象的创建者拥有生命周期,有时生命周期会被移交给新对象;但几乎永远不会被你打电话的方法终止。
你想要AES(一种限制形式的Rijndael,但是它可以更好地互操作)。你"可能"切换到AesManaged
,但不应该。相反,您应该使用Aes.Create()
(某些Aes派生类型仅适用于特定的(特定版本)操作系统。Aes.Create()
应始终有效。
您对msEncrypt.ToArray()
的来电是在CryptoStream的using
内,但您希望它在外面。翻转这两行。
虽然这可能是你想要的,但它可能不是。 AES(和Rijndael)是一种分组密码算法,分组密码需要完整的块才能运行。当最后一个区块不足时,它会得到" padded"完成。 PKCS7是"标准"填充模式,解密可以删除它(因为它有足够强大的规则)。在解密期间也可以删除ANSI X.923和ISO 10126。 Zeros不能,因为" unpadder"无法判断零是真正的零还是填充零。
dataToDecrypt
。您将其传递给Encrypt,然后将Encrypt的输出传递给Decrypt。所以这只是data
。
您的文字是1到16之间的字节,绝对不是UTF-8文字。
您使用的StreamReader / StreamWriter建议您尝试对字符串执行加密。唐'吨。加密/解密是以字节为单位的。 (除了像凯撒密码这样的新奇事物)。
// The using goes here, with the Create call. Not in anything it gets passed to.
using (Aes aes = Aes.Create())
{
aes.Key = key;
aes.IV = iv;
// PKCS7 is the default padding mode,
// if you don't like trusting defaults you can set it here.
byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
byte[] encrypted = Encrypt(data, aes);
byte[] roundtrip = Decrypt(encrypted, aes);
}
private static byte[] Encrypt(byte[] data, SymmetricAlgorithm alg)
{
// You didn't have a using for this, but should have:
using (ICryptoTransform encryptor = alg.CreateEncryptor())
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(data, 0, data.Length);
}
// Now that the CryptoStream has closed the data has been padded.
return msEncrypt.ToArray();
}
}
private static byte[] Decrypt(byte[] data, SymmetricAlgorithm alg)
{
using (ICryptoTransform decryptor = alg.CreateDecryptor())
using (MemoryStream msDecrypt = new MemoryStream())
{
// Just keep using this in write mode. All it does is say whether
// You'll be explicitly loading data via Write, or implicitly via Read.
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write))
{
csDecrypt.Write(data, 0, data.Length);
}
// Now that the CryptoStream has closed the data has been de-padded.
return msDecrypt.ToArray();
}
}