java实现Django的PBKDF2PasswordHasher加密算法
来源:互联网 发布:php var_export 编辑:程序博客网 时间:2024/05/18 03:25
因为业务的需要,java要实现Django的PBKDF2PasswordHasher加密算法。本来以为算法嘛,知道源码,自己模仿写一套应该很简单,事实却是打脸了!在同事的帮忙下分析了半天的python源码,终于明白加密后的是下面这种格式的字符串:
<algorithm>$<iterations>$<salt>$<hash>
上面就是用于储存用户密码的部分,以美元字符分分隔并由哈希算法、算法迭代次数(工作因数)、随机的salt、以及生成的密码哈希值组成。算法是Django可以使用的,单向哈希或者密码储存算法之一。详细介绍请参考:http://python.usyiyi.cn/translate/django_182/topics/auth/passwords.html
下面的工具类是根据https://gist.github.com/lukaszb/1af1bd4233326e37a8a0代码基础上添加了生成随机的salt。
package test;/* Example implementation of password hasher similar on Django's PasswordHasher * Requires Java8 (but should be easy to port to older JREs) * Currently it would work only for pbkdf2_sha256 algorithm */import java.nio.charset.Charset;import java.security.NoSuchAlgorithmException;import java.security.spec.InvalidKeySpecException;import java.security.spec.KeySpec;import java.util.Base64;import java.util.Random;import javax.crypto.SecretKey;import javax.crypto.SecretKeyFactory;import javax.crypto.spec.PBEKeySpec;class Hasher { public final Integer DEFAULT_ITERATIONS = 20000; public final String algorithm = "pbkdf2_sha256"; public Hasher() {} public String getEncodedHash(String password, String salt, int iterations) { // Returns only the last part of whole encoded password SecretKeyFactory keyFactory = null; try { keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); } catch (NoSuchAlgorithmException e) { System.err.println("Could NOT retrieve PBKDF2WithHmacSHA256 algorithm"); System.exit(1); } KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt.getBytes(Charset.forName("UTF-8")), iterations, 256); SecretKey secret = null; try { secret = keyFactory.generateSecret(keySpec); } catch (InvalidKeySpecException e) { System.out.println("Could NOT generate secret key"); e.printStackTrace(); } byte[] rawHash = secret.getEncoded(); byte[] hashBase64 = Base64.getEncoder().encode(rawHash); return new String(hashBase64); } /** * make salt * @return String */ private static String getsalt(){ int length = 12; Random rand = new Random(); char[] rs = new char[length]; for(int i = 0; i < length; i++){ int t = rand.nextInt(3); if (t == 0) { rs[i] = (char)(rand.nextInt(10)+48); } else if (t == 1) { rs[i] = (char)(rand.nextInt(26)+65); } else { rs[i] = (char)(rand.nextInt(26)+97); } } return new String(rs); } /** * rand salt * iterations is default 20000 * @param password * @return */ public String encode(String password) { return this.encode(password, getsalt()); } /** * rand salt * @param password * @return */ public String encode(String password,int iterations) { return this.encode(password, getsalt(),iterations); } /** * iterations is default 20000 * @param password * @param salt * @return */ public String encode(String password, String salt) { return this.encode(password, salt, this.DEFAULT_ITERATIONS); } /** * * @param password * @param salt * @param iterations * @return */ public String encode(String password, String salt, int iterations) { // returns hashed password, along with algorithm, number of iterations and salt String hash = getEncodedHash(password, salt, iterations); return String.format("%s$%d$%s$%s", algorithm, iterations, salt, hash); } public boolean checkPassword(String password, String hashedPassword) { // hashedPassword consist of: ALGORITHM, ITERATIONS_NUMBER, SALT and // HASH; parts are joined with dollar character ("$") String[] parts = hashedPassword.split("\\$"); if (parts.length != 4) { // wrong hash format return false; } Integer iterations = Integer.parseInt(parts[1]); String salt = parts[2]; String hash = encode(password, salt, iterations); return hash.equals(hashedPassword); } public static void main(String[] args) { runTests(); } // Following examples can be generated at any Django project: // // >>> from django.contrib.auth.hashers import make_password // >>> make_password('mystery', hasher='pbkdf2_sha256') # salt would be randomly generated // 'pbkdf2_sha256$10000$HqxvKtloKLwx$HdmdWrgv5NEuaM4S6uMvj8/s+5Yj+I/d1ay6zQyHxdg=' // >>> make_password('mystery', salt='mysalt', hasher='pbkdf2_sha256') // 'pbkdf2_sha256$10000$mysalt$KjUU5KrwyUbKTGYkHqBo1IwUbFBzKXrGQgwA1p2AuY0=' // // // mystery // pbkdf2_sha256$10000$qx1ec0f4lu4l$3G81rAm/4ng0tCCPTrx2aWohq7ztDBfFYczGNoUtiKQ= // // s3cr3t // pbkdf2_sha256$10000$BjDHOELBk7fR$xkh1Xf6ooTqwkflS3rAiz5Z4qOV1Jd5Lwd8P+xGtW+I= // // puzzle // pbkdf2_sha256$10000$IFYFG7hiiKYP$rf8vHYFD7K4q2N3DQYfgvkiqpFPGCTYn6ZoenLE3jLc= // // riddle // pbkdf2_sha256$10000$A0S5o3pNIEq4$Rk2sxXr8bonIDOGj6SU4H/xpjKHhHAKpFXfmNZ0dnEY= private static void runTests() { System.out.println(new Hasher().encode("123456", 20000)); System.out.println("==========================="); System.out.println("= Testing password hasher ="); System.out.println("==========================="); System.out.println(); String result = (new Hasher()).encode("123456", "sdSn1014Ipgx", 20000); System.out.println(result); System.out.println(); passwordShouldMatch("123456", "pbkdf2_sha256$20000$2uuTxG6587YA$xL2ygkbvlW63xQW7SSvlHkNl6xvipByGiuFTJzp0N28="); passwordShouldMatch("123456", "pbkdf2_sha256$20000$sdSn1014Ipgx$DM5NiPLH2UN1LgV/0QPsSYLuekWi8KfdV1pDYCK3zfU="); passwordShouldMatch("mystery", "pbkdf2_sha256$10000$qx1ec0f4lu4l$3G81rAm/4ng0tCCPTrx2aWohq7ztDBfFYczGNoUtiKQ="); passwordShouldMatch("mystery", "pbkdf2_sha256$10000$mysalt$KjUU5KrwyUbKTGYkHqBo1IwUbFBzKXrGQgwA1p2AuY0="); // custom salt passwordShouldMatch("s3cr3t", "pbkdf2_sha256$10000$BjDHOELBk7fR$xkh1Xf6ooTqwkflS3rAiz5Z4qOV1Jd5Lwd8P+xGtW+I="); passwordShouldMatch("puzzle", "pbkdf2_sha256$10000$IFYFG7hiiKYP$rf8vHYFD7K4q2N3DQYfgvkiqpFPGCTYn6ZoenLE3jLc="); passwordShouldMatch("riddle", "pbkdf2_sha256$10000$A0S5o3pNIEq4$Rk2sxXr8bonIDOGj6SU4H/xpjKHhHAKpFXfmNZ0dnEY="); } private static void passwordShouldMatch(String password, String expectedHash) { Hasher hasher = new Hasher(); if (hasher.checkPassword(password, expectedHash)) { System.out.println(" => OK"); } else { String[] parts = expectedHash.split("\\$"); if (parts.length != 4) { System.out.printf(" => Wrong hash provided: '%s'\n", expectedHash); return; } String salt = parts[2]; String resultHash = hasher.encode(password, salt); String msg = " => Wrong! Password '%s' hash expected to be '%s' but is '%s'\n"; System.out.printf(msg, password, expectedHash, resultHash); } }}
阅读全文
1 0
- java实现Django的PBKDF2PasswordHasher加密算法
- 加密算法的Java实现
- java的MD5加密算法实现
- java实现的MD5加密算法
- DES加密算法的java实现
- base64加密算法的java实现
- java Aes256 加密算法的实现
- MD5加密算法的java实现
- RSA加密算法的java实现
- MD5加密算法的java实现
- Java MD5加密算法的实现
- Java MD5加密算法的实现
- 常用加密算法的Java实现
- 常用加密算法的Java实现
- MD5加密算法的java实现
- MD5加密算法的Java实现
- 常用加密算法的Java实现
- AES加密算法的JAVA实现
- C进阶之递归应用
- Tolua使用笔记三:Tolua协程用法
- 微博环境下利用综合策略构建推荐引擎
- 络性能测试工具iperf详细使用图文教程【转载】
- linux work queue
- java实现Django的PBKDF2PasswordHasher加密算法
- (108)调用事件调度器
- javaScript中with函数用法实例分析
- 怎么恢复回收站清空的文件
- IDE文件识别错误导致开发人员没有找出错误
- 七天学会ASP.NET MVC (五)——Layout页面使用和用户角色管理
- LeetCode 61 Rotate List
- Node.Js运行Express框架中遇到的问题(备忘)
- js阻止冒泡