常用的对称加密算法


需要对加密和解密使用相同密钥的加密算法。由于其速度快,对称性加密通常在消息发送方需要加密大量数据时使用。对称性加密也称为密钥加密。

所谓对称,就是采用这种加密方法的双方使用方式用同样的密钥进行加密和解密。密钥是控制加密及解密过程的指令。算法是一组规则,规定如何进行加密和解密。

因此加密的安全性不仅取决于加密算法本身,密钥管理的安全性更是重要。因为加密和解密都使用同一个密钥,如何把密钥安全地传递到解密者手上就成了必须要解决的问题。

在对称加密算法中常用的算法有:DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK等。

下面列举几个比较常用的:

1、DES(Data Encryption Standard)

DES加密算法出自IBM的研究,后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位(8字节)密钥,以现代计算能力,
24小时内即可被破解。虽然如此,在某些简单应用中,我们还是可以使用DES加密算法

特点:数据加密标准,速度较快,适用于加密大量数据的场合

提供一个 DES 加密工具类:

package com.blog.www.util.coder;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

/**
 * DES 加密工具
 * <br/>
 * 参考:<a href='https://blog.csdn.net/bbaiggey/article/details/79414646'>java加解密之DES多种使用方式</a>
 * <br/>
 * DES加密介绍
 * <br/>
 * DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究,
 * 后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力,
 * 24小时内即可被破解。虽然如此,在某些简单应用中,我们还是可以使用DES加密算法,本文简单讲解DES的JAVA实现
 * 。
 * 注意:DES加密和解密过程中,密钥长度都必须是8的倍数
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class DESCoder {

	/**
	 * Cipher加密器初始化需要一个字符串,字符串里提供了三种设置。
	 * 一是,加解密算法;二是,加解密模式;三是,是否需要填充。
	 * <br/>
	 * ECB(电码本模式),CBC(加密块链模式),OFB(输出反馈模式),CFB(加密反馈模式)
	 */
	private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding";

	private static final String ALGORITHM = "DES";


	/**
	 * 生成密钥
	 *
	 * @param seed 偶数种子
	 */
	public static String initDesKey(String seed) throws DecoderException, NoSuchAlgorithmException {
		SecureRandom secureRandom;
		if (StringUtils.isNotBlank(seed)) {
			secureRandom = new SecureRandom(Hex.decodeHex(seed));
		} else {
			secureRandom = new SecureRandom();
		}
		// init key生成器
		KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
		kg.init(secureRandom);
		// 生成一个Key
		SecretKey secretKey = kg.generateKey();
		// 转变为字节数组
		byte[] encoded = secretKey.getEncoded();
		// 生成密钥字符串
		return Hex.encodeHexString(encoded);
	}


	/**
	 * 加密
	 *
	 * @param data 原始数据
	 * @param key  DES密钥 可使用 initDesKey() 方法获取,也可自定义(密钥长度都必须是8的倍数)
	 * @return 加密后数据
	 */
	public static String encrypt(@NonNull final String data, @NonNull String key) throws InvalidKeyException,
			InvalidKeySpecException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
			NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException {
		// 创建一个DESKeySpec对象
		DESKeySpec desKeySpec = createDesKeySpec(key);
		Cipher cipher = getCipher(desKeySpec, Cipher.ENCRYPT_MODE);
		// 现在,获取数据并加密
		return Hex.encodeHexString(cipher.doFinal(data.getBytes())).toUpperCase();
	}


	/**
	 * 解密
	 *
	 * @param data 待解密内容
	 * @param key  DES密钥 可使用 initDesKey() 方法获取,也可自定义(密钥长度都必须是8的倍数)
	 * @return 原始数据
	 */
	public static String decrypt(@NonNull final String data, @NonNull String key) throws InvalidKeyException,
			InvalidKeySpecException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
			NoSuchPaddingException, DecoderException, BadPaddingException, IllegalBlockSizeException {
		// 创建一个DESKeySpec对象
		DESKeySpec desKeySpec = createDesKeySpec(key);
		Cipher cipher = getCipher(desKeySpec, Cipher.DECRYPT_MODE);
		// 解密操作
		return new String(cipher.doFinal(Hex.decodeHex(data)));
	}


	private static DESKeySpec createDesKeySpec(String key) throws InvalidKeyException {
		// 创建一个DESKeySpec对象
		return new DESKeySpec(key.getBytes());
	}

	private static Cipher getCipher(DESKeySpec desKeySpec, Integer mode) throws NoSuchAlgorithmException, InvalidKeySpecException,
			NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException {
		// 创建一个密匙工厂
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
		// 将DESKeySpec对象转换成SecretKey对象
		SecretKey secureKey = keyFactory.generateSecret(desKeySpec);
		// Cipher对象实际完成解密操作
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
		// 用密匙初始化Cipher对象
		cipher.init(mode, secureKey, new IvParameterSpec(desKeySpec.getKey()));
		return cipher;
	}
}

使用测试:

/**
 * DES 加密测试
 */
class DesTest {
	public static void main(String[] args) {
		try {
			// 待加密字符
			String originalStr = "七里香";
			System.out.println(String.format("待加密字符: %s", originalStr));
			String desKey = DESCoder.initDesKey("12345678");
			System.out.println(String.format("密钥:%s", desKey));
			String encrypt = DESCoder.encrypt(originalStr, desKey);
			System.out.println(String.format("%s 加密结果:%s", originalStr, encrypt));
			System.out.println(String.format("%s 解密结果:%s", originalStr, DESCoder.decrypt(encrypt, desKey)));
		} catch (DecoderException | NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException
				| InvalidAlgorithmParameterException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException e) {
			e.printStackTrace();
		}
	}
}

测试结果:

20191026102555.png

2、3DES(Triple DES)

基于DES,对一块数据用三个不同的密钥进行三次加密,强度更高

3DES是三重数据加密,且可以逆推的一种算法方案。但由于3DES的算法是公开的,所以算法本身没有密钥可言,主要依靠唯一密钥来确保数据加解密的安全。到目前为止,仍没有人能破解3DES。

3DES 加密工具类:

package com.blog.www.util.coder;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.*;
import javax.crypto.spec.DESedeKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

/**
 * 3DES 加密工具
 * <br/>
 * 参考:<a href='https://www.cnblogs.com/shindo/p/6021976.html'>3DES加密算法</a>
 * <br/>
 * 3DES加密介绍
 * <br/>
 * 3DES是三重数据加密,且可以逆推的一种算法方案。
 * 但由于3DES的算法是公开的,所以算法本身没有密钥可言,
 * 主要依靠唯一密钥来确保数据加解密的安全。到目前为止,仍没有人能破解3DES。
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class DES3Coder {

	/**
	 * Cipher加密器初始化需要一个字符串,字符串里提供了三种设置。
	 * 一是,加解密算法;二是,加解密模式;三是,是否需要填充。
	 * <br/>
	 * ECB(电码本模式),CBC(加密块链模式),OFB(输出反馈模式),CFB(加密反馈模式)
	 */
	private static final String CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding";

	private static final String ALGORITHM = "DESede";


	/**
	 * 生成密钥
	 *
	 * @param seed 偶数种子
	 */
	public static String initKey(String seed) throws DecoderException, NoSuchAlgorithmException {
		SecureRandom secureRandom;
		if (StringUtils.isNotBlank(seed)) {
			secureRandom = new SecureRandom(Hex.decodeHex(seed));
		} else {
			secureRandom = new SecureRandom();
		}
		// init key生成器
		KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
		kg.init(secureRandom);
		// 生成一个Key
		SecretKey secretKey = kg.generateKey();
		// 转变为字节数组
		byte[] encoded = secretKey.getEncoded();
		// 生成密钥字符串
		return Hex.encodeHexString(encoded);
	}


	/**
	 * 加密
	 *
	 * @param data 原始数据
	 * @param key  3DES密钥对象 使用 initKey() 方法获取,也可自定义,key长度必须是大于等于 3*8 = 24 位
	 * @return 加密后数据
	 */
	public static String encrypt(@NonNull final String data, @NonNull String key) throws InvalidKeyException,
			InvalidKeySpecException, NoSuchAlgorithmException,
			NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException {
		// 创建一个DESKeySpec对象
		DESedeKeySpec deSedeKeySpec = createDesKeySpec(key);
		Cipher cipher = getCipher(deSedeKeySpec, Cipher.ENCRYPT_MODE);
		// 现在,获取数据并加密
		return Hex.encodeHexString(cipher.doFinal(data.getBytes())).toUpperCase();
	}


	/**
	 * 解密
	 *
	 * @param data 待解密内容
	 * @param key  3DES密钥对象 可使用 initKey() 方法获取,也可自定义,key长度必须是大于等于 3*8 = 24 位
	 * @return 原始数据
	 */
	public static String decrypt(@NonNull final String data, @NonNull String key) throws InvalidKeyException,
			InvalidKeySpecException, NoSuchAlgorithmException,
			NoSuchPaddingException, DecoderException, BadPaddingException, IllegalBlockSizeException {
		// 创建一个DESKeySpec对象
		DESedeKeySpec deSedeKeySpec = createDesKeySpec(key);
		Cipher cipher = getCipher(deSedeKeySpec, Cipher.DECRYPT_MODE);
		// 解密操作
		return new String(cipher.doFinal(Hex.decodeHex(data)));
	}


	/**
	 * @param key 3DES 加密, key必须是长度大于等于 3*8 = 24 位
	 * @return {@link DESedeKeySpec}
	 * @throws InvalidKeyException invalidKeyException
	 */
	private static DESedeKeySpec createDesKeySpec(String key) throws InvalidKeyException {
		// 创建一个 DESedeKeySpec 对象
		return new DESedeKeySpec(key.getBytes());
	}

	private static Cipher getCipher(DESedeKeySpec deSedeKeySpec, Integer mode) throws NoSuchAlgorithmException, InvalidKeySpecException,
			NoSuchPaddingException, InvalidKeyException {
		// 创建一个密匙工厂
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
		// 将 DESedeKeySpec 对象转换成 SecretKey 对象
		SecretKey secureKey = keyFactory.generateSecret(deSedeKeySpec);
		// Cipher对象实际完成解密操作
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
		// 用密匙初始化 Cipher对象
		cipher.init(mode, secureKey);
		return cipher;
	}

}

3DES测试:

/**
 * 3DES 加密测试
 */
class Des3Test {
	public static void main(String[] args) {
		try {
			// 待加密字符
			String originalStr = "发如雪";
			System.out.println(String.format("待加密字符: %s", originalStr));
			String des3Key = DES3Coder.initKey("4545454545AAAA");
			System.out.println(String.format("密钥:%s", des3Key));
			String encrypt = DES3Coder.encrypt(originalStr, des3Key);
			System.out.println(String.format("%s 加密结果:%s", originalStr, encrypt));
			System.out.println(String.format("%s 解密结果:%s", originalStr, DES3Coder.decrypt(encrypt, des3Key)));
		} catch (DecoderException | NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException
				| NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException e) {
			e.printStackTrace();
		}
	}
}

测试结果:

20191026105618.png

3、AES(Advanced Encryption Standard)推荐使用

密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。

这个标准用来替代原先的DES(Data Encryption Standard),已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院 (NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一 [1] 。
该算法为比利时密码学家Joan Daemen和Vincent Rijmen所设计,结合两位作者的名字,以Rijdael之名命之,投稿高级加密标准的甄选流程。(Rijdael的发音近于 “Rhine doll”。)

高级加密标准,是下一代的加密算法标准,速度快,安全级别高,支持128、192、256、512位密钥的加密。

AES 加密工具类

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

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 * AES加密
 * <br/>
 * 介绍:
 * <br/>
 * 密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。
 * <br/>
 * 这个标准用来替代原先的DES(Data Encryption Standard),已经被多方分析且广为全世界所使用。
 * 经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院 (NIST)于2001年11月26日发布于FIPS PUB 197,
 * 并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一
 * <br/>
 * 参考:
 * <ul>
 *     <li>
 *         <a href='【JAVA】AES加密 简单实现 AES-128/ECB/PKCS5Padding'>https://segmentfault.com/a/1190000015943620</a>
 *     </li>
 *     <li>
 *         <a href='Java加密技术(二)——对称加密算法DES&AES'>https://www.iteye.com/blog/snowolf-380034</a>
 *     </li>
 * </ul>
 * <p>
 * <br/>
 *
 * @author :leigq
 * @date :2019/8/8 17:20
 */
@Slf4j
public class AESCoder {

	/**
	 * Cipher加密器初始化需要一个字符串,字符串里提供了三种设置。
	 * 一是,加解密算法;二是,加解密模式;三是,是否需要填充。
	 * <br/>
	 * ECB(电码本模式),CBC(加密块链模式),OFB(输出反馈模式),CFB(加密反馈模式)
	 */
	private static final String CIPHER_MODE = "AES/ECB/PKCS5Padding";

	private static final String ALGORITHM = "AES";

	/**
	 * 生成密钥
	 */
	public static String initAesKey(String seed) throws NoSuchAlgorithmException, DecoderException {
		SecureRandom secureRandom;
		if (StringUtils.isNotBlank(seed)) {
			secureRandom = new SecureRandom(Hex.decodeHex(seed));
		} else {
			secureRandom = new SecureRandom();
		}
		// init key生成器
		KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
		// 要生成多少位,只需要修改这里即可 128, 192 或 256,单位 bit
		kg.init(128, secureRandom);
		// 生成一个Key
		SecretKey secretKey = kg.generateKey();
		// 转变为字节数组
		byte[] encoded = secretKey.getEncoded();
		// 生成密钥字符串
		return Hex.encodeHexString(encoded);
	}

	/**
	 * AES加密
	 *
	 * @param data 待加密的数据
	 * @param key  密钥
	 * @return 加密后的数据
	 */
	public static String encrypt(String data, String key) {
		try {
			Cipher cipher = getCipher(key, Cipher.ENCRYPT_MODE);
			return Hex.encodeHexString(cipher.doFinal(data.getBytes())).toUpperCase();
		} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | DecoderException | IllegalBlockSizeException | BadPaddingException e) {
			log.error("加密异常:", e);
			return null;
		}
	}


	/**
	 * AES解密
	 *
	 * @param data 待解密的数据
	 * @param key  密钥
	 * @return 解密后的数据
	 */
	public static String decrypt(String data, String key) {
		try {
			Cipher cipher = getCipher(key, Cipher.DECRYPT_MODE);
			return new String(cipher.doFinal(Hex.decodeHex(data)));
		} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | DecoderException | IllegalBlockSizeException | BadPaddingException e) {
			log.error("解密异常:", e);
			return null;
		}
	}

	private static Cipher getCipher(String key, Integer mode) throws NoSuchAlgorithmException,
			NoSuchPaddingException, InvalidKeyException, DecoderException {
		// 创建密匙
		SecretKey secretKey = new SecretKeySpec(Hex.decodeHex(key), ALGORITHM);
		// Cipher 对象实际完成解密操作
		Cipher cipher = Cipher.getInstance(CIPHER_MODE);
		// 用密匙初始化 Cipher 对象
		cipher.init(mode, secretKey);
		return cipher;
	}

}

使用测试:

/**
 * AES 加密测试
 */
class AesTest {
	public static void main(String[] args) {
		try {
			// 待加密字符
			String originalStr = "美女,约吗?";
			System.out.println(String.format("待加密字符: %s", originalStr));
			String aesKey = AESCoder.initAesKey(null);
			System.out.println(String.format("密钥:%s", aesKey));
			String encrypt = AESCoder.encrypt(originalStr, aesKey);
			System.out.println(String.format("%s 加密结果:%s", originalStr, encrypt));
			System.out.println(String.format("%s 解密结果:%s", originalStr, AESCoder.decrypt(encrypt, aesKey)));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

测试结果:

20191026152340.png

posted @ 2019-10-26 17:21  leigq  阅读(1996)  评论(0编辑  收藏  举报