【问题标题】:.NET AES/Rijndael — inconsistent decryption when reusing decryptor.NET AES/Rijndael — 重用解密器时解密不一致
【发布时间】:2010-07-29 20:48:57
【问题描述】:

我创建了一个使用 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
}

如您所见,在这两种情况下,我都通过CryptoStreamMemoryStream。如果我在每次调用Decrypt 时通过m_provider.CreateDecyptor(s_key, s_iv) 创建一个新的解密器,它就可以正常工作。

这里出了什么问题?为什么解密器表现得好像忘记了 IV?对StreamReader.ReadToEnd() 的调用是否有助于m_decryptor 正常运行?

我想避免我在此处列出的两种“有效”方法中的任何一种,因为这两种方法都会影响性能,这是一条非常关键的路径。提前致谢。

【问题讨论】:

  • 请发布实际加解密代码。这种方法听起来没有问题。

标签: .net encryption aes rijndael


【解决方案1】:

好的,我承认我不知道为什么会这样,但是将 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();
        }
    }
}

【讨论】:

  • 我正要发布同样的内容!如您所说,它可以与 RijndaelManaged 或 AesManaged 一起使用。我找到了一些关于三者之间差异的信息 (stackoverflow.com/questions/1228451/…),我选择了 AesManaged。相当神秘,但至少它正在工作!谢谢!
  • 使用托管加密算法的唯一问题是不符合FIPS。带着同样的问题来到这里,但我需要我的暗示才能符合 FIPS。
  • @iamtyler,您还可以重用 AesCryptoServiceProvider 实例,并为每次调用创建新的加密器和解密器。这对我有用。
猜你喜欢
  • 1970-01-01
  • 2023-03-23
  • 2014-05-08
  • 2012-07-20
  • 2013-08-24
  • 1970-01-01
  • 1970-01-01
  • 2015-09-03
  • 1970-01-01
相关资源
最近更新 更多