天天看點

淺談幾種常見的加密算法一、編碼格式 (這個按道理來講是算不上加密的,但是比較常用)二、消息摘要算法 (這個按道理來講是算不上加密的,但是比較常用)三、對稱加密四、非對稱加密線上加密測試工具參考相關文章

文章目錄

  • 一、編碼格式 (這個按道理來講是算不上加密的,但是比較常用)
  • 二、消息摘要算法 (這個按道理來講是算不上加密的,但是比較常用)
  • 三、對稱加密
  • 四、非對稱加密
  • 線上加密測試工具
  • 參考相關文章

下面所有代碼都是基于

jdk8

所有基于Apache的實作都需要引入下面這個包:

<!-- apache.codec:編碼方法的工具類包 -->
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.11</version>
</dependency>
           

一、編碼格式 (這個按道理來講是算不上加密的,但是比較常用)

編碼格式算法

二、消息摘要算法 (這個按道理來講是算不上加密的,但是比較常用)

消息摘要算法

基于上面的

編碼格式算法

消息摘要算法

寫了一個基礎加密工具,

對稱加密

非對稱加密

有單獨的工具類,往下看就知道了。

package com.blog.www.util.coder.base;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
import org.springframework.util.Base64Utils;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.util.Objects;
import java.util.Random;

/**
 * 基礎編碼工具類
 * <br/>
 * 包含以下幾種加密:
 * <ul>
 *     <li>Base64</li>
 *     <li>URLEncoder、URLDecoder</li>
 *     <li>MD5</li>
 *     <li>MD5加随機鹽</li>
 *     <li>SHA</li>
 *     <li>MAC</li>
 * </ul>
 * <p>
 * 注意: <br>
 * Base64加密可逆,一般用來編碼資訊發送,甚至可以把圖檔轉換成字元串發送到前端顯示。注意不要用來發送機密資訊! <br>
 * MD5、SHA、MAC這三種加密算法,是不可逆加密,我們通常隻把他們作為加密的基礎。單純的以上三種的加密并不可靠。
 * <p>
 * 建立人:leigq <br>
 * 建立時間:2017年10月23日 下午10:39:06 <br>
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class BaseCoderUtils {
	/* ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ BASE64 編碼、解碼 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */

	/**
	 * BASE64加密
	 * <br/>
	 *
	 * @param binaryData 待加密二進制資料
	 * @return 加密後字元串
	 */
	public static String encryptBase64(final byte[] binaryData) {
		// 安卓自帶實作,因為安卓用不了Apache的實作,是以隻能用自帶的實作。注意,Base64.CRLF才對應Apache的預設模式!
		// return Base64.encodeToString(key, Base64.CRLF);
		return Base64Utils.encodeToString(binaryData);
	}

	/**
	 * BASE64解密
	 * <br/>
	 *
	 * @param base64String 加密後字元串
	 * @return 原始二進制資料
	 */
	public static byte[] decryptBase64(final String base64String) {
		// 安卓自帶實作
		// return Base64.decode(key, Base64.CRLF);
		return Base64Utils.decodeFromString(base64String);
	}
	/* ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ BASE64 編碼、解碼 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ */






	/* ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ URL 編碼、解碼  ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */

	/**
	 * 将 URL 編碼
	 */
	public static String encodeURL(final String data) {
		String target;
		try {
			target = URLEncoder.encode(data, StandardCharsets.UTF_8.name());
		} catch (Exception e) {
			log.error("編碼出錯!", e);
			throw new RuntimeException(e);
		}
		return target;
	}

	/**
	 * 将 URL 解碼
	 */
	public static String decodeURL(final String data) {
		String target;
		try {
			target = URLDecoder.decode(data, StandardCharsets.UTF_8.name());
		} catch (Exception e) {
			log.error("解碼出錯!", e);
			throw new RuntimeException(e);
		}
		return target;
	}
	/* ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ URL 編碼、解碼  ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ */







	/* ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ MD5加密相關  ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */

	/**
	 * MD5加密
	 *
	 * @param data
	 * @return 大寫
	 */
	public static String encryptMD5(final byte[] data) {
		return DigestUtils.md5Hex(data).toUpperCase();
	}

	/**
	 * MD5加密,字元串到字元串
	 *
	 * @param data
	 * @return 大寫
	 */
	public static String encryptMD5(final String data) {
		return encryptMD5(data.getBytes());
	}

	/**
	 * 3次MD5加密,字元串到字元串
	 *
	 * @param data
	 * @return 大寫
	 */
	public static String encryptTriMD5(final String data) {
		int count = 3;
		String md5 = data;
		for (int i = 0; i < count; i++) {
			md5 = encryptMD5(md5);
		}
		return md5;
	}

	/**
	 * 生成含有随機鹽的加密字元串
	 *
	 * @param data 待加密的字元
	 * @return 加密後的字元(含 16 位随機鹽),大寫
	 */
	public static String encryptMD5WithRandomSalt(final String data) {
		return encryptMd5WithRandomSalt(data);
	}

	/**
	 * 校驗密碼是否正确
	 *
	 * @param data              待驗證的字元(明文)
	 * @param md5StringWithSalt 加密後的字元(含 16 位随機鹽)
	 * @return 驗證結果
	 */
	public static boolean verifyMD5WithRandomSalt(final String data, final String md5StringWithSalt) {
		return verifyMd5WithRandomSalt(data, md5StringWithSalt);
	}
	/* ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ MD5加密相關  ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ */




	/* ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ SHA 加密 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */
	/**
	 * 預設使用 SHA-1 20位元組 160位
	 * 其他還有:
	 * SHA-224 32位元組 224位
	 * SHA-256 32位元組 256位
	 * SHA-384 48位元組 384位
	 * SHA-512 64位元組 512位
	 * 由于它産生的資料摘要的長度更長,是以更難以發生碰撞,是以較之MD5更為安全,它是未來資料摘要算法的發展方向。
	 * 由于SHA系列算法的資料摘要長度較長,是以其運算速度與MD5相比,也相對較慢。
	 */
	/**
	 * SHA 加密
	 *
	 * @param data
	 * @return
	 */
	public static String encryptSHA(final byte[] data) {
		return DigestUtils.sha1Hex(data).toUpperCase();

	}

	/**
	 * SHA 加密,字元串到字元串 <br>
	 * <br>
	 *
	 * @param data
	 * @return
	 */
	public static String encryptSHA(final String data) {
		return DigestUtils.sha1Hex(data).toUpperCase();
	}
	/* ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ SHA 加密 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ */




	/* ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ MAC加密相關 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */
	/**
	 * 預設使用 HmacMD5 加密。
	 * 其他還有:
	 * HmacSHA1
	 * HmacSHA256
	 * HmacSHA384
	 * HmacSHA512
	 */
	/**
	 * 初始化 MAC 密鑰
	 *
	 * @return MAC 密鑰
	 * @throws NoSuchAlgorithmException
	 */
	public static String initMacKey() throws NoSuchAlgorithmException {
		KeyGenerator keyGenerator = KeyGenerator.getInstance(HmacAlgorithms.HMAC_MD5.getName());
		SecretKey secretKey = keyGenerator.generateKey();
		return encryptBase64(secretKey.getEncoded());
	}

	/**
	 * MAC 加密
	 *
	 * @param data 待加密資料
	 * @param key  密鑰,可用 initMacKey() 方法生成,也可自定義
	 * @return 加密後資料
	 */
	public static String encryptHMAC(final byte[] data, final String key) {
		HmacUtils hmacMd5 = new HmacUtils(HmacAlgorithms.HMAC_MD5, key);
		return hmacMd5.hmacHex(data).toUpperCase();
	}
	/* ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ MAC加密相關 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ */


	/**
	 * 生成含有随機鹽的加密字元串
	 *
	 * @param data 待加密的字元
	 * @return 加密後的字元(含 16 位随機鹽),大寫
	 */
	private static String encryptMd5WithRandomSalt(String data) {
		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();
		String md5WithSaltStr = DigestUtils.md5Hex(data + salt);
		char[] cs = new char[48];
		for (int i = 0; i < 48; i += 3) {
			cs[i] = md5WithSaltStr.charAt(i / 3 * 2);
			char c = salt.charAt(i / 3);
			cs[i + 1] = c;
			cs[i + 2] = md5WithSaltStr.charAt(i / 3 * 2 + 1);
		}
		return new String(cs).toUpperCase();
	}

	/**
	 * 校驗密碼是否正确
	 *
	 * @param data                    待驗證的字元(明文)
	 * @param md5StrContainRandomSalt 加密後的字元(含 16 位随機鹽)
	 * @return 驗證結果
	 */
	private static boolean verifyMd5WithRandomSalt(String data, String md5StrContainRandomSalt) {
		// 32 位加密字元(不含鹽)
		char[] cs1 = new char[32];
		// 16 位的随機鹽
		char[] cs2 = new char[16];
		for (int i = 0; i < 48; i += 3) {
			cs1[i / 3 * 2] = md5StrContainRandomSalt.charAt(i);
			cs1[i / 3 * 2 + 1] = md5StrContainRandomSalt.charAt(i + 2);
			cs2[i / 3] = md5StrContainRandomSalt.charAt(i + 1);
		}
		String salt = new String(cs2);
		return Objects.equals(DigestUtils.md5Hex(data + salt).toUpperCase(), new String(cs1));
	}

}
           

三、對稱加密

對稱加密

四、非對稱加密

先來看看這兩篇文章,幫助了解

非對稱加密

數字簽名

,寫得挺好的。

  • RSA算法原理(一)
  • RSA算法原理(二)
  • 數字簽名是什麼?

非對稱加密

線上加密測試工具

線上加密解密工具

參考相關文章

  • Java加密技術(一)——BASE64與單向加密算法MD5&SHA&MAC
  • Java加密技術(二)——對稱加密算法DES&AES
  • 【JAVA】AES加密 簡單實作 AES-128/ECB/PKCS5Padding
  • java加解密之DES多種使用方式
  • 3DES加密算法
  • Java加密技術(四)——非對稱加密算法RSA
  • RSA加密解密及數字簽名Java實作
  • AES apache commons-crypto 對稱加密