什么是哈希加盐法?
废话少说:对于MD5这种加密算法,同样的密码每次加密后得到的密文是一样的,所以黑客可以利用已知的密码库(彩虹库)对目标数据库密文进行对比进行攻击。
怎样解决:哈希加盐法,以下是网上给出的方案。http://blog.csdn.net/cryeyes/article/details/5375810
方案一:将用户密码与固定salt字串进行拼接,再进行Hash计算得到密文。
此方案的缺点很明显,通过密码库进行对比,直接可获得很多[用户密码 + salt]的字串,即可推断出salt字串,改进算法,获得用户密码。
方案二:先为用户生成随机salt字串,进行方案一的计算,然后将随机salt字串,作为一列存储在用户表中进行登录验证。
此方案可以明显改进方案一,因为salt不重复,所以加大破解难度。
AspNet.Identity 是怎么做的?
上反编译神器,反编译Dll --> Microsoft.AspNet.Identity.Core.dll,先定位到创建用户方法CreateAsync(TUser user, string password)
再往下看,已经找到加密方法了,GOGOGO。
最后会到这里,核心加密的地方了,如图:
这里Rfc2898DeriveBytes的构造方法的第二个参数的意义是随机生成16位的Salt,第一个参数构造为一个hmacsha1,为后面的hash做基础数据。
第三个参数是什么意思呢?在后面的方法得到验证是将密码进行多少次hash,1000次……
具体算法太复杂,伤不起,也没必要看了,关键是了解方法,总结一下流程:
1.随机生成一个16位的salt字节数组。
2.通过计算密码与salt得到32位密文。
3.组建一个49位字节数组,第一位固定为0x00,2 - 17位为salt,18 - 49位为密文。
4.对字节数组进行Base64加密得到最终密文。
现在是不是你也可以使用哈希加盐法设计一个自己的用户密码加密算法了呢?
如何在自己代码中使用?
方案一:
这是在asp.net mvc中的实现,如果在低版本或客户端,如何实现类似的功能呢,通过gg得知,原来Rfc2898DeriveBytes已经是NF中的一个加密工具类,那么自己实现就很简单了,就是抄反编译出的代码嘛。http://msdn.microsoft.com/zh-cn/library/system.security.cryptography.rfc2898derivebytes(v=vs.110).aspx
1 internal static class Crypto 2 { 3 private const int PBKDF2IterCount = 1000; 4 5 private const int PBKDF2SubkeyLength = 32; 6 7 private const int SaltSize = 16; 8 9 private static bool ByteArraysEqual(byte[] a, byte[] b) 10 { 11 if (object.ReferenceEquals(a, b)) 12 { 13 return true; 14 } 15 if (a == null || b == null || (int)a.Length != (int)b.Length) 16 { 17 return false; 18 } 19 bool flag = true; 20 for (int i = 0; i < (int)a.Length; i++) 21 { 22 flag = flag & a[i] == b[i]; 23 } 24 return flag; 25 } 26 27 public static string HashPassword(string password) 28 { 29 byte[] salt; 30 byte[] bytes; 31 if (password == null) 32 { 33 throw new ArgumentNullException("password"); 34 } 35 using (Rfc2898DeriveBytes rfc2898DeriveByte = new Rfc2898DeriveBytes(password, 16, 1000)) 36 { 37 salt = rfc2898DeriveByte.Salt; 38 bytes = rfc2898DeriveByte.GetBytes(32); 39 } 40 byte[] numArray = new byte[49]; 41 Buffer.BlockCopy(salt, 0, numArray, 1, 16); 42 Buffer.BlockCopy(bytes, 0, numArray, 17, 32); 43 return Convert.ToBase64String(numArray); 44 } 45 46 public static bool VerifyHashedPassword(string hashedPassword, string password) 47 { 48 byte[] bytes; 49 if (hashedPassword == null) 50 { 51 return false; 52 } 53 if (password == null) 54 { 55 throw new ArgumentNullException("password"); 56 } 57 byte[] numArray = Convert.FromBase64String(hashedPassword); 58 if ((int)numArray.Length != 49 || numArray[0] != 0) 59 { 60 return false; 61 } 62 byte[] numArray1 = new byte[16]; 63 Buffer.BlockCopy(numArray, 1, numArray1, 0, 16); 64 byte[] numArray2 = new byte[32]; 65 Buffer.BlockCopy(numArray, 17, numArray2, 0, 32); 66 using (Rfc2898DeriveBytes rfc2898DeriveByte = new Rfc2898DeriveBytes(password, numArray1, 1000)) 67 { 68 bytes = rfc2898DeriveByte.GetBytes(32); 69 } 70 return Crypto.ByteArraysEqual(numArray2, bytes); 71 } 72 }
方案二:
更懒一点你就直接使用Microsoft.AspNet.Identity.Core中的PasswordHasher工具类吧。