EN VI

C# .NET CryptographicException with AES256?

2024-03-13 20:00:06
How to C# .NET CryptographicException with AES256

I'm trying to create a class to encrypt and decrypt large numbers of files with AES in C# .NET. However, during decryption I have an exception which is always thrown.

Encryptor class :

public class Encryptor
{
    private const int KeySize = 256;
    private const int BlockSize = 128;
    private const CipherMode Cipher = CipherMode.CBC;
    private const PaddingMode Padding = PaddingMode.PKCS7;
    private  byte[]? key;

    private static byte[] ProtectData(byte[] data)
    {
        return ProtectedData.Protect(data, null, DataProtectionScope.CurrentUser);
    }

    private static byte[] UnprotectData(byte[] protectedData)
    {
        return ProtectedData.Unprotect(protectedData, null, DataProtectionScope.CurrentUser);
    }

    public void SetEncryptionKey(string key)
    {
        if (string.IsNullOrEmpty(key))  throw new ArgumentException("Key cannot be null or empty");
        this.key = ProtectData(Encoding.UTF8.GetBytes(key));
    }

    public void SetEncryptionKey(byte[] key)
    {
        if (key == null || key.Length == 0)  throw new ArgumentException("Key cannot be null or empty");
        this.key = ProtectData(key);
    }

    private void ValidateInputs(string inputFilepath, string? outputFilepath = null)
    {
        if (key is null) throw new ArgumentNullException("The key has not been defined");
        if (!File.Exists(inputFilepath)) throw new FileNotFoundException("Input file doesn't exist");
        if (outputFilepath is not null && File.Exists(outputFilepath)) throw new ArgumentException("Output file already exists");
    }

    public void DecryptFile(string inputFilepath, string outputFilepath)
    {
        ValidateInputs(inputFilepath, outputFilepath);

        using (Aes aes = Aes.Create())
        {
        aes.Key = UnprotectData(key);
        aes.KeySize = KeySize;
        aes.BlockSize = BlockSize;
        aes.Mode = Cipher;
        aes.Padding = Padding;

        using (FileStream inputFileStream = new FileStream(inputFilepath, FileMode.Open, FileAccess.Read, FileShare.None))
        {
            byte[] buffer = new byte[BlockSize/8];
            inputFileStream.Read(buffer, 0, buffer.Length);
            inputFileStream.Seek(BlockSize / 8, SeekOrigin.Begin);
            aes.IV = buffer;
            using (FileStream outputFileStream = new FileStream(outputFilepath, FileMode.Create, FileAccess.Write, FileShare.None))
            using (CryptoStream cryptoStream = new CryptoStream(outputFileStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
            {
            inputFileStream.CopyTo(cryptoStream);
            }
        }
        }
    }

    public void EncryptFile(string inputFilepath, string outputFilepath)
    {
        ValidateInputs(inputFilepath, outputFilepath);

        using (Aes aes = Aes.Create())
        {
        aes.Key = UnprotectData(key);
        aes.KeySize = KeySize;
        aes.BlockSize = BlockSize;
        aes.Mode = Cipher;
        aes.Padding = Padding;
        aes.GenerateIV();

        using (FileStream inputFileStream = new FileStream(inputFilepath, FileMode.Open, FileAccess.Read, FileShare.None))
        using (FileStream outputFileStream = new FileStream(outputFilepath, FileMode.Create, FileAccess.Write, FileShare.None))
        using (CryptoStream cryptoStream = new CryptoStream(outputFileStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
        {
            outputFileStream.Write(aes.IV,0, aes.IV.Length);
            inputFileStream.CopyTo(cryptoStream);
        }
        }
    }
}

Main class :

public static Main(string[] args)
{
    const ssl_nopass = "...";
    const input = "...";
    const output_encrypted = "...";
    const output_decrypted = "..."

    Encryptor encryptor = new Encryptor();
    encryptor.SetEncryptionKey(File.ReadAllBytes(ssl_nopass));
    encryptor.EncryptFile(input, output_encrypted + "ssl_nopass");
    encryptor.DecryptFile(output_encrypted + "ssl_nopass", output_decrypted + "ssl_nopass.txt");
}

Exception :

System.Security.Cryptography.CryptographicException
  HResult=0x80131501
  Message=Padding is invalid and cannot be removed.
  Source=System.Security.Cryptography
  Procedure call tree :
   at System.Security.Cryptography.SymmetricPadding.GetPaddingLength(ReadOnlySpan`1 block, PaddingMode paddingMode, Int32 blockSize)
   at System.Security.Cryptography.UniversalCryptoDecryptor.UncheckedTransformFinalBlock(ReadOnlySpan`1 inputBuffer, Span`1 outputBuffer)
   at System.Security.Cryptography.UniversalCryptoDecryptor.UncheckedTransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
   at System.Security.Cryptography.UniversalCryptoTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
   at System.Security.Cryptography.CryptoStream.<FlushFinalBlockAsync>d__30.MoveNext()
   at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
   at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing)
   at System.IO.Stream.Close()
   at Encryption.Encryptor.DecryptFile(String inputFilepath, String outputFilepath) dans C:\...\Encryptor.cs :ligne 108
   at Program.<Main>$(String[] args) dans C:\...\Program.cs :ligne 21

How the key was created :

openssl rand -out key.bin 32

With debugging mode I have already verified that:

  • the byte key used during encryption and decryption is same;
  • the byte IV used during encryption and decryption is same.

Thank you for your help.

Solution:

While decrypting, what you need to do is read data from the encrypted file through CryptoStream.

using (CryptoStream cryptoStream = new CryptoStream(inputFileStream, 
                                                    aes.CreateDecryptor(),
                                                    CryptoStreamMode.Read))
{
    cryptoStream.CopyTo(outputFileStream);
}
Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login