0

With a bit of help from people on here, i've converted the following PHP functions to C# - But I get very different results between the two and can't work out where i've gone wrong:

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();
        }

EDIT The string 'password' in the PHP function comes out as

"d899d91adf31e0b37e7b99c5d2316ed3f6a999443OZl" 

in the c# it comes out as:

"905d25819d950cf73f629fc346c485c819a3094a6facef08253c4e3a709e17d9ff4ba197"
Baba
  • 94,024
  • 28
  • 166
  • 217
MissCoder87
  • 2,669
  • 10
  • 47
  • 82
  • This is not an efficient way to generate random strings or hash password .... – Baba Jun 27 '13 at 16:08
  • How are the results different? Given that there's pseudorandomness involved, it's not surprising that you wouldn't get the same exact results. Which function is not returning the values that you expect? – Ryan M Jun 27 '13 at 16:13
  • What are the _very different results_ you're getting? – Dave Zych Jun 27 '13 at 16:13
  • I've added an example of the different results above. This is when i call String x = hashPassword(txtPassword.Text); – MissCoder87 Jun 27 '13 at 16:16
  • You should seriously consider reading the selected answer on this SO post. http://stackoverflow.com/questions/1054022/best-way-to-store-password-in-database – Pete Garafano Jun 27 '13 at 16:25

1 Answers1

1

You're not using salts correctly, or you're not hashing correctly.

If you salt your data before you hash it, which is good practice, you have to store the salt you used.

The use case is:

A user signs up with your service. They give you a password. You generate a new salt, hash their password with the salt, and then store the hash and the salt.

The user later attempts to log in. You look up the salt you used when they signed up, and then perform the hash again using the same salt. If the hash of the password from the login attempt matches the hash stored in the database, you can authenticate them.

Right now, every time you call hashPassword you hash with a completely new salt because you keep invoking your salt generator. This won't ever work.

You've got other problems too.

When you're creating salts, you use a new instance of Random every single invocation. new Random() without any parameters uses the system time as the seed, and the system time only changes every 10-15 milliseconds. If you do that in a tight loop, it's going to generate the same random value a bunch of times in a row.

Either: create a Random singleton that is constructed once when your program is first started, or use a seed to Random that is going to change constantly. Alternatively, especially since you're implementing security, use a cryptographic-quality random number generator : RNGCryptoServiceProvider

You may also want to use SecureString in your implementation, since that user's password is sitting in memory in the application: SecureString. Yes, you will have to resolve the SecureString to a regular string at some point but SecureString can help prevent the total time that the password is in plain text in memory.

antiduh
  • 11,853
  • 4
  • 43
  • 66