Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Security.Cryptography;
- namespace RedacaoOnline.Models.Utilities
- {
- public class PasswordStorage
- {
- // These constants may be changed without breaking existing hashes.
- public const int SALT_BYTES = 24;
- public const int HASH_BYTES = 18;
- public const int PBKDF2_ITERATIONS = 64000;
- // These constants define the encoding and may not be changed.
- public const int HASH_SECTIONS = 5;
- public const int HASH_ALGORITHM_INDEX = 0;
- public const int ITERATION_INDEX = 1;
- public const int HASH_SIZE_INDEX = 2;
- public const int SALT_INDEX = 3;
- public const int PBKDF2_INDEX = 4;
- public static string CreateHash(string password)
- {
- // Generate a random salt
- byte[] salt = new byte[SALT_BYTES];
- try
- {
- using (RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider())
- {
- csprng.GetBytes(salt);
- }
- }
- catch (Exception ex)
- {
- throw new Exception(ex.Message);
- }
- byte[] hash = PBKDF2(password, salt, PBKDF2_ITERATIONS, HASH_BYTES);
- // format: algorithm:iterations:hashSize:salt:hash
- String parts = "sha1:" +
- PBKDF2_ITERATIONS +
- ":" +
- hash.Length +
- ":" +
- Convert.ToBase64String(salt) +
- ":" +
- Convert.ToBase64String(hash);
- return parts;
- }
- public static bool VerifyPassword(string password, string goodHash)
- {
- char[] delimiter = { ':' };
- string[] split = goodHash.Split(delimiter);
- if (split.Length != HASH_SECTIONS)
- {
- throw new Exception("Fields are missing from the password hash.");
- }
- // We only support SHA1 with C#.
- if (split[HASH_ALGORITHM_INDEX] != "sha1")
- {
- throw new Exception("Unsupported hash type.");
- }
- int iterations = 0;
- try
- {
- iterations = Int32.Parse(split[ITERATION_INDEX]);
- }
- catch (Exception ex)
- {
- throw new Exception(ex.Message);
- }
- if (iterations < 1)
- {
- throw new Exception("Invalid number of iterations. Must be >= 1.");
- }
- byte[] salt = null;
- try
- {
- salt = Convert.FromBase64String(split[SALT_INDEX]);
- }
- catch (Exception ex)
- {
- throw new Exception(ex.Message);
- }
- byte[] hash = null;
- try
- {
- hash = Convert.FromBase64String(split[PBKDF2_INDEX]);
- }
- catch (Exception ex)
- {
- throw new Exception(ex.Message);
- }
- int storedHashSize = 0;
- try
- {
- storedHashSize = Int32.Parse(split[HASH_SIZE_INDEX]);
- }
- catch (Exception ex)
- {
- throw new Exception(ex.Message);
- }
- if (storedHashSize != hash.Length)
- {
- throw new Exception("Hash length doesn't match stored hash length.");
- }
- byte[] testHash = PBKDF2(password, salt, iterations, hash.Length);
- return SlowEquals(hash, testHash);
- }
- private static bool SlowEquals(byte[] a, byte[] b)
- {
- uint diff = (uint)a.Length ^ (uint)b.Length;
- for (int i = 0; i < a.Length && i < b.Length; i++)
- {
- diff |= (uint)(a[i] ^ b[i]);
- }
- return diff == 0;
- }
- private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes)
- {
- using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt))
- {
- pbkdf2.IterationCount = iterations;
- return pbkdf2.GetBytes(outputBytes);
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement