2010-07-09 10 views
13

Ich habe die C# Bouncy Castle API durcheinandergebracht, um herauszufinden, wie man eine PBKDF2-Schlüsselableitung durchführt.PBKDF2 in Hüpfburg C#

Ich bin im Moment wirklich ahnungslos.

Ich habe versucht, durch die Dateien Pkcs5S2ParametersGenerator.cs und PBKDF2Params.cs lesen, aber ich kann wirklich nicht herausfinden, wie es geht.

Nach den Forschungen, die ich bisher gemacht habe, benötigt PBKDF2 eine Zeichenfolge (oder char []), die das Passwort, eine Salz- und eine Iterationszählung ist.

Bisher ist der PBKDF2Params und der Pkcs5S2ParametersGenerator das vielversprechendste und offensichtlichste, was ich bisher erreicht habe.

Keiner von diesen scheint einen String oder ein char [] zu akzeptieren.

Hat jemand dies in C# getan oder irgendwelche Anhaltspunkte dafür? Oder vielleicht jemand, der BouncyCastle in Java implementiert hat und helfen kann?

Thanx viel im Voraus :)

UPDATE: Ich habe festgestellt, wie dies in Hüpfburg zu tun. Suchen Sie unten nach Antworten :)

Antwort

13

Nach stundenlangem Durcharbeiten des Codes habe ich herausgefunden, dass der einfachste Weg, dies zu tun, darin besteht, ein paar Teile des Codes in Pkcs5S2ParametersGenerator.cs zu nehmen und meine eigene Klasse zu erstellen Verwenden Sie andere BouncyCastle-APIs. Dies funktioniert perfekt mit dem Dot Net Compact Framework (Windows Mobile). Dies entspricht der Klasse Rfc2898DeriveBytes, die im Dot Net Compact Framework 2.0/3.5 nicht vorhanden ist. Na ja, vielleicht nicht die genaue Äquivalent aber macht den Job :)

Dies ist PKCS5/PKCS # 5

Die PRF (Pseudo Random Function), die verwendet wird, wird HMAC-SHA1

Erste Sachen, zuerst. Laden Sie die kompilierte Assembly der Hüpfburg von http://www.bouncycastle.org/csharp/ herunter und fügen Sie die BouncyCastle.Crypto.dll als Referenz zu Ihrem Projekt hinzu.

Danach erstellen Sie eine neue Klassendatei mit dem folgenden Code.

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


    } 
} 

So, wie man diese Funktion benutzt? Einfach! :) Dies ist ein sehr einfaches Beispiel, in dem das Passwort und das Salz vom Benutzer bereitgestellt werden.

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; 

     } 

Wie überprüft man, ob das korrekt ist? Es ist ein Online-JavaScript-Implementierung von PBKDF2 http://anandam.name/pbkdf2/

ich konsistente Ergebnisse bekam :) Bitte melden, wenn jemand ein falsches Ergebnis bekommen :)

Hope this jemand hilft :)

UPDATE: Bestätigt mit Testvektoren arbeiten hier bereitgestellten

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

UPDAT E: Alternativ können wir für das Salz eine RNGCryptoServiceProvider verwenden. Stellen Sie sicher, dass Sie auf den Namensbereich System.Security.Cryptography verweisen.

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();   

byte[] salt = new byte[16]; 

rng.GetBytes(salt); 
+1

Sie beantworten Ihre eigenen Fragen ziemlich schnell! –

+1

Sie haben mir gerade viel Zeit gespart. Vielen Dank! – John

+0

@John: Freut mich, irgendeine Hilfe zu sein :) –

1

Ich hatte gerade dieses Problem selbst und fand einen direkteren Ansatz. Wie von mindestens 1,7 Hüpfburg Sie können es tun, wie folgt (in VB 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() 

ich dies gegen .Net System.Security.Cryptography getestet, und es funktioniert!