0

在人们的帮助下,我已将以下 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 函数中的字符串“密码”作为

"d899d91adf31e0b37e7b99c5d2316ed3f6a999443OZl" 

在 c# 中,它显示为:

"905d25819d950cf73f629fc346c485c819a3094a6facef08253c4e3a709e17d9ff4ba197"
4

1 回答 1

1

您没有正确使用盐,或者您没有正确散列。

如果在散列数据之前对数据加盐,这是一种很好的做法,则必须存储使用的盐。

用例是:

用户注册了您的服务。他们给你一个密码。你生成一个新的盐,用盐散列他们的密码,然后存储散列和盐。

用户稍后尝试登录。您查找他们注册时使用的 salt,然后使用相同的 salt再次执行哈希。如果来自登录尝试的密码哈希与存储在数据库中的哈希匹配,则可以对其进行身份验证。

现在,每次你hashPassword用一个全新的盐调用你的哈希,因为你一直在调用你的盐生成器。这永远行不通。

你还有其他问题。

当您创建盐时,您使用Random每个调用的新实例。new Random()不带任何参数以系统时间为种子,系统时间仅每10-15毫秒变化一次。如果你在一个紧密的循环中这样做,它将连续多次生成相同的随机值。

要么:创建一个在程序首次启动时构建一次的 Random 单例,要么使用将不断变化的 Random 种子。或者,特别是因为您正在实施安全性,请使用加密质量随机数生成器RNGCryptoServiceProvider

您可能还想在您的实现中使用 SecureString ,因为该用户的密码位于应用程序的内存中:SecureString。是的,您必须在某个时候将 SecureString 解析为常规字符串,但 SecureString 可以帮助防止密码在内存中以纯文本形式出现的总时间。

于 2013-06-27T16:22:23.400 回答