Last active
August 29, 2015 13:56
-
-
Save khellang/8985124 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ExampleUsage | |
{ | |
private readonly IPasswordHasher _hasher; | |
public ExampleUsage(IPasswordHasher hasher) | |
{ | |
_hasher = hasher; | |
} | |
public void Register(string username, string password) | |
{ | |
var hashBase64 = default(string); | |
var saltBase64 = default(string); | |
_hasher.Generate(password, out hashBase64, out saltBase64); | |
Database.Save(new User | |
{ | |
Username = username, | |
PasswordHash = hashBase64, | |
Salt = saltBase64 | |
}); | |
} | |
public bool Login(string username, string password) | |
{ | |
var user = Database.Get(username); | |
if (user == null) | |
{ | |
return false; | |
} | |
return _hasher.Verify(password, user.PasswordHash, user.Salt); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface IPasswordHasher | |
{ | |
void Generate(string password, out string hashBase64, out string saltBase64); | |
bool Verify(string password, string hashBase64, string saltBase64); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class PasswordHasher : IPasswordHasher | |
{ | |
private readonly int _saltSize; | |
private readonly int _hashSize; | |
private readonly int _iterations; | |
public PasswordHasher(int saltSize = 10, int hashSize = 40, int iterations = 10000) | |
{ | |
_saltSize = saltSize; | |
_hashSize = hashSize; | |
_iterations = iterations; | |
} | |
public void Generate(string password, out string hashBase64, out string saltBase64) | |
{ | |
using (var hashGenerator = new Rfc2898DeriveBytes(password, _saltSize, _iterations)) | |
{ | |
hashBase64 = Convert.ToBase64String(hashGenerator.GetBytes(_hashSize)); | |
saltBase64 = Convert.ToBase64String(hashGenerator.Salt); | |
} | |
} | |
public bool Verify(string password, string hashBase64, string saltBase64) | |
{ | |
var hashBytes = Convert.FromBase64String(hashBase64); | |
var saltBytes = Convert.FromBase64String(saltBase64); | |
using (var hashGenerator = new Rfc2898DeriveBytes(password, saltBytes, _iterations)) | |
{ | |
return SlowEquals(hashGenerator.GetBytes(hashBytes.Length), hashBytes); | |
} | |
} | |
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] | |
private static bool SlowEquals(IList<byte> a, IList<byte> b) | |
{ | |
var diff = a.Count ^ b.Count; | |
for (var i = 0; i < a.Count && i < b.Count; i++) | |
{ | |
diff |= a[i] ^ b[i]; | |
} | |
return diff == 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment