Secure password hashing I have found a password hashing article and an implementation.

Is this code secure if I increase the salt to 64 bytes, hash key size to 128 bytes and the iterations to 10000? Are there vulnerabilities or incorrectly implemented sections in this code?

I know that Rfc2898DeriveBytes is making use of HMAC-SHA1, but with a high salt bit count, the SHA1 risk is lowered (if my googling can be trusted).

Any advice or words of caution or ways to secure or correct this code would be welcome.

// The following constants may be changed without breaking existing hashes.
public const int SALT_BYTE_SIZE = 24;
public const int HASH_BYTE_SIZE = 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_BYTE_SIZE];
    csprng.GetBytes(salt);

    // Hash the password and encode the parameters
    byte[] hash = PBKDF2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
    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="correctHash"&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 correctHash)
{
    // Extract the parameters from the hash
    char[] delimiter = { ':' };
    string[] split = correctHash.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);
}
Number of iterations is pretty low. Since .NET's PBKDF2 implementation is very slow, you can't afford a good number of iterations. But even with it, 20000 should be affordable for server side hashing. For client side hashing you can go much higher.
You're outputting more than the natural size (20 bytes for SHA-1), which decreases performance twofold without a security gain. At the same cost you could double the number of iteration, which improves security.

=> Increasing the output size beyond 20 bytes decreases security for a given hashing cost.
SlowEquals is a bad name. I'd call it ConstantTimeEquals.
No point in having large salts. Salts should be globally unique. 16 bytes is enough for that, so going beyond that doesn't increase security.
There are no known weaknesses in SHA-1 (or even MD5!) that apply to password hashing. Collision attacks are no threat in this context. The most important distinction between different hashes is the relative software (CPU) vs. hardware (GPU, FPGA, ASIC) performance. So on a 64 bit CPU, SHA-512 is probably a decent choice since it relies on 64 bit arithmetic.