Rfc2898DeriveBytes 密码与字符串匹配而不是字节 []
Rfc2898DeriveBytes password matches with string and not with byte[]
我正在尝试创建一个带有登录名和密码凭据的身份验证服务器,我使用了 this tutorial,它给了我以下 PasswordHash
class。当我将 Verify
方法与字符串一起使用时效果很好,但出于安全原因我不想通过 UDP 发送未加密的密码,但是当我通过向它提供字节数组直接测试哈希时 returns false(如下图class).
public sealed class PasswordHash
{
const int SaltSize = 16, HashSize = 20, HashIter = 10000;
readonly byte[] _salt, _hash;
private PasswordHash() { }
public PasswordHash(string password)
{
new RNGCryptoServiceProvider().GetBytes(_salt = new byte[SaltSize]);
_hash = new Rfc2898DeriveBytes(password, _salt, HashIter).GetBytes(HashSize);
}
public PasswordHash(byte[] hashBytes)
{
Array.Copy(hashBytes, 0, _salt = new byte[SaltSize], 0, SaltSize);
Array.Copy(hashBytes, SaltSize, _hash = new byte[HashSize], 0, HashSize);
}
public PasswordHash(byte[] salt, byte[] hash)
{
Array.Copy(salt, 0, _salt = new byte[SaltSize], 0, SaltSize);
Array.Copy(hash, 0, _hash = new byte[HashSize], 0, HashSize);
}
public byte[] ToArray()
{
byte[] hashBytes = new byte[SaltSize + HashSize];
Array.Copy(_salt, 0, hashBytes, 0, SaltSize);
Array.Copy(_hash, 0, hashBytes, SaltSize, HashSize);
return hashBytes;
}
public byte[] Salt { get { return (byte[])_salt.Clone(); } }
public byte[] Hash { get { return (byte[])_hash.Clone(); } }
public bool Verify(string password)
{
byte[] test = new Rfc2898DeriveBytes(password, _salt, HashIter).GetBytes(HashSize);
for (int i = 0; i < HashSize; i++)
if (test[i] != _hash[i])
return false;
return true;
}
public bool Verify(byte[] passwordHash)
{
for (int i = 0; i < HashSize; i++)
if (passwordHash[i] != _hash[i])
return false;
return true;
}
}
我使用以下方法对其进行了测试:
bool test = new PasswordHash("test123").Verify("test123"); //TRUE
bool test2 = new PasswordHash("test123").Verify(newPasswordHash("test123").ToArray()); //FALSE
所以正如 Nissim 指出的那样,它们不匹配,因为盐是在我每次调用时随机生成的 new PasswordHash().
是否可以绕过添加到 byte[] 的盐?
每次调用 PasswordHash 的构造函数时,它都会创建一个新盐,因此在以下示例中:
byte[] pass1 = new HashPassword("abc").ToArray();
byte[] pass2 = new HashPassword("abc").ToArray();
pass1 与 pass2 不同
我正在尝试创建一个带有登录名和密码凭据的身份验证服务器,我使用了 this tutorial,它给了我以下 PasswordHash
class。当我将 Verify
方法与字符串一起使用时效果很好,但出于安全原因我不想通过 UDP 发送未加密的密码,但是当我通过向它提供字节数组直接测试哈希时 returns false(如下图class).
public sealed class PasswordHash
{
const int SaltSize = 16, HashSize = 20, HashIter = 10000;
readonly byte[] _salt, _hash;
private PasswordHash() { }
public PasswordHash(string password)
{
new RNGCryptoServiceProvider().GetBytes(_salt = new byte[SaltSize]);
_hash = new Rfc2898DeriveBytes(password, _salt, HashIter).GetBytes(HashSize);
}
public PasswordHash(byte[] hashBytes)
{
Array.Copy(hashBytes, 0, _salt = new byte[SaltSize], 0, SaltSize);
Array.Copy(hashBytes, SaltSize, _hash = new byte[HashSize], 0, HashSize);
}
public PasswordHash(byte[] salt, byte[] hash)
{
Array.Copy(salt, 0, _salt = new byte[SaltSize], 0, SaltSize);
Array.Copy(hash, 0, _hash = new byte[HashSize], 0, HashSize);
}
public byte[] ToArray()
{
byte[] hashBytes = new byte[SaltSize + HashSize];
Array.Copy(_salt, 0, hashBytes, 0, SaltSize);
Array.Copy(_hash, 0, hashBytes, SaltSize, HashSize);
return hashBytes;
}
public byte[] Salt { get { return (byte[])_salt.Clone(); } }
public byte[] Hash { get { return (byte[])_hash.Clone(); } }
public bool Verify(string password)
{
byte[] test = new Rfc2898DeriveBytes(password, _salt, HashIter).GetBytes(HashSize);
for (int i = 0; i < HashSize; i++)
if (test[i] != _hash[i])
return false;
return true;
}
public bool Verify(byte[] passwordHash)
{
for (int i = 0; i < HashSize; i++)
if (passwordHash[i] != _hash[i])
return false;
return true;
}
}
我使用以下方法对其进行了测试:
bool test = new PasswordHash("test123").Verify("test123"); //TRUE
bool test2 = new PasswordHash("test123").Verify(newPasswordHash("test123").ToArray()); //FALSE
所以正如 Nissim 指出的那样,它们不匹配,因为盐是在我每次调用时随机生成的 new PasswordHash().
是否可以绕过添加到 byte[] 的盐?
每次调用 PasswordHash 的构造函数时,它都会创建一个新盐,因此在以下示例中:
byte[] pass1 = new HashPassword("abc").ToArray();
byte[] pass2 = new HashPassword("abc").ToArray();
pass1 与 pass2 不同