1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- using System;
- using System.Security.Cryptography;
-
- namespace iiie.Authentication.Business.JWT
- {
- /// <summary>
- /// Hash generator for passwords
- /// </summary>
- public static class PasswordHash
- {
- private const int ITERATION_INDEX = 0;
- private const int SALT_INDEX = 1;
- private const int PBKDF2_INDEX = 2;
-
- private const int SALT_BYTE_SIZE = 24;
- private const int HASH_BYTE_SIZE = 42;
- private const int PBKDF2_ITERATIONS = 2048;
-
- /// <summary>
- /// Crée un hash à partir du password
- /// </summary>
- /// <param name="password">le password à hasher</param>
- /// <returns>le hash du password</returns>
- public static string CreateHash(string password)
- {
- // génaration du SALT aléatoire
- RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider();
- byte[] salt = new byte[SALT_BYTE_SIZE];
- csprng.GetBytes(salt);
-
- // hash le password et création de la chaine avec les paramêtres
- byte[] hash = PBKDF2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
- return PBKDF2_ITERATIONS + ":" +
- Convert.ToBase64String(salt) + ":" + Convert.ToBase64String(hash);
- }
-
- /// <summary>
- /// Valide le password en adequation avec le hash
- /// </summary>
- /// <param name="password">le password à vérifier</param>
- /// <param name="correctHash">le hash du password stocké en base</param>
- /// <returns>True si c'est bon sinon false</returns>
- public static bool ValidatePassword(string password, string correctHash)
- {
- // Extraction des paramêtres du 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);
- }
-
-
- 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;
- }
-
- /// <summary>
- /// Calcul le PBKDF2-SHA1 hash du password.
- /// </summary>
- /// <param name="password">The password à hasher</param>
- /// <param name="salt">le salt</param>
- /// <param name="iterations">le nombre d'itération</param>
- /// <param name="outputBytes">la longueur du hash à générer</param>
- /// <returns>le hash du password.</returns>
- 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);
- }
- }
- }
|