I am confused about this topic when it comes to AES encryption.
The MSDN page shows quite a lot of code used to encrypt/decrypt and uses multiple streams:
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
While the video on encryption from MS shows all of this done in a single line:
byte[] plainText = cryptTransform.TransofmrFinalBlock(cipherText, 0, cipherText.Length);
Why would I use the former over the latter? Is there something the first one does that the second on can't?
Related
I'm getting the following warning in the following code snippet but I cannot understand why
warning CA2202: Microsoft.Usage : Object 'memStream' can be disposed more than once in method 'Encrypt(string)'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.
Code:
string Encrypt(string toEncrypt)
{
byte[] key = ...
byte[] iv = ...
using (AesCng aes = new AesCng())
using (ICryptoTransform encryptor = aes.CreateEncryptor(key, iv))
using (MemoryStream memStream = new MemoryStream())
using (CryptoStream cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write))
{
UTF7Encoding encoder = new UTF7Encoding();
byte[] bytes = encoder.GetBytes(toEncrypt);
cryptoStream.Write(bytes, 0, bytes.Length);
cryptoStream.FlushFinalBlock();
return Convert.ToBase64String(memStream.ToArray());
}
}
The CryptoStream object, to the best of my knowledge, does not dispose of the passed in Stream when it itself is disposed. So how is it possible that the variable memStream can be disposed of more than once?
Many thanks.
CryptoStream.Dispose() will, by default, dispose the underlying stream. If you don't want that behavior you need to use the constructor overload that explicitly makes the underlying stream remain open when the CryptoStream is disposed.
You can see how that's implemented here.
You can use overloaded CryptoStream constructor with leaveOpen parameter.
And no need this because CryptoStream object in using block
cryptoStream.FlushFinalBlock();
Code:
string Encrypt(string toEncrypt)
{
byte[] key = ...
byte[] iv = ...
using (AesCng aes = new AesCng())
using (ICryptoTransform encryptor = aes.CreateEncryptor(key, iv))
using (MemoryStream memStream = new MemoryStream())
using (CryptoStream cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write,true))
{
UTF7Encoding encoder = new UTF7Encoding();
byte[] bytes = encoder.GetBytes(toEncrypt);
cryptoStream.Write(bytes, 0, bytes.Length);
return Convert.ToBase64String(memStream.ToArray());
}
}
leaveOpen: true to not close the underlying stream when the CryptoStream object is disposed
CryptoStream ctor
I am having some issues using RFC2898DeriveBytes. Here is the situation: I am creating a public/private key pair using RSACryptoProvider and I use Rfc2898 to encrypt the private key file. I am using the following code for encryption:
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(frm2.txtPassphrase.Text, saltbyte);
// Encrypt the data.
TripleDES encAlg = TripleDES.Create();
encAlg.Key = key.GetBytes(16);
// Create the streams used for encryption.
byte[] encrypted;
using (FileStream fsEncrypt = new FileStream(#"D:\test.xml", FileMode.Create, System.IO.FileAccess.Write))
{
using (CryptoStream csEncrypt = new CryptoStream(fsEncrypt, encAlg.CreateEncryptor(), CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(privateKeyXml);
}
}
}
This is for decryption:
TripleDES decAlg = TripleDES.Create();
Rfc2898DeriveBytes key1 = new Rfc2898DeriveBytes(frm1.txtPassphrase.Text, saltbyte);
decAlg.Key = key1.GetBytes(16);
// Create the streams used for decryption.
using (FileStream fsDecrypt = new FileStream(#"D:\test.xml", FileMode.Open, System.IO.FileAccess.Read))
{
using (CryptoStream csDecrypt = new CryptoStream(fsDecrypt, decAlg.CreateDecryptor(), CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
decPrivateKeyXml = srDecrypt.ReadToEnd();
}
}
}
Now the problem is that when I get the decPrivateKeyXml, all except the first few words come out correct. The first few words are just scrambled:
"�� ���dalue><Modulus>u9N+amIgXTw1zzJ+bxXoKaaGwCVFeXkKvdx0vhd24X7vvcJpnkA6gFgOeypbTTGm3if1QM/lyLN3qoprBkHJKDo7ldzj5a4L2Xb1tP1yUyNDban/KzkzsGK0h3fLO8UxRE6cHIB5cyEUmgmkjpFoXzz7DovUrZh3Z3qV20AHZLs=</Modulus><Exponent>AQAB</Exponent><P>5pCr4yPtn8ZyZskIpFM9pgZI1BUBIJYYhnYPywrMTj1smsQGuCswXNrcKsGvF6c9KrrXFF69AgbzcAsQwI449Q==</P><Q>0IvXoP8uELT/v8lG5R0YmvrgTfVQNJp8n8PT7J1dN3dsCDUHa+rK2Q4XSehFHT8XQgiENICkYg6xsdJqXXxY7w==</Q><DP>KwpSrAIm966J6JoanOJVHcsKiVyqazTZuzAK3rJTVT+uKG3zeynEy3CnrOufDeFQT8u1Hr5YtioqA35tUCS8iQ==</DP><DQ>UXZOxJTpaZ1KSaBWESlMcz2MYOdybRnrlHzqS4Ms5n2/tXUBcSZGFoNqlXQli0cZzrGE8v1NOQCEaPHImrv4AQ==</DQ><InverseQ>rX3TlQMreZvjm+fNS5UK90tj/KQQAlP0u5xxgEAUVfr8ZE/hsSOcB0MuXPyeGExRyRiBdSUsj64BHOVPH9+mcw==</InverseQ><D>H04JtNtz/3YolccZsZQaJM7/iIjtwmg9NRXIU2J/yueoN51ukxSra3bBux99JimPYVmRk+LSrpfS6xa07c8LIqMaC6nFQCVF6yJH3sHuDuL7Hob2dVZ+egyjeCVu8vyn1R4/SAZ4AaWtmc8c0Zt3hSvdDMCtN61HWegFmugvRkk=</D></RSAKeyValue>"
I don't know what is wrong with the code....
.NET uses a random IV for CBC encryption. You need to store this IV with the ciphertext and initialize your decryptor with it. Normally the IV is prefixed to the ciphertext.
the other links are not being useful to me.
i am encrypting string before saving in mysql database.that is working fine.but when i want to retrieve, its giving me length of data to encrypt is invalid error.
before my encryption requirement, i was using datatype of varchar size 500.now im using varbinary of size 800.can any1 advise me on the size too?
encryption method:
public static byte[] encryptStringToBytes(string plainText)
{
byte[] encrypted;
//create an Rijndael object
using (Rijndael rijAlg = Rijndael.Create())
{
//create a decrytor to perform the stream transform.
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
//create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
return encrypted;
}
decryption method:
public static string decryptStringFromBytes(byte[] cipherText)
{
string plaintext = null;
//create an Rijndael object
using (Rijndael rijAlg = Rijndael.Create())
{
//create a decrytor to perform the stream transform.
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
//create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
//read the decrypted bytes from the decrypting stream and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
retrieving from resultset
using (Rijndael myRijndael = Rijndael.Create())
{
temp5 = EncryptDecrypt.decryptStringFromBytes((byte[])reader.GetValue(reader.GetOrdinal("Body")));
}
You are not controlling key and IV in any way. This is kind of a problem... :) It results in your encryption being a random scrambling of the data because key and IV are randomly initialized by the framework.
Use the same key and IV for decryption as you are using them for encryption. Why do you think the database has to do with the problem? It hasn't and there is not evidence for that.
Please suggest me where i need to update/refactor the code to get rid of exception. I am getting exception while I try to decrypt the encrypted string using following code.
Following line is throwing exception
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
public string EncryptAuthenticationTokenAes(string plainText)
{
byte[] encrypted;
// Create an AesManaged object
// with the specified key and IV.
using (AesManaged aesAlg = new AesManaged())
{
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
aesAlg.Padding = PaddingMode.None;
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return Convert.ToBase64String(encrypted);
}
public string DecryptPasswordAes(string encryptedString)
{
//Convert cipher text back to byte array
byte[] cipherText = Convert.FromBase64String(encryptedString);
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an AesManaged object
// with the specified key and IV.
using (AesManaged aesAlg = new AesManaged())
{
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
aesAlg.Padding = PaddingMode.None;
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
Pretty standard bug when using CryptoStream, you forgot to force it to encrypt the last bytes of the stream. It keeps bytes in an internal buffer until enough of them arrive to emit a block. You must force the last few bytes out. Fix:
using (var msEncrypt = new MemoryStream())
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (var swEncrypt = new StreamWriter(csEncrypt)) {
swEncrypt.Write(plainText);
csEncrypt.FlushFinalBlock();
encrypted = msEncrypt.ToArray();
}
You got the exception when decrypting it because encrypted is missing the final padding. The real problem is caused by the using statement, you wouldn't have this problem if you waited obtaining the encrypted bytes until after the CryptoStream is closed. But that doesn't work well because the using statement on the StreamWriter also closes the CryptoStream and the MemoryStream. Explicitly using FlushFinalBlock() is the best workaround.
I got this (i also tried crStream.CopyTo(ms)):
var cryptic = new DESCryptoServiceProvider();
cryptic.Key = ASCIIEncoding.ASCII.GetBytes(passKey);
cryptic.IV = ASCIIEncoding.ASCII.GetBytes(passKey);
Stream crStream = new CryptoStream(data, cryptic.CreateEncryptor(), CryptoStreamMode.Write);
Stream ms = new MemoryStream();
var buffer = new byte[0x10000];
int n;
while ((n = crStream.Read(buffer, 0, buffer.Length)) != 0) // Exception occurs here
ms.Write(buffer, 0, n);
crStream.Close();
Data = Stream and contains a binary serialized class
The following exception occurs when i run it:
"Stream does not support reading."
What i am trying to accomplish is simply encrypt data from a stream. So i have an incoming stream and i want to encrypt that data and put it into the memory stream. This will then be compressed and saved to a file.
the error says everything: you create the stream for encryption (= put plain-text into and get encrypted output, in write):
Stream crStream = new CryptoStream(data, cryptic.CreateEncryptor(), CryptoStreamMode.Write);
Just have a look at the MSDN-Documentation for CryptoStream - there is a example included of how to do it right - it's basically this part (right from MSDN):
using (MemoryStream msEncrypt = new MemoryStream())
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}