2010-07-29 96 views
3

不一致解密时,我创建了一个类用于加密和使用AES解密。.NET AES/Rijndael算法 - 重用解密

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正常工作?

我想避免我在这里列出的两种“工作”方法中的任何一种,因为这两种方法都会对性能造成影响,这是一条非常关键的途径。提前致谢。

+1

请发布**加密和解密的**实际**代码。这种做法听起来不像是有问题的。 – 2010-07-29 21:32:02

+0

更新完整的课程。 – iamtyler 2010-07-29 21:53:34

回答

1

好吧,我承认我不知道为什么这个工作,但改变AesCryptoServiceProviderAesManaged,瞧。

我还建议让你的类实现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(); 
     } 
    } 
} 
+0

我正准备发布相同的东西!它可以与RijndaelManaged一起使用,如您所说,或者AesManaged。我发现了关于三者之间差异的一些信息(http://stackoverflow.com/questions/1228451/when-would-i-choose-aescryptoserviceprovider-over-aesmanaged-or-rijndaelmanaged),并选择了AesManaged。很神秘,但至少它工作正常!谢谢! – iamtyler 2010-07-29 22:58:10

+0

使用托管加密算法唯一的问题是不存在[FIPS](http://en.wikipedia.org/wiki/FIPS_140)兼容。来到这里的同一个问题,但我需要我的implimentation符合FIPS。 – Darren 2013-06-28 13:24:40

+0

@iamtyler,你也可以重用AesCryptoServiceProvider实例,只是为每次调用创建新的加密器和解密器。这对我有效。 – 2017-08-02 15:39:13