0

I have a very big csv file which is encrypted using AES. The code that does the encryption

using var aes = new AesCryptoServiceProvider();

aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.None;
aes.Key = key;
aes.IV = initializationVector;

using var memoryStream = new MemoryStream();

var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write);

cryptoStream.Write(data, 0, data.Length);

cryptoStream.Flush();

This is later saved into a file. On the decryption end, I'm trying to decrypt it in chunks, e.g.

using var sourceStream = File.OpenRead(path_to_encrypted_file);

using var aes = new AesCryptoServiceProvider();

aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.None;
aes.Key = key;
aes.IV = iv;

using (var fs = File.Create(path_to_decrypted_file))
using (var cryptoStream = new CryptoStream(fs, aes.CreateDecryptor(), CryptoStreamMode.Write)
{
    var dataBuffer = new byte[81290];
    int read;

    while ((read = await sourceStream.ReadAsync(dataBuffer)) != 0)
    {
        ReadOnlyMemory<byte> buffer = dataBuffer.AsMemory().Slice(0, read);
        await cryptoStream.WriteAsync(buffer);
        await cryptoStream.FlushAsync();
    }
}

File is decrypted, however, I see some random bytes and empty lines at the end of the file

enter image description here

Is there anything wrong with how I decrypt ?

Mike
  • 561
  • 1
  • 5
  • 20

2 Answers2

0

There's a couple potential issues I'd investigate first, at least in the existing provided code. There may be more depending on how you're generating the initial data byte array, how you're generating your key, how you're writing the encrypted stream to disk, etc.

  1. You're using ECB and you almost certainly shouldn't. It isn't doing anything with your IV, either. Consider CBC or GCM depending on the application. https://stackoverflow.com/a/22958889/13374279

  2. You're not using a padding mode. Unless your data is exactly contained within the block size, there's a chance you're losing some data, which might be contributing to the gibberish at the end.

  3. You don't show the original encrypting stream disposal, you just show the Flush(). Depending on its disposal, it is likely not calling the CryptoStream's FlushFinalBlock() method, which is important. Given the lack of the padding mode, if you add this in, you'll likely suddenly see yourself with an exception here to alert you that The input data is not a complete block. due to #2 until you swap that out.

Adam
  • 3,339
  • 1
  • 10
  • 15
0

Thanks to the answer by @Adam G I reimplemented encrypt/decrypt following suggestions in the answer + comments.

A little background – I needed a solution where encryption happens on the client machine (disconnected from the internet) & decryption later on takes place in the cloud once the encrypted file uploaded to a blob storage.

I wanted to have a hybrid encryption, where key is RSA encrypted, data - AES. So the file contents on the client:

  • RSA encrypted key
  • RSA encrypted IV (RSA encryption of the IV is not necessary AFAIK)
  • AES encrypted data

This is the final implementation:

// Local
var localRsa = RSA.Create();

localRsa.ImportRSAPublicKey(
    Convert.FromBase64String(public_key),
    out var _);

var localAes = Aes.Create();
localAes.GenerateKey();
localAes.GenerateIV();

localAes.Mode = CipherMode.CBC;
localAes.Padding = PaddingMode.PKCS7;

using (var dataStream = File.OpenRead(file_to_encrypt))
using (var secretFileStream = File.Create(encrypted_file))
{
    await secretFileStream.WriteAsync(localRsa.Encrypt(localAes.Key, RSAEncryptionPadding.OaepSHA256));
    await secretFileStream.WriteAsync(localRsa.Encrypt(localAes.IV, RSAEncryptionPadding.OaepSHA256));

    using (var cryptoStream = new CryptoStream(secretFileStream, localAes.CreateEncryptor(localAes.Key, localAes.IV), CryptoStreamMode.Write))
    {
        await dataStream.CopyToAsync(cryptoStream);
    }
}

And the decryption piece:

// Cloud
var cloudRsa = RSA.Create();

cloudRsa.ImportRSAPrivateKey(
    Convert.FromBase64String(private_key),
    out var _);

var cloudAes = Aes.Create();

cloudAes.Mode = CipherMode.CBC;
cloudAes.Padding = PaddingMode.PKCS7;

using (var secretFileStream = File.OpenRead(encrypted_file))
{
    var keyBuffer = new byte[256];
    await secretFileStream.ReadAsync(keyBuffer, 0, keyBuffer.Length);

    cloudAes.Key = cloudRsa.Decrypt(keyBuffer, RSAEncryptionPadding.OaepSHA256);

    var ivBuffer = new byte[256];
    await secretFileStream.ReadAsync(ivBuffer, 0, keyBuffer.Length);

    cloudAes.IV = cloudRsa.Decrypt(ivBuffer, RSAEncryptionPadding.OaepSHA256);

    secretFileStream.Position = 512;

    using (var plainTextStream = File.Create(decrypted_file))
    {
        using (var cryptoStream = new CryptoStream(secretFileStream, cloudAes.CreateDecryptor(cloudAes.Key, cloudAes.IV), CryptoStreamMode.Read))
        {
            await cryptoStream.CopyToAsync(plainTextStream);
        }
    }
}
Troll
  • 1,895
  • 3
  • 15
  • 34
Mike
  • 561
  • 1
  • 5
  • 20