瞭解:java
- MD5加密,是屬於不可逆的。咱們知道正常使用MD5加密技術,同一字符,加密後的16進制數是不變的,自從出現彩虹表,對於公司內部員工來講,能夠反查數據,獲取不可能的權限,因此出現了salt算法。
代碼以下:
package com.md5.demo; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * 普通的MD加密 * @author peaceliu * */ public class MD5Utils { /** * 使用md5的算法進行加密 */ public static String md5(String plainText) { byte[] secretBytes = null; try { secretBytes = MessageDigest.getInstance("md5").digest(plainText.getBytes()); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("沒有md5這個算法!"); } String md5code = new BigInteger(1, secretBytes).toString(16);// 16進制數字 // 若是生成數字未滿32位,須要前面補0 for (int i = 0; i < 32 - md5code.length(); i++) { md5code += "0"; } return md5code; } public static void main(String[] args) { System.out.println(md5("lhp")); } }
- 通常使用的加鹽:
md5(Password+UserName),即將用戶名和密碼字符串相加再MD5,這樣的MD5摘要基本上不可反查。
但有時候用戶名可能會發生變化,發生變化後密碼即不可用了(驗證密碼實際上就是再次計算摘要的過程)。
----------- 所以咱們作了一個很是簡單的加鹽算法,每次保存密碼到數據庫時,都生成一個隨機16位數字,將這16位數字和密碼相加再求MD5摘要,而後在摘要中再將這16位數字按規則摻入造成一個48位的字符串。
- 在驗證密碼時再從48位字符串中按規則提取16位數字,和用戶輸入的密碼相加再MD5。按照這種方法造成的結果確定是不可直接反查的,且同一個密碼每次保存時造成的摘要也都是不一樣的。
代碼以下:
package com.md5.demo; import java.security.MessageDigest; import java.util.Random; import org.apache.commons.codec.binary.Hex; /** * MD5加鹽加密 */ public class PasswordUtil { /** * 生成含有隨機鹽的密碼 */ public static String generate(String password) { Random r = new Random(); StringBuilder sb = new StringBuilder(16); sb.append(r.nextInt(99999999)).append(r.nextInt(99999999)); int len = sb.length(); if (len < 16) { for (int i = 0; i < 16 - len; i++) { sb.append("0"); } } String salt = sb.toString(); password = md5Hex(password + salt); char[] cs = new char[48]; for (int i = 0; i < 48; i += 3) { cs[i] = password.charAt(i / 3 * 2); char c = salt.charAt(i / 3); cs[i + 1] = c; cs[i + 2] = password.charAt(i / 3 * 2 + 1); } return new String(cs); } /** * 校驗密碼是否正確 */ public static boolean verify(String password, String md5) { char[] cs1 = new char[32]; char[] cs2 = new char[16]; for (int i = 0; i < 48; i += 3) { cs1[i / 3 * 2] = md5.charAt(i); cs1[i / 3 * 2 + 1] = md5.charAt(i + 2); cs2[i / 3] = md5.charAt(i + 1); } String salt = new String(cs2); return md5Hex(password + salt).equals(new String(cs1)); } /** * 獲取十六進制字符串形式的MD5摘要 */ public static String md5Hex(String src) { try { MessageDigest md5 = MessageDigest.getInstance("MD5"); byte[] bs = md5.digest(src.getBytes()); return new String(new Hex().encode(bs)); } catch (Exception e) { return null; } } }
測試:算法
public static void main(String[] args) { // 加密+加鹽 String password1 = generate("admin"); System.out.println("結果:" + password1 + " 長度:"+ password1.length()); // 解碼 System.out.println(verify("admin", password1)); // 加密+加鹽 String password2= generate("admin"); System.out.println("結果:" + password2 + " 長度:"+ password2.length()); // 解碼 System.out.println(verify("admin", password2)); }
結果:shell