2012-03-05 38 views
1

我想使用eith Rijndael或Aes和下面的代碼來加密/解密字符串。Rijndael填充或長度無效

public class Crypto 
{ 
    private const string defaultVector = "asdfg123456789"; 
    private const CipherMode cipherMode = CipherMode.CBC; 
    //Have tried PaddingMode.ISO10126, PaddingMode.None, and PaddingMode.PKCS7 
    private const PaddingMode paddingMode = PaddingMode.ISO10126; 
    private const int iterations = 2; 
    private static Rijndael GetCrypto(string passphrase) 
    { 
     var crypt = Rijndael.Create(); 
     crypt.Mode = cipherMode; 
     crypt.Padding = paddingMode; 
     crypt.BlockSize = 256; 
     crypt.KeySize = 256; 
     crypt.Key = 
      new Rfc2898DeriveBytes(passphrase, Encoding.Unicode.GetBytes(defaultVector), iterations).GetBytes(32); 
     crypt.IV = new Rfc2898DeriveBytes(passphrase, Encoding.Unicode.GetBytes(defaultVector), iterations).GetBytes(32); 
     return crypt; 
    } 
    public static string Encrypt(string plainText, string passphrase) 
    { 
     byte[] clearData = Encoding.Unicode.GetBytes(plainText); 
     byte[] encryptedData; 
     var crypt = GetCrypto(passphrase); 
     using (var ms = new MemoryStream()) 
     { 
      using (var cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write)) 
      { 
       cs.Write(clearData, 0, clearData.Length); 
       //cs.FlushFinalBlock(); //Have tried this active and commented with no change. 
      } 
      encryptedData = ms.ToArray(); 
     } 
     //Changed per Xint0's answer. 
     return Convert.ToBase64String(encryptedData); 
    } 
    public static string Decrypt(string cipherText, string passphrase) 
    { 
     //Changed per Xint0's answer. 
     byte[] encryptedData = Convert.FromBase64String(cipherText); 
     byte[] clearData; 
     var crypt = GetCrypto(passphrase); 
     using (var ms = new MemoryStream()) 
     { 
       using (var cs = new CryptoStream(ms, crypt.CreateDecryptor(), CryptoStreamMode.Write)) 
       { 
        cs.Write(encryptedData, 0, encryptedData.Length); 
        //I have tried adding a cs.FlushFinalBlock(); here as well. 
       } 
       clearData = ms.ToArray(); 
     } 
     return Encoding.Unicode.GetString(clearData); 
    } 
} 

//編輯:我已經改變了統一調用按照以下XINT0的回答Convert.ToBase64String。

在解密方法中的cs.Write,我得到錯誤,「填充無效,無法刪除。」

我曾嘗試將填充設置爲PaddingMode.None,但我得到「要加密的數據長度無效」。在加密方法中的cs.Write上。

我看過這些,他們所說的沒有什麼似乎可以工作。

Padding is invalid and cannot be removed

Padding is invalid and cannot be removed?

棧跟蹤顯示System.Security.CryptographicException從RijndaelManagedTransform.DecryptData(字節[] INPUTBUFFER,的Int32 inputOffset,的Int32 inputCount,字節[] & OutputBuffer中,的Int32 outputOffset,PaddingMode未來paddingMode,Boolean fLast)。

回答

1

我看到兩個問題:

  1. 你不沖水,並呼籲ms.ToArray()前關閉流。將其更改爲:

    ... 
    using (var cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write)) 
    { 
        cs.Write(clearData, 0, clearData.Length); 
        cs.FlushFinalBlock(); 
        cs.Close(); 
    } 
    
    ms.Close(); 
    encryptedData = ms.ToArray(); 
    ... 
    
  2. Encrypt生成的字節數組encryptedData不是 Unicode字符串,但使用的是一個Unicode編碼器來獲得從字節數組的字符串。代替代替EncryptSystem.Convert.FromBase64String()代替Decrypt

Encrypt做:

return System.Convert.ToBase64String(encryptedData); 

Decrypt做:

byte[] encryptedData = System.Convert.FromBase64String(cipherText); 

編輯

最大的問題是Encrypt返回值。加密Unicode字符串的字節表示的結果是不是 Unicode字符串的字節表示形式。您不應使用encryptedDataEncoding.Unicode.GetString()的值來獲取加密數據的字符串表示形式。使用System.Convert.ToBase64String()可獲取加密數據的字符串表示形式。請參閱Encoding Class MSDN文檔中的註釋部分。

EDIT 2

注意Rijndael算法是不完全的AES,如果您正在使用AES互操作的塊大小應始終是128位的獨立密鑰大小的。詳情請參閱here

+0

我曾嘗試加入cs.Close()和cs.FlushFinalBlock()的每一個排列。堆棧跟蹤顯示來自CryptoStream調用的System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte [] inputBuffer,Int32 inputOffset,Int32 inputCount,Byte []&outputBuffer,Int32 outputOffset,PaddingMode paddingMode,Boolean fLast)的錯誤。 FlushFinalBlock()。當CryptoStream被關閉/處置時FlushFinalBlock也被調用。所以我在這裏虧本。 – PMontgomery 2012-03-06 15:24:45

+0

@PMontgomery你用'System.Convert.ToBase64String(encryptedData)'替換'Encoding.Unicode.GetString(encryptedBytes)'?這是你最大的問題。 – Xint0 2012-03-06 17:45:07

+0

是的,我已經做了這些修改並編輯了原始問題以反映。它沒有改變錯誤。 – PMontgomery 2012-03-06 19:41:03

2

我花了很多的時間來找到造成的原因CryptographicException我也是googling,包括Stackoverflow。

它是從實例投擲方法FlushFinalBlock()的CryptoStream的:
它(用複製粘貼編程時經常)如下是一個愚蠢的錯誤。

WRONG代碼:

CryptoStream cs = new CryptoStream(ms, rj.CreateDecryptor(rj.Key, rj.IV), CryptoStreamMode.Write); 

我用它來加密,所以你可以看到CryptoStreamMode。 但在相同的指令中,我創建瞭解密器而不是加密器(請參閱構造函數中的第二個參數)。

仔細的檢查,以避免浪費您的寶貴時間;)

問候
布羅尼斯瓦夫

0

我也有類似的問題,在解密方法的問題是初始化一個空的內存流。當它工作時,我與密文字節數組像這樣初始化它:

MemoryStream ms = new MemoryStream(cipherText);