title: Secure password hashing with salt, but what about storing it in local cookies?
body: <p>I've recently read an interesting article about securely hashing user passwords by using "salt". (This is the <a href="http://crackstation.net/hashing-security.htm" rel="nofollow">original article</a>, which unfortunately seems to be down at the time of this post, so <a href="http://webcache.googleusercontent.com/search?q=cache%3a-KnqE3F0Me8J%3acrackstation.net/hashing-security.htm%20&amp;cd=1&amp;hl=en&amp;ct=clnk&amp;gl=us" rel="nofollow">here's</a> the cached version.)</p>
  
  <p>I totally agree with this concept, except that I can't seem to find a way of securely storing a user login in a local cookie (or session) since the salt + PBKDF2 hash combination is done randomly for each time. To better understand what I mean, let me copy the C# code from <a href="http://webcache.googleusercontent.com/search?q=cache%3a-KnqE3F0Me8J%3acrackstation.net/hashing-security.htm%20&amp;cd=1&amp;hl=en&amp;ct=clnk&amp;gl=us#aspsourcecode" rel="nofollow">the article</a>:</p>
  
  <pre><code>using System;
  using System.Text;
  using System.Security.Cryptography;
  
  namespace PasswordHash
  {
      /// &lt;summary&gt;
      /// Salted password hashing with PBKDF2-SHA1.
      /// Author: havoc AT defuse.ca
      /// www: http://crackstation.net/hashing-security.htm
      /// Compatibility: .NET 3.0 and later.
      /// &lt;/summary&gt;
      class PasswordHash
      {
          // The following constants may be changed without breaking existing hashes.
          public const int SALT_BYTES = 24;
          public const int HASH_BYTES = 24;
          public const int PBKDF2_ITERATIONS = 1000;
  
          public const int ITERATION_INDEX = 0;
          public const int SALT_INDEX = 1;
          public const int PBKDF2_INDEX = 2;
  
          /// &lt;summary&gt;
          /// Creates a salted PBKDF2 hash of the password.
          /// &lt;/summary&gt;
          /// &lt;param name="password"&gt;The password to hash.&lt;/param&gt;
          /// &lt;returns&gt;The hash of the password.&lt;/returns&gt;
          public static string CreateHash(string password)
          {
              // Generate a random salt
              RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider();
              byte[] salt = new byte[SALT_BYTES];
              csprng.GetBytes(salt);
  
              // Hash the password and encode the parameters
              byte[] hash = PBKDF2(password, salt, PBKDF2_ITERATIONS, HASH_BYTES);
              return PBKDF2_ITERATIONS + ":" +
                  Convert.ToBase64String(salt) + ":" +
                  Convert.ToBase64String(hash);
          }
  
          /// &lt;summary&gt;
          /// Validates a password given a hash of the correct one.
          /// &lt;/summary&gt;
          /// &lt;param name="password"&gt;The password to check.&lt;/param&gt;
          /// &lt;param name="goodHash"&gt;A hash of the correct password.&lt;/param&gt;
          /// &lt;returns&gt;True if the password is correct. False otherwise.&lt;/returns&gt;
          public static bool ValidatePassword(string password, string goodHash)
          {
              // Extract the parameters from the hash
              char[] delimiter = { ':' };
              string[] split = goodHash.Split(delimiter);
              int iterations = Int32.Parse(split[ITERATION_INDEX]);
              byte[] salt = Convert.FromBase64String(split[SALT_INDEX]);
              byte[] hash = Convert.FromBase64String(split[PBKDF2_INDEX]);
  
              byte[] testHash = PBKDF2(password, salt, iterations, hash.Length);
              return SlowEquals(hash, testHash);
          }
  
          /// &lt;summary&gt;
          /// Compares two byte arrays in length-constant time. This comparison
          /// method is used so that password hashes cannot be extracted from
          /// on-line systems using a timing attack and then attacked off-line.
          /// &lt;/summary&gt;
          /// &lt;param name="a"&gt;The first byte array.&lt;/param&gt;
          /// &lt;param name="b"&gt;The second byte array.&lt;/param&gt;
          /// &lt;returns&gt;True if both byte arrays are equal. False otherwise.&lt;/returns&gt;
          private static bool SlowEquals(byte[] a, byte[] b)
          {
              uint diff = (uint)a.Length ^ (uint)b.Length;
              for (int i = 0; i &lt; a.Length &amp;&amp; i &lt; b.Length; i++)
                  diff |= (uint)(a[i] ^ b[i]);
              return diff == 0;
          }
  
          /// &lt;summary&gt;
          /// Computes the PBKDF2-SHA1 hash of a password.
          /// &lt;/summary&gt;
          /// &lt;param name="password"&gt;The password to hash.&lt;/param&gt;
          /// &lt;param name="salt"&gt;The salt.&lt;/param&gt;
          /// &lt;param name="iterations"&gt;The PBKDF2 iteration count.&lt;/param&gt;
          /// &lt;param name="outputBytes"&gt;The length of the hash to generate, in bytes.&lt;/param&gt;
          /// &lt;returns&gt;A hash of the password.&lt;/returns&gt;
          private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes)
          {
              Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt);
              pbkdf2.IterationCount = iterations;
              return pbkdf2.GetBytes(outputBytes);
          }
      }
  }
  </code></pre>
  
  <p>So as you can see, the only way to validate a password would be to call <code>ValidatePassword</code> with a plain-text password. In my previous implementation of plain SHA1, to store user login in a local browser, I'd put that SHA1 value in a cookie and compare it with the one stored in the database on a server for each page. But how do you do the same with this "secure" approach?</p>
  
  <p>Any ideas?</p>