top of page

How To Encrypt/Decrypt File In Chunks in .NET Core

Let’s assume we have an app that runs on customer’s device and produces diagnostic data. Device is not connected to the internet. Requirements are to be able to encrypt diagnostic data, so that it will be stored on a USB drive and later on uploaded to the cloud (blob storage). From there, we need to decrypt the file and process diagnostic data. We know that the file we’re going to encrypt/decrypt can be very big (few gigabytes).


I want to take a hybrid encryption approach — that is the AES key will be encrypted using RSA public key on the client device. The data itself will be AES encrypted.


Final encrypted file will consist of few pieces:

  • 16 bytes initialization vector

  • 256 bytes of encrypted AES key

  • X bytes of encrypted data


With this cleared out, let’s look into the implementation.


Here’s the encryption part:

using var rsa = RSA.Create();

rsa.ImportRSAPublicKey(
    Convert.FromBase64String("public_key"),
    out var_);
    
var aes = Aes.Create();
aes.Mode=CipherMode.CBC;
aes.Padding=PaddingMode.PKCS7;

aes.GenerateKey();
aes.GenerateIV();

using (vardataStream=File.OpenRead("filetoencrypt"))
using (varsecretFileStream=File.Create("encryptedfile"))
{
    await secretFileStream.WriteAsync(aes.IV);
    await secretFileStream.WriteAsync(rsa.Encrypt
                   (aes.Key, RSAEncryptionPadding.OaepSHA256));
    
    using (var cryptoStream = new CryptoStream         
            (secretFileStream, aes.CreateEncryptor(aes.Key, 
            aes.IV), CryptoStreamMode.Write))    
    {
        await dataStream.CopyToAsync(cryptoStream);    
    }
}

At this point we have an encrypted file that is ready to be transferred to the cloud.


Decryption on the cloud will be done via Azure Function which gets triggered once encrypted file is uploaded to the storage container. File is decrypted & saved back into the storage account inside a different container.


To stay concentrated on decryption, I’ll skip setup of storage account & Azure Function’s bindings.


Here’s the code that does the decryption:

using var rsa = RSA.Create();

rsa.ImportRSAPrivateKey(
    Convert.FromBase64String("private_key"),
    out var_);

var aes = Aes.Create();

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

var ivBuffer = new byte[16];
while (await encryptedBlob.ReadAsync
            (ivBuffer, 0, ivBuffer.Length) != ivBuffer.Length)
{ }

aes.IV = ivBuffer;

var keyBuffer = new byte[256];
while (await encryptedBlob.ReadAsync
        (keyBuffer, 0, keyBuffer.Length) != keyBuffer.Length) ;

aes.Key = rsa.Decrypt(keyBuffer, RSAEncryptionPadding.OaepSHA256);

using (varcryptoStream=newCryptoStream(encryptedBlob, aes.CreateDecryptor(aes.Key, aes.IV), CryptoStreamMode.Read))
{
    awaitcryptoStream.CopyToAsync(decryptedBlob);
}

First we read the initialization vector & encrypted AES key. Then we decrypt the AES key using RSA private key and initialize AES. Having AES fully initialized, we decrypt encrypted data by chunks and write decrypted bytes to output stream.


Let’s trigger the function. I encrypted 1,4 GB file & uploaded to the blob storage. Function execution time ~ 107 seconds.


Function execution time


If we’d try to buffer entire content before decrypting, we’d most probably hit OutOfMemory exception (I tried in Consumption mode, OutOfMemory exception was thrown).


Source: Medium - gmanvel


The Tech Platform

0 comments
bottom of page