I have issues to get the data decrypted and not sure what I do wrong as tried almost everything.
private static byte[] AES_Encrypt(byte[] byteArray)
{
byte[] salt = GenerateRandomSalt();
MemoryStream fsCrypt = new MemoryStream();
byte[] ms = new byte[0];
byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(keyName);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = 256;
AES.BlockSize = 128;
AES.Padding = PaddingMode.None;
var key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CFB;
fsCrypt.Write(salt, 0, salt.Length);
CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write);
MemoryStream fsIn = new MemoryStream(byteArray);
byte[] buffer = new byte[1048576];
int read;
try
{
if (byteArray.Length <= buffer.Length)
cs.Write(buffer, 0, buffer.Length);
else
while ((read = fsIn.Read(buffer, 0, buffer.Length)) > 0)
{
cs.Write(buffer, 0, read);
}
ms = fsCrypt.ToArray();
fsIn.Close();
}
catch (Exception ex)
{
}
finally
{
try
{
cs.Close();
fsCrypt.Close();
}
catch (Exception err)
{
}
}
string response = Encoding.UTF8.GetString(ms.ToArray());
return ms.ToArray();
}
private static byte[] AES_Decrypt(byte[] byteArray)
{
byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(keyName);
byte[] salt = new byte[32];
byte[] ms = new byte[0];
MemoryStream fsCrypt = new MemoryStream(byteArray);
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.None;
AES.Mode = CipherMode.CFB;
MemoryStream fsOut = new MemoryStream();
CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateDecryptor(), CryptoStreamMode.Read);
int read;
byte[] buffer = new byte[1048576];
try
{
string response = Encoding.UTF8.GetString(byteArray);
if (byteArray.Length <= buffer.Length)
{
while ((read = cs.Read(byteArray, 0, byteArray.Length)) > 0)
{
fsOut.Read(byteArray, 0, read);
}
string vresponse = Encoding.UTF8.GetString(fsOut.ToArray());
}
else
while ((read = cs.Read(buffer, 0, buffer.Length)) > 0)
{
fsOut.Write(buffer, 0, read);
}
}
catch (System.Security.Cryptography.CryptographicException ex_CryptographicException)
{
}
catch (Exception ex)
{
}
try
{
cs.Close();
}
catch (Exception ex)
{
}
finally
{
fsOut.Close();
//fsCrypt.Close();
}
return ms.ToArray();
}
My data is sometimes shorter than the 1MB being used so I want to catch th shorter data to use less byte, however its for later concern.
The data I send to the decryptor is using the same static keys now and the inbound encrypted data is identical as the out type encrypted data.
If I put the PaddingMode.None; to PaddingMode.PKCS7 it gives me a mapping error, which comes as I assume in the shorter string than the buffer actually is, so as far my assumations this is correct, so I use for now 'none'.
I have looked to lots of links as:
https://stackoverflow.com/questions/31486028/decrypting-cryptostream-into-memorystream
https://stackoverflow.com/questions/31486028/decrypting-cryptostream-into-memorystream
https://stackoverflow.com/questions/8583112/padding-is-invalid-and-cannot-be-removed
[Encrypt to memory stream, pass it to file stream
[AES encryption on large files
The problem I cant figure out why the encrypted data wont decrypt as should.
100% sure I do something not correct but cant figure out what, any help would be appriciated.
I have changes some code and tried different options, now using this but on both option I get errors.
using (var msi = new MemoryStream())
{
try
{
using (var cs = new CryptoStream(msi, aesAlg.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytes, 0, bytes.Length); //Option 1, gives error, length is invalid of byte array
do //Option 2, give error, Padding is invalid and cannot be removed.
{
count = msi.Read(bytes, 0, blockSizeBytes);
offset += count;
cs.Write(data, 0, count);
}
while (count > 0);
}
var plainText = msi.ToArray();
var text = Encoding.Unicode.GetString(plainText);
}
catch (Exception e)
{
}
//return text;
}
I checked the data length and using Unicode encoding it is 4258 and the bytes are 8516, which should be from my point of view as using Unicode.
Not sure if using the right encoding as found this https://stackoverflow.com/a/10380166/3763117 and can do without but gives same lengthas unicode. little stucked on this any help with some samples would be appriciated.
Related
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?
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);
}
I am attempting to decrypt a file to ONLY the process memory. I do not want the actual file to be sent to plain text as it will be storing sensitive data. I do not want the raw text sitting on the system at all.
I am currently testing with a eula file in C:\ BUT get the same issue no matter what file I use.
I am using AES with salting. Decrypting the file does work as right now I am dumping the decrypted data to the text document but when I am attempting to compile the decrpytedBytes into a string, it only outputs 3 characters that are non-existent in that order anywhere inside of the document.
https://i.imgur.com/WAQ2njB.png
Those 2 characters show up while using System.Text.Encoding.UTF8.GetString(bytesDecrypted, 0, bytesDecrypted.Length) to compile the byte array to a string.
I have attempted just a basic .ToString() but that returned System.Byte[] and nothing more
https://i.imgur.com/Gg5Et72.png
While using var str = System.Text.Encoding.Default.GetString(bytesDecrypted) it only outputs ÿþ*
https://i.imgur.com/94hMuB3.png
Here is the code I am using for encryption and decryption
public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
public void EncryptFile(string file, string fileEncrypted, string password)
{
byte[] bytesToBeEncrypted = File.ReadAllBytes(file);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);
File.WriteAllBytes(fileEncrypted, bytesEncrypted);
listBox1.Items.Add("Enrypted the file");
}
public void DecryptFile(string fileEncrypted, string file, string password)
{
byte[] bytesToBeDecrypted = File.ReadAllBytes(fileEncrypted);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
byte[] bytesDecrypted = AES_Decrypt(bytesToBeDecrypted, passwordBytes);
listBox1.Items.Add("Attempting Decryption");
File.WriteAllBytes(file, bytesDecrypted);
var str = System.Text.Encoding.Default.GetString(bytesDecrypted);
richTextBox1.Text = str;
}
If you have any idea/clues on how I could manage to get this working I would greatly appreciate it!
You used the incorrect encoding to to decode your decrypted byte array. The encoding of the original text file is most likely Unicode/UTF-16. Thus, use the Encoding.Unicode encoding to decode the decrypted byte array back to text:
var str = System.Text.Encoding.Unicode.GetString(bytesDecrypted);
Some background information
So, what made me think that the encoding of the original text file is UTF-16/Unicode?
This information from the question gives a crucial hint:
While using var str = System.Text.Encoding.Default.GetString(bytesDecrypted) it only outputs ÿþ*
Note the ÿþ. This is how an UTF-16 LE BOM (*) appears if text data having this BOM is decoded/shown using the ISO/IEC 8859-1 (or CP-1252) code page, which often is the default code page used in many (english/non-localized) Windows installations.
(*) The UTF-16 LE BOM (UTF-16 Little-Endian Byte Order Mark) are two bytes 0xFF,0xFE. To learn more about what BOMs are and what their purpose is, i suggest this Wikipedia article: https://en.wikipedia.org/wiki/Byte_order_mark
Found this answer that I think applies to your issue. Pay special attention to "encryptedData = output.ToArray();"
Reading from a cryptostream to the end of the stream
byte[] encryptedData;
rijCrypto.Padding = System.Security.Cryptography.PaddingMode.ISO10126;
rijCrypto.KeySize = 256;
using (var input = new MemoryStream(Encoding.Unicode.GetBytes(tempData)))
using (var output = new MemoryStream())
{
var encryptor = rijCrypto.CreateEncryptor();
using (var cryptStream = new CryptoStream(output, encryptor, CryptoStreamMode.Write))
{
var buffer = new byte[1024];
var read = input.Read(buffer, 0, buffer.Length);
while (read > 0)
{
cryptStream.Write(buffer, 0, read);
read = input.Read(buffer, 0, buffer.Length);
}
cryptStream.FlushFinalBlock();
encryptedData = output.ToArray();
}
}
Edit: solved - problem was the decryption function. Corrected decryption function can be found in the answer below.
I have spent the last day at work trying to figure out where I went wrong with this implementation of AES. We need to be able to encrypt/decrypt large files so I have used file streams and write to disk each chunk. AES is a requirement as this needs to work with an existing system written in java which uses AES/CBC/PKCS5Padding (which as far as I am aware is equivalent to PKCS7/CBC)
This implementation works for most files. However there are a few files where the last 5 bytes of raw data are missing. The file will decrypt without errors however the hash doesn't match and the missing bytes are a combination of real data and trailing zeros.
It should be noted that these streams are gzipped before and after encryption (code at the bottom).
Encryption
public static void AesEncrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream)
{
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.BlockSize = 128;
symmetricKey.KeySize = 256;
const int chunkSize = 4096;//1024 * 1024 * 10;
using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, ivBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(outStream, encryptor, CryptoStreamMode.Write))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes ? new byte[(int)remainingBytes] : new byte[chunkSize];
dataStream.Read(buffer, 0, buffer.Length);
cryptoStream.Write(buffer, 0, buffer.Length);
cryptoStream.Flush();
}
cryptoStream.FlushFinalBlock();
}
}
symmetricKey.Clear();
}
Decryption
public static void AesDecrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream)
{
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.BlockSize = 128;
symmetricKey.KeySize = keyBytes.Length == 32 ? 256 : 128;
const int chunkSize = 4096;
using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, ivBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(dataStream, decryptor, CryptoStreamMode.Read))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes
? new byte[(int) remainingBytes]
: new byte[chunkSize];
cryptoStream.Read(buffer, 0, buffer.Length);
outStream.Write(buffer, 0, buffer.Length);
outStream.Flush();
}
//cryptoStream.FlushFinalBlock(); // Was throwing an exception
}
}
symmetricKey.Clear();
}
Compression (Prior to encryption)
public static void StreamCompress(Stream dataStream, FileStream outStream)
{
dataStream.Position = 0;
outStream.Position = 0;
const int chunkSize = 4096;
using (GZipStream gzs = new GZipStream(outStream, CompressionMode.Compress))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes ? new byte[(int)remainingBytes] : new byte[chunkSize];
dataStream.Read(buffer, 0, buffer.Length);
gzs.Write(buffer, 0, buffer.Length);
gzs.Flush();
}
}
}
Decompression (After decryption)
public static void StreamDecompress(Stream dataStream, FileStream outStream)
{
byte[] buffer = new byte[4096];
dataStream.Position = 0;
using (GZipStream gzs = new GZipStream(dataStream, CompressionMode.Decompress))
{
for (int r = -1; r != 0; r = gzs.Read(buffer, 0, buffer.Length))
if (r > 0) outStream.Write(buffer, 0, r);
}
}
I have gone through some other questions but cannot figure out why this only occurs on some files. The file size which fails is 46,854,144 bytes. This seems to work fine with larger and smaller files though.
Any help would be greatly appreciated.
The issue was with the way I was decrypting the data. I was incorrectly using the CryptoStream. The updated Decrypt function is below if anyone was interested.
public static void AesDecrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream)
{
dataStream.Position = 0;
outStream.Position = 0;
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.BlockSize = 128;
symmetricKey.KeySize = keyBytes.Length == 32 ? 256 : 128;
const int chunkSize = 4096;
using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, ivBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(outStream, decryptor, CryptoStreamMode.Write))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes
? new byte[(int) remainingBytes]
: new byte[chunkSize];
var bytesRead = dataStream.Read(buffer, 0, buffer.Length);
cryptoStream.Write(buffer, 0, bytesRead);
}
cryptoStream.FlushFinalBlock();
}
}
symmetricKey.Clear();
}
I am trying to encrypt a Generic Stream in C#. Although the program has no problems, the encryption and decryption return blank when converted to strings. Any help is appreciated.
public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
// Set your salt here, change it to meet your flavor:
// The salt bytes must be at least 8 bytes.
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 10000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}
public byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
// Set your salt here, change it to meet your flavor:
// The salt bytes must be at least 8 bytes.
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 10000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
private void Encrypt(Stream input, Stream output, String password)
{
input.Position = 0;
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
using (var stream = new MemoryStream())
{
byte[] buffer = new byte[2048]; // read in chunks of 2KB
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, bytesRead);
var tmp = AES_Encrypt(buffer, passwordBytes);
output.Write(tmp, 0, tmp.Length);
}
}
}
private void Decrypt(Stream input, Stream output, String password)
{
input.Position = 0;
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
using (var stream = new MemoryStream())
{
byte[] buffer = new byte[2048]; // read in chunks of 2KB
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, bytesRead);
var tmp = AES_Decrypt(buffer, passwordBytes);
output.Write(tmp, 0, tmp.Length);
}
}
}
static void Main(string[] args)
{
Program obj = new Program();
var message = new MemoryStream();
var cipher = new MemoryStream();
string tmp = "This is a test if the encryption is working!";
StreamWriter sw = new StreamWriter(message);
sw.Write(tmp);
obj.Encrypt(message, cipher, "password");
cipher.Position = 0;
message = new MemoryStream();
obj.Decrypt(cipher, message, "password");
using (var memoryStream = new MemoryStream())
{
message.CopyTo(memoryStream);
var bytesdecrypt = memoryStream.ToArray();
string result = Encoding.UTF8.GetString(bytesdecrypt);
Console.WriteLine(result);
Console.ReadLine();
}
}
}
}
The problem is probably when I am reading and writing from and to the streams.
There are many problems with this code.
The reason why nothing is decrypted is because you forgot to reset the message stream before doing message.CopyTo(memoryStream), because CopyTo works from the current position and you haven't changed the position after decryption.
You could reset it with
message.Position = 0;
If arbitrary data is encrypted, AES with some mode of operation like CBC is not enough. We generally need some kind of padding scheme. In C# the default scheme is PKCS#7 padding. Unambiguous padding is always added even when the plaintext is already a multiple of the block size. In those cases a full padding block is added.
Now the problem is that you're reading 2048 byte chunks during encryption and decryption, but the encryption produces 2064 byte ciphertext chunks which must be read as such during decryption. This is a simple fix, but it would be better to use streams all the way instead of encrypting such separate chunks.
You're invoking Rfc2898DeriveBytes for every 2048 byte chunk, but it never changes. Either introduce randomness, but actually using a random salt and random IV, or cache the key. (random salt and random IV are still necessary to reach semantic security)
I have error from CryptoStream:
Padding is invalid and cannot be removed.
Code
public MemoryStream EncrypteBytes(Stream inputStream, string passPhrase, string saltValue)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
RijndaelCipher.Padding = PaddingMode.PKCS7;
RijndaelCipher.Mode = CipherMode.CBC;
byte[] salt = Encoding.ASCII.GetBytes(saltValue);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, salt, "SHA1", 2);
ICryptoTransform Encryptor = RijndaelCipher.CreateEncryptor(password.GetBytes(32), password.GetBytes(16));
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, Encryptor, CryptoStreamMode.Write);
var buffer = new byte[1024];
var read = inputStream.Read(buffer, 0, buffer.Length);
while (read > 0)
{
cryptoStream.Write(buffer, 0, read);
read = inputStream.Read(buffer, 0, buffer.Length);
}
cryptoStream.FlushFinalBlock();
memoryStream.Position = 0;
return memoryStream;
}
// Example usage: DecryptBytes(encryptedBytes, "SensitivePhrase", "SodiumChloride");
public byte[] DecrypteBytes(MemoryStream memoryStream, string passPhrase, string saltValue)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
RijndaelCipher.Padding = PaddingMode.PKCS7;
RijndaelCipher.Mode = CipherMode.CBC;
byte[] salt = Encoding.ASCII.GetBytes(saltValue);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, salt, "SHA1", 2);
ICryptoTransform Decryptor = RijndaelCipher.CreateDecryptor(password.GetBytes(32), password.GetBytes(16));
CryptoStream cryptoStream = new CryptoStream(memoryStream, Decryptor, CryptoStreamMode.Read);
byte[] plainBytes = new byte[memoryStream.Length];
int DecryptedCount = cryptoStream.Read(plainBytes, 0, plainBytes.Length);
return plainBytes;
}
Use PaddingMode.Zeros to fix problem , Following code:
public byte[] EncryptFile(Stream input, string password, string salt)
{
// Essentially, if you want to use RijndaelManaged as AES you need to make sure that:
// 1.The block size is set to 128 bits
// 2.You are not using CFB mode, or if you are the feedback size is also 128 bits
var algorithm = new RijndaelManaged { KeySize = 256, BlockSize = 128 };
var key = new Rfc2898DeriveBytes(password, Encoding.ASCII.GetBytes(salt));
algorithm.Key = key.GetBytes(algorithm.KeySize / 8);
algorithm.IV = key.GetBytes(algorithm.BlockSize / 8);
algorithm.Padding = PaddingMode.Zeros;
using (Stream cryptoStream = new MemoryStream())
using (var encryptedStream = new CryptoStream(cryptoStream, algorithm.CreateEncryptor(), CryptoStreamMode.Write))
{
CopyStream(input, encryptedStream);
return ReadToEnd(cryptoStream);
}
}
public byte[] DecryptFile(Stream input, Stream output, string password, string salt)
{
// Essentially, if you want to use RijndaelManaged as AES you need to make sure that:
// 1.The block size is set to 128 bits
// 2.You are not using CFB mode, or if you are the feedback size is also 128 bits
var algorithm = new RijndaelManaged { KeySize = 256, BlockSize = 128 };
var key = new Rfc2898DeriveBytes(password, Encoding.ASCII.GetBytes(salt));
algorithm.Key = key.GetBytes(algorithm.KeySize / 8);
algorithm.IV = key.GetBytes(algorithm.BlockSize / 8);
algorithm.Padding = PaddingMode.Zeros;
try
{
using (var decryptedStream = new CryptoStream(output, algorithm.CreateDecryptor(), CryptoStreamMode.Write))
{
CopyStream(input, decryptedStream);
return ReadToEnd(output);
}
}
catch (CryptographicException ex)
{
throw new InvalidDataException("Please supply a correct password");
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
I hop help you.
Please check your pass phrase - it should be same in both methods EncrypteBytes and DecrypteBytes. If both are not same, then it will generate the error.
My problem was I was taking the encryped output in bytes and converting it to a string. The string back to byte array (for decrypting) was not the same. I was using UTF8Encoding, then I tried ASCIIEnconding. Neither worked.
Convert.FromBase64String/ToBase64String worked fine, got rid of the padding issues and actually decrypted the data.
It's work
using (FileStream fs = new FileStream( absolute, FileMode.Open )) {
// create a CryptoStream in read mode
using (CryptoStream cryptoStream = new CryptoStream( fs, decryptor, CryptoStreamMode.Read )) {
int readLength = ( int )fs.Length;
byte[] buffer = new byte[readLength];
cryptoStream.Read( buffer, 0, readLength );
using (MemoryStream ms = new MemoryStream( buffer )) {
BinaryFormatter bf = new BinaryFormatter( );
settings = ( SettingsJson )bf.Deserialize( ms );// Deserialize SettingsJson array
}
}
fs.Close( );
}