I am trying to create an AES encryption method where the same file is read and write at the same time. Other codes I have read all create a new file, I don't want to have new file. Other encrypted line matched my reference output from separate output, except my method generated an incorrect last line as plain text plus additional bytes.
I have tried replacing FileStream argument of CryptoStream and remove fs.Seek() at line 58, the program runs correctly and generated new .aes encrypted file for my reference output above.
static void Main(string[] args)
{
AESCryptFile(@"C:\Users\user\Downloads\test.txt",
new byte[] { 0x13, 0x11, 0x7F, 0x08, 0x45, 0x2E, 0x96, 0x33 },
new byte[] { 0x13, 0x11, 0x7F, 0x08, 0x45, 0x2E, 0x96, 0x33 }, false);
Console.WriteLine("Done");
Console.ReadLine();
}
public async static void AESCryptFile
(string path, byte[] key, byte[] iv, bool encrypt)
{
// validation
if (path == null || !File.Exists(path))
throw new FileNotFoundException("Path does not exist");
if (key == null || key.Length == 0)
throw new ArgumentNullException("Password is null");
if (iv == null || iv.Length < 8)
throw new ArgumentException("IV is null or under 8 bytes long");
// in and out stream for files
FileStream fs = new FileStream
(path, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
// initialize aes with safe hash and mode
RijndaelManaged algo = new RijndaelManaged();
Rfc2898DeriveBytes hashed = new Rfc2898DeriveBytes(key, iv, 25000);
algo.Key = hashed.GetBytes(32);
algo.IV = hashed.GetBytes(16);
algo.Padding = PaddingMode.PKCS7;
algo.Mode = CipherMode.CFB;
// mediator stream for cryptography
CryptoStream cs = new CryptoStream(fs,
encrypt ? algo.CreateEncryptor() : algo.CreateDecryptor(),
encrypt ? CryptoStreamMode.Write : CryptoStreamMode.Read);
// main file transfer and crypto
await Task.Run(
() => readCryptWrite(new FileInfo(path).Length, fs, cs, encrypt));
}
private static void readCryptWrite(long fileSize, FileStream fs,
CryptoStream cs, bool encrypt)
{
// 1 MB of buffer zone allocation
byte[] buffer = new byte[1048576];
int nextBlockSize;
long processedSize = 0;
// loop while there are more to read
while ((nextBlockSize = encrypt ? fs.Read(buffer, 0, buffer.Length) :
cs.Read(buffer, 0, buffer.Length)) > 0)
{
// set pointer back to last written space
fs.Seek(processedSize, SeekOrigin.Begin);
// write out to file
if (encrypt) cs.Write(buffer, 0, nextBlockSize);
else fs.Write(buffer, 0, nextBlockSize);
// set progress
processedSize = fs.Position;
SetProgress?.Invoke((int)((double)processedSize / fileSize * 100));
if (nextBlockSize != buffer.Length) break;
}
// close streams
cs.Clear();
cs.Close();
fs.Close();
}
The input I used: Long English file