.NET AES / Rijndael - противоречивая расшифровка при повторном использовании расшифровщика - PullRequest
3 голосов
/ 30 июля 2010

Я создал класс для шифрования и дешифрования с использованием 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
}

Как видите, в обоих случаях я записываю в MemoryStream черезCryptoStream.Если я создаю новый расшифровщик через m_provider.CreateDecyptor(s_key, s_iv) при каждом вызове Decrypt, он работает просто отлично.

Что здесь не так?Почему расшифровщик ведет себя так, как будто он забыл IV?Есть ли что-то, что делает вызов StreamReader.ReadToEnd(), который помогает m_decryptor функционировать правильно?

Я хотел бы избежать любого из двух «работающих» подходов, которые я перечислил здесь, так как есть потеря производительности на обоихи это очень важный путь.Заранее спасибо.

1 Ответ

1 голос
/ 30 июля 2010

Хорошо, я признаю, что понятия не имею, почему это работает, но измените AesCryptoServiceProvider на AesManaged и вуаля.

Я также рекомендую сделать ваш класс реализующим 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();
        }
    }
}
...