带有自定义加盐密码的 .NET Identity 2.0
.NET Identity 2.0 with custom salted passwords
我正在尝试从现有 MVC 应用程序中的旧自定义成员身份提供程序切换到 .NET Identity,并将 Dapper 维护为 ORM,而不是开箱即用的 EntityFramework。
我一直在尝试实现我自己的 IPasswordHasher
,因为我需要现有的凭据才能工作。在 HashPassword
中,我想 return 将明文输入的 SHA 计算散列与用户特定的盐相结合,但该方法仅接收明文值,并且没有对用户的引用尝试登录。
我在哪里可以买到这种盐?还是我用错了方法?
我必须为迁移做几乎相同的事情。推荐的 migration article 为您的问题提供了解决方案。
您需要将旧密码哈希与盐合并到一个 Password
字段中,用特殊符号分隔(在文章中是 |
,但您可以选择自己的分隔符)。
然后 PasswordHasher
应检查该特殊符号的密码,如果存在,则将盐与密码分开并应用散列。
这是上面链接文章中的一个代码片段,不过我删除了一些用于检查纯文本密码存储的杂音。这假定您的哈希以 SH1hash|salt
格式存储
public class SQLPasswordHasher : PasswordHasher
{
public override string HashPassword(string password)
{
return base.HashPassword(password);
}
public override PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
{
string[] passwordProperties = hashedPassword.Split('|');
if (passwordProperties.Length != 2)
{
// use default Identity implementation
return base.VerifyHashedPassword(hashedPassword, providedPassword);
}
else
{
string passwordHash = passwordProperties[0];
string salt = passwordProperties[1];
if (String.Equals(EncryptPassword(providedPassword, salt), passwordHash, StringComparison.CurrentCultureIgnoreCase))
{
return PasswordVerificationResult.SuccessRehashNeeded;
}
else
{
return PasswordVerificationResult.Failed;
}
}
}
//This is copied from the existing SQL provider
private string EncryptPassword(string pass, string salt)
{
byte[] bIn = Encoding.Unicode.GetBytes(pass);
byte[] bSalt = Convert.FromBase64String(salt);
byte[] bRet = null;
HashAlgorithm hm = HashAlgorithm.Create("SHA1");
if (hm is KeyedHashAlgorithm)
{
KeyedHashAlgorithm kha = (KeyedHashAlgorithm)hm;
if (kha.Key.Length == bSalt.Length)
{
kha.Key = bSalt;
}
else if (kha.Key.Length < bSalt.Length)
{
byte[] bKey = new byte[kha.Key.Length];
Buffer.BlockCopy(bSalt, 0, bKey, 0, bKey.Length);
kha.Key = bKey;
}
else
{
byte[] bKey = new byte[kha.Key.Length];
for (int iter = 0; iter < bKey.Length; )
{
int len = Math.Min(bSalt.Length, bKey.Length - iter);
Buffer.BlockCopy(bSalt, 0, bKey, iter, len);
iter += len;
}
kha.Key = bKey;
}
bRet = kha.ComputeHash(bIn);
}
else
{
byte[] bAll = new byte[bSalt.Length + bIn.Length];
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
bRet = hm.ComputeHash(bAll);
}
return Convert.ToBase64String(bRet);
}
}
我正在尝试从现有 MVC 应用程序中的旧自定义成员身份提供程序切换到 .NET Identity,并将 Dapper 维护为 ORM,而不是开箱即用的 EntityFramework。
我一直在尝试实现我自己的 IPasswordHasher
,因为我需要现有的凭据才能工作。在 HashPassword
中,我想 return 将明文输入的 SHA 计算散列与用户特定的盐相结合,但该方法仅接收明文值,并且没有对用户的引用尝试登录。
我在哪里可以买到这种盐?还是我用错了方法?
我必须为迁移做几乎相同的事情。推荐的 migration article 为您的问题提供了解决方案。
您需要将旧密码哈希与盐合并到一个 Password
字段中,用特殊符号分隔(在文章中是 |
,但您可以选择自己的分隔符)。
然后 PasswordHasher
应检查该特殊符号的密码,如果存在,则将盐与密码分开并应用散列。
这是上面链接文章中的一个代码片段,不过我删除了一些用于检查纯文本密码存储的杂音。这假定您的哈希以 SH1hash|salt
public class SQLPasswordHasher : PasswordHasher
{
public override string HashPassword(string password)
{
return base.HashPassword(password);
}
public override PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
{
string[] passwordProperties = hashedPassword.Split('|');
if (passwordProperties.Length != 2)
{
// use default Identity implementation
return base.VerifyHashedPassword(hashedPassword, providedPassword);
}
else
{
string passwordHash = passwordProperties[0];
string salt = passwordProperties[1];
if (String.Equals(EncryptPassword(providedPassword, salt), passwordHash, StringComparison.CurrentCultureIgnoreCase))
{
return PasswordVerificationResult.SuccessRehashNeeded;
}
else
{
return PasswordVerificationResult.Failed;
}
}
}
//This is copied from the existing SQL provider
private string EncryptPassword(string pass, string salt)
{
byte[] bIn = Encoding.Unicode.GetBytes(pass);
byte[] bSalt = Convert.FromBase64String(salt);
byte[] bRet = null;
HashAlgorithm hm = HashAlgorithm.Create("SHA1");
if (hm is KeyedHashAlgorithm)
{
KeyedHashAlgorithm kha = (KeyedHashAlgorithm)hm;
if (kha.Key.Length == bSalt.Length)
{
kha.Key = bSalt;
}
else if (kha.Key.Length < bSalt.Length)
{
byte[] bKey = new byte[kha.Key.Length];
Buffer.BlockCopy(bSalt, 0, bKey, 0, bKey.Length);
kha.Key = bKey;
}
else
{
byte[] bKey = new byte[kha.Key.Length];
for (int iter = 0; iter < bKey.Length; )
{
int len = Math.Min(bSalt.Length, bKey.Length - iter);
Buffer.BlockCopy(bSalt, 0, bKey, iter, len);
iter += len;
}
kha.Key = bKey;
}
bRet = kha.ComputeHash(bIn);
}
else
{
byte[] bAll = new byte[bSalt.Length + bIn.Length];
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
bRet = hm.ComputeHash(bAll);
}
return Convert.ToBase64String(bRet);
}
}