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);
Bạn trả lời câu hỏi của riêng mình khá nhanh! –
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
@John: Rất vui được trợ giúp :) –