gpt4 book ai didi

c# - .Net Framework 4.5 中具有 128 位 key 长度和 1,024 次 SHA256 迭代的 PBKDF2 函数

转载 作者:太空宇宙 更新时间:2023-11-03 22:39:16 26 4
gpt4 key购买 nike

我正在尝试使用 .Net framework 4.5 中的 api,它应该为我提供加密货币钱包。在它的一部分 documentations它说:

Pass Pin Code through the PBKDF2 function with 128 Bit Key Length and 1,024 iterations of SHA256

我找不到 C# 中的 Specify 方法来执行此操作。在文档中,他们输入了“be9d3a4f1220495a96c38d36d8558365”作为 pin 码,输出为“4369cb0560d54f55d0c03564fbd983c4”。看来我应该使用 Rfc2898DeriveBytes 方法,我像下面的代码一样使用它,但没有得到相同的结果。

string output = Convert.ToBase64String((new Rfc2898DeriveBytes("e24546d6643137a310968566cf1cd42b",16, 1024)).GetBytes(32));

输出 ==> 'x10zclBJY2eeZqjMyPfQm4ljyMFPvWbxF72Om2DCzHE='

最佳答案

最好实现您自己的 PBKDF2 版本。 PBKDF2 是由错误命名的 Rfc2898DeriveBytes 类实现的实际算法。

因为 .NET 4.5 不包含使用具有不同哈希的 PBKDF2 的功能。 .NET 版本 4.7.2 确实包含该功能,但它不允许 salt 为零字节。

因此最好实现自己的版本。 Microsoft 的 .NET 版本具有似乎不兼容的特定版权声明。解决这个问题的一种方法是从 Mono 实现 PBKDF2,但是 Mono 的更高版本没有实现这个类(看起来)并且它们没有实现可以选择散列的版本。

幸运的是bartonjs has indicated a version具有许可的 MIT 许可,可以使用,导致以下解决方案:

using System;
using System.Security.Cryptography;
using System.Text;

namespace StackOverflow
{
public class Rfc2898DeriveBytes : DeriveBytes
{
private const string DEFAULT_HASH_ALGORITHM = "SHA-1";

private const int MinimumSaltSize = 0;
private readonly byte[] _password;
private byte[] _salt;
private uint _iterations;
private HMAC _hmac;
private int _blockSize;

private byte[] _buffer;
private uint _block;
private int _startIndex;
private int _endIndex;

public string HashAlgorithm { get; }

public Rfc2898DeriveBytes(byte[] password, byte[] salt, int iterations)
: this(password, salt, iterations, DEFAULT_HASH_ALGORITHM)
{
}

public Rfc2898DeriveBytes(byte[] password, byte[] salt, int iterations, string hashAlgorithm)
{
if (salt == null)
throw new ArgumentNullException(nameof(salt));
if (salt.Length < MinimumSaltSize)
throw new ArgumentException(nameof(salt));
if (iterations <= 0)
throw new ArgumentOutOfRangeException(nameof(iterations));
if (password == null)
throw new NullReferenceException(); // This "should" be ArgumentNullException but for compat, we throw NullReferenceException.

_salt = (byte[])salt.Clone();
_iterations = (uint)iterations;
_password = (byte[])password.Clone();
HashAlgorithm = hashAlgorithm;
_hmac = OpenHmac();
// _blockSize is in bytes, HashSize is in bits.
_blockSize = _hmac.HashSize >> 3;

Initialize();
}

public Rfc2898DeriveBytes(string password, byte[] salt)
: this(password, salt, 1000)
{
}

public Rfc2898DeriveBytes(string password, byte[] salt, int iterations)
: this(password, salt, iterations, DEFAULT_HASH_ALGORITHM)
{
}

public Rfc2898DeriveBytes(string password, byte[] salt, int iterations, string hashAlgorithm)
: this(Encoding.UTF8.GetBytes(password), salt, iterations, hashAlgorithm)
{
}

public Rfc2898DeriveBytes(string password, int saltSize)
: this(password, saltSize, 1000)
{
}

public Rfc2898DeriveBytes(string password, int saltSize, int iterations)
: this(password, saltSize, iterations, DEFAULT_HASH_ALGORITHM)
{
}

public Rfc2898DeriveBytes(string password, int saltSize, int iterations, string hashAlgorithm)
{
if (saltSize < 0)
throw new ArgumentOutOfRangeException(nameof(saltSize));
if (saltSize < MinimumSaltSize)
throw new ArgumentException(nameof(saltSize));
if (iterations <= 0)
throw new ArgumentOutOfRangeException(nameof(iterations));

_salt = new byte[saltSize];
RandomNumberGenerator.Create().GetBytes(_salt);
_iterations = (uint)iterations;
_password = Encoding.UTF8.GetBytes(password);
HashAlgorithm = hashAlgorithm;
_hmac = OpenHmac();
// _blockSize is in bytes, HashSize is in bits.
_blockSize = _hmac.HashSize >> 3;

Initialize();
}

public int IterationCount
{
get
{
return (int)_iterations;
}

set
{
if (value <= 0)
throw new ArgumentOutOfRangeException(nameof(value));
_iterations = (uint)value;
Initialize();
}
}

public byte[] Salt
{
get
{
return (byte[])_salt.Clone();
}

set
{
if (value == null)
throw new ArgumentNullException(nameof(value));
if (value.Length < MinimumSaltSize)
throw new ArgumentException("Too few bytes for salt");
_salt = (byte[])value.Clone();
Initialize();
}
}

protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_hmac != null)
{
_hmac.Dispose();
_hmac = null;
}

if (_buffer != null)
Array.Clear(_buffer, 0, _buffer.Length);
if (_password != null)
Array.Clear(_password, 0, _password.Length);
if (_salt != null)
Array.Clear(_salt, 0, _salt.Length);
}
base.Dispose(disposing);
}

public override byte[] GetBytes(int cb)
{
if (cb <= 0)
throw new ArgumentOutOfRangeException(nameof(cb));
byte[] password = new byte[cb];

int offset = 0;
int size = _endIndex - _startIndex;
if (size > 0)
{
if (cb >= size)
{
Buffer.BlockCopy(_buffer, _startIndex, password, 0, size);
_startIndex = _endIndex = 0;
offset += size;
}
else
{
Buffer.BlockCopy(_buffer, _startIndex, password, 0, cb);
_startIndex += cb;
return password;
}
}

while (offset < cb)
{
byte[] T_block = Func();
int remainder = cb - offset;
if (remainder > _blockSize)
{
Buffer.BlockCopy(T_block, 0, password, offset, _blockSize);
offset += _blockSize;
}
else
{
Buffer.BlockCopy(T_block, 0, password, offset, remainder);
offset += remainder;
Buffer.BlockCopy(T_block, remainder, _buffer, _startIndex, _blockSize - remainder);
_endIndex += (_blockSize - remainder);
return password;
}
}
return password;
}

public byte[] CryptDeriveKey(string algname, string alghashname, int keySize, byte[] rgbIV)
{
// If this were to be implemented here, CAPI would need to be used (not CNG) because of
// unfortunate differences between the two. Using CNG would break compatibility. Since this
// assembly currently doesn't use CAPI it would require non-trivial additions.
// In addition, if implemented here, only Windows would be supported as it is intended as
// a thin wrapper over the corresponding native API.
// Note that this method is implemented in PasswordDeriveBytes (in the Csp assembly) using CAPI.
throw new PlatformNotSupportedException();
}

public override void Reset()
{
Initialize();
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "HMACSHA1 is needed for compat. (https://github.com/dotnet/corefx/issues/9438)")]
private HMAC OpenHmac()
{
String hashAlgorithm = HashAlgorithm;

if (string.IsNullOrEmpty(hashAlgorithm))
throw new CryptographicException("HashAlgorithm name not present");

if (hashAlgorithm.Equals("SHA-1", StringComparison.OrdinalIgnoreCase))
return new HMACSHA1(_password);
if (hashAlgorithm.Equals("SHA-256", StringComparison.OrdinalIgnoreCase))
return new HMACSHA256(_password);
if (hashAlgorithm.Equals("SHA-384", StringComparison.OrdinalIgnoreCase))
return new HMACSHA384(_password);
if (hashAlgorithm.Equals("SHA-512", StringComparison.OrdinalIgnoreCase))
return new HMACSHA512(_password);

throw new CryptographicException("MAC algorithm " + hashAlgorithm + " not available");
}

private void Initialize()
{
if (_buffer != null)
Array.Clear(_buffer, 0, _buffer.Length);
_buffer = new byte[_blockSize];
_block = 1;
_startIndex = _endIndex = 0;
}

// This function is defined as follows:
// Func (S, i) = HMAC(S || i) | HMAC2(S || i) | ... | HMAC(iterations) (S || i)
// where i is the block number.
private byte[] Func()
{
byte[] temp = new byte[_salt.Length + sizeof(uint)];
Buffer.BlockCopy(_salt, 0, temp, 0, _salt.Length);



WriteInt(_block, temp, _salt.Length);

temp = _hmac.ComputeHash(temp);

byte[] ret = temp;
for (int i = 2; i <= _iterations; i++)
{
temp = _hmac.ComputeHash(temp);

for (int j = 0; j < _blockSize; j++)
{
ret[j] ^= temp[j];
}
}

// increment the block count.
_block++;
return ret;
}

private void WriteInt(uint i, byte[] buf, int bufOff)
{
buf[bufOff++] = (byte)(i >> 24);
buf[bufOff++] = (byte)(i >> 16);
buf[bufOff++] = (byte)(i >> 8);
buf[bufOff] = (byte)i;
}
}
}

这是一个类,其中更具体的异常已被重写,一些专门的克隆被替换,随机盐生成被推广。最小盐大小也已设置为 0。否则它是不同 namespace 中的相同代码。

可以这样使用:

string pw = "be9d3a4f1220495a96c38d36d8558365";
byte[] salt = new byte[0];
int iterations = 1024;

Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(pw, salt, iterations, "SHA-256");
byte[] key = pbkdf2.GetBytes(16);

请注意,PIN 是十六进制编码为 UTF-8,这是 PBKDF2 的默认编码(不是 .NET 的默认编码!)。结果是一个 key ,当以十六进制表示时等于 4369cb0560d54f55d0c03564fbd983c4

我已经使用字符串转换为 4.5 兼容类来指示哈希函数,对于带有枚举 HashAlgorithm(4.6 或类似的东西)的类,请查看 the revision history .

关于c# - .Net Framework 4.5 中具有 128 位 key 长度和 1,024 次 SHA256 迭代的 PBKDF2 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53228398/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com