-
Zetetic
哈希算法PBKDF2比SHA1或SHA256-SHA512等要好得多。PBKDF2、SCRYPT或ARGON2等最新算法在哈希方面处于领先地位。但是在这种情况下使用PBKDF2是有用的,因为它是由实现的。净入
Rfc2898DeriveBytes
a.Zetetic默认使用5000次迭代。可定制,如果您使用
Pbkdf2Hash256K
b.玉米的使用
Rfc2898衍生字节
Rfc2898衍生字节
基于
HMACSHA1
-
好消息!我已经定制了
Rfc2898衍生字节
使用
HMACSHA512
通过128000次迭代,SQLMembershipProvider可以使用到目前为止还不可用的PBKDF2。为了实现这一目标,我结合了
Zetetic's
代码与我的实现
Rfc2898衍生字节
如下图所示:
using System.Security.Cryptography;
namespace custom.hashing.keyderivation
{
/// <summary>
/// This derived class of PBKDF2Hash provided necessary capabilities to SQLMembershipProvider in order to hash passwords in PBKDF2 way with 128,000 iterations.
/// </summary>
public class PBKDF2Hash : KeyedHashAlgorithm
{
private const int kHashBytes = 64;
private System.IO.MemoryStream _ms;
public int WorkFactor { get; set; }
public PBKDF2Hash()
: base()
{
this.WorkFactor = 128000;
this.Key = new byte[32]; // 32 Bytes will give us 256 bits.
using (var rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(this.Key);
}
}
/// <summary>
/// Hash size in bits
/// </summary>
public override int HashSize
{
get
{
return kHashBytes * 8;
}
}
protected override void HashCore(byte[] array, int ibStart, int cbSize)
{
(_ms = _ms ?? new System.IO.MemoryStream()).Write(array, ibStart, cbSize);
}
protected override byte[] HashFinal()
{
if (this.Key == null || this.Key.Length == 0)
{
throw new CryptographicException("Missing KeyedAlgorithm key");
}
_ms.Flush();
var arr = _ms.ToArray();
_ms = null;
using (var hmac = new HMACSHA512())
{
return new MyRfc2898DeriveBytes(arr, this.Key, this.WorkFactor, hmac).GetBytes(kHashBytes);
}
}
public override void Initialize()
{
_ms = null;
}
}
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// <OWNER>Microsoft</OWNER>
//
//
// Rfc2898DeriveBytes.cs
//
// This implementation follows RFC 2898 recommendations. See http://www.ietf.org/rfc/Rfc2898.txt
/// <summary>
/// Microsoft has implemented PBKDF2 but with HMACSHA1. We are customizing this class to use HMACSHA512 in hashing process.
/// </summary>
public class MyRfc2898DeriveBytes : DeriveBytes
{
private byte[] m_buffer;
private byte[] m_salt;
private HMAC m_hmac; // The pseudo-random generator function used in PBKDF2
private uint m_iterations;
private uint m_block;
private int m_startIndex;
private int m_endIndex;
private int m_blockSize;
//
// public constructors
//
// This method needs to be safe critical, because in debug builds the C# compiler will include null
// initialization of the _safeProvHandle field in the method. Since SafeProvHandle is critical, a
// transparent reference triggers an error using PasswordDeriveBytes.
[SecuritySafeCritical]
public MyRfc2898DeriveBytes(byte[] password, byte[] salt, int iterations, HMAC hmac)
{
Salt = salt;
IterationCount = iterations;
hmac.Key = password;
m_hmac = hmac;
// m_blockSize is in bytes, HashSize is in bits.
m_blockSize = hmac.HashSize >> 3;
Initialize();
}
//
// public properties
//
public int IterationCount
{
get { return (int)m_iterations; }
set
{
if (value <= 0)
throw new ArgumentOutOfRangeException("value", "Error: Iteration count is zero or less");
m_iterations = (uint)value;
Initialize();
}
}
public byte[] Salt
{
get { return (byte[])m_salt.Clone(); }
set
{
if (value == null)
throw new ArgumentNullException("value");
if (value.Length < 8)
throw new ArgumentException("Error: Salt size is less than 8");
m_salt = (byte[])value.Clone();
Initialize();
}
}
//
// public methods
//
public override byte[] GetBytes(int cb)
{
if (cb <= 0)
{ throw new ArgumentOutOfRangeException("cb", "Error: Hash size is zero or less"); }
Contract.Assert(m_blockSize > 0);
byte[] password = new byte[cb];
int offset = 0;
int size = m_endIndex - m_startIndex;
if (size > 0)
{
if (cb >= size)
{
Buffer.BlockCopy(m_buffer, m_startIndex, password, 0, size);
m_startIndex = m_endIndex = 0;
offset += size;
}
else
{
Buffer.BlockCopy(m_buffer, m_startIndex, password, 0, cb);
m_startIndex += cb;
return password;
}
}
Contract.Assert(m_startIndex == 0 && m_endIndex == 0, "Invalid start or end index in the internal buffer.");
while (offset < cb)
{
byte[] T_block = Func();
int remainder = cb - offset;
if (remainder > m_blockSize)
{
Buffer.BlockCopy(T_block, 0, password, offset, m_blockSize);
offset += m_blockSize;
}
else
{
Buffer.BlockCopy(T_block, 0, password, offset, remainder);
offset += remainder;
Buffer.BlockCopy(T_block, remainder, m_buffer, m_startIndex, m_blockSize - remainder);
m_endIndex += (m_blockSize - remainder);
return password;
}
}
return password;
}
public override void Reset()
{
Initialize();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
if (m_hmac != null)
{
((IDisposable)m_hmac).Dispose();
}
if (m_buffer != null)
{
Array.Clear(m_buffer, 0, m_buffer.Length);
}
if (m_salt != null)
{
Array.Clear(m_salt, 0, m_salt.Length);
}
}
}
private void Initialize()
{
if (m_buffer != null)
Array.Clear(m_buffer, 0, m_buffer.Length);
m_buffer = new byte[m_blockSize];
m_block = 1;
m_startIndex = m_endIndex = 0;
}
internal static byte[] GetBytesFromInt(uint i)
{
return unchecked(new byte[] { (byte)(i >> 24), (byte)(i >> 16), (byte)(i >> 8), (byte)i });
}
// This function is defined as follow :
// Func (S, i) = HMAC(S || i) | HMAC2(S || i) | ... | HMAC(iterations) (S || i)
// where i is the block number.
private byte[] Func()
{
byte[] INT_block = GetBytesFromInt(m_block);
m_hmac.TransformBlock(m_salt, 0, m_salt.Length, null, 0);
m_hmac.TransformBlock(INT_block, 0, INT_block.Length, null, 0);
m_hmac.TransformFinalBlock(new byte[0], 0, 0);
byte[] temp = m_hmac.Hash;
m_hmac.Initialize();
byte[] ret = temp;
for (int i = 2; i <= m_iterations; i++)
{
m_hmac.TransformBlock(temp, 0, temp.Length, null, 0);
m_hmac.TransformFinalBlock(new byte[0], 0, 0);
temp = m_hmac.Hash;
for (int j = 0; j < m_blockSize; j++)
{
ret[j] ^= temp[j];
}
m_hmac.Initialize();
}
// increment the block count.
if (m_block == uint.MaxValue)
{ throw new InvalidOperationException("Derived key too long."); }
m_block++;
return ret;
}
}
创建此类后,请执行以下操作:
-
System.Security.Cryptography.CryptoConfig.AddAlgorithm(typeof(custom.hashing.keyderivation.PBKDF2Hash), "PBKDF2Hash_HB");
-
并将web.config更改为:
<membership defaultProvider="sitecore" hashAlgorithmType="PBKDF2Hash_HB">
构建此答案的参考文献来自: