在这里的人们的帮助下,我已经将以下PHP函数转换为C# - 但是我在两者之间得到了非常不同的结果,并且无法解决我出错的地方:
PHP:
function randomKey($amount)
{
$keyset = "abcdefghijklmABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$randkey = "";
for ($i=0; $i<$amount; $i++)
$randkey .= substr($keyset, rand(0, strlen($keyset)-1), 1);
return $randkey;
}
public static function hashPassword($password)
{
$salt = self::randomKey(self::SALTLEN);
$site = new Sites();
$s = $site->get();
return self::hashSHA1($s->siteseed.$password.$salt.$s->siteseed).$salt;
}
c#中
public static string randomKey(int amount)
{
string keyset = "abcdefghijklmABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
string randkey = string.Empty;
Random random = new Random();
for (int i = 0; i < amount; i++)
{
randkey += keyset.Substring(0, random.Next(2, keyset.Length - 2));
}
return randkey;
}
static string hashPassword(string password)
{
string salt = randomKey(4);
string siteSeed = "6facef08253c4e3a709e17d9ff4ba197";
return CalculateSHA1(siteSeed + password + salt + siteSeed) + siteSeed;
}
static string CalculateSHA1(string ipString)
{
SHA1 sha1 = new SHA1CryptoServiceProvider();
byte[] ipBytes = Encoding.Default.GetBytes(ipString.ToCharArray());
byte[] opBytes = sha1.ComputeHash(ipBytes);
StringBuilder stringBuilder = new StringBuilder(40);
for (int i = 0; i < opBytes.Length; i++)
{
stringBuilder.Append(opBytes[i].ToString("x2"));
}
return stringBuilder.ToString();
}
编辑 PHP函数中的字符串'password'显示为
"d899d91adf31e0b37e7b99c5d2316ed3f6a999443OZl"
在c#中它出现为:
"905d25819d950cf73f629fc346c485c819a3094a6facef08253c4e3a709e17d9ff4ba197"
答案 0 :(得分:1)
您没有正确使用盐,或者您没有正确散列。
如果您在散列数据之前将数据加盐,这是一种很好的做法,您必须存储您使用的盐。
用例是:
用户注册您的服务。他们给你一个密码。你生成一个新的salt,用salt哈希他们的密码,然后存储哈希和盐。
用户稍后尝试登录。您查找注册时使用的盐,然后使用相同的盐再次执行哈希。如果登录尝试的密码哈希值与数据库中存储的哈希值匹配,则可以对它们进行身份验证。
现在,每当你打电话给hashPassword
时,你都会用全新的盐进行哈希,因为你一直在调用你的盐生成器。这将永远不会奏效。
你也有其他问题。
当您创建salt时,每次调用都会使用Random
的新实例。没有任何参数的new Random()
使用系统时间作为种子,系统时间仅每10-15毫秒更改一次。如果你在紧密循环中这样做,它将连续多次生成相同的随机值。
要么:创建一个随机单例,它在您的程序首次启动时构造一次,或者使用随机变量不断变化的种子。或者,特别是因为您正在实施安全性,请使用加密质量随机数生成器:RNGCryptoServiceProvider
您可能还希望在实现中使用SecureString,因为该用户的密码位于应用程序的内存中:SecureString。是的,您必须在某些时候将SecureString解析为常规字符串,但SecureString可以帮助防止密码在内存中以明文形式显示的总时间。