2012-10-04 27 views
0

我試圖使用bouncycastle庫加密和解密數據,解密數據後第一個數據塊信息被破壞就好像它未能成功解密並且最後一塊完全丟失一樣。我是bouncycastle圖書館的新手,我一直在搜索整個互聯網,試圖通過使用PKCS7Padding在CBC模式下找到一個明智的AES加密實現,但是我一直沒有遇到過很多文檔。提供的任何幫助將不勝感激,也應該指出,我是一名學生而不是專業開發人員。謝謝。輸出的Rijndael使用BouncyCastle解密產生損壞的數據開始和結尾,但其餘數據完全解密

`public class RijndaelCBC 
{ 
    private int _keySize; 
    private byte[] _passphrase; 

    public byte[] _iv { get; private set; } 

    private IBlockCipher blockCipher; 
    private PaddedBufferedBlockCipher aesCipher; 
    private ParametersWithIV _param; 

    public RijndaelCBC(int KeySize, string Passphrase) 
    { 
     if (Passphrase.Length < KeySize/8) 
      Passphrase = Passphrase.PadRight(KeySize/8, '0'); 
     if (Passphrase.Length > KeySize) 
      Passphrase = Passphrase.Substring(0, KeySize/8); 

     _passphrase = System.Convert.FromBase64String(Passphrase); 
     Array.Resize(ref _passphrase, KeySize/8); 
     _keySize = KeySize; 

     Random rnd = new Random(); 
     _iv = new byte[_keySize/8]; 
     for (int t = 0; t < _keySize/8; t++) 
      rnd.Next(); 
     rnd.NextBytes(_iv); 

     if (_keySize != 128 && _keySize != 192 && _keySize != 256) 
      throw new Exception(string.Format("Invalid key size of {0} provided, cannot continue with the process.", _keySize)); 
    } 

    public RijndaelCBC(int KeySize, string Passphrase, byte[] iv) 
    { 
     if (Passphrase.Length < KeySize/8) 
      Passphrase = Passphrase.PadRight(KeySize/8, '0'); 
     if (Passphrase.Length > KeySize) 
      Passphrase = Passphrase.Substring(0, KeySize/8); 


     _passphrase = System.Convert.FromBase64String(Passphrase); 
     Array.Resize(ref _passphrase, KeySize/8); 
     _keySize = KeySize; 
     _iv = iv; 
     if (_keySize != 128 && _keySize != 192 && _keySize != 256) 
      throw new Exception(string.Format("Invalid key size of {0} provided, cannot continue with the process.", _keySize)); 
    } 

    public byte[] Encrypt(byte[] data) 
    { 
     try 
     { 
      blockCipher = new CbcBlockCipher(new RijndaelEngine(_keySize)); 
      _param = new ParametersWithIV(new KeyParameter(_passphrase), _iv); 
      blockCipher.Init(true, _param); 

      aesCipher = new PaddedBufferedBlockCipher(blockCipher, new Pkcs7Padding()); 
      byte[] cipherTextBlock = null; 
      int blockSize = aesCipher.GetBlockSize(); 
      List<byte> output = new List<byte>(); 
      int outputLen = 0; 
      int chunkPosition = 0; 
      for (chunkPosition = 0; chunkPosition < data.Length; chunkPosition += blockSize) 
      { 
       byte[] dataToProcess = new byte[blockSize]; 
       int chunkSize = (data.Length - chunkPosition) < blockSize ? (data.Length - chunkPosition) : blockSize; 
       Buffer.BlockCopy(data, chunkPosition, dataToProcess, 0, chunkSize); 

       cipherTextBlock = new byte[blockSize]; 
       outputLen = aesCipher.ProcessBytes(dataToProcess, 0, chunkSize, cipherTextBlock, 0); 
       output.AddRange(cipherTextBlock); 
      } 
      try 
      { 
       if(chunkPosition < data.Length && 
        chunkPosition + blockSize > data.Length) 
       { 
        byte[] dataToProcess = new byte[blockSize]; 
        int chunkSize = (chunkPosition + blockSize) - data.Length; 
        Buffer.BlockCopy(data, chunkPosition, dataToProcess, 0, chunkSize); 
        aesCipher.DoFinal(cipherTextBlock, 0); 
        output.AddRange(cipherTextBlock); 
       } 
      } 
      catch (CryptoException ex) 
      {} 
      return output.ToArray(); 
     } 
     catch (System.Exception ex) 
     { } 
     return null; 
    } 

    public byte[] Decrypt(byte[] data) 
    { 
     try 
     { 
      blockCipher = new CbcBlockCipher(new RijndaelEngine(_keySize)); 
      _param = new ParametersWithIV(new KeyParameter(_passphrase), _iv); 
      blockCipher.Init(false, _param); 

      aesCipher = new PaddedBufferedBlockCipher(blockCipher, new Pkcs7Padding()); 
      byte[] cipherTextBlock = null; 
      int blockSize = aesCipher.GetBlockSize(); 
      List<byte> output = new List<byte>(); 
      int outputLen = 0; 
      int chunkPosition = 0; 
      for (chunkPosition = 0; chunkPosition < data.Length; chunkPosition += blockSize) 
      { 
       byte[] dataToProcess = new byte[blockSize]; 
       int chunkSize = (data.Length - chunkPosition) < blockSize ? (data.Length - chunkPosition) : blockSize; 
       Buffer.BlockCopy(data, chunkPosition, dataToProcess, 0, chunkSize); 
       cipherTextBlock = new byte[blockSize]; 

       outputLen = aesCipher.ProcessBytes(dataToProcess, 0, chunkSize, cipherTextBlock, 0); 
       output.AddRange(cipherTextBlock); 
      } 
      try 
      { 
       if (chunkPosition < data.Length && 
        chunkPosition + blockSize > data.Length) 
       { 
        byte[] dataToProcess = new byte[blockSize]; 
        int chunkSize = (chunkPosition + blockSize) - data.Length; 
        Buffer.BlockCopy(data, chunkPosition, dataToProcess, 0, chunkSize); 
        aesCipher.DoFinal(cipherTextBlock, 0); 
        output.AddRange(cipherTextBlock); 
       } 
      } 
      catch (CryptoException ex) 
      { } 
      return output.ToArray(); 
     } 
     catch (System.Exception ex) 
     { } 
     return null; 
    } 
}` 

示例: 開頭數據的應該是:

生產版本發佈

但作爲最終: [¨dZJÊ)UOL)ȱýº-NU 〜VE'·ðúœ×ñðersion發行

和數據結束應該是: 對於此類產品,英特爾不承擔任何責任, 和英特爾不做任何明示或暗示的擔保, 與銷售和/或使用英特爾產品,包括 責任或適用性的保證了 特定目的,適銷性或侵犯任何 專利,版權或其他知識產權。英特爾產品不適用於醫療, 拯救生命或維持生命的應用程序。

但作爲結束: 此類產品,英特爾不承擔任何責任, 和英特爾不做任何明示或暗示的擔保, 與銷售和/或使用英特爾產品,包括 責任或warran

我試圖加密和解密一個例子,但是最終數據丟失了,開始時數據沒有正確解密,但52KB文件的其餘部分是完美的。

+1

您能否將您的代碼示例轉換爲[SSCCE](http://sscce.org),我們可以複製/粘貼並自行觀察問題? –

+0

如果您希望代碼在完成後能夠正常工作,則不應該捕獲Exception或CryptoException。如果你希望你的代碼在某些情況下工作,其餘的是一個錯誤的混亂,請不要讓它進入。 – Henrik

+0

有些東西告訴我,局部變量keySizeBytes是個好主意。 –

回答

3

這段代碼有幾個問題,但是導致解密問題的問題是使用IV。你在加密過程中生成一個隨機的IV(好的),但是你把它扔掉了。然後在解密過程中生成一個不同的隨機IV,這是不正確的。您需要使用與解密相同的IV作爲加密。您通常會將IV與密文一起傳遞(通常預置爲密文最簡單)。

你的密鑰生成也是不正確的。盡我所知,你期待在Base-64編碼中使用「密碼」。然後在關鍵長度將其切斷,或用0填充。這是非常不安全的。你基本上把AES-256轉換成AES-50左右。它看起來是加密的,但它實際上只有一個很小的密鑰空間,可以被強制使用。

將人類密碼轉換爲AES密鑰的正確方法是使用稱爲PBKDF2的算法。我對bouncycastle並不是特別熟悉,也不知道他們用於PBKDF2的提供商。請參閱PBKDF2 with bouncycastle in Java瞭解更多有關bouncycastle的詳細信息。

+0

感謝您的意見,但是我用於加密的iv與在解密過程中使用的iv相同,因爲我使用_iv屬性獲得了iv,但我確實認爲第二部分中的密碼可能是導致因爲我沒有將其轉換爲AES密鑰。再次感謝。 – user1327159

+0

沒有。如果密鑰不正確,那麼純文本的任何內容都不會解密(對於正確的值,對稱加密塊將始終解密)。 –

+0

我生成的密鑰使用PbeParametersGenerator和它仍然產生相同的問題,它似乎是一個內存問題,因爲當我在循環之外的臨時緩衝區調用aesCipher.ProcessBytes然後開始解密過程如上所示我會得到數據的開始被解密,但是來自隨機內存塊的一些數據仍然被複制到我的輸出byte []數組中,就好像BlockCipher的緩衝區中仍有一些數據被複制到我的輸出中一樣,所以我嘗試了在這個答案中的解決方案,兩者仍然失敗 – user1327159

1

那麼,你沒有正確得到第一個塊的原因必須是IV值或緩衝區處理問題。最後一個可能會比你期望的更合乎邏輯,因爲你錯誤地使用了DoFinal,所以最後結果不見了。您提供輸入緩衝區而不是輸出緩衝區。

0

我最終做的工作是讓代碼工作,將填充的分組密碼更改爲緩衝分組密碼,不知道他們是否有這樣做的負面影響,但我包含代碼以防萬一需要因爲它是難以找到BouncyCastle的例子在C#

public class RijndaelCBC 
{ 
    private int _keyBitSize; 
    public byte[] _iv { get; private set; } 

    private BufferedBlockCipher cipher; 
    private KeyParameter key; 
    private ParametersWithIV IVkey; 

    public RijndaelCBC(int KeySize, byte[] salt, string Passphrase) 
    { 
    _keyBitSize = KeySize; 

     Random rnd = new Random(); 

     _iv = new byte[_keyBitSize/8]; 
     for (int t = 0; t < _keyBitSize/8; t++) 
      rnd.Next(); 
     rnd.NextBytes(_iv); 

     PbeParametersGenerator generator = new Pkcs5S2ParametersGenerator(); 
     generator.Init(PbeParametersGenerator.Pkcs5PasswordToUtf8Bytes((Passphrase).ToCharArray()), salt, 1000); 
     key = (KeyParameter)generator.GenerateDerivedParameters("AES", _keyBitSize); 
    } 

    public RijndaelCBC(int KeySize, byte[] salt, string Passphrase, byte[] iv) 
    { 
     _iv = iv; 

     PbeParametersGenerator generator = new Pkcs5S2ParametersGenerator(); 
     generator.Init(PbeParametersGenerator.Pkcs5PasswordToUtf8Bytes((Passphrase).ToCharArray()), salt, 1000); 
     key = (KeyParameter)generator.GenerateDerivedParameters("AES", _keyBitSize); 
    } 


    public byte[] Encrypt(byte[] data) 
    { 
     IBlockCipher theCipher = null; 
     theCipher = new RijndaelEngine(_keyBitSize); 
     cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(theCipher)); 
     IVkey = new ParametersWithIV(key, _iv); 
     cipher.Init(true, IVkey); 

     int size = cipher.GetOutputSize(data.Length); 
     byte[] result = new byte[size]; 
     int olen = cipher.ProcessBytes(data, 0, data.Length, result, 0); 
     olen += cipher.DoFinal(result, olen); 

     if (olen < size) 
     { 
      byte[] tmp = new byte[olen]; 
      Array.Copy(result, 0, tmp, 0, olen); 
      result = tmp; 
     } 

     return result; 
    } 

    public byte[] Decrypt(byte[] data) 
    { 
     IBlockCipher theCipher = null; 
     theCipher = new RijndaelEngine(_keyBitSize); 
     cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(theCipher)); 
     IVkey = new ParametersWithIV(key, _iv); 
     cipher.Init(false, IVkey); 

     int size = cipher.GetOutputSize(data.Length); 
     byte[] result = new byte[size]; 
     int olen = cipher.ProcessBytes(data, 0, data.Length, result, 0); 
     olen += cipher.DoFinal(result, olen); 

     if (olen < size) 
     { 
      byte[] tmp = new byte[olen]; 
      Array.Copy(result, 0, tmp, 0, olen); 
      result = tmp; 
     } 

     return result; 
    } 
} 

正如上面提出類的初始化的問題,第一個構造使用隨機數據,其可以被用於加密生成IV,代的後所述IV可以通過訪問_iv屬性來獲得IV。或者你可以在加密和/或使用第二類構造函數進行解密時傳遞IV。

相關問題