.NET AES / Rijndael - inconsistent decryption when re-decrypting

I created a class for encryption and decryption using AES.

public class AesEncryptionProvider {
    #region Fields

    // Encryption key
    private static readonly byte[] s_key = new byte[32] {
        // Omitted...
    };

    // Initialization vector
    private static readonly byte[] s_iv = new byte[16] {
        // Omitted...
    };

    private AesCryptoServiceProvider m_provider;
    private ICryptoTransform m_encryptor;
    private ICryptoTransform m_decryptor;

    #endregion

    #region Constructors

    private AesEncryptionProvider () {
        m_provider = new AesCryptoServiceProvider();
        m_encryptor = m_provider.CreateEncryptor(s_key, s_iv);
        m_decryptor = m_provider.CreateDecryptor(s_key, s_iv);
    }

    static AesEncryptionProvider () {
        Instance = new AesEncryptionProvider();
    }

    #endregion

    #region Properties

    public static AesEncryptionProvider Instance { get; private set; }

    #endregion

    #region Methods

    public string Encrypt (string value) {
        if (string.IsNullOrEmpty(value)) {
            throw new ArgumentException("Value required.");
        }

        return Convert.ToBase64String(
            Transform(
                Encoding.UTF8.GetBytes(value),
                m_encryptor));
    }

    public string Decrypt (string value) {
        if (string.IsNullOrEmpty(value)) {
            throw new ArgumentException("Value required.");
        }

        return Encoding.UTF8.GetString(
            Transform(
                Convert.FromBase64String(value),
                m_decryptor));
    }

    #endregion

    #region Private methods

    private byte[] Transform (byte[] input, ICryptoTransform transform) {
        byte[] output;
        using (MemoryStream memory = new MemoryStream()) {
            using (CryptoStream crypto = new CryptoStream(
                memory,
                transform,
                CryptoStreamMode.Write
            )) {
                crypto.Write(input, 0, input.Length);
                crypto.FlushFinalBlock();

                output = memory.ToArray();
            }
        }
        return output;
    }

    #endregion
}

As you can see, in both cases I write <<21> through CryptoStream. If I create a new decoder using m_provider.CreateDecyptor(s_key, s_iv)with every call Decrypt, it works fine.

What happened here? Why does the decoder behave as if IV had forgotten it? Is there something that makes a call StreamReader.ReadToEnd()that helps m_decryptorto function properly?

I would like to avoid either of the two “working” approaches listed here, as there is a performance hit for both, and this is a very important way. Thanks in advance.

+3
1

, , , , AesCryptoServiceProvider AesManaged voila.

IDisposable, -, . :

public sealed class AesEncryptionProvider : IDisposable
{
    // Encryption key
    private static readonly byte[] key = new byte[]
    {
        // Omitted...
    };

    // Initialization vector
    private static readonly byte[] iv = new byte[]
    {
        // Omitted...
    };

    private static readonly AesEncryptionProvider instance = new AesEncryptionProvider();

    private readonly AesManaged provider;

    private readonly ICryptoTransform encryptor;

    private readonly ICryptoTransform decryptor;

    private AesEncryptionProvider()
    {
        this.provider = new AesManaged();
        this.encryptor = this.provider.CreateEncryptor(key, iv);
        this.decryptor = this.provider.CreateDecryptor(key, iv);
    }

    public static AesEncryptionProvider Instance
    {
        get
        {
            return instance;
        }
    }

    public void Dispose()
    {
        this.decryptor.Dispose();
        this.encryptor.Dispose();
        this.provider.Dispose();
        GC.SuppressFinalize(this);
    }

    public string Encrypt(string value)
    {
        if (string.IsNullOrEmpty(value))
        {
            throw new ArgumentException("Value required.");
        }

        return Convert.ToBase64String(Transform(Encoding.UTF8.GetBytes(value), this.encryptor));
    }

    public string Decrypt(string value)
    {
        if (string.IsNullOrEmpty(value))
        {
            throw new ArgumentException("Value required.");
        }

        return Encoding.UTF8.GetString(Transform(Convert.FromBase64String(value), this.decryptor));
    }

    private static byte[] Transform(byte[] input, ICryptoTransform transform)
    {
        using (var memory = new MemoryStream())
        using (var crypto = new CryptoStream(memory, transform, CryptoStreamMode.Write))
        {
            crypto.Write(input, 0, input.Length);
            crypto.FlushFinalBlock();
            return memory.ToArray();
        }
    }
}
+1

Source: https://habr.com/ru/post/1757227/


All Articles