1. 程式人生 > >加密演算法簡要介紹與JAVA實現

加密演算法簡要介紹與JAVA實現

【1】MD5是什麼

MD5即Message-Digest Algorithm 5(資訊-摘要演算法5),用於確保資訊傳輸完整一致。是計算機廣泛使用的雜湊演算法之一(又譯摘要演算法、雜湊演算法),主流程式語言普遍已有MD5實現。將資料(如漢字)運算為另一固定長度值,是雜湊演算法的基礎原理,MD5的前身有MD2、MD3和MD4。

該演算法的檔案號為:

RFC 1321(R.Rivest,MIT Laboratory for Computer Science and RSA Data Security Inc. April 1992)

MD5的作用是讓大容量資訊在用數字簽名軟體簽署私人金鑰前被”壓縮”成一種保密的格式(就是把一個任意長度的位元組串變換成一定長的十六進位制數字串)。除了MD5以外,其中比較有名的還有sha-1、RIPEMD以及Haval等。

對MD5演算法簡要的敘述可以為:MD5以512位分組來處理輸入的資訊,且每一分組又被劃分為16個32位子分組,經過了一系列的處理後,演算法的輸出由四個32位分組組成,將這四個32位分組級聯後將生成一個128位雜湊值。

128位雜湊值轉換為16進位制字串為32個字元。即,加密後的結果為32位16進位制的字串。

經典的雜湊(雜湊)演算法還有:MD2、MD4 和 SHA-1(目的是將任意長輸入通過演算法變為固定長輸出,且保證輸入變化一點輸出都不同,且不能反向解密)。

【2】MD5的特點

① 長度固定

不管多長的字串,加密後長度都是一樣長,方便平時資訊的統計和管理。

② 容易計算

從原資料計算出MD5值很容易。

③ 抗修改性

對原資料進行任何改動,哪怕只修改1個位元組,所得到的MD5值都有很大區別。

④ 強抗碰撞

已知原資料和其MD5值,想找到一個具有相同MD5值的資料(即偽造資料)是非常困難的(並非不可以)。

【3】MD5加密過程

第一種,加密字串

① 獲取資訊摘要物件:md5

通過資訊摘要單例的建構函式獲取:

MessageDigest md5 = MessageDigest.getInstance("MD5");

② 獲取摘要位元組陣列

兩種方式:

byte[] bytes = str.getBytes();
byte
[] digest = md5.digest(bytes); 或 byte[] bytes = str.getBytes(); md5.update(bytes); byte[] digest = md5.digest();

③ 把摘要陣列中的每一個位元組轉換成16進位制,並拼在一起就得到了MD5值.

第二種,加密檔案

方法傳入的是檔案物件 : file

① 因為是檔案不是方法,所以不是像剛才那樣通過摘要獲取字串。

② 使用到另一個方法即可:就是資訊摘要物件更新:md5.update(byte[] input)方法,用法是通過讀取流,不斷的更新從流中讀到的”資訊陣列”。

③ 然後通過”資訊摘要物件”獲取摘要,不用引數:md5.digest(),此時返回的陣列就已經是包含內容的摘要陣列了。

④ 把摘要陣列中的每一個位元組轉換成16進位制,並拼在一起就得到了MD5值。

同樣來源除了檔案還可以是url,過程同上。

【4】MD5工具類

package com.web.encrypt;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


public class MD5Util {
    // 用來將位元組轉換成 16 進製表示的字元
    private static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd','e', 'f' };
    protected static MessageDigest messagedigest = null;

    static {
        try {
            messagedigest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException nsaex) {
            System.err.println(MD5Util.class.getName()
                    + "初始化失敗,MessageDigest不支援MD5Util。");
            nsaex.printStackTrace();
        }
    }

    // 加密字串
    public static String getMD5(String str){

        byte[] bs = str.getBytes();

        return getMD5FromByte(bs);
    }

    private static String getMD5FromByte(byte[] source) {
        String s = null;

        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
            md.update(source);
            byte tmp[] = messagedigest.digest();
            // MD5 的計算結果是一個 128 位的長整數(16個位元組),轉為16進位制則為32個字元
            char str[] = new char[16 * 2]; 
    // 每個位元組用 16 進製表示的話,使用兩個字元(一個8位->2個4位->2個16進位制字元),所以表示成 16 進位制需要 32 個字元
            int k = 0; // 表示轉換結果中對應的字元位置
            for (int i = 0; i < 16; i++) { 
                // 從第一個位元組開始,對 MD5 的每一個位元組
                // 轉換成 16 進位制字元的轉換
                byte byte0 = tmp[i]; // 取第 i 個位元組
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                 // 取位元組中高 4 位的數字轉換,>>>為邏輯右移,將符號位一起右移
                str[k++] = hexDigits[byte0 & 0xf];
                 // 取位元組中低 4 位的數字轉換
            }
            s = new String(str); 
            // 換後的結果轉換為字串

        } catch (Exception e) {
            e.printStackTrace();
        }
        return s;
    }

    // 加密檔案物件
    public static String getFileMD5String(File file) throws FileNotFoundException {  
        String value = null;  
        FileInputStream in = new FileInputStream(file);  
        try {  
            MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());  
            MessageDigest md5 = MessageDigest.getInstance("MD5");  
            md5.update(byteBuffer);  
            BigInteger bi = new BigInteger(1, md5.digest());  
            value = bi.toString(16);  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            if(null != in) {  
                try {  
                    in.close();  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
        return value;  
    }  

    //引數為檔案路徑
    public static String getFileMD5String(String  filePath) throws FileNotFoundException {  
            String value = null;  
            File file=new File(filePath);
            FileInputStream in = new FileInputStream(file);  
        try {  
            MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());  
            MessageDigest md5 = MessageDigest.getInstance("MD5");  
            md5.update(byteBuffer);  
            BigInteger bi = new BigInteger(1, md5.digest());  
            value = bi.toString(16);  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
                if(null != in) {  
                    try {  
                    in.close();  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
           return value;  
        }  

    //引數為url
    public static String getFileMD5StringByURL(String urlString) throws IOException {       

        URL url = new URL(urlString);

        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        BufferedInputStream fis = null;

        fis = new BufferedInputStream(connection.getInputStream());

        byte[] buffer = new byte[1024];
        int numRead = 0;
        while ((numRead = fis.read(buffer)) > 0) {

            messagedigest.update(buffer, 0, numRead);
        }
        fis.close();
        return bufferToHex(messagedigest.digest());
    }

    //引數為位元組陣列
    public static String getMD5String(byte[] bytes) {
        messagedigest.update(bytes);
        return bufferToHex(messagedigest.digest());
    }

    // 將位元組陣列轉換為16進位制的字串
    private static String bufferToHex(byte bytes[]) {
        int m = 0;
        int n = bytes.length;
        StringBuffer stringbuffer = new StringBuffer(2 * n);
        int k = m + n;
        for (int l = m; l < k; l++) {
            appendHexPair(bytes[l], stringbuffer);
        }
        return stringbuffer.toString();
    }

    private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
        char c0 = hexDigits[(bt & 0xf0) >> 4];
        // 取位元組中高 4 位的數字轉換, >>> 為邏輯右移,將符號位一起右移
        char c1 = hexDigits[bt & 0xf];
        // 取位元組中低 4 位的數字轉換 
        stringbuffer.append(c0);
        stringbuffer.append(c1);
    }

}