每天記錄學習的新知識:加密和解密

Base64的加密和解密

轉載:Java如何進行Base64的編碼(Encode)與解碼(Decode)?

Base64是一種能將任意Binary資料用64種字元組合成字串的方法,而這個Binary資料和字串資料彼此之間是可以互相轉換的,十分方便。在實際應用上,Base64除了能將Binary資料可視化之外,也常用來表示資料加密過後的內容。如果要使用Java程式語言來實作Base64的編碼與解碼功能,可以參考本篇文章的作法。

    @Test
    public void textDisplayMetrics() {
        
        final Base64.Decoder decoder = Base64.getDecoder();
        final Base64.Encoder encoder = Base64.getEncoder();

        final String text = "字串文字";
        byte[] textByte = new byte[0];
        try {
            textByte = text.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        final String encodedText = encoder.encodeToString(textByte);
        System.out.println("編碼 encodedText ==" + encodedText);

        try {
            System.out.println("解碼 ==" + new String(decoder.decode(encodedText), "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

    }

這是Java8中提供的方法,和傳統加密解密方法得到的值一致,之前的方法已經在Java9過期。

MD5加密

以下內容大部分轉載自:MD(Message Digest ) 消息摘要算法之MD5

實現

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;

public class MD5Utils {

    public static String md5(String s) {
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] btInput = s.getBytes();
            // 獲得MD5摘要算法的 MessageDigest 對象

            //// 如果輸入“SHA”,就是實現SHA加密
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            // 使用指定的字節更新摘要
            mdInst.update(btInput);
            // 獲得密文
            byte[] md = mdInst.digest();
            // 把密文轉換成十六進制的字符串形式
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 對數據,進行MD5算法的信息摘要計算
     *
     * @param data 數據的字節數組
     * @return
     */
    public static String encryptMD5(byte[] data) {
        try {
            // 判斷數據的合法性
            if (data == null) {
                throw new RuntimeException("數據不能爲NULL");
            }
            // 獲取MD5算法
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            // 加入要獲取摘要的數據
            md5.update(data);
            // 獲取數據的信息摘要
            byte[] resultBytes = md5.digest();
            // 將字節數組轉化爲16進制
            String resultString = fromBytesToHex(resultBytes);
            return resultString;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 對數據,進行MD5算法的信息摘要計算
     *
     * @param data 要進行計算信息摘要的數據
     * @return
     */
    public static String encryptMD5(String data) {
        try {
            // 判斷數據的合法性
            if (data == null) {
                throw new RuntimeException("數據不能爲NULL");
            }
            // 獲取MD5算法
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            // 加入要獲取摘要的數據
            md5.update(data.getBytes());
            // 獲取數據的信息摘要
            byte[] resultBytes = md5.digest();
            // 將字節數組轉化爲16進制
            String resultString = fromBytesToHex(resultBytes);
            return resultString;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 計算給定文件的信息摘要
     *
     * @param path 文件的路徑
     * @return
     * @throws Exception
     */
    public static String getMD5OfFile(String path) {
        FileInputStream fis = null;
        DigestInputStream dis = null;
        String resultString = null;
        try {
            fis = new FileInputStream(new File(path));
            dis = new DigestInputStream(fis, MessageDigest.getInstance("MD5"));
            // 流輸入
            byte[] buffer = new byte[1024];
            int read = dis.read(buffer, 0, 1024);
            while (read != -1) {
                read = dis.read(buffer, 0, 1024);
            }

            MessageDigest md = dis.getMessageDigest();
            byte[] resultBytes = md.digest();
            // 將字節數組轉化爲16進制
            resultString = fromBytesToHex(resultBytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 關閉流,釋放資源
            close(fis, dis);
        }
        return resultString;
    }

    public static void close(Closeable... closeables) {
        for (int i = 0; i < closeables.length; i++) {
            if (closeables[i] != null) {
                try {
                    closeables[i].close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 對數據,進行MD5算法的信息摘要計算,加入了salt
     *
     * @param data 數據的字節數組
     * @param salt 加入的鹽
     * @return
     */
    public static String encryptMD5AndSalt(byte[] data, Object salt) {
        try {
            // 將data和鹽拼接
            String datatemp = new String(data);
            String data_salt = mergeDataAndSalt(datatemp, salt);
            // 加入鹽後,數據的信息摘要
            // 獲取MD5算法
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            // 加入要獲取摘要的數據
            md5.update(data_salt.getBytes());
            // 獲取數據的信息摘要
            byte[] resultBytes = md5.digest();
            // 將字節數組轉化爲16進制
            String resultString = fromBytesToHex(resultBytes);
            return resultString;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 對數據,進行MD5算法的信息摘要計算,加入了salt
     *
     * @param data 數據的字節數組
     * @param salt 加入的鹽
     * @return
     */
    public static String encryptMD5AndSalt(String data, Object salt) {
        try {
            // 完成數據和鹽的拼接
            String data_salt = mergeDataAndSalt(data, salt);
            // 加入鹽後,數據的信息摘要
            // 獲取MD5算法
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            // 加入要獲取摘要的數據
            md5.update(data_salt.getBytes());
            // 獲取數據的信息摘要
            byte[] resultBytes = md5.digest();
            // 將字節數組轉化爲16進制
            String resultString = fromBytesToHex(resultBytes);
            return resultString;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 用於數據和salt的拼接
     *
     * @param data 要計算數據摘要的數據
     * @param salt 加入的鹽
     * @return
     */
    private static String mergeDataAndSalt(String data, Object salt) {
        if (data == null) {
            data = "";
        }

        if ((salt == null) || "".equals(salt)) {
            return data;
        } else {
            return data + "{" + salt.toString() + "}";
        }

    }

    /**
     * @param encPass 加入鹽後,計算的數據摘要
     * @param rawPass 加鹽前的數據
     * @param salt    要加入的鹽
     * @return
     */
    public static boolean isPasswordValid(String encPass, String rawPass,
                                          Object salt) {
        String data1 = encPass;
        String data2 = encryptMD5AndSalt(rawPass, salt);
        return data2.equals(data1);
    }

    /**
     * 將給定的字節數組,轉化爲16進制數據
     *
     * @param resultBytes
     * @return
     */
    private static String fromBytesToHex(byte[] resultBytes) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < resultBytes.length; i++) {
            if (Integer.toHexString(0xFF & resultBytes[i]).length() == 1) {
                builder.append("0").append(
                        Integer.toHexString(0xFF & resultBytes[i]));
            } else {
                builder.append(Integer.toHexString(0xFF & resultBytes[i]));
            }
        }
        return builder.toString();
    }
}

測試:

    @Test
    public void textDisplayMetrics() {

        final String text = "字串文字";
        byte[] textByte = new byte[0];
        try {
            textByte = text.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        System.out.println(" MD5 encryptMD5 ==" + MD5Utils.encryptMD5(text));

        System.out.println(" MD5 getMd5 ==" + com.alibaba.motu.tbrest.utils.MD5Utils.getMd5(textByte));
        System.out.println(" MD5 getMd5 ==" + com.alibaba.motu.tbrest.utils.MD5Utils.getMd5Hex(textByte));

        System.out.println(" MD5 encrypt ==" + com.taobao.android.tlog.protocol.utils.MD5Utils.encrypt(textByte));
        System.out.println(" MD5 encryptMD5 ==" + MD5Utils.encryptMD5(textByte));

    }

控制檯輸出:

 MD5 encryptMD5 ==c48582ace57f8d96c315138a2ed34148
 MD5 getMd5 ==[B@504bae78
 MD5 getMd5 ==c48582ace57f8d96c315138a2ed34148
 MD5 encrypt ==c48582ace57f8d96c315138a2ed34148
 MD5 encryptMD5 ==c48582ace57f8d96c315138a2ed34148

我原本的MD5加密是用的 com.taobao.android.tlog.protocol.utils.MD5Utils.encrypt()這個方法。

經過測試,證明都好用~

MD5是什麼?

MD5全稱爲“Message Digest Algorithm 5”,中文名“消息摘要算法第五版”,又可以稱爲消息摘要算法之MD5

消息摘要算法一個三種:

  1. MD (Message Digest) 消息摘要算法

  2. SHA(Secure Hash Algorithm) 安全散列算法

  3. MAC(Message Authentication Code) 消息認證碼算法

MD5的特點:

  1. 壓縮性:任意長度的數據,算出的MD5值長度都是固定的。
  2. 容易計算:從原數據計算出MD5值很容易。
  3. 抗修改性:對原數據進行任何改動,哪怕只修改1個字節,所得到的MD5值都有很大區別。
  4. 弱抗碰撞:已知原數據和其MD5值,想找到一個具有相同MD5值的數據(即僞造數據)是非常困難的。
  5. 強抗碰撞:想找到兩個不同的數據,使它們具有相同的MD5值,是非常困難的。

MD5實現講解:

轉載 Java 自帶的加密類MessageDigest類(加密MD5和SHA)

    /** 
     * 由於MD5 與SHA-1均是從MD4 發展而來,它們的結構和強度等特性有很多相似之處 
     * SHA-1與MD5 的最大區別在於其摘要比MD5 摘要長 32 比特(1byte=8bit,相當於長4byte,轉換16進制後比MD5多8個字符)。  
     * 對於強行攻擊,:MD5 是2128 數量級的操作,SHA-1 是2160數量級的操作。 
     * 對於相同摘要的兩個報文的難度:MD5是 264 是數量級的操作,SHA-1 是280 數量級的操作。 
     * 因而,SHA-1 對強行攻擊的強度更大。 但由於SHA-1 的循環步驟比MD5 多(80:64)且要處理的緩存大(160 比特:128 比特),SHA-1 的運行速度比MD5 慢。 
     *  
     * @param source 需要加密的字符串 
     * @param hashType 加密類型 (MD5 和 SHA) 
     * @return 
     */  
    public static String getHash(String source, String hashType) {  
        // 用來將字節轉換成 16 進製表示的字符  
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};  
  
        try {  
            MessageDigest md = MessageDigest.getInstance(hashType);  
            md.update(source.getBytes()); // 通過使用 update 方法處理數據,使指定的 byte數組更新摘要   (爲什麼需要先使用update方法   有的md5方法中怎麼不使用?)
            byte[] encryptStr = md.digest(); // 獲得密文完成哈希計算,產生128 位的長整數  
            char str[] = new char[16 * 2]; // 每個字節用 16 進製表示的話,使用兩個字符  
            int k = 0; // 表示轉換結果中對應的字符位置  
            for (int i = 0; i < 16; i++) { // 從第一個字節開始,對每一個字節,轉換成 16 進制字符的轉換  
                byte byte0 = encryptStr[i]; // 取第 i 個字節  
                str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字節中高 4 位的數字轉換, >>> 爲邏輯右移,將符號位一起右移  
                str[k++] = hexDigits[byte0 & 0xf]; // 取字節中低 4 位的數字轉換  
            }  
            return new String(str); // 換後的結果轉換爲字符串  
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
        }  
        return null;  
    }  

URL加密和解密

實現

import com.yoshin.company.blogdemo.utils.LogUtils;

import java.net.URLDecoder;
import java.net.URLEncoder;

public class UrlEncodeUtils {

    private static final String TAG = "UrlEncodeUtils";

    public static String toURLEncoded(String paramString) {
        if (paramString == null || paramString.equals("")) {
            LogUtils.w(TAG, "toURLEncoded error:" + paramString);
            return "";
        }

        try {
            String str = new String(paramString.getBytes(), "UTF-8");
            str = URLEncoder.encode(str, "UTF-8");
            return str;
        } catch (Exception localException) {
            LogUtils.e(TAG, "toURLEncoded error:" + paramString, localException);
        }

        return "";
    }


    public static String toURLDecoded(String paramString) {
        if (paramString == null || paramString.equals("")) {
            LogUtils.w(TAG, "toURLDecoded error:" + paramString);
            return "";
        }

        try {
            String str = new String(paramString.getBytes(), "UTF-8");
            str = URLDecoder.decode(str, "UTF-8");
            return str;
        } catch (Exception localException) {
            LogUtils.e(TAG, "toURLDecoded error:" + paramString, localException);
        }

        return "";
    }
    
}

測試:

    @Test
    public void textDisplayMetrics() {
        final String text = "字串文字";
        System.out.println("  toURLEncoded ==" + UrlEncodeUtils.toURLEncoded(text));
        System.out.println("  toURLDecoded ==" + UrlEncodeUtils.toURLDecoded(text));
    }

結果:

  toURLEncoded ==%E5%AD%97%E4%B8%B2%E6%96%87%E5%AD%97
  toURLDecoded ==字串文字

URL爲何需要加密?

發送給服務端的請求中的參數值,如果含有特殊符號,需要是做URLEncode,服務端纔可以正常解析,否則可能會出錯。
URLEncode主要是把一些特殊字符轉換成轉移字符,比如:&要轉換成&這樣的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章