2010-07-29 94 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