MD5加密+加鹽

瞭解: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

相關文章
相關標籤/搜索