将.Net 4.5.1中的KeyDerivation.Pbkdf2转换为.Net 4.0 [英] Convert KeyDerivation.Pbkdf2 in .Net 4.5.1 to .Net 4.0

查看:56
本文介绍了将.Net 4.5.1中的KeyDerivation.Pbkdf2转换为.Net 4.0的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个使用.net 4.0和.net 4.6.1的项目,KeyDerivation仅在.net 4.5.1之后可用.如何使用其他哈希库(例如Rfc2898DeriveBytes/Crypto)在.Net 4.0中获得相同的哈希结果

I have two project which using .net 4.0 and .net 4.6.1, the KeyDerivation only available after .net 4.5.1. How can I get the same hash result in .Net 4.0 using other hash library such as Rfc2898DeriveBytes/ Crypto

byte[] salt = new byte[128 / 8];
var hashedPassword = Convert.ToBase64String(KeyDerivation.Pbkdf2(
    password: "GN(o@D30",
    salt: salt,
    prf: KeyDerivationPrf.HMACSHA512,
    iterationCount: 100000,
    numBytesRequested: 256 / 8)
);

推荐答案

Rfc2898DeriveBytes 的问题是它仅支持 HMACSHA1 (出于未知原因).在您的情况下,您想使用 HMACSHA512 .您可以在此处中使用描述的实现,请注意,这不是一些自定义的实现-作者只是获取了 Rfc2898DeriveBytes 标准内置类的源代码,并将其调整为使用通过构造函数参数提供的hmac实现(并丢弃了不相关的部分).为了清楚起见,我将在此处提供完整的源代码:

Problem with Rfc2898DeriveBytes is that it only supports HMACSHA1 (for unknown reasons). In your case you want to use HMACSHA512. You can use implementation described here, note that it's not some custom implementation - author just took source code of Rfc2898DeriveBytes standard built-in class and adjusted it to use hmac implementation you provide via constructor argument (and thrown away irrelevant parts). I'll provide full source code here for clarity:

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Pbkdf", Justification = "Spelling is correct.")]
public class Pbkdf2
{

    /// <summary>
    /// Creates new instance.
    /// </summary>
    /// <param name="algorithm">HMAC algorithm to use.</param>
    /// <param name="password">The password used to derive the key.</param>
    /// <param name="salt">The key salt used to derive the key.</param>
    /// <param name="iterations">The number of iterations for the operation.</param>
    /// <exception cref="System.ArgumentNullException">Algorithm cannot be null - Password cannot be null. -or- Salt cannot be null.</exception>
    public Pbkdf2(HMAC algorithm, Byte[] password, Byte[] salt, Int32 iterations)
    {
        if (algorithm == null) { throw new ArgumentNullException("algorithm", "Algorithm cannot be null."); }
        if (salt == null) { throw new ArgumentNullException("salt", "Salt cannot be null."); }
        if (password == null) { throw new ArgumentNullException("password", "Password cannot be null."); }
        this.Algorithm = algorithm;
        this.Algorithm.Key = password;
        this.Salt = salt;
        this.IterationCount = iterations;
        this.BlockSize = this.Algorithm.HashSize / 8;
        this.BufferBytes = new byte[this.BlockSize];
    }

    /// <summary>
    /// Creates new instance.
    /// </summary>
    /// <param name="algorithm">HMAC algorithm to use.</param>
    /// <param name="password">The password used to derive the key.</param>
    /// <param name="salt">The key salt used to derive the key.</param>
    /// <exception cref="System.ArgumentNullException">Algorithm cannot be null - Password cannot be null. -or- Salt cannot be null.</exception>
    public Pbkdf2(HMAC algorithm, Byte[] password, Byte[] salt)
        : this(algorithm, password, salt, 1000)
    {
    }

    /// <summary>
    /// Creates new instance.
    /// </summary>
    /// <param name="algorithm">HMAC algorithm to use.</param>
    /// <param name="password">The password used to derive the key.</param>
    /// <param name="salt">The key salt used to derive the key.</param>
    /// <param name="iterations">The number of iterations for the operation.</param>
    /// <exception cref="System.ArgumentNullException">Algorithm cannot be null - Password cannot be null. -or- Salt cannot be null.</exception>
    public Pbkdf2(HMAC algorithm, String password, String salt, Int32 iterations) :
        this(algorithm, UTF8Encoding.UTF8.GetBytes(password), UTF8Encoding.UTF8.GetBytes(salt), iterations)
    {
    }

    /// <summary>
    /// Creates new instance.
    /// </summary>
    /// <param name="algorithm">HMAC algorithm to use.</param>
    /// <param name="password">The password used to derive the key.</param>
    /// <param name="salt">The key salt used to derive the key.</param>
    /// <exception cref="System.ArgumentNullException">Algorithm cannot be null - Password cannot be null. -or- Salt cannot be null.</exception>
    public Pbkdf2(HMAC algorithm, String password, String salt) :
        this(algorithm, password, salt, 1000)
    {
    }


    private readonly int BlockSize;
    private uint BlockIndex = 1;

    private byte[] BufferBytes;
    private int BufferStartIndex = 0;
    private int BufferEndIndex = 0;


    /// <summary>
    /// Gets algorithm used for generating key.
    /// </summary>
    public HMAC Algorithm { get; private set; }

    /// <summary>
    /// Gets salt bytes.
    /// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Byte array is proper return value in this case.")]
    public Byte[] Salt { get; private set; }

    /// <summary>
    /// Gets iteration count.
    /// </summary>
    public Int32 IterationCount { get; private set; }


    /// <summary>
    /// Returns a pseudo-random key from a password, salt and iteration count.
    /// </summary>
    /// <param name="count">Number of bytes to return.</param>
    /// <returns>Byte array.</returns>
    public Byte[] GetBytes(int count)
    {
        byte[] result = new byte[count];
        int resultOffset = 0;
        int bufferCount = this.BufferEndIndex - this.BufferStartIndex;

        if (bufferCount > 0)
        { //if there is some data in buffer
            if (count < bufferCount)
            { //if there is enough data in buffer
                Buffer.BlockCopy(this.BufferBytes, this.BufferStartIndex, result, 0, count);
                this.BufferStartIndex += count;
                return result;
            }
            Buffer.BlockCopy(this.BufferBytes, this.BufferStartIndex, result, 0, bufferCount);
            this.BufferStartIndex = this.BufferEndIndex = 0;
            resultOffset += bufferCount;
        }

        while (resultOffset < count)
        {
            int needCount = count - resultOffset;
            this.BufferBytes = this.Func();
            if (needCount > this.BlockSize)
            { //we one (or more) additional passes
                Buffer.BlockCopy(this.BufferBytes, 0, result, resultOffset, this.BlockSize);
                resultOffset += this.BlockSize;
            }
            else
            {
                Buffer.BlockCopy(this.BufferBytes, 0, result, resultOffset, needCount);
                this.BufferStartIndex = needCount;
                this.BufferEndIndex = this.BlockSize;
                return result;
            }
        }
        return result;
    }


    private byte[] Func()
    {
        var hash1Input = new byte[this.Salt.Length + 4];
        Buffer.BlockCopy(this.Salt, 0, hash1Input, 0, this.Salt.Length);
        Buffer.BlockCopy(GetBytesFromInt(this.BlockIndex), 0, hash1Input, this.Salt.Length, 4);
        var hash1 = this.Algorithm.ComputeHash(hash1Input);

        byte[] finalHash = hash1;
        for (int i = 2; i <= this.IterationCount; i++)
        {
            hash1 = this.Algorithm.ComputeHash(hash1, 0, hash1.Length);
            for (int j = 0; j < this.BlockSize; j++)
            {
                finalHash[j] = (byte)(finalHash[j] ^ hash1[j]);
            }
        }
        if (this.BlockIndex == uint.MaxValue) { throw new InvalidOperationException("Derived key too long."); }
        this.BlockIndex += 1;

        return finalHash;
    }

    private static byte[] GetBytesFromInt(uint i)
    {
        var bytes = BitConverter.GetBytes(i);
        if (BitConverter.IsLittleEndian)
        {
            return new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] };
        }
        else
        {
            return bytes;
        }
    }

}

现在,与该类类似的代码在您的问题中将是:

Now with that class complete analog of code in your question would be:

byte[] salt = new byte[128 / 8];
string hashedPassword;
using (var hmac = new HMACSHA512()) {
     hashedPassword = Convert.ToBase64String(new Pbkdf2(
         hmac, "GN(o@D30", Encoding.UTF8.GetString(salt), 100000).GetBytes(256 / 8));                
}

这篇关于将.Net 4.5.1中的KeyDerivation.Pbkdf2转换为.Net 4.0的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆