25 Apr

Encrypt files with Certificate in .Net

Encryption

These days everything needs to be secure. Because, let’s face it, you don’t want a hacker to crawl around in your data.
One way to be secure is to encrypt your data so only you, or whoever you want, can decrypt and read it. In this post I want to show you how this can be done by using a certificate.

The Plan

Encryption with a certificate isn’t hard at all. The only problem is that the size of the object you want to encrypt can not exceed 245 bytes. These days, files are bit larger then that, so how are we going to overcome this issue?
Instead of encrypting the file with a certificate, we will encrypt the file with a key. And it’s that key which we’re going to encrypt with the certificate. So lets says we encrypt a file with key “123” and we encrypt “123” with the certificate. It’s really that simple, or is it?
The next thing you need to think of is, how am I going to transfer that encrypted “123” with my encrypted file? Well, even that’s not difficult. We’re just going to put the byte-array of our encrypted key in front of our file byte-array. By doing so, we both have the file and the key in one byte array.



The code

Encrypting

Like I said in the plan, we’re going to encrypt the file with a key, and encrypt that key with the certificate. Once we got both things encrypted, we’ll add the encrypted key in front encrypted file and we’re done.

public static async Task Encrypt(string filePath, string certName, string password)
{
    //We're using AES encryption to create my key.
    Aes aesKey = Aes.Create();
    aesKey.GenerateKey();
    byte[] ivKey = new byte[aesKey.IV.Length];
    Array.Copy(aesKey.Key, ivKey, aesKey.IV.Length);
    aesKey.IV = ivKey;
    var encryptor = aesKey.CreateEncryptor();
    var encryptedKey = EncryptKey(aesKey.Key, certName, password);

    //Copy the file to memory so we can overwrite the source with it's encrypted version.
    var file = await File.ReadAllBytesAsync(filePath);

    //We're using truncate mode, so the file opens up and is empty.
    using (var outputStream = new FileStream(filePath, FileMode.Truncate))
    {
        //Add the encrypted key to the start of file.
        await outputStream.WriteAsync(encryptedKey, 0, encryptedKey.Length);
        using (var encryptStream = new CryptoStream(outputStream, encryptor, CryptoStreamMode.Write))
        using (var inputStream = new MemoryStream(file))
            await inputStream.CopyToAsync(encryptStream);
    }
}

 

Encrypting the key itself is even easier.

public static byte[] EncryptKey(byte[] key, string certName, string password)
{
    var cert = new X509Certificate2(certName, password);
    var publicKey = cert.GetRSAPublicKey();
    //Encrypt the key with certificate
    return publicKey.Encrypt(key, RSAEncryptionPadding.OaepSHA512);
}


Decrypting

As you can see, encrypting wasn’t that hard. Now lets see how we can use our file again by decrypting it.

public static async Task Decrypt(string filePath, string certName, string password)
{
    //Read the file in memory so we can overwrite the source with it's original file.
    //We also need it in memory so we can extract the key.
    var file = (await File.ReadAllBytesAsync(filePath)).ToList();
    var encryptedKey = new Collection<byte>();
    //Checking the length so we know how much bytes we need to take from the file.
    //Different certificates can create different size of keys.
    var encryptLength = Encrypter.EncryptKey(Encoding.UTF8.GetBytes("string"), certName, password).Length;
    //Extract the key.
    for (var i = 0; i < encryptLength; i++)
        encryptedKey.Add(file[i]);
    file.RemoveRange(0, encryptLength);

    var decryptedKey = DecryptKey(encryptedKey.ToArray(), certName, password);

    using (var managed = new AesManaged())
    {
        //I'm using AES encryption, but this time we do not generate the key but pass our decrypted key.
        Aes aesKey = Aes.Create();
        aesKey.Key = decryptedKey;
        byte[] ivKey = new byte[aesKey.IV.Length];
        Array.Copy(aesKey.Key, ivKey, aesKey.IV.Length);
        aesKey.IV = ivKey;
        var decryptor = aesKey.CreateDecryptor();

        //We're using truncate mode, so the file opens up and is empty.
        using (var fileStream = new FileStream(filePath, FileMode.Truncate))
        using (var decryptStream = new CryptoStream(fileStream, decryptor, CryptoStreamMode.Write))
        using (var encryptedFileStream = new MemoryStream(file.ToArray()))
            await encryptedFileStream.CopyToAsync(decryptStream);
    }
}

 

Decrypting the key is almost similar as encrypting.

private static byte[] DecryptKey(byte[] keyBytes, string certName, string password)
{
    var cert = new X509Certificate2(certName, password);
    var privateKey = cert.GetRSAPrivateKey();
    //Decrypt the key with the same padding used to encrypt it.
    return privateKey.Decrypt(keyBytes, RSAEncryptionPadding.OaepSHA512);
}


And that’s all you need to encrypt en decrypt your files with a certificate.
Keep in mind though, everything can be broken. So even if your file is encrypted; using this piece of code, I’m sure one day a person will still be able to break it and read your file.

GitHub

https://github.com/JeffreyRosselle/file-certificate-encryption

Leave a Reply

Your email address will not be published. Required fields are marked *