C# AES-256 CBC Encryption and Decryption (SimpleEncryptor) Source Code/GitHub

SimpleEncryptor is a simple CLI (command-line interface) encryptor and decryptor for Windows and Linux that uses the PBKDF2 algorithm for key derivation, AES-256 (Advanced Encryption Standard) for the encryption and decryption algorithm, and CBC mode as the block cipher mode of operation (C# AES-256-CBC).

The SimpleEncryptor application does not store a salt or IV (initialization vector) with the encrypted data, as these values need not be secret. This means that you will need to use static and unchanging values as the IV and salt are stored within the application source code. They can be changed in the source code but need to be the same values that were originally used to encrypt data, when decryption occurs.


Usage

SimpleEncryptor.exe encrypt <source file> <encrypted destination file>

SimpleEncryptor.exe decrypt <encrypted source file> <destination file>

Usage of this application is simple. A user will provide a source and destination file as parameters along with the mode of operation (encrypt or decrypt) that should be used.

Below you will see the KeyGenerator.cs file with the KeyGenerator method. In the KeyGenerator method the application will derive an encryption key from a user provided passphrase. This is the passphrase that a user will use to encrypt a file and need to decrypt the resultant encrypted file.

KeyGenerator.cs

using System;
using System.Security.Cryptography;
using System.Text;

namespace SimpleEncryptor
{
    public class keyGenerator
    {
        public static byte[] generateEncryptionKey(string passphrase)
        {
            byte[] password = Encoding.UTF8.GetBytes(passphrase);
            byte[] salt = Encoding.UTF8.GetBytes("staticsalt123456staticsalt123456");
            //byte[] salt = RandomNumberGenerator.GetBytes(32);
            int iterations = 1000;
            HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA256;
            int outputLength = 32;

            var encryptionKey = Rfc2898DeriveBytes.Pbkdf2(password, salt, iterations, hashAlgorithm, outputLength);

            return encryptionKey;
        }
    }
}

This passphrase is input by the user after starting the application.

During encryption:

PS C:\tools> .\SimpleEncryptor.exe encrypt c:\tools\enc\test.pdf c:\tools\enc\test.pdf.aes
[+] Enter a passphrase to encrypt the file (c:\tools\enc\test.pdf) with:
<user input>

During decryption:

PS C:\tools> .\SimpleEncryptor.exe decrypt c:\tools\enc\test.pdf.aes c:\tools\enc\test2.pdf
[+] Enter the correct passphrase to decrypt the file (c:\tools\enc\test.pdf.aes):
<user input>

The passphrase is not visible when entered by the user and is built into a string char by char (keypress by keypress) and returned from the method as a string to be used in the password derivation method.

This is done using the code shown below in Program.cs.

        public static string buildPassphrase()
        {
            string passphrase = string.Empty;

            while (true)
            {
                var key = Console.ReadKey(true);
                char passphraseChar = key.KeyChar;

                if (passphraseChar == (char)ConsoleKey.Enter)
                {
                    break;
                }
                else if (passphraseChar == (char)ConsoleKey.Backspace)
                {
                    try
                    {
                        passphrase = passphrase.Remove(passphrase.Length - 1);
                    }
                    catch (ArgumentOutOfRangeException)
                    {
                        continue;
                    }
                }
                else
                {
                    passphrase += passphraseChar;
                }
            }
            return passphrase;

In the prior KeyGenerator.cs code, you will notice that the salt is a static value.

The salt need not be encrypted or secret1. In the SimpleEncryptor program a 32-byte value, “staticsalt123456staticsalt123456” is used.

In the KeyGenerator.cs file, the derivation algorithm performs the operation 1000 times int iterations = 1000; and the hash algorithm used is SHA-256. The output key is 32 bytes in length.

This key is then returned from the method and used in the encryption and decryption process return encryptionKey;.

Encryptor.cs

using System;
using System.Security.Cryptography;
using System.Text;

namespace SimpleEncryptor
{
    public class Encryptor
    {
        public static void encrypt(string fileLocation, string encryptedOutFileLocation, string passphrase)
        {
            var keyGenerator = new keyGenerator();
            var key = keyGenerator.generateEncryptionKey(passphrase);

            FileStream fileStreamInputFile = new FileStream(fileLocation, FileMode.Open, FileAccess.Read);
            FileStream fileStreamOutputFile = new FileStream(encryptedOutFileLocation, FileMode.Create);

            using (Aes aes = Aes.Create())
            {
                aes.Key = key;
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;
                aes.IV = Encoding.UTF8.GetBytes("1234567812345678");  // first block only

                ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
                CryptoStream cryptoStream = new CryptoStream(fileStreamOutputFile, encryptor, CryptoStreamMode.Write);

                byte[] buffer = new byte[1024];
                int read;

                try
                {
                    while ((read = fileStreamInputFile.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        cryptoStream.Write(buffer, 0, read);
                    }
                    cryptoStream.FlushFinalBlock();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
                finally
                {
                    fileStreamInputFile.Close();
                    fileStreamOutputFile.Close();
                }
            }
        }
    }
}

The IV or Initialization vector does not need to be secret2 in this mode of operation (CBC). It is used only once on the first block of data. We have simply set the IV equal to “1234567812345678” 16-bytes of data total and this value is stored in the source code.

Decryptor.cs

using System;
using System.Security.Cryptography;
using System.Text;

namespace SimpleEncryptor
{
    internal class Decryptor
    {
        public static void decrypt(string fileLocation, string decryptedOutFileLocation, string passphrase)
        {
            var keyGenerator = new keyGenerator();
            var key = keyGenerator.generateEncryptionKey(passphrase);

            FileStream fileStreamInputFile = new FileStream(fileLocation, FileMode.Open, FileAccess.Read);
            FileStream fileStreamOutputFile = new FileStream(decryptedOutFileLocation, FileMode.Create);

            using (Aes aes = Aes.Create())
            {
                aes.Key = key;
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;
                aes.IV = Encoding.UTF8.GetBytes("1234567812345678");  // first block only

                ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
                CryptoStream cryptoStream = new CryptoStream(fileStreamInputFile, decryptor, CryptoStreamMode.Read);

                try
                {
                    byte[] buffer = new byte[1024];
                    int read;

                    while ((read = cryptoStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        fileStreamOutputFile.Write(buffer, 0, read);
                        fileStreamOutputFile.Flush();
                    }
                    Console.WriteLine($"[+] Decryption Successful ({decryptedOutFileLocation}).");
                }
                catch (CryptographicException)
                {
                    Console.WriteLine("[!] Incorrect Passphrase");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
                finally
                {
                    fileStreamInputFile.Close();
                    fileStreamOutputFile.Close();
                }
            }
        }
    }
}

Once again the IV is set to the 16-byte value, “1234567812345678″ in the decryption method.


Linux Binary

If you’re using Kali Linux, you can use the Linux x64 compiled binary located on GitHub.com to encrypt and decrypt files on a Linux system.

To get the current installed version of the .NET Core framework on Kali Linux use the following command dotnet --list-sdks.

$ dotnet --list-sdks
6.0.400 [/usr/share/dotnet/sdk]

$ ./SimpleEncryptor                                  
[?] SimpleEncryptor encrypt c:\tools\passwords.txt c:\tools\passwords.txt.aes
[?] SimpleEncryptor decrypt c:\tools\passwords.txt.aes c:\tools\passwords2.txt

The Linux binary release on GitHub is compiled for .NET Core 6.0.4 and will function the same as the Windows version.

Downloads

C# linux-x64 net6.0 Release on GitHub

C# SimpleEncryptor Solution on GitHub


References

Wikimedia Foundation. (2023, July 24). Block cipher mode of Operation. Wikipedia.
  https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation

tdykstra. (2022, October 11). dotnet command – .NET CLI. Learn.microsoft.com.
  https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet

dotnet-bot. (n.d.-a). FileStream Class (System.IO). Learn.microsoft.com.
  https://learn.microsoft.com/en-us/dotnet/api/system.io.filestream?view=net-7.0

dotnet-bot. (n.d.-a). CryptoStream Class (System.Security.Cryptography). Learn.microsoft.com.
  https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptostream?view=net-7.0

dotnet-bot. (n.d.-d). KeyDerivation.Pbkdf2(String, Byte[], KeyDerivationPrf, Int32, Int32) Method (Microsoft.AspNetCore.Cryptography.KeyDerivation). Learn.microsoft.com.
  https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.cryptography.keyderivation.keyderivation.pbkdf2?view=aspnetcore-7.0

Footnotes

  1. https://en.wikipedia.org/wiki/Salt_(cryptography) ↩︎
  2. https://en.wikipedia.org/wiki/Initialization_vector ↩︎

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisement -spot_img

Latest article