Switch to using DataProtection for Crypto

This commit is contained in:
Hao Kung 2014-03-07 12:23:20 -08:00
parent 56c67d5ef0
commit d845ef0b7c
4 changed files with 22 additions and 45 deletions

View File

@ -1,15 +1,14 @@
#if NET45
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Security.Cryptography; using System.Text;
using Microsoft.AspNet.Security.DataProtection;
namespace Microsoft.AspNet.Identity namespace Microsoft.AspNet.Identity
{ {
internal static class Crypto internal static class Crypto
{ {
private const int PBKDF2IterCount = 1000; // default for Rfc2898DeriveBytes private const int Pbkdf2IterCount = 1000; // default for Rfc2898DeriveBytes
private const int PBKDF2SubkeyLength = 256/8; // 256 bits private const int Pbkdf2SubkeyLength = 256/8; // 256 bits
private const int SaltSize = 128/8; // 128 bits private const int SaltSize = 128/8; // 128 bits
/* ======================= /* =======================
@ -30,17 +29,13 @@ namespace Microsoft.AspNet.Identity
} }
// Produce a version 0 (see comment above) text hash. // Produce a version 0 (see comment above) text hash.
byte[] salt; var salt = new byte[SaltSize];
byte[] subkey; CryptRand.FillBuffer(new ArraySegment<byte>(salt));
using (var deriveBytes = new Rfc2898DeriveBytes(password, SaltSize, PBKDF2IterCount)) var passwordBytes = Encoding.UTF8.GetBytes(password);
{ var subkey = PBKDF2.DeriveKey("SHA1", passwordBytes, salt, Pbkdf2IterCount, Pbkdf2SubkeyLength);
salt = deriveBytes.Salt; var outputBytes = new byte[1 + SaltSize + Pbkdf2SubkeyLength];
subkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);
}
var outputBytes = new byte[1 + SaltSize + PBKDF2SubkeyLength];
Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize); Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, PBKDF2SubkeyLength); Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, Pbkdf2SubkeyLength);
return Convert.ToBase64String(outputBytes); return Convert.ToBase64String(outputBytes);
} }
@ -56,26 +51,19 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("password"); throw new ArgumentNullException("password");
} }
var hashedPasswordBytes = Convert.FromBase64String(hashedPassword);
// Verify a version 0 (see comment above) text hash. // Verify a version 0 (see comment above) text hash.
var hashedPasswordBytes = Convert.FromBase64String(hashedPassword);
if (hashedPasswordBytes.Length != (1 + SaltSize + PBKDF2SubkeyLength) || hashedPasswordBytes[0] != 0x00) if (hashedPasswordBytes.Length != (1 + SaltSize + Pbkdf2SubkeyLength) || hashedPasswordBytes[0] != 0x00)
{ {
// Wrong length or version header. // Wrong length or version header.
return false; return false;
} }
var salt = new byte[SaltSize]; var salt = new byte[SaltSize];
Buffer.BlockCopy(hashedPasswordBytes, 1, salt, 0, SaltSize); Buffer.BlockCopy(hashedPasswordBytes, 1, salt, 0, SaltSize);
var storedSubkey = new byte[PBKDF2SubkeyLength]; var storedSubkey = new byte[Pbkdf2SubkeyLength];
Buffer.BlockCopy(hashedPasswordBytes, 1 + SaltSize, storedSubkey, 0, PBKDF2SubkeyLength); Buffer.BlockCopy(hashedPasswordBytes, 1 + SaltSize, storedSubkey, 0, Pbkdf2SubkeyLength);
var passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] generatedSubkey; var generatedSubkey = PBKDF2.DeriveKey("SHA1", passwordBytes, salt, Pbkdf2IterCount, Pbkdf2SubkeyLength);
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt, PBKDF2IterCount))
{
generatedSubkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);
}
return ByteArraysEqual(storedSubkey, generatedSubkey); return ByteArraysEqual(storedSubkey, generatedSubkey);
} }
@ -87,12 +75,10 @@ namespace Microsoft.AspNet.Identity
{ {
return true; return true;
} }
if (a == null || b == null || a.Length != b.Length) if (a == null || b == null || a.Length != b.Length)
{ {
return false; return false;
} }
var areSame = true; var areSame = true;
for (var i = 0; i < a.Length; i++) for (var i = 0; i < a.Length; i++)
{ {
@ -102,4 +88,3 @@ namespace Microsoft.AspNet.Identity
} }
} }
} }
#endif

View File

@ -12,11 +12,7 @@ namespace Microsoft.AspNet.Identity
/// <returns></returns> /// <returns></returns>
public virtual string HashPassword(string password) public virtual string HashPassword(string password)
{ {
#if NET45
return Crypto.HashPassword(password); return Crypto.HashPassword(password);
#else
return password;
#endif
} }
/// <summary> /// <summary>
@ -27,11 +23,7 @@ namespace Microsoft.AspNet.Identity
/// <returns></returns> /// <returns></returns>
public virtual PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword) public virtual PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
{ {
#if NET45
return Crypto.VerifyHashedPassword(hashedPassword, providedPassword) ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed; return Crypto.VerifyHashedPassword(hashedPassword, providedPassword) ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed;
#else
return hashedPassword == providedPassword ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed;
#endif
} }
} }
} }

View File

@ -2,10 +2,10 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using Microsoft.AspNet.DependencyInjection;
using System.Security.Claims; using System.Security.Claims;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.DependencyInjection;
namespace Microsoft.AspNet.Identity namespace Microsoft.AspNet.Identity
{ {
@ -41,7 +41,7 @@ namespace Microsoft.AspNet.Identity
PasswordHasher = serviceProvider.GetService<IPasswordHasher>(); PasswordHasher = serviceProvider.GetService<IPasswordHasher>();
UserValidator = serviceProvider.GetService<IUserValidator<TUser>>(); UserValidator = serviceProvider.GetService<IUserValidator<TUser>>();
PasswordValidator = serviceProvider.GetService<IPasswordValidator>(); PasswordValidator = serviceProvider.GetService<IPasswordValidator>();
// TODO: validator interfaces, and maybe each optional store as well? Email and SMS services? // TODO: maybe each optional store as well? Email and SMS services?
} }
/// <summary> /// <summary>
@ -57,7 +57,7 @@ namespace Microsoft.AspNet.Identity
Store = store; Store = store;
UserValidator = new UserValidator<TUser, TKey>(this); UserValidator = new UserValidator<TUser, TKey>(this);
PasswordHasher = new PasswordHasher(); PasswordHasher = new PasswordHasher();
//ClaimsIdentityFactory = new ClaimsIdentityFactory<TUser, TKey>(); //TODO: ClaimsIdentityFactory = new ClaimsIdentityFactory<TUser, TKey>();
} }
/// <summary> /// <summary>
@ -243,8 +243,7 @@ namespace Microsoft.AspNet.Identity
get get
{ {
ThrowIfDisposed(); ThrowIfDisposed();
return false; return Store is IUserClaimStore<TUser, TKey>;
//return Store is IUserClaimStore<TUser, TKey>;
} }
} }

View File

@ -2,7 +2,8 @@
"version" : "0.1-alpha-*", "version" : "0.1-alpha-*",
"dependencies": { "dependencies": {
"Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*", "Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*",
"System.Security.Claims" : "0.1-alpha-*" "System.Security.Claims" : "0.1-alpha-*",
"Microsoft.AspNet.Security.DataProtection" : "0.1-alpha-*"
}, },
"configurations": { "configurations": {
"net45": {}, "net45": {},