I have the need to calculate the size of a file I am encrypting using Rijndael.
According to other answers on this site, and on google, the following is the correct way of calculating encrypted data length:
EL = UL + (BS - (UL Mod BS) Mod BS)
Where:
EL = Encrypted Length
UL = Unencrypted Length
BS = Block Size
In my instance, the unencrypted file length is 5,101,972 bytes, and I am using a 128bit encryption key, giving me a block size of 16 bytes.
Therefore, the equation is:
EL = 5101972 + (16 - (5101972 Mod 16) Mod 16)
EL = 5101972 + (16 - 4 Mod 16)
EL = 5101972 + (12 Mod 16)
EL = 5101972 + 12
EL = 5101984
Giving an encrypted file length of 5,101,984 bytes.
However, the size of my file after encryption weighs in at 5,242,896
A massive difference in sizes of 140,912 bytes!
Now.. I'm obviously doing SOMETHING wrong, but I can't work out what it is.
Below is my encryption and decryption test code, as well as the method used to calculate the encrypted size:
private static void Enc(string decryptedFileName, string encryptedFileName)
{
PasswordDeriveBytes passwordDB = new PasswordDeriveBytes("ThisIsMyPassword", Encoding.ASCII.GetBytes("thisIsMysalt!"), "MD5", 2);
byte[] passwordBytes = passwordDB.GetBytes(128 / 8);
using (FileStream fsOutput = File.OpenWrite(encryptedFileName))
{
using(FileStream fsInput = File.OpenRead(decryptedFileName))
{
byte[] IVBytes = Encoding.ASCII.GetBytes("1234567890123456");
fsOutput.Write(BitConverter.GetBytes(fsInput.Length), 0, 8);
fsOutput.Write(IVBytes, 0, 16);
RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC,Padding=PaddingMode.Zeros};
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(passwordBytes, IVBytes);
using (CryptoStream cryptoStream = new CryptoStream(fsOutput, encryptor, 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, chunkSize);
}
}
}
}
}
}
private static void Dec(string encryptedFileName, string decryptedFileName)
{
PasswordDeriveBytes passwordDB = new PasswordDeriveBytes("ThisIsMyPassword", Encoding.ASCII.GetBytes("thisIsMysalt!"), "MD5", 2);
byte[] passwordBytes = passwordDB.GetBytes(128 / 8);
using (FileStream fsInput = File.OpenRead(encryptedFileName))
{
using (FileStream fsOutput = File.OpenWrite(decryptedFileName))
{
byte[] buffer = new byte[8];
fsInput.Read(buffer, 0, 8);
long fileLength = BitConverter.ToInt64(buffer, 0);
byte[] IVBytes = new byte[16];
fsInput.Read(IVBytes, 0, 16);
RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC,Padding=PaddingMode.Zeros};
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(passwordBytes, IVBytes);
using (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);
}
}
fsOutput.SetLength(fileLength);
}
}
}
}
private static void CalcEncSize(string decryptedFileName)
{
FileInfo fi = new FileInfo(decryptedFileName);
if (fi.Exists)
{
long blockSize = 128/8;
long fileLength = fi.Length;
long encryptedSize = fileLength + ((blockSize - (fileLength % blockSize)) % blockSize);
encryptedSize += 24; //16 bytes for the IV, and 8 more for the filelength, both stored at the start of the file.
Console.WriteLine("Estimated Encryption Size: " + encryptedSize.ToString());
}
}
Note: In the calculations at the start, I am NOT including the extra 24 bytes that are used at the start of the encrypted file by myself to store the original file length, and the IV... I know this, but didn't want to complicate the equation more than necessary.
You shouldn't write to the output file before the actual encryption process. The CryptoStream will handle all the necessary padding when it is closed. Also the for loop isn't necessary as the inner while loop will read the entire file. Also you should only write as much as was read from the file. Try these changes.
private static void Enc(string decryptedFileName, string encryptedFileName)
{
PasswordDeriveBytes passwordDB = new PasswordDeriveBytes("ThisIsMyPassword", Encoding.ASCII.GetBytes("thisIsMysalt!"), "MD5", 2);
byte[] passwordBytes = passwordDB.GetBytes(128 / 8);
using (FileStream fsOutput = File.OpenWrite(encryptedFileName))
{
using(FileStream fsInput = File.OpenRead(decryptedFileName))
{
byte[] IVBytes = Encoding.ASCII.GetBytes("1234567890123456");
RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC,Padding=PaddingMode.Zeros};
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(passwordBytes, IVBytes);
using (CryptoStream cryptoStream = new CryptoStream(fsOutput, encryptor, CryptoStreamMode.Write))
{
byte[] chunkData = new byte[chunkSize];
int bytesRead = 0;
while ((bytesRead = fsInput.Read(chunkData, 0, chunkSize)) > 0)
{
cryptoStream.Write(chunkData, 0, bytesRead); //KEY FIX
}
}
}
}
}
[edit]
Oh I've missed out on a lot of information. I misread what your sizes were thinking 140,912 was the size, not difference. Now that I see that, I can make more intelligible response. Based on your code, the difference in sizes should be comparable to your chunk size. Since the chunkSize can be somewhat large, your code will typically write up to chunkSize more data than is actually in your input file (as Greg and caf pointed out). The line that I've marked is the reason for the discrepancy.
Related
I'm trying to write an encryption/decryption method for practice and after getting an initial run working, I decided to step it up and make it less vulnerable by encrypting the IV into the data. I got that working, and decided to step it up again by introducing an offset for the IV's location in the data, by adding some random data to the left hand side of the IV. Up until this point, everything was working fine, but now I'm receiving an error on decryption that states:
The input data is not a complete block.
Which with my limited knowledge of encryption and decryption is quite useless to me in debugging the issue. I've searched high and low, and none of the answers to this problem, that I've found seem to fix my issue. The answers are typically along the lines of the developer isn't decrypting a byte[] but instead something like a base 64 string.
private static Guid TestGuid = Guid.NewGuid();
private static DateTime Timestamp = DateTime.Now;
private static string key = "PPPQmyuzqKtjzYlWM3mP0aDxaxCzlsACajIkTVN4IjI=";
public static void Main()
{
string data = TestGuid + "|" + Timestamp;
Console.WriteLine("Request Parameter: " + data);
string encryptedData = AESEncrypt(key, data, 1);
Console.WriteLine("Encrypted: " + encryptedData);
string decryptedData = AESDecrypt(key, encryptedData, 1);
Console.WriteLine("Decrypted: " + decryptedData);
}
public static string AESEncrypt(string key, string data, int offset)
{
if (string.IsNullOrWhiteSpace(data))
throw new ArgumentException("Data");
byte[] encryptedData;
byte[] keyData = Convert.FromBase64String(key);
using (Aes algo = Aes.Create())
{
algo.Key = keyData;
algo.GenerateIV();
algo.Padding = PaddingMode.PKCS7;
byte[] iv = new byte[offset + 16];
Random r = new Random();
using (MemoryStream ms = new MemoryStream())
{
for (int i = 0; i < offset; i++)
iv[i] = (byte)r.Next(1, 200);
for (int i = 0; i < algo.IV.Length; i++)
iv[offset + i - 1] = algo.IV[i];
ICryptoTransform encryptor = algo.CreateEncryptor(algo.Key, algo.IV);
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (BinaryWriter bw = new BinaryWriter(cs))
{
bw.Write(iv, 0, offset);
ms.Write(iv, offset, algo.IV.Length);
bw.Write(data);
cs.FlushFinalBlock();
}
encryptedData = ms.ToArray();
}
}
}
if (encryptedData != null)
return Convert.ToBase64String(encryptedData);
throw new Exception("An unxpected error occurred and the provided data was not encrypted.");
}
public static string AESDecrypt(string key, string data, int offset)
{
if (string.IsNullOrWhiteSpace(data))
throw new ArgumentException("Data");
string decryptedData;
byte[] keyData = Convert.FromBase64String(key);
using (Aes algo = Aes.Create())
{
algo.Key = keyData;
algo.Padding = PaddingMode.PKCS7;
byte[] decodedData = Convert.FromBase64String(data);
using (MemoryStream ms = new MemoryStream(decodedData))
{
byte[] ivData = new byte[offset + 16];
ms.Read(ivData, 0, offset + 16);
List<byte> iv = new List<byte>();
for (int i = offset - 1; i < ivData.Length - 1; i++)
iv.Add(ivData[i]);
algo.IV = iv.ToArray();
ICryptoTransform decryptor = algo.CreateDecryptor(algo.Key, algo.IV);
List<byte> dataToDecrypt = new List<byte>();
for (int i = 0; i + offset < decodedData.Length; i++)
dataToDecrypt.Add(decodedData[i + offset]);
using (MemoryStream ds = new MemoryStream(dataToDecrypt.ToArray()))
{
using (CryptoStream cs = new CryptoStream(ds, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
decryptedData = sr.ReadToEnd();
}
}
}
}
}
if (!string.IsNullOrWhiteSpace(decryptedData))
return decryptedData;
throw new Exception("An unxpected error occurred and the provided data was not decrypted.");
}
What is causing this error, why is it causing the error, how do I resolve the error, and why does that resolution work?
Messing with the final encryption stream during the encryption process (feeding into it raw bytes) is a fatal mistake and should be avoided
The problem in question occurs because
bw.Write(iv, 0, offset);
ms.Write(iv, offset, algo.IV.Length);
Feeding the first random bytes of the modified IV to the encryption stream and the rest of it to the raw output stream, the first bytes of the modified iv will not be written to the memory stream immediately and instead will be part of the first encryption block, thus, the size of the cipher during decryption will lack some bytes, for example it lacks 1 byte where offset = 1
But you expect them to be written immediately as independent bytes, because in the decryption part you read offset + 16 bytes from the stream and thus you read into the encrypted block and cause it to be less than the block size for AES. You can see this if you debug the code. The final size of the encrypted bytes is 0x50 while the size of bytes for decryption is 0x50 - offset = 0x4f (offset = 1)
For solution,
You can derive the IV from the Key (which is not secure if you are reusing the key) and will not have to include it in your cipher.
You can prepend the IV (and your random bytes) to your encrypted buffer and read it first then use it for decryption,
like:
public static string AESEncrypt(string key, string data, int offset)
{
if (string.IsNullOrWhiteSpace(data))
throw new ArgumentException("Data");
byte[] encryptedData;
byte[] keyData = Convert.FromBase64String(key);
using (Aes algo = Aes.Create())
{
algo.Key = keyData;
algo.GenerateIV();
algo.Padding = PaddingMode.PKCS7;
Random r = new Random();
using (MemoryStream ms = new MemoryStream())
{
for (int i = 0; i < offset; i++)
{
ms.WriteByte((byte)r.Next(0, 200));
}
ms.Write(algo.IV, 0, 16);
ICryptoTransform encryptor = algo.CreateEncryptor(algo.Key, algo.IV);
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (BinaryWriter bw = new BinaryWriter(cs))
{
bw.Write(data);
cs.FlushFinalBlock();
}
encryptedData = ms.ToArray();
}
}
}
if (encryptedData != null)
return Convert.ToBase64String(encryptedData);
throw new Exception("An unxpected error occurred and the provided data was not encrypted.");
}
public static string AESDecrypt(string key, string data, int offset)
{
if (string.IsNullOrWhiteSpace(data))
throw new ArgumentException("Data");
string decryptedData;
byte[] keyData = Convert.FromBase64String(key);
using (Aes algo = Aes.Create())
{
algo.Key = keyData;
algo.Padding = PaddingMode.PKCS7;
byte[] decodedData = Convert.FromBase64String(data);
using (MemoryStream ms = new MemoryStream(decodedData))
{
for (int i = 0; i < offset; i++) ms.ReadByte();
byte[] iv = new byte[16];
ms.Read(iv, 0, 16);
algo.IV = iv.ToArray();
ICryptoTransform decryptor = algo.CreateDecryptor(algo.Key, algo.IV);
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
decryptedData = sr.ReadToEnd();
}
}
}
}
if (!string.IsNullOrWhiteSpace(decryptedData))
return decryptedData;
throw new Exception("An unxpected error occurred and the provided data was not decrypted.");
}
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 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 am using C# in a Visual Studio Windows form application to write a program that can encrypt and decrypt files. I am following this walkthrough: https://msdn.microsoft.com/en-US/library/Aa964697(v=VS.85).aspx and have everything completed with some minor changes made to my environment and preferences.
When I try to encrypt a file I am given a 'FileNotFoundException was unhandled' error when the program tries to use a filestream to encrypt the file. Everything up to that point seems to be working.
Here is the code for the EncryptFile method:
private void EncryptFile(string inFile)
{
// Create an instance of Rijndael for symmetric encryption of the data.
RijndaelManaged rjndl = new RijndaelManaged();
rjndl.KeySize = 256;
rjndl.BlockSize = 256;
rjndl.Mode = CipherMode.CBC;
ICryptoTransform transform = rjndl.CreateEncryptor();
// Use RSACryptoServiceProvider to enrypt the Rijndael key.
byte[] keyEncrypted = rsa.Encrypt(rjndl.Key, false);
// Create byte arrays to contain the length values of the key and IV.
byte[] LenK = new byte[4];
byte[] LenIV = new byte[4];
int lKey = keyEncrypted.Length;
LenK = BitConverter.GetBytes(lKey);
int lIV = rjndl.IV.Length;
LenIV = BitConverter.GetBytes(lIV);
// Write the following to the FileStream for the encrypted file (outFs):
// - length of the key
// - length of the IV
// - ecrypted key
// - the IV
// - the encrypted cipher content
// Change the file's extension to ".enc"
string outFile = EncrFolder + inFile.Substring(0, inFile.LastIndexOf(".")) + ".enc";
using (FileStream outFs = new FileStream(outFile, FileMode.Create))
{
outFs.Write(LenK, 0, 4);
outFs.Write(LenIV, 0, 4);
outFs.Write(keyEncrypted, 0, lKey);
outFs.Write(rjndl.IV, 0, lIV);
// Now write the cipher text using a CryptoStream for encrypting.
using (CryptoStream outStreamEncrypted = new CryptoStream(outFs, transform, CryptoStreamMode.Write))
{
// By encrypting a chunk at a time, you can save memory and accommodate large files.
int count = 0;
int offset = 0;
// blockSizeBytes can be any arbitrary size.
int blockSizeBytes = rjndl.BlockSize / 8;
byte[] data = new byte[blockSizeBytes];
int bytesRead = 0;
using (FileStream inFs = new FileStream(inFile, FileMode.Open))
{
do
{
count = inFs.Read(data, 0, blockSizeBytes);
offset += count;
outStreamEncrypted.Write(data, 0, count);
bytesRead += blockSizeBytes;
}
while (count > 0);
inFs.Close();
}
outStreamEncrypted.FlushFinalBlock();
outStreamEncrypted.Close();
}
outFs.Close();
}
}
The error happens at the line "using (FileStream inFs = new FileStream(inFile, FileMode.Open))".
Here is an image of the error:
What is causing the error and what is the fix?
you may overthink this line :
string outFile = EncrFolder + inFile.Substring(0, inFile.LastIndexOf(".")) + ".enc";
(https://msdn.microsoft.com/en-us/library/fyy7a5kt(v=vs.110).aspx)
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.