充气城堡 C# 中的 PBKDF2

时间:2023-03-28
本文介绍了充气城堡 C# 中的 PBKDF2的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我一直在搞乱 C# Bouncy Castle API 以寻找如何进行 PBKDF2 密钥派生.

I've being messing around the C# Bouncy Castle API to find how to do a PBKDF2 key derivation.

我现在真的一无所知.

我尝试阅读 Pkcs5S2ParametersGenerator.cs 和 PBKDF2Params.cs 文件,但我真的不知道该怎么做.

I tried reading through the Pkcs5S2ParametersGenerator.cs and PBKDF2Params.cs files but i really cant figure out how to do it.

根据我目前所做的研究,PBKDF2 需要一个字符串(或 char[]),即密码、盐和迭代次数.

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.

到目前为止,我最有希望和最明显的是 PBKDF2Params 和 Pkcs5S2ParametersGenerator.

So far the most promising and most obvious i've come so far is the PBKDF2Params and Pkcs5S2ParametersGenerator.

这些似乎都不接受字符串或 char[].

None of these seems to be accepting a string or a char[].

有没有人在 C# 中做过这个或对此有任何线索?或者也许有人用 Java 实现了 BouncyCastle 并且可以提供帮助?

Has anyone done this in C# or have any clue about this? Or perhaps someone who has implemented BouncyCastle in Java and can help?

提前感谢很多:)

更新:我在 Bouncy Castle 中找到了如何做到这一点.看看下面的答案:)

UPDATE: I have found how to do this in Bouncy Castle. Look below for answer :)

推荐答案

经过几个小时的代码检查,我发现最简单的方法是在 Pkcs5S2ParametersGenerator.cs 和创建我自己的课程,当然使用其他 BouncyCastle API.这与 Dot Net Compact Framework (Windows Mobile) 完美配合.这相当于点网紧凑框架 2.0/3.5 中不存在的 Rfc2898DeriveBytes 类.好吧,也许不是确切的等价物,但可以完成工作:)

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

这是 PKCS5/PKCS#5

This is PKCS5/PKCS#5

使用的 PRF(伪随机函数)将是 HMAC-SHA1

The PRF (Pseudo Random Function) which is used will be HMAC-SHA1

第一件事,第一.从 http://www.bouncycastle.org/csharp/ 下载 Bouncy Castle 编译程序集,添加BouncyCastle.Crypto.dll 作为对您项目的引用.

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;

        }

如何检查这是否正确?有一个 PBKDF2 的在线 javascript 实现http://anandam.name/pbkdf2/

How to check whether this is correct? There is an online javascript implementation of PBKDF2 http://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

https://datatracker.ietf.org/doc/html/draft-josefsson-pbkdf2-test-vectors-00

更新:或者,对于盐,我们可以使用 RNGCryptoServiceProvider.确保引用 System.Security.Cryptography 命名空间.

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

这篇关于充气城堡 C# 中的 PBKDF2的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:使用 RSACryptoServiceProvider 进行公钥加密 下一篇:使用 Base64 编码的公钥验证 RSA 签名

相关文章