Reputation: 141
I have function for decrypting files using Rijnadel (AES). Looks like this:
public static bool FileDecrypt(string inputFile, string outputFile, string password)
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] salt = new byte[32];
FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);
fsCrypt.Read(salt, 0, salt.Length);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Padding = PaddingMode.PKCS7;
AES.Mode = CipherMode.CFB;
CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateDecryptor(), CryptoStreamMode.Read);
FileStream fsOut = new FileStream(outputFile, FileMode.Create);
int read;
byte[] buffer = new byte[1048576];
try
{
while ((read = cs.Read(buffer, 0, buffer.Length)) > 0)
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
fsOut.Write(buffer, 0, read);
}
}
catch (CryptographicException ex_CryptographicException)
{
fsOut.Close();
fsCrypt.Close();
LogWriter loger = new LogWriter("Cryptography error: " + ex_CryptographicException.ToString());
return false;
}
catch (Exception ex)
{
fsOut.Close();
fsCrypt.Close();
LogWriter loger = new LogWriter("Exception error: " + ex.ToString());
return false;
}
try
{
cs.Close();
}
catch (Exception ex)
{
fsCrypt.Close();
fsOut.Close();
LogWriter loger = new LogWriter("Error when closing Cryptostream. Error: " + ex.ToString());
return false;
}
finally
{
fsOut.Close();
fsCrypt.Close();
}
return true;
}
It decrypts the file and creates new decrypted file.
But i would like to decrypt that file and load it only into memory. Mostly xml configuration files so then i would like to read the xml configuration with xmlserializer and use it in my program and then dispose the file from memory. Is that possible? Thanks for all answers.
PS: Dont mind closing of streams in all catches. Finally block didnt work for some reason, still trying to figure that out.
//EDIT:
This is my try:
MemoryStream inMemoryCopy = new MemoryStream();
byte[] salt = new byte[32];
using (FileStream fs = File.OpenRead(inputfile))
{
fs.Read(salt, 0, salt.Length);
fs.CopyTo(inMemoryCopy);
}
byte[] bytesToBeDecrypted = inMemoryCopy.ToArray();
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Padding = PaddingMode.PKCS7;
AES.Mode = CipherMode.CFB;
CryptoStream cs = new CryptoStream(bytesToBeDecrypted, AES.CreateDecryptor(), CryptoStreamMode.Read);
Problem is i cannot use byte array in cryptostream. And can i somehow do that even without filestream?
Upvotes: 1
Views: 1004
Reputation: 911
You want to use XmlSerializer kinda like this to get some configuration object from stream. It doesn't matter wether the source stream is a FileStream, NetworkStream or even the CryptoStream itself. So there is no need to work with a byte buffer.
Note the following code is adapted from your code. I stripped the try catch from it to just only show the core code needed for the deserialization.
public SomeConfig ReadEncryptedConfiguration(string inputFile, string password)
{
using (var stream = CreateStream(inputFile, password))
{
var ser = new XmlSerializer(typeof(SomeConfig));
var config = (SomeConfig) ser.Deserialize(stream);
return config;
}
}
The CreateStream method will make the stream which is used and disposed in the previous part. I used another constructor to make sure that the underlying file stream is disposed when the CryptoStream is being disposed.
public CryptoStream CreateStream(string inputFile, string password)
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] salt = new byte[32];
FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);
fsCrypt.Read(salt, 0, salt.Length);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Padding = PaddingMode.PKCS7;
AES.Mode = CipherMode.CFB;
return new CryptoStream(fsCrypt, AES.CreateDecryptor(), CryptoStreamMode.Read, false);
}
Upvotes: 1