java 密碼非對(duì)稱加密和驗(yàn)證

為什么持久化的時(shí)候要加密

密碼肯定是不能明文存儲(chǔ)的,要不然數(shù)據(jù)庫(kù)被攻破,就可以獲得大批對(duì)應(yīng)個(gè)人信息的密碼,畢竟很多人就那幾個(gè)密碼,拿著個(gè)人信息和密碼去試試沒(méi)準(zhǔn)就破解了了一大堆賬號(hào)。再者密碼明文存儲(chǔ),萬(wàn)一有個(gè)搞 事情的員工,可以輕易的獲取客戶的密碼信息,很不安全的。更多危害請(qǐng)自行百度,總之就是不能明文存儲(chǔ)。

什么是哈希算法

簡(jiǎn)單的說(shuō)哈希算法是一個(gè)多對(duì)一的映射函數(shù),他有兩個(gè)重要的性質(zhì):不可逆無(wú)沖突。
因?yàn)槭且粋€(gè)多對(duì)一映射,可以由多個(gè)x推出y,但是不能由y推出他是來(lái)源于哪個(gè)x,這就是不可逆。
無(wú)沖突是值當(dāng)你知道一個(gè)x可以推出y,你無(wú)法推出另一個(gè)可以推出y的x。
不可逆意味著不可能獲取明文信息,無(wú)沖突意味著不可能破解加密算法。這兩個(gè)理論上都是不能實(shí)現(xiàn)的,但是如果正向計(jì)算很容易,逆向計(jì)算窮盡計(jì)算資源也做不到就認(rèn)為已經(jīng)實(shí)現(xiàn)了不可逆和無(wú)沖突。所以哈希算法是一種不可逆的非對(duì)稱加密算法。

使用加鹽哈希加密密碼基本思路

鹽值來(lái)源于英文salt,應(yīng)該是佐料差不多的意思,加鹽哈希的基本思路就是生成一堆隨機(jī)字符作為salt值混入要加密的數(shù)據(jù)中,然后進(jìn)行多次哈希獲取最終的哈希值,并將哈希值和salt保存到數(shù)據(jù)庫(kù)等實(shí)現(xiàn)持久化。驗(yàn)證數(shù)據(jù)的時(shí)候使用相同的salt值以同樣的算法插入并進(jìn)行哈希計(jì)算出新的哈希值與查出來(lái)的哈希值進(jìn)行對(duì)比是否一致。
這里需要保存哈希值和salt值兩個(gè)值,也可以簡(jiǎn)單直接將salt插入哈希值中存儲(chǔ),解密的時(shí)候?qū)?duì)應(yīng)位置的值截取出來(lái)作為salt。

java代碼實(shí)現(xiàn):

maven導(dǎo)包:

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.12</version>
</dependency>

核心代碼:

package lixingchen.FlexBlog.common.utils;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringEscapeUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;

public class SecurityUtils {

    //搗亂的鹽值長(zhǎng)度
    public static final int SALT_SIZE = 16;
    //采用的哈希算法
    private static final String SHA256 = "SHA-256";
    //安全隨機(jī)函數(shù)
    private static SecureRandom random = new SecureRandom();
    //哈希次數(shù)
    public static final int HASH_INTERATIONS = 1024;

    /**
     * Hex編碼.byte[]轉(zhuǎn)為數(shù)據(jù)庫(kù)可以存取的String
     */
    public static String encodeHex(byte[] input) {
        return new String(Hex.encodeHex(input));
    }

    /**
     * Hex解碼.
     */
    public static byte[] decodeHex(String input) {
        try {
            return Hex.decodeHex(input.toCharArray());
        } catch (DecoderException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 生成隨機(jī)的Byte[]作為salt.
     *
     * @param numBytes byte數(shù)組的大小
     */
    private static byte[] generateSalt(int numBytes) {
        byte[] bytes = new byte[numBytes];
        random.nextBytes(bytes);
        return bytes;
    }

    /**
     *
     * @param input
     * @param algorithm hash算法
     * @param salt
     * @param iterations 哈希次數(shù)
     * @return
     */
    private static byte[] digest(byte[] input, String algorithm, byte[] salt,int iterations) {
        try {
            MessageDigest digest = MessageDigest.getInstance(algorithm);
            if (salt != null) {
                digest.update(salt);
            }
            byte[] result = digest.digest(input);
            for (int i = 1; i < iterations; i++) {
                digest.reset();
                result = digest.digest(result);
            }
            return result;
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 傳入明文密碼,生成密文密碼
     */
    public static String entryptPassword(String plainPassword) {
        String plain =StringEscapeUtils.unescapeHtml(plainPassword);
        byte[] salt = generateSalt(SALT_SIZE);
        byte[] hashPassword = digest(plain.getBytes(),SHA256, salt, HASH_INTERATIONS);
        return encodeHex(salt) + encodeHex(hashPassword);
    }

    /**
     * 對(duì)比
     * @param plainPassword(明文密碼)
     * 與
     * @param encryptedPassword(密文密碼)
     */
    public static boolean comparePassword(String plainPassword,String encryptedPassword) {
        byte[] salt = decodeHex(encryptedPassword.substring(0, 32));//一個(gè)英文字符倆字節(jié),截取16位鹽值
        String plain = StringEscapeUtils.unescapeHtml(plainPassword);
        byte[] hashPassword = digest(plain.getBytes(),SHA256, salt, HASH_INTERATIONS);
        return  encodeHex(hashPassword).equals(encryptedPassword.substring(32));
    }
    /**
     * @param args
     */
    public static void main(String[] args)throws Exception {
        String plainPassword = "123456中文qwetyu";
        String encryptedPassword = entryptPassword(plainPassword);
        System.out.println(encryptedPassword);
        System.out.println(comparePassword(plainPassword,encryptedPassword));
        System.out.println(comparePassword("wrong_password",encryptedPassword));
    }
}

執(zhí)行結(jié)果

77a8063988c6f69e661f5a256e8a72670442cfc26be36ed98dca1788529d26a05cd428ba1142a7d7448e95f5dd7b71e2
true
false
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容