2010-07-09 38 views
13

Tôi đang rối tung xung quanh API Lâu đài Bouncy C# để tìm cách thực hiện một dẫn xuất khóa PBKDF2.PBKDF2 trong Lâu đài Bouncy C#

Tôi thực sự không biết gì ngay bây giờ.

Tôi đã thử đọc qua các tệp Pkcs5S2ParametersGenerator.cs và PBKDF2Params.cs nhưng tôi thực sự không thể tìm ra cách thực hiện.

Theo nghiên cứu tôi đã thực hiện cho đến nay, PBKDF2 yêu cầu một chuỗi (hoặc char []) là mật khẩu, số muối và số lần lặp lại.

Cho đến nay, hứa hẹn nhất và rõ ràng nhất tôi đã đến từ trước đến nay là PBKDF2Params và Pkcs5S2ParametersGenerator.

Không ai trong số này có vẻ như đang chấp nhận chuỗi hoặc char [].

Có ai đã làm điều này trong C# hoặc có bất kỳ đầu mối nào về điều này không? Hoặc có lẽ một người đã thực hiện BouncyCastle trong Java và có thể giúp đỡ?

Thanx rất nhiều trước :)

UPDATE: Tôi đã tìm thấy làm thế nào để làm điều này trong Bouncy Castle. Nhìn bên dưới để có câu trả lời :)

Trả lời

13

Sau giờ và giờ đi qua mã, tôi thấy rằng cách dễ nhất để thực hiện việc này là lấy một vài phần của mã trong Pkcs5S2ParametersGenerator.cs và tạo lớp của riêng tôi sử dụng các API BouncyCastle khác. Điều này hoạt động hoàn hảo với Dot Net Compact Framework (Windows Mobile). Đây là tương đương với lớp Rfc2898DeriveBytes mà không có trong Dot Net Compact Framework 2.0/3.5. Vâng, có lẽ không phải là chính xác tương đương nhưng không được công việc :)

Đây là PKCS5/PKCS # 5

PRF (Pseudo Random Function) được sử dụng sẽ là HMAC-SHA1

thứ Thứ nhất, Đầu tiên. Tải xuống cụm từ Bouncy Castle được biên dịch từ http://www.bouncycastle.org/csharp/, thêm BouncyCastle.Crypto.dll làm tham chiếu đến dự án của bạn.

Sau đó tạo tệp lớp mới với mã bên dưới.

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; 
     } 


    } 
} 

Vậy làm thế nào để sử dụng chức năng này? Đơn giản! :) Đây là một ví dụ rất đơn giản, nơi mật khẩu và muối được cung cấp bởi người dùng.

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; 

     } 

Cách kiểm tra xem điều này có đúng không? Có một tuyến javascript thực hiện PBKDF2 http://anandam.name/pbkdf2/

tôi nhận kết quả phù hợp :) Đề nghị thông báo nếu có ai là nhận được một kết quả không chính xác :)

Hy vọng điều này sẽ giúp người :)

UPDATE: Xác nhận làm việc với các vectơ thử nghiệm được cung cấp tại đây

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

UPDAT E: Hoặc, đối với muối, chúng tôi có thể sử dụng RNGCryptoServiceProvider. Đảm bảo tham chiếu không gian tên System.Security.Cryptography.

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();   

byte[] salt = new byte[16]; 

rng.GetBytes(salt); 
+1

Bạn trả lời câu hỏi của riêng mình khá nhanh! –

+1

Bạn vừa mới tiết kiệm cho tôi rất nhiều thời gian. Cảm ơn bạn! – John

+0

@John: Rất vui được trợ giúp :) –

1

Tôi chỉ gặp vấn đề này và tìm ra cách tiếp cận trực tiếp hơn. Tính đến ít nhất Bouncy Castle 1,7 bạn có thể làm điều đó như thế này (trong VB sử dụng Org.BouncyCastle.Crypto):

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() 

Tôi đã thử nghiệm này để chống lại System.Security.Cryptography Net, và nó hoạt động!

Các vấn đề liên quan