2010-07-09 125 views
13

我一直在搞亂C#Bouncy Castle API以找到如何做PBKDF2密鑰派生。Bouncy Castle C中的PBKDF2#

我現在真的無言以對。

我試着讀通過Pkcs5S2ParametersGenerator.cs和PBKDF2Params.cs文件,但我真的不知道如何做到這一點。根據我到目前爲止所做的研究,PBKDF2需要一個字符串(或字符[]),它是密碼,鹽和迭代計數。

到目前爲止,我迄今爲止最有前途和最明顯的發現是PBKDF2Params和Pkcs5S2ParametersGenerator。

這些似乎都不接受字符串或字符[]。

有沒有人在C#中做過這件事,或者對此有任何線索?或者也許有人在Java中實現了BouncyCastle並可以提供幫助?

感謝名單了很多提前:)

更新:我已經找到了如何在充氣城堡做到這一點。請看下面的答案:)

回答

13

經過幾小時和幾小時的代碼,我發現最簡單的方法是在Pkcs5S2ParametersGenerator.cs中獲取代碼的幾個部分並創建自己的類,當然使用其他BouncyCastle API的。這適用於DotNet Compact Framework(Windows Mobile)。這相當於Rfc2898DeriveBytes類,它不在DotNet Compact Framework 2.0/3.5中。好吧,也許不是完全等效,但做這項工作:)

這是PKCS5/PKCS#5

這是用來將HMAC-SHA1

第一件事情PRF(僞隨機函數)第一。從http://www.bouncycastle.org/csharp/下載Bouncy Castle編譯程序集,將BouncyCastle.Crypto.dll作爲參考添加到您的項目中。

之後,用下面的代碼創建新的類文件。

using System; 
using Org.BouncyCastle.Crypto; 
using Org.BouncyCastle.Crypto.Parameters; 
using Org.BouncyCastle.Crypto.Digests; 
using Org.BouncyCastle.Crypto.Macs; 
using Org.BouncyCastle.Math; 
using Org.BouncyCastle.Security; 

namespace PBKDF2_PKCS5 
{ 
    class PBKDF2 
    { 

     private readonly IMac hMac = new HMac(new Sha1Digest()); 

     private void F(
      byte[] P, 
      byte[] S, 
      int c, 
      byte[] iBuf, 
      byte[] outBytes, 
      int outOff) 
     { 
      byte[] state = new byte[hMac.GetMacSize()]; 
      ICipherParameters param = new KeyParameter(P); 

      hMac.Init(param); 

      if (S != null) 
      { 
       hMac.BlockUpdate(S, 0, S.Length); 
      } 

      hMac.BlockUpdate(iBuf, 0, iBuf.Length); 

      hMac.DoFinal(state, 0); 

      Array.Copy(state, 0, outBytes, outOff, state.Length); 

      for (int count = 1; count != c; count++) 
      { 
       hMac.Init(param); 
       hMac.BlockUpdate(state, 0, state.Length); 
       hMac.DoFinal(state, 0); 

       for (int j = 0; j != state.Length; j++) 
       { 
        outBytes[outOff + j] ^= state[j]; 
       } 
      } 
     } 

     private void IntToOctet(
      byte[] Buffer, 
      int i) 
     { 
      Buffer[0] = (byte)((uint)i >> 24); 
      Buffer[1] = (byte)((uint)i >> 16); 
      Buffer[2] = (byte)((uint)i >> 8); 
      Buffer[3] = (byte)i; 
     } 

     // Use this function to retrieve a derived key. 
     // dkLen is in octets, how much bytes you want when the function to return. 
     // mPassword is the password converted to bytes. 
     // mSalt is the salt converted to bytes 
     // mIterationCount is the how much iterations you want to perform. 


     public byte[] GenerateDerivedKey(
      int dkLen, 
      byte[] mPassword, 
      byte[] mSalt, 
      int mIterationCount 
      ) 
     { 
      int hLen = hMac.GetMacSize(); 
      int l = (dkLen + hLen - 1)/hLen; 
      byte[] iBuf = new byte[4]; 
      byte[] outBytes = new byte[l * hLen]; 

      for (int i = 1; i <= l; i++) 
      { 
       IntToOctet(iBuf, i); 

       F(mPassword, mSalt, mIterationCount, iBuf, outBytes, (i - 1) * hLen); 
      } 

     //By this time outBytes will contain the derived key + more bytes. 
     // According to the PKCS #5 v2.0: Password-Based Cryptography Standard (www.truecrypt.org/docs/pkcs5v2-0.pdf) 
     // we have to "extract the first dkLen octets to produce a derived key". 

     //I am creating a byte array with the size of dkLen and then using 
     //Buffer.BlockCopy to copy ONLY the dkLen amount of bytes to it 
     // And finally returning it :D 

     byte[] output = new byte[dkLen]; 

     Buffer.BlockCopy(outBytes, 0, output, 0, dkLen); 

     return output; 
     } 


    } 
} 

那麼如何使用這個函數呢?簡單! :) 這是一個非常簡單的例子,其中密碼和salt由用戶提供。

private void cmdDeriveKey_Click(object sender, EventArgs e) 
     { 
      byte[] salt = ASCIIEncoding.UTF8.GetBytes(txtSalt.Text); 

      PBKDF2 passwordDerive = new PBKDF2(); 


     // I want the key to be used for AES-128, thus I want the derived key to be 
     // 128 bits. Thus I will be using 128/8 = 16 for dkLen (Derived Key Length) . 
     //Similarly if you wanted a 256 bit key, dkLen would be 256/8 = 32. 

      byte[] result = passwordDerive.GenerateDerivedKey(16, ASCIIEncoding.UTF8.GetBytes(txtPassword.Text), salt, 1000); 

      //result would now contain the derived key. Use it for whatever cryptographic purpose now :) 
      //The following code is ONLY to show the derived key in a Textbox. 

      string x = ""; 

      for (int i = 0; i < result.Length; i++) 
      { 
       x += result[i].ToString("X"); 
      } 

      txtResult.Text = x; 

     } 

如何檢查這是否正確? 有一個在線的JavaScript PBKDF2 http://anandam.name/pbkdf2/

的執行我得到一致的結果:) 請報告,如果有人越來越不正確的結果:)

希望這可以幫助別人:)

更新:已確認與測試向量的工作提供了這裏

http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-00

UPDAT E: 或者,對於鹽,我們可以使用RNGCryptoServiceProvider。確保引用System.Security.Cryptography名稱空間。

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();   

byte[] salt = new byte[16]; 

rng.GetBytes(salt); 
+1

你很快回答你自己的問題! – 2010-07-09 23:28:23

+1

你剛剛爲我節省了很多時間。謝謝! – John 2011-01-20 17:10:55

+0

@John:很高興能有任何幫助:) – 2011-01-21 01:00:39

1

我剛纔自己也有這個問題,並且找到了一個更直接的方法。至少充氣城堡1.7,你可以(使用Org.BouncyCastle.Crypto在VB)做這樣的:

Dim bcKeyDer As New Generators.Pkcs5S2ParametersGenerator() 
bcKeyDer.Init(password, salt, keyIterations) 
Dim bcparam As Parameters.KeyParameter = bcKeyDer.GenerateDerivedParameters("aes256", 256) 
Dim key1() As Byte = bcparam.GetKey() 

我已經測試過這個對NET的System.Security.Cryptography,和它的作品!

相關問題