Reputation: 11218
I found this one article: link to msdn
What I'm trying to do: encrypt Byte() array and then decrypt it. It works but the result of decrypting is not equal to origin array. Mine code:
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)
Where
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
And
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
How it works:
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
As we can see it looks like encryption is right, but decryption is totally wrong - it even have another number of members!
P.S. can it be in due to incorrect converting from string to Byte() in Decrypt
function?
One more interesting moment: decrypted
change it's size and give a new answer every time!
Upvotes: 1
Views: 1240
Reputation: 33098
Okay, really there's a whole lot wrong with your code.
My code snippets are going to be in C# because I haven't written VB in over 15 years. While they can read similarly I don't want to end up giving invalid syntax.
using
, then use it again.Apparently for RijndaelManaged
this just puts it back in the "I've never been used state", which causes the next use to generate a random key and IV. This was probably your biggest problem.
So, your Encrypt and Decrypt methods should remove the using
statements for the symmetric algorithm object (currently named RMCrypto
). Usually the creator of an object owns the lifetime, sometimes the lifetime is handed off to new objects; but almost never is the lifetime supposed to be terminated by a method you call.
You want AES (a restricted form of Rijndael, but one that interoperates much better). You "could" switch to AesManaged
, but shouldn't. Instead, you should use Aes.Create()
(some of the Aes-derived types only work on specific (versions of specific) operating systems. Aes.Create()
is supposed to always work.
Your call to msEncrypt.ToArray()
is inside the CryptoStream's using
, but you want it to be outside. Flip those two lines.
While this might be what you want, it probably isn't. AES (and Rijndael) is a block cipher algorithm, and block ciphers require complete blocks to operate. When the last block is deficient it gets "padded" to completion. PKCS7 is the "standard" padding mode, and the decryption can remove it (because it has strong enough rules). ANSI X.923 and ISO 10126 can also both be removed during decryption. Zeros cannot, because the "unpadder" can't tell if the zeros were real zeros, or padding zeros.
dataToDecrypt
.You're passing it to Encrypt, then the output of Encrypt to Decrypt. So this is just data
.
Your text is bytes from 1 to 16, that's definitely not UTF-8 text.
The StreamReader/StreamWriter you use suggest that you were trying to perform encryption on strings. Don't. Encryption/decryption is on bytes. (Aside from novelties like the Caesar cipher).
// 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();
}
}
Upvotes: 7