问题描述
我现在真的很无知。
我已经搞乱了C#Bouncy Castle API,找到如何做一个PBKDF2密钥派生。我试过阅读Pkcs5S2ParametersGenerator.cs和PBKDF2Params.cs文件,但我真的不知道该怎么做。
根据我到目前为止的研究,PBKDF2需要一个字符串(或char []),它是密码,盐和迭代计数。
到目前为止最有前途的和最明显的,我到目前为止是PBKDF2Params和Pkcs5S2ParametersGenerator。
这些似乎都不接受字符串或char []。
有没有人在C#中做这个或有任何线索?
Thanx提前很多:)
更新:我已经找到如何在Bouncy城堡这样做。看下面的答案:)
经过几个小时和几个小时的代码,我发现最简单的方法是采取Pkcs5S2ParametersGenerator.cs中的一些部分代码,并创建我自己的类,当然使用其他BouncyCastle API的。这与Dot Net Compact Framework(Windows Mobile)完美配合。这相当于在Dot Net Compact Framework 2.0 / 3.5中不存在的Rfc2898DeriveBytes类。那么,也许不是EXACT的等效,但是工作:)
这是PKCS5 / PKCS#5
使用的PRF(伪随机函数)将是HMAC-SHA1
首先,从下载Bouncy Castle编译的程序集,添加 BouncyCastle.Crypto.dll
作为对您的项目的引用。
之后,使用以下代码创建新类文件。
使用系统;
使用Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
使用Org.BouncyCastle.Crypto.Digests;
使用Org.BouncyCastle.Crypto.Macs;
使用Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
命名空间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;
}
//使用此函数检索派生密钥。
// dkLen是以八位字节为单位的,当函数返回时需要多少字节。
// mPassword是转换为字节的密码。
// mSalt是盐转换为字节
// mIterationCount是要执行的迭代次数。
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 {
IntToOctet(iBuf,i);
F(mPassword,mSalt,mIterationCount,iBuf,outBytes,(i - 1)* hLen);
}
//此时outBytes将包含衍生密钥+更多字节。
//根据PKCS#5 v2.0:基于密码的加密标准(www.truecrypt.org/docs/pkcs5v2-0.pdf)
//我们必须提取第一个dkLen八位字节以产生导出密钥。
//我创建一个大小为dkLen的字节数组,然后使用
//Buffer.BlockCopy仅复制dkLen的字节数
//最后返回它:D
byte [] output = new byte [dkLen];
Buffer.BlockCopy(outBytes,0,output,0,dkLen);
返回输出;
}
}
} b $ b
那么如何使用这个函数呢?简单! :)
这是一个非常简单的例子,其中密码和salt由用户提供。
private void cmdDeriveKey_Click(object sender,EventArgs e)
{
byte [] salt = ASCIIEncoding.UTF8.GetBytes(txtSalt.Text);
PBKDF2 passwordDerive = new PBKDF2();
//我想要的密钥用于AES-128,因此我想要导出的密钥是
// 128位。因此,我将使用128/8 = 16 dkLen(派生密钥长度)。
//类似地,如果你想要一个256位的密钥,dkLen将是256/8 = 32.
byte [] result = passwordDerive.GenerateDerivedKey(16,ASCIIEncoding.UTF8.GetBytes(txtPassword .text),salt,1000);
//结果现在将包含派生密钥。现在使用它为任何加密目的:)
//以下代码只是在文本框中显示导出的键。
string x =;
for(int i = 0; i {
x + = result [i] .ToString(X);
}
txtResult.Text = x;
}
如何检查这是否正确?
有一个在线javascript实现的PBKDF2
我得到一致的结果:)
请报告如果有人得到不正确的结果:)
希望这有助于某人:)
更新:确认使用此处提供的测试向量
a href =http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-00 =nofollow noreferrer> http://tools.ietf.org/html/draft-josefsson -pbkdf2-test-vectors-00
UPDATE:
或者,对于salt,我们可以使用 RNGCryptoServiceProvider
。请确保引用 System.Security.Cryptography
命名空间。
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte [] salt = new byte [16];
rng.GetBytes(salt);
I've being messing around the C# Bouncy Castle API to find how to do a PBKDF2 key derivation.
I am really clueless right now.
I tried reading through the Pkcs5S2ParametersGenerator.cs and PBKDF2Params.cs files but i really cant figure out how to do it.
According to the research I have done so far, PBKDF2 requires a string (or char[]) which is the password, a salt and an iteration count.
So far the most promising and most obvious i've come so far is the PBKDF2Params and Pkcs5S2ParametersGenerator.
None of these seems to be accepting a string or a char[].
Has anyone done this in C# or have any clue about this? Or perhaps someone who has implemented BouncyCastle in Java and can help?
Thanx a lot in advance :)
UPDATE: I have found how to do this in Bouncy Castle. Look below for answer :)
After hours and hours of going through the code, I found that the easiest way to do this is to take a few parts of the code in Pkcs5S2ParametersGenerator.cs and create my own class which of course use other BouncyCastle API's. This works perfectly with the Dot Net Compact Framework (Windows Mobile). This is the equivalent of Rfc2898DeriveBytes class which is not present in the Dot Net Compact Framework 2.0/3.5. Well, maybe not the EXACT equivalent but does the job :)
This is PKCS5/PKCS#5
The PRF (Pseudo Random Function) which is used will be HMAC-SHA1
First things, first. Download the Bouncy Castle compiled assembly from http://www.bouncycastle.org/csharp/, add the BouncyCastle.Crypto.dll
as a reference to your project.
After that create new class file with the code below.
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 how to use this function? Simple! :)This is a very simple example where the password and the salt is provided by the user.
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;
}
How to check whether this is correct?There is an online javascript implementation of PBKDF2http://anandam.name/pbkdf2/
I got consistent results :)Please report if anyone is getting an incorrect result :)
Hope this helps someone :)
UPDATE: Confirmed working with test vectors provided here
http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-00
UPDATE:Alternatively, for the salt we can use a RNGCryptoServiceProvider
. Make sure to reference the System.Security.Cryptography
namespace.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] salt = new byte[16];
rng.GetBytes(salt);
这篇关于PBKDF2在Bouncy城堡C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!