Can you help please...
I want to encrypt / decrypt the file using Aes. Encryption part is successful working. But my problem is when decrypting the text encrypted error is occurred : Padding is invalid and cannot removed
My error is occurred on line (private void FileDecrypt) :
while ((read = cryptoStream.Read(buffer, 0, buffer.Length)) > 0)
My code :
private void FileEncrypt(string inputFile, string outputFile, string password)
{
byte[] salt = GenerateSalt();
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = 256;//AES 256 bits
AES.BlockSize = 128;//AES 128 bits
AES.Padding = PaddingMode.PKCS7;
//AES.Padding = PaddingMode.Zeros;
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;
using (FileStream filestreamCrypt = new FileStream(outputFile, FileMode.Create))
{
filestreamCrypt.Write(salt, 0, salt.Length);
using (CryptoStream cs = new CryptoStream(filestreamCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
using (FileStream filestreamIn = new FileStream(inputFile, FileMode.Open))
{
int readLength = (int)filestreamIn.Length;
byte[] buffer = new byte[readLength];
int read;
while ((read = filestreamIn.Read(buffer, 0, buffer.Length)) > 0)
{
cs.Write(buffer, 0, read);
cs.FlushFinalBlock();
}
}
}
filestreamCrypt.Dispose();
}
}
private void FileDecrypt(string inputFileName, string outputFileName, string password)
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] salt = new byte[32];
using (FileStream filestreamCrypt = new FileStream(inputFileName, FileMode.Open))
{
filestreamCrypt.Read(salt, 0, salt.Length);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = 256;//AES 256 bits
AES.BlockSize = 128;//AES 128 bits
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.Padding = PaddingMode.Zeros;
AES.Mode = CipherMode.CFB;
using (CryptoStream cryptoStream = new CryptoStream(filestreamCrypt, AES.CreateDecryptor(), CryptoStreamMode.Read))
{
using (FileStream filestreamOut = new FileStream(outputFileName, FileMode.Create))
{
int read;
int readLength = (int)filestreamCrypt.Length;
byte[] buffer = new byte[readLength];
//var fullCipher = Convert.FromBase64String(filestreamOut.ToString());
while ((read = cryptoStream.Read(buffer, 0, buffer.Length)) > 0) **//ERROR**
{
filestreamOut.Write(buffer, 0, read);
}
}
}
}
}
Thank you very much for help.
Replace this:
while ((read = filestreamIn.Read(buffer, 0, buffer.Length)) > 0)
{
cs.Write(buffer, 0, read);
cs.FlushFinalBlock(); <--- Flush final block every time around loop !
}
With this:
while ((read = filestreamIn.Read(buffer, 0, buffer.Length)) > 0)
{
cs.Write(buffer, 0, read);
}
cs.FlushFinalBlock();
Related
I was doing a program for encrypting private files on another computer apart, where this same formula worked correctly, I don't understand why this part of code doesn't work, even though it worked before:
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
byte[] saltBytes = new byte[] { 2, 0, 0, 4, 0, 3, 0, 3 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 256;
AES.Padding = PaddingMode.PKCS7;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CFB;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
I've been trying to find out for about 2 hours because it gives me that error when decrypting, but counting on the little encryption knowledge that I have have it's absolutely impossible.
First of all, when i say ChunkSize i mean ChunkSize, because first of all I split the file into 5Mb bytes array, then i encrypt or decrypt the Byte Array and write the data into the file.
Problem was, that ChunkSize was like less than 1Mb and thats why CryptographicException arises.
if (File.Exists(FileToDecrypt)) {
byte[] PasswordBytes;
if (IsFileTypePassword) {
PasswordBytes = File.ReadAllBytes(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),"K3ys\\" + PasswordToDecrypt));
} else {
PasswordBytes = Encoding.UTF8.GetBytes(PasswordToDecrypt);
}
DecryptFile(5000000, FileToDecrypt, PasswordBytes); // Here was the problem
DecThread.Abort();
}
And here is the function that splits the file, its a little bit different than mine but it does the same, also this piece of code is grabbed from another Question form StackOverflow.
public static void SplitFile(string inputFile, int chunkSize, string path)
{
byte[] buffer = new byte[chunkSize];
using (Stream input = File.OpenRead(inputFile))
{
int index = 0;
while (input.Position < input.Length)
{
using (Stream output = File.Create(path + "\\" + index))
{
int chunkBytesRead = 0;
while (chunkBytesRead < chunkSize)
{
int bytesRead = input.Read(buffer,
chunkBytesRead,
chunkSize - chunkBytesRead);
if (bytesRead == 0)
{
break;
}
chunkBytesRead += bytesRead;
}
output.Write(buffer, 0, chunkBytesRead);
}
index++;
}
}
}
I am performing independent encrypt-decrypt (1st app performs enc 2nd decrypts)
While decryption I either get "Padding invalid" or "Length of data to decrypt is invalid" error.Any help is appreciated thanks
My encryption code:
static void EncryptFile(string file, string password)
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = AES.LegalKeySizes[0].MaxSize;
AES.BlockSize = AES.LegalBlockSizes[0].MaxSize;
AES.Padding = PaddingMode.Zeros;
using (var key = new Rfc2898DeriveBytes(passwordBytes, salt, 1000))
{
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CFB;
}
using (FileStream fsCrypt = new FileStream(file + ".ecc", FileMode.Create))
{
fsCrypt.Write(salt, 0, salt.Length);
}
int bytesToRead = 128 * 1024 * 1024; // 128MB
byte[] buffer = new byte[bytesToRead]; // create the array that will be used encrypted
long fileOffset = 0;
int read = 0;
bool allRead = false;
while (!allRead)
{
using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
{
fs.Seek(fileOffset, SeekOrigin.Begin); // continue reading from where we were...
read = fs.Read(buffer, 0, bytesToRead); // read the next chunk
}
if (read == 0)
allRead = true;
else
fileOffset += read;
using (FileStream fsCrypt = new FileStream(file + ".ecc", FileMode.Open)) // automatically dispose fsCrypt
{
using (CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
fsCrypt.Seek(fileOffset, SeekOrigin.End);
cs.FlushFinalBlock();
cs.Write(buffer, 0, read);
}
}
}
}
and My decryption code:
public void DecryptFile(string file, string password)
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = AES.LegalKeySizes[0].MaxSize;
AES.BlockSize = AES.LegalBlockSizes[0].MaxSize;
AES.Padding = PaddingMode.Zeros;
using (var key = new Rfc2898DeriveBytes(passwordBytes, salt, 1000))
{
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CFB;
}
string extension = System.IO.Path.GetExtension(file);
string result = file.Substring(0, file.Length - extension.Length);
using (FileStream destination = new FileStream(result, FileMode.CreateNew, FileAccess.Write, FileShare.None))
{
using (CryptoStream cryptoStream = new CryptoStream(destination, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
try
{
using (FileStream source = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
source.CopyTo(cryptoStream);
}
}
catch (CryptographicException exception)
{
if (exception.Message == "Padding is invalid and cannot be removed.")
throw new ApplicationException("Universal Microsoft Cryptographic Exception (Not to be believed!)", exception);
else
throw;
}
}
}
}
The following calls are executed in the wrong order:
cs.FlushFinalBlock();
and
cs.Write(buffer, 0, read);
FlushFinalBlock should always come last (it will be automatically called when the stream is closed though, so it should be OK if you don't close the underlying stream first). FlushFinalBlock should certainly never be called in a (while) loop.
The buffer handling is not correct: the streams should not be closed and opened all the time. Instead a block of bytes should be read, then written to the crypto stream. The using statements should be outside the while loop.
For CFB mode PaddingMode.PKCS7 should be set. Padding is not required at all for CFB. Unfortunately .NET seems to have a buggy implementation that does require padding to be used in combination to the streams.
I am making a app that will encrypt 5 video files. The problem is that it only encrypts 4 out of 5 files(the ones <1gb).
On the 5th file, which is over 1GB, the System.OutOfMemoryException is thrown.
(i know i asked it previously ,but i made some changes as suggested but it still wont work, i dont mean to spam)
Here's my code:
//Encrypts single file
public void EncryptFile(string file, string password)
{
byte[] bytesToBeEncrypted = File.ReadAllBytes(file);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
// Hash the password with SHA256
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
byte[] salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
FileStream fsCrypt = new FileStream(file + ".enc", FileMode.Create);
//Set Rijndael symmetric encryption algorithm
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = AES.LegalKeySizes[0].MaxSize;
AES.BlockSize = AES.LegalBlockSizes[0].MaxSize;
AES.Padding = PaddingMode.PKCS7;
//"What it does is repeatedly hash the user password along with the salt." High iteration counts.
var key = new Rfc2898DeriveBytes(passwordBytes, salt, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CFB;
//write salt to the beginning of the output file, so in this case can be random every time
fsCrypt.Write(salt, 0, salt.Length);
CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write);
FileStream fsIn = new FileStream(file, FileMode.Open);
//create a buffer (1mb) so only this amount will allocate in the memory and not the whole file
byte[] buffer = new byte[5048576];
int read;
try
{
while ((read = fsIn.Read(buffer, 0, buffer.Length)) > 0)
{
Application.DoEvents();
cs.Write(buffer, 0, read);
}
fsIn.Close();
fsIn.Dispose();
}
catch (System.OutOfMemoryException ex)
{
cs.Flush();
cs.Dispose();
}
finally
{
cs.Close();
fsCrypt.Close();
}
You are reading the entire file at the start of the method:
byte[] bytesToBeEncrypted = File.ReadAllBytes(file);
This is causing the OutOfMemoryException. Here's an idea of how you'd do this:
static void EncryptFile(string file, string password)
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = AES.LegalKeySizes[0].MaxSize;
AES.BlockSize = AES.LegalBlockSizes[0].MaxSize;
AES.Padding = PaddingMode.PKCS7;
//"What it does is repeatedly hash the user password along with the salt." High iteration counts.
using (var key = new Rfc2898DeriveBytes(passwordBytes, salt, 1000)) // automatically dispose key
{
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CFB;
}
using (FileStream fsCrypt = new FileStream(file + ".enc", FileMode.Create)) // automatically dispose fsCrypt
{
//write salt to the beginning of the output file, so in this case can be random every time
fsCrypt.Write(salt, 0, salt.Length);
}
int bytesToRead = 128 * 1024 * 1024; // 128MB
byte[] buffer = new byte[bytesToRead]; // create the array that will be used encrypted
long fileOffset = 0;
int read = 0;
bool allRead = false;
while (!allRead)
{
using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
{
fs.Seek(fileOffset, SeekOrigin.Begin); // continue reading from where we were...
read = fs.Read(buffer, 0, bytesToRead); // read the next chunk
}
if (read == 0)
allRead = true;
else
fileOffset += read;
using (FileStream fsCrypt = new FileStream(file + ".enc", FileMode.Open)) // automatically dispose fsCrypt
{
using (CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
fsCrypt.Seek(fileOffset, SeekOrigin.End);
cs.Write(buffer, 0, read);
}
}
}
I need to encrypt and decrypt large file (~1GB).
I tried using this example: http://www.codeproject.com/Articles/769741/Csharp-AES-bits-Encryption-Library-with-Salt
But my problem is since the file is very large, I'm getting outOfMemory exception.
So I need to replace the memory stream with file stream, I just not sure how to do it...
(Adding my code:)
private static void AES_Encrypt(string srcFile, string encryptedFile, byte[] passwordBytes)
{
// 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};
FileStream fsInput = new FileStream(srcFile,
FileMode.Open,
FileAccess.Read);
FileStream fsEncrypted = new FileStream(encryptedFile,
FileMode.Create,
FileAccess.Write);
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(fsEncrypted, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
byte[] bytearrayinput = new byte[fsInput.Length - 1];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cs.Write(bytearrayinput, 0, bytearrayinput.Length);
cs.Close();
fsInput.Flush();
fsInput.Close();
fsEncrypted.Close();
}
}
}
public static void AES_Decrypt(string encryptedFile, string decryptedFile, 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};
FileStream fsread = new FileStream(encryptedFile,
FileMode.Open,
FileAccess.Read);
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;
FileStream fsDecrypted = new FileStream(decryptedFile,
FileMode.Create,
FileAccess.Write);
using (var cs = new CryptoStream(fsDecrypted, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
byte[] bytearrayinput = new byte[fsread.Length - 1];
fsread.Read(bytearrayinput, 0, bytearrayinput.Length);
cs.Write(bytearrayinput, 0, bytearrayinput.Length);
cs.Close();
fsread.Close();
fsDecrypted.Close();
}
}
}
Eventually, this is the code that worked for me:
private static void AES_Encrypt(string inputFile, string outputFile, byte[] passwordBytes)
{
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8};
string cryptFile = outputFile;
FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
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.Padding = PaddingMode.Zeros;
AES.Mode = CipherMode.CBC;
CryptoStream cs = new CryptoStream(fsCrypt,
AES.CreateEncryptor(),
CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inputFile, FileMode.Open);
int data;
while ((data = fsIn.ReadByte()) != -1)
cs.WriteByte((byte)data);
fsIn.Close();
cs.Close();
fsCrypt.Close();
}
private static void AES_Decrypt(string inputFile, string outputFile, byte[] passwordBytes)
{
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8};
FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);
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.Padding = PaddingMode.Zeros;
AES.Mode = CipherMode.CBC;
CryptoStream cs = new CryptoStream(fsCrypt,
AES.CreateDecryptor(),
CryptoStreamMode.Read);
FileStream fsOut = new FileStream(outputFile, FileMode.Create);
int data;
while ((data = cs.ReadByte()) != -1)
fsOut.WriteByte((byte)data);
fsOut.Close();
cs.Close();
fsCrypt.Close();
}
}
So I created a fairly fast and low memory consumption version:
I use a "temporary buffer" and also "use a random salt and store it with the ciphertext".
To encrypt:
private void AES_Encrypt(string inputFile, string password)
{
//http://stackoverflow.com/questions/27645527/aes-encryption-on-large-files
//generate random salt
byte[] salt = GenerateRandomSalt();
//create output file name
FileStream fsCrypt = new FileStream(inputFile + ".aes", FileMode.Create);
//convert password string to byte arrray
byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(password);
//Set Rijndael symmetric encryption algorithm
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = 256;
AES.BlockSize = 128;
AES.Padding = PaddingMode.PKCS7;
//http://stackoverflow.com/questions/2659214/why-do-i-need-to-use-the-rfc2898derivebytes-class-in-net-instead-of-directly
//"What it does is repeatedly hash the user password along with the salt." High iteration counts.
var key = new Rfc2898DeriveBytes(passwordBytes, salt, 50000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
//Cipher modes: http://security.stackexchange.com/questions/52665/which-is-the-best-cipher-mode-and-padding-mode-for-aes-encryption
AES.Mode = CipherMode.CFB;
//write salt to the begining of the output file, so in this case can be random every time
fsCrypt.Write(salt, 0, salt.Length);
CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inputFile, FileMode.Open);
//create a buffer (1mb) so only this amount will allocate in the memory and not the whole file
byte[] buffer = new byte[1048576];
int read;
try
{
while ((read = fsIn.Read(buffer, 0, buffer.Length)) > 0)
{
Application.DoEvents(); // -> for responsive GUI, using Task will be better!
cs.Write(buffer, 0, read);
}
//close up
fsIn.Close();
}
catch (Exception ex)
{
Debug.WriteLine("Error: " + ex.Message);
}
finally
{
cs.Close();
fsCrypt.Close();
}
}
To decrypt:
private void AES_Decrypt(string inputFile, string password)
{
//todo:
// - create error message on wrong password
// - on cancel: close and delete file
// - on wrong password: close and delete file!
// - create a better filen name
// - could be check md5 hash on the files but it make this slow
byte[] passwordBytes = System.Text.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(inputFile + ".decrypted", FileMode.Create);
int read;
byte[] buffer = new byte[1048576];
try
{
while ((read = cs.Read(buffer, 0, buffer.Length)) > 0)
{
Application.DoEvents();
fsOut.Write(buffer, 0, read);
}
}
catch (System.Security.Cryptography.CryptographicException ex_CryptographicException)
{
Debug.WriteLine("CryptographicException error: " + ex_CryptographicException.Message);
}
catch (Exception ex)
{
Debug.WriteLine("Error: " + ex.Message);
}
try
{
cs.Close();
}
catch (Exception ex)
{
Debug.WriteLine("Error by closing CryptoStream: " + ex.Message);
}
finally
{
fsOut.Close();
fsCrypt.Close();
}
}
To generate random salt:
public static byte[] GenerateRandomSalt()
{
//Source: http://www.dotnetperls.com/rngcryptoserviceprovider
byte[] data = new byte[32];
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
// Ten iterations.
for (int i = 0; i < 10; i++)
{
// Fill buffer.
rng.GetBytes(data);
}
}
return data;
}
Since you are reading from a file and writing to a file just replace the memory streams by IOStream or FileStream.
You'll have to refactor the procedures a bit so they don't expect/return byte arrays.
For anyone still looking into this and don't want the output to a file but rather a stream
the key is to make sure to call cryptoStream.FlushFinalBlock(); otherwise the decrypt will miss the last few characters.
public MemoryStream FileEncrypt(string inputFilePath, byte[] passwordBytes)
{
var saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
var memoryStream = new MemoryStream();
var aes = new RijndaelManaged {KeySize = 256, BlockSize = 128};
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
aes.Key = key.GetBytes(aes.KeySize / 8);
aes.IV = key.GetBytes(aes.BlockSize / 8);
aes.Padding = PaddingMode.Zeros;
aes.Mode = CipherMode.CBC;
var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write);
var fileStream = new FileStream(inputFilePath, FileMode.Open);
int data;
while ((data = fileStream.ReadByte()) != -1)
cryptoStream.WriteByte((byte)data);
cryptoStream.FlushFinalBlock();
return memoryStream;
}
public MemoryStream FileDecrypt(Stream encryptedFileStream, byte[] passwordBytes)
{
var saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
var AES = new RijndaelManaged {KeySize = 256, BlockSize = 128};
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Padding = PaddingMode.Zeros;
AES.Mode = CipherMode.CBC;
var cryptoStream = new CryptoStream(encryptedFileStream, AES.CreateDecryptor(), CryptoStreamMode.Read);
var memoryStream = new MemoryStream();
int data;
while ((data = cryptoStream.ReadByte()) != -1)
memoryStream.WriteByte((byte)data);
return memoryStream;
}
I have made a cryptography application and it was working fine until I started doing the encryption/decryption in blocks. here's my encryption/decryption code:
public static class AESCryptography
{
private const int keysize = 256;
public static void Encrypt(string Input, string passPhrase)
{
var chunkSize = 16;
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
byte[] keyBytes = password.GetBytes(keysize / 8);
FileStream fsOutput = File.OpenWrite(Input.Substring(0, Input.LastIndexOf('.')) + ".aent");
FileStream fsInput = File.OpenRead(Input);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.GenerateIV();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, symmetricKey.IV);
CryptoStream cryptoStream = new CryptoStream(fsOutput, encryptor, CryptoStreamMode.Write);
fsOutput.Write(symmetricKey.IV, 0, symmetricKey.IV.Length);
for (long i = 0; i < fsInput.Length; i += chunkSize)
{
byte[] chunkData = new byte[chunkSize];
int bytesRead = 0;
while ((bytesRead = fsInput.Read(chunkData, 0, chunkSize)) > 0)
{
if (bytesRead != chunkSize)
{
for (int x = bytesRead - 1; x < chunkSize; x++)
{
chunkData[x] = 0;
}
}
cryptoStream.Write(chunkData, 0, chunkSize);
}
}
cryptoStream.FlushFinalBlock();
cryptoStream.Dispose();
fsOutput.Dispose();
fsInput.Dispose();
encryptor.Dispose();
symmetricKey.Dispose();
password.Dispose();
}
public static void Decrypt(string Input, string passPhrase)
{
var chunkSize = 16;
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
byte[] keyBytes = password.GetBytes(keysize / 8);
FileStream fsInput = File.OpenRead(Input);
FileStream fsOutput = File.OpenWrite(Input.Substring(0, Input.LastIndexOf('.')) + ".txt");
byte[] initVectorBytes = new byte[16];
byte[] buffer = new byte[8];
fsInput.Read(buffer, 0, 8);
long fileLength = BitConverter.ToInt64(buffer, 0);
fsInput.Read(initVectorBytes, 0, 16);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
CryptoStream cryptoStream = new CryptoStream(fsOutput, decryptor, CryptoStreamMode.Write);
for (long i = 0; i < fsInput.Length; i += chunkSize)
{
byte[] chunkData = new byte[chunkSize];
int bytesRead = 0;
while ((bytesRead = fsInput.Read(chunkData, 0, chunkSize)) > 0)
{
cryptoStream.Write(chunkData, 0, bytesRead);
}
}
}
}
if I encrypt a .txt file that says for example: "hello world! the app works!!" i will get some awkward Chinese text mixed with symbols I've never seen.
You've left some code incomplete. This code here in Decrypt is a problem:
byte[] buffer = new byte[8];
fsInput.Read(buffer, 0, 8);
long fileLength = BitConverter.ToInt64(buffer, 0);
This reads eight bytes that were never written by Encrypt, shifting everything you read after that by eight bytes. Comment out those three lines and your code works.
You are also missing a cryptoStream.FlushFinalBlock() after your loop in Decrypt. Because of the 8-byte offset by the bug, you would get a CryptographicException "Length of the data to decrypt is invalid." (You missed 8 bytes.) But after commenting out those lines, FlushFinalBlock() will succeed.