zoukankan      html  css  js  c++  java
  • 浅谈几种常见的加密算法


    下面所有代码都是基于 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));
    	}
    
    }
    

    三、对称加密

    对称加密

    四、非对称加密

    先来看看这两篇文章,帮助理解 非对称加密数字签名,写得挺好的。

    非对称加密

    在线加密测试工具

    在线加密解密工具

    参考相关文章


    作者:不敲代码的攻城狮
    出处:https://www.cnblogs.com/leigq/
    任何傻瓜都能写出计算机可以理解的代码。好的程序员能写出人能读懂的代码。

     
  • 相关阅读:
    万恶的VS2010 快捷键
    C# 入门篇之listview用法
    MySQL安装常见错误及解决方案
    【转】MySQL命令
    #字符串 770. 单词替换
    #字符串 字符串替换 POJ
    # 4 Values whose Sum is 0 (POJ
    #Shopping HDU
    #疯狂搜索( POJ-1200) #哈希
    #哈希 题目:Eqs(POJ
  • 原文地址:https://www.cnblogs.com/leigq/p/13406512.html
Copyright © 2011-2022 走看看