Rfc2898/PBKDF2与SHA256作为c#中的摘要

Car*_*ten 15 c# cryptography

我想在c#中使用Rfc2898来获取密钥.我还需要使用SHA256作为Rfc2898的摘要.我找到了这个类Rfc2898DeriveBytes,但是它使用了SHA-1,我没有看到让它使用不同的摘要的方法.

有没有办法在带有SHA256的c#中使用Rfc2898作为摘要(从头开始实现它)?

Pet*_* O. 15

请参阅Bruno Garcia的回答.

卡斯滕:请接受这个答案而不是这个答案.

当我开始这个答案时,Rfc2898DeriveBytes无法配置为使用不同的哈希函数.与此同时,它已得到改善; 看布鲁诺加西亚的回答.

对于较旧的.NET框架的用户,这仍然有用:

// NOTE: The iteration count should
// be as high as possible without causing
// unreasonable delay.  Note also that the password
// and salt are byte arrays, not strings.  After use,
// the password and salt should be cleared (with Array.Clear)

public static byte[] PBKDF2Sha256GetBytes(int dklen, byte[] password, byte[] salt, int iterationCount){
    using(var hmac=new System.Security.Cryptography.HMACSHA256(password)){
        int hashLength=hmac.HashSize/8;
        if((hmac.HashSize&7)!=0)
            hashLength++;
        int keyLength=dklen/hashLength;
        if((long)dklen>(0xFFFFFFFFL*hashLength) || dklen<0)
            throw new ArgumentOutOfRangeException("dklen");
        if(dklen%hashLength!=0)
            keyLength++;
        byte[] extendedkey=new byte[salt.Length+4];
        Buffer.BlockCopy(salt,0,extendedkey,0,salt.Length);
        using(var ms=new System.IO.MemoryStream()){
            for(int i=0;i<keyLength;i++){
                extendedkey[salt.Length]=(byte)(((i+1)>>24)&0xFF);
                extendedkey[salt.Length+1]=(byte)(((i+1)>>16)&0xFF);
                extendedkey[salt.Length+2]=(byte)(((i+1)>>8)&0xFF);
                extendedkey[salt.Length+3]=(byte)(((i+1))&0xFF);
                byte[] u=hmac.ComputeHash(extendedkey);
                Array.Clear(extendedkey,salt.Length,4);
                byte[] f=u;
                for(int j=1;j<iterationCount;j++){
                    u=hmac.ComputeHash(u);
                    for(int k=0;k<f.Length;k++){
                        f[k]^=u[k];
                    }
                }
                ms.Write(f,0,f.Length);
                Array.Clear(u,0,u.Length);
                Array.Clear(f,0,f.Length);
            }
            byte[] dk=new byte[dklen];
            ms.Position=0;
            ms.Read(dk,0,dklen);
            ms.Position=0;
            for(long i=0;i<ms.Length;i++){
                ms.WriteByte(0);
            }
            Array.Clear(extendedkey,0,extendedkey.Length);
            return dk;
        }
    }
Run Code Online (Sandbox Code Playgroud)


Bru*_*cia 12

.NET Core有一个新的实现Rfc2898DeriveBytes.

CoreFX版本不再有散列算法硬编码

该代码可在Github上获得.它于2017年3月合并为master,并随.NET Core 2.0一起提供.

  • 这是目前最好的答案.如果微软已经发布了更新的库,原则上它将比任何其他实现更好,仅仅是因为它的微软QA签收.Matthew的回答和Peter O.的回答可能是很好的代码,但从我所看到的,随后的评论已经发现了实现中的潜在错误.这支持了不滚动自己的一般原则...... (3认同)

Tie*_* T. 8

对于那些需要它的人,.NET Framework 4.7.2包含Rfc2898DeriveBytes重载,允许指定散列算法:

byte[] bytes;
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt, iterations, HashAlgorithmName.SHA256))
{
    bytes = deriveBytes.GetBytes(PBKDF2SubkeyLength);
}
Run Code Online (Sandbox Code Playgroud)

目前的HashAlgorithmName选项是:

  • MD5
  • SHA1
  • SHA256
  • SHA3​​84
  • SHA512

  • .NET Core 2.1 也支持这一点。 (2认同)
  • 我应该为 PBKDF2SubkeyLength 使用什么值? (2认同)

Eam*_*nne 6

BCLRfc2898DeriveBytes被硬编码为使用 sha-1。

KeyDerivation.Pbkdf2允许完全相同的输出,但它也允许 HMAC SHA-256 和 HMAC SHA-512。它也更快;在我的机器上大约 5 倍 - 这对安全有好处,因为它允许更多的回合,这使得饼干的生活变得更加艰难(顺便说一句,sha-512 对 gpu 的友好程度远低于 sha-256 或 sha1)。并且 api 更简单,启动:

byte[] salt = ...
string password = ...
var rounds = 50000;                       // pick something bearable
var num_bytes_requested = 16;             // 128 bits is fine
var prf = KeyDerivationPrf.HMACSHA512;    // or sha256, or sha1
byte[] hashed = KeyDerivation.Pbkdf2(password, salt, prf, rounds, num_bytes_requested);
Run Code Online (Sandbox Code Playgroud)

这是从NuGet包Microsoft.AspNetCore.Cryptography.KeyDerivation这也不能依赖于asp.net核心; 它在 .net 4.5.1 或 .net standard 1.3 或更高版本上运行。