Home > Software engineering >  How to encrypt / decrypt binary data in .NET 6.0 with AES in C#?
How to encrypt / decrypt binary data in .NET 6.0 with AES in C#?

Time:10-24

I'm trying to encrypt binary data with AES in .Net 6.0. Unfortunately, the decryption does not bring back the original data:

public static byte[] Encrypt(byte[] plainBytes)
{
    using (var aes = System.Security.Cryptography.Aes.Create())
    {
        byte[] cipherBytes;

        using (MemoryStream cipherStream = new MemoryStream())
        using (CryptoStream cryptoStream = new CryptoStream(cipherStream, aes.CreateEncryptor(aes.Key, aes.IV), CryptoStreamMode.Write))
        {
            cryptoStream.Write(plainBytes, 0, plainBytes.Length);
            cryptoStream.FlushFinalBlock();

            cipherStream.Seek(0, SeekOrigin.Begin);
            cipherBytes = new byte[cipherStream.Length];
            cipherStream.Read(cipherBytes, 0, cipherBytes.Length);
        }

        byte[] wrongPlainBytes;
        using (MemoryStream cipherStream = new MemoryStream(cipherBytes))
        using (CryptoStream cryptoStream = new CryptoStream(cipherStream, aes.CreateDecryptor(aes.Key, aes.IV), CryptoStreamMode.Read))
        {
            wrongPlainBytes = cipherStream.ToArray();
        }

        bool shouldBeTrue = plainBytes.Equals(wrongPlainBytes);

        return cipherBytes;
    }
}

After executing this code, shouldBeTrue should be true, but it's false. Also, plainBytes.Length is different from wrongPlainBytes.Length.

What do I wrong while encryption / decryption?

CodePudding user response:

Try to avoid direct Read on streams where possible - this operation is not guaranteed to read the amount of bytes you requested, so when you do use it - you need to check the return value (which you ignore) to figure out actual number of bytes that were read, and then act accordingly (do more reads if that amount is less than what you need).

There are several issues in your code, which you can avoid this way:

public static byte[] Encrypt(byte[] plainBytes)
{
    using (var aes = System.Security.Cryptography.Aes.Create())
    {
        byte[] cipherBytes;

        using (MemoryStream cipherStream = new MemoryStream()) {
            // use leaveOpen parameter here, that way it will NOT dispose cipherStream when closing cryptoStream
            using (CryptoStream cryptoStream = new CryptoStream(cipherStream, aes.CreateEncryptor(aes.Key, aes.IV), CryptoStreamMode.Write, true)) {
                // just write
                cryptoStream.Write(plainBytes, 0, plainBytes.Length);
            }
            // now, cryptoStream is disposed, so we can be sure all data is propertly written to the cipherStream
            // no need to flush or anything
            
            // do not manage buffer yourself, use ToArray
            cipherBytes = cipherStream.ToArray();
        }

        byte[] wrongPlainBytes;
        using (MemoryStream cipherStream = new MemoryStream(cipherBytes)) {
            using (CryptoStream cryptoStream = new CryptoStream(cipherStream, aes.CreateDecryptor(aes.Key, aes.IV), CryptoStreamMode.Read)) {
                using (var output = new MemoryStream()) {
                    // same story here, avoid direct reads, use CopyTo, it will copy all data, decrypted, to memory stream
                    cryptoStream.CopyTo(output);

                    // again, just ToArray to avoid manage buffer directly
                    wrongPlainBytes = output.ToArray();
                }
            }
        }

        bool shouldBeTrue = plainBytes.SequenceEqual(wrongPlainBytes);

        return cipherBytes;
    }
}

CodePudding user response:

public static byte[] Encrypt( byte[] plainBytes )
{
    using ( var aes = System.Security.Cryptography.Aes.Create() )
    {
        byte[] cipherBytes;

        using ( MemoryStream cipherStream = new MemoryStream() )
        using ( CryptoStream cryptoStream = new CryptoStream( cipherStream, aes.CreateEncryptor( aes.Key, aes.IV ), CryptoStreamMode.Write ) )
        {

            cryptoStream.Write( plainBytes, 0, plainBytes.Length );
            cryptoStream.FlushFinalBlock();
            cipherBytes = cipherStream.ToArray();



        }
        byte[] wrongPlainBytes;
        using ( MemoryStream cipherStream = new MemoryStream() )
        using ( CryptoStream cryptoStream = new CryptoStream( cipherStream, aes.CreateDecryptor( aes.Key, aes.IV ), CryptoStreamMode.Write ) )
        {
            cryptoStream.Write( cipherBytes, 0, cipherBytes.Length );
            cryptoStream.FlushFinalBlock();
            wrongPlainBytes = cipherStream.ToArray();

        }

        bool shouldBeTrue = plainBytes.SequenceEqual( wrongPlainBytes );

        return cipherBytes;
    }
}
  • Related