文章目录

  • java数据安全 系列文章
  • 一、maven依赖
  • 二、对称加密算法
  • 1、介绍
  • 2、DES
  • 1)、介绍
  • 2)、应用场景
  • 3)、DES示例
  • 1、实现源码
  • 2、testNG测试
  • 4)、3DES示例
  • 1、实现源码
  • 2、testNG测试
  • 3、AES
  • 1)、介绍
  • 2)、应用场景
  • 3)、示例
  • 1、实现源码
  • 2、testNG测试
  • 4、IDEA
  • 1)、介绍
  • 2)、应用场景
  • 3)、示例
  • 1、实现源码
  • 2、testNG测试
  • 5、PBE
  • 1)、介绍
  • 2)、应用场景
  • 3)、示例
  • 1、实现源码
  • 2、testNG测试



本文简单的介绍了对称加密的5种(DES/3DES、AES、IDEA、PBE)常见算法的使用示例,并给出推荐的应用示例。

一、maven依赖

<dependency>
			<groupId>org.testng</groupId>
			<artifactId>testng</artifactId>
			<version>6.9.10</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
			<version>1.11</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
		<dependency>
			<groupId>org.bouncycastle</groupId>
			<artifactId>bcprov-jdk15on</artifactId>
			<version>1.60</version>
		</dependency>

二、对称加密算法

1、介绍

对称加密就是加密与解密拥有相同的密钥,根据加密方式可分为密码和分组密码。
分组密码工作模式可分为ECB、CBC、CFB、OFB和CTR等,密钥长度决定了加密算法的安全性。
常见的加密算法有DES或3DES、AES和RC系列算法,除此之外,还有Blowfish、Twofish、Serpent、IDEA和PBE等。

2、DES

1)、介绍

DES(Data Encryption Standard)数据加密标准,其衍生算法有DESede(3DES),由于安全性的原因AES逐步替代DES。

2)、应用场景

应用于安全性要求不高的对称加密场景,基本上不用DES,3DES是其替代。

3)、DES示例

以下是jdk实现示例

1、实现源码

import java.security.Key;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

/**
 * @author alan 2018年11月16日
 */
public class DESCoder {
	/**
	 * 密钥算法 <br>
	 * Java 6 只支持56bit密钥 <br>
	 * Bouncy Castle 支持64bit密钥
	 */
	public static final String KEY_ALGORITHM = "DES";
	/**
	 * 加密/解密算法 / 工作模式 / 填充方式
	 */
	public static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5PADDING";

	/**
	 * 转换密钥
	 * 
	 * @param key
	 *            二进制密钥
	 * @return Key 密钥
	 * @throws Exception
	 */
	private static Key toKey(byte[] key) throws Exception {
		// 实例化DES密钥材料
		DESKeySpec dks = new DESKeySpec(key);
		// 实例化秘密密钥工厂
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
		// 生成秘密密钥
		SecretKey secretKey = keyFactory.generateSecret(dks);
		return secretKey;
	}

	/**
	 * 解密
	 * 
	 * @param data
	 *            待解密数据
	 * @param key
	 *            密钥
	 * @return byte[] 解密数据
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
		// 还原密钥
		Key k = toKey(key);
		// 实例化
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
		// 初始化,设置为解密模式
		cipher.init(Cipher.DECRYPT_MODE, k);
		// 执行操作
		return cipher.doFinal(data);
	}

	/**
	 * 加密
	 * 
	 * @param data
	 *            待加密数据
	 * @param key
	 *            密钥
	 * @return byte[] 加密数据
	 * @throws Exception
	 */
	public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
		// 还原密钥
		Key k = toKey(key);
		// 实例化
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
		// 初始化,设置为加密模式
		cipher.init(Cipher.ENCRYPT_MODE, k);
		// 执行操作
		return cipher.doFinal(data);
	}

	/**
	 * 生成密钥 <br>
	 * Java 6 只支持56bit密钥 <br>
	 * Bouncy Castle 支持64bit密钥 <br>
	 * 
	 * @return byte[] 二进制密钥
	 * @throws Exception
	 */
	public static byte[] initKey() throws Exception {
		/*
		 * 实例化密钥生成器
		 * 
		 * 若要使用64bit密钥注意替换 将下述代码中的KeyGenerator.getInstance(CIPHER_ALGORITHM);
		 * 替换为KeyGenerator.getInstance(CIPHER_ALGORITHM, "BC");
		 */
		KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
		/*
		 * 初始化密钥生成器 若要使用64bit密钥注意替换 将下述代码kg.init(56); 替换为kg.init(64);
		 */
		kg.init(56, new SecureRandom());
		// 生成秘密密钥
		SecretKey secretKey = kg.generateKey();
		// 获得密钥的二进制编码形式
		return secretKey.getEncoded();
	}
}

2、testNG测试

import static org.testng.Assert.assertEquals;

import org.apache.commons.codec.binary.Base64;
import org.testng.annotations.Test;

/**
 * @author alan 2018年11月16日
 */
public class DESCoderTest {
	@Test
	public final void test() throws Exception {
		String inputStr = "DES";
		byte[] inputData = inputStr.getBytes();
		System.err.println("原文:\t" + inputStr);

		// 初始化密钥
		byte[] key = DESCoder.initKey();
		System.err.println("密钥:\t" + Base64.encodeBase64String(key));

		// 加密
		inputData = DESCoder.encrypt(inputData, key);
		System.err.println("加密后:\t" + Base64.encodeBase64String(inputData));

		// 解密
		byte[] outputData = DESCoder.decrypt(inputData, key);
		String outputStr = new String(outputData);
		System.err.println("解密后:\t" + outputStr);

		// 校验
		assertEquals(inputStr, outputStr);
	}
}

4)、3DES示例

以下是jdk实现示例

1、实现源码

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;

/**
 * @author alan 2018年11月16日
 */
public class DESedeCoder {
	public static final String KEY_ALGORITHM = "DESede";

	/**
	 * 加密/解密算法 / 工作模式 / 填充方式 Java 6支持PKCS5PADDING填充方式 Bouncy
	 * Castle支持PKCS7Padding填充方式
	 */
	public static final String CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding";

	/**
	 * 转换密钥
	 * 
	 * @param key
	 *            二进制密钥
	 * @return Key 密钥
	 * @throws Exception
	 */
	private static Key toKey(byte[] key) throws Exception {
		// 实例化DES密钥材料
		DESedeKeySpec dks = new DESedeKeySpec(key);
		// 实例化秘密密钥工厂
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
		// 生成秘密密钥
		SecretKey secretKey = keyFactory.generateSecret(dks);
		return secretKey;
	}

	/**
	 * 解密
	 * 
	 * @param data
	 *            待解密数据
	 * @param key
	 *            密钥
	 * @return byte[] 解密数据
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
		// 还原密钥
		Key k = toKey(key);
		/*
		 * 实例化 使用PKCS7Padding填充方式 Cipher.getInstance(CIPHER_ALGORITHM, "BC");
		 */
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
		// 初始化,设置为解密模式
		cipher.init(Cipher.DECRYPT_MODE, k);
		// 执行操作
		return cipher.doFinal(data);
	}

	/**
	 * 加密
	 * 
	 * @param data
	 *            待加密数据
	 * @param key
	 *            密钥
	 * @return byte[] 加密数据
	 * @throws Exception
	 */
	public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
		// 还原密钥
		Key k = toKey(key);
		/*
		 * 实例化 使用PKCS7Padding填充方式 Cipher.getInstance(CIPHER_ALGORITHM, "BC");
		 */
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
		// 初始化,设置为加密模式
		cipher.init(Cipher.ENCRYPT_MODE, k);
		// 执行操作
		return cipher.doFinal(data);
	}

	/**
	 * 生成密钥 <br>
	 * 
	 * @return byte[] 二进制密钥
	 * @throws Exception
	 */
	public static byte[] initKey() throws Exception {
		// 实例化
		KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
		/*
		 * DESede 要求密钥长度为 112位或168位
		 */
		kg.init(168);
		// 生成秘密密钥
		SecretKey secretKey = kg.generateKey();
		// 获得密钥的二进制编码形式
		return secretKey.getEncoded();
	}
}

2、testNG测试

import static org.testng.Assert.assertEquals;

import org.apache.commons.codec.binary.Base64;
import org.testng.annotations.Test;

/**
 * @author alan 2018年11月16日
 */
public class DESedeCoderTest {
	@Test
	public final void test() throws Exception {
		String inputStr = "DESede";
		byte[] inputData = inputStr.getBytes();
		System.err.println("原文:\t" + inputStr);

		// 初始化密钥
		byte[] key = DESedeCoder.initKey();
		System.err.println("密钥:\t" + Base64.encodeBase64String(key));

		// 加密
		inputData = DESedeCoder.encrypt(inputData, key);
		System.err.println("加密后:\t" + Base64.encodeBase64String(inputData));

		// 解密
		byte[] outputData = DESedeCoder.decrypt(inputData, key);

		String outputStr = new String(outputData);
		System.err.println("解密后:\t" + outputStr);

		// 校验
		assertEquals(inputStr, outputStr);
	}
}

3、AES

1)、介绍

AES(Advanced Encryption Standard)高级数据加密标准,作为DES算法的替代。AES算法具有密钥建立时间短、灵敏性好、内存需求低等优点,应用比较广泛。

2)、应用场景

作为DES的替代,在对称加密中一般场合的首选。

3)、示例

以下是jdk实现示例

1、实现源码

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * @author alan 2018年11月16日
 */
public class AESCoder {
	public static final String KEY_ALGORITHM = "AES";

	/**
	 * 加密/解密算法 / 工作模式 / 填充方式 Java 6支持PKCS5Padding填充方式 Bouncy
	 * Castle支持PKCS7Padding填充方式
	 */
	public static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";

	/**
	 * 转换密钥
	 * 
	 * @param key
	 *            二进制密钥
	 * @return Key 密钥
	 * @throws Exception
	 */
	private static Key toKey(byte[] key) throws Exception {
		// 实例化AES密钥材料
		SecretKey secretKey = new SecretKeySpec(key, KEY_ALGORITHM);
		return secretKey;
	}

	/**
	 * 解密
	 * 
	 * @param data
	 *            待解密数据
	 * @param key
	 *            密钥
	 * @return byte[] 解密数据
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
		// 还原密钥
		Key k = toKey(key);
		/*
		 * 实例化 使用PKCS7Padding填充方式,按如下方式实现 Cipher.getInstance(CIPHER_ALGORITHM, "BC");
		 */
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
		// 初始化,设置为解密模式
		cipher.init(Cipher.DECRYPT_MODE, k);
		// 执行操作
		return cipher.doFinal(data);
	}

	/**
	 * 加密
	 * 
	 * @param data
	 *            待加密数据
	 * @param key
	 *            密钥
	 * @return byte[] 加密数据
	 * @throws Exception
	 */
	public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
		// 还原密钥
		Key k = toKey(key);
		/*
		 * 实例化 使用PKCS7Padding填充方式,按如下方式实现 Cipher.getInstance(CIPHER_ALGORITHM, "BC");
		 */
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
		// 初始化,设置为加密模式
		cipher.init(Cipher.ENCRYPT_MODE, k);
		// 执行操作
		return cipher.doFinal(data);
	}

	/**
	 * 生成密钥 <br>
	 * 
	 * @return byte[] 二进制密钥
	 * @throws Exception
	 */
	public static byte[] initKey() throws Exception {
		// 实例化
		KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
		/*
		 * AES 要求密钥长度为 128位、192位或 256位
		 */
		kg.init(256);
		// 生成秘密密钥
		SecretKey secretKey = kg.generateKey();
		// 获得密钥的二进制编码形式
		return secretKey.getEncoded();
	}
}

2、testNG测试

import static org.testng.Assert.assertEquals;

import org.apache.commons.codec.binary.Base64;
import org.testng.annotations.Test;

/**
 * @author alan 2018年11月16日
 */
public class AESCoderTest {
	@Test
	public final void test() throws Exception {
		String inputStr = "AES";
		byte[] inputData = inputStr.getBytes();
		System.err.println("原文:\t" + inputStr);

		// 初始化密钥
		byte[] key = AESCoder.initKey();
		System.err.println("密钥:\t" + Base64.encodeBase64String(key));

		// 加密
		inputData = AESCoder.encrypt(inputData, key);
		System.err.println("加密后:\t" + Base64.encodeBase64String(inputData));

		// 解密
		byte[] outputData = AESCoder.decrypt(inputData, key);
		String outputStr = new String(outputData);
		System.err.println("解密后:\t" + outputStr);

		// 校验
		assertEquals(inputStr, outputStr);
	}
}

4、IDEA

1)、介绍

IDEA(International Data Encryption Algorithm)国际数据加密算法是一种对称分组密码,其密钥长度为128位,数据块大小为64位,目前常用的场景是邮件加密算法。

2)、应用场景

目前常用的场景是邮件加密算法

3)、示例

以下是bouncy castle实现示例

1、实现源码

import java.security.Key;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

/**
 * @author alan 2018年11月16日
 */
public class IDEACoder {
	public static final String KEY_ALGORITHM = "IDEA";

	/**
	 * 加密/解密算法 / 工作模式 / 填充方式
	 */
	public static final String CIPHER_ALGORITHM = "IDEA/ECB/PKCS5Padding";

	/**
	 * 转换密钥
	 * 
	 * @param key
	 *            二进制密钥
	 * @return Key 密钥
	 * @throws Exception
	 */
	private static Key toKey(byte[] key) throws Exception {
		// 生成秘密密钥
		SecretKey secretKey = new SecretKeySpec(key, KEY_ALGORITHM);
		return secretKey;
	}

	/**
	 * 解密
	 * 
	 * @param data
	 *            待解密数据
	 * @param key
	 *            密钥
	 * @return byte[] 解密数据
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
		// 加入BouncyCastleProvider支持
		Security.addProvider(new BouncyCastleProvider());
		// 还原密钥
		Key k = toKey(key);
		// 实例化
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
		// 初始化,设置为解密模式
		cipher.init(Cipher.DECRYPT_MODE, k);
		// 执行操作
		return cipher.doFinal(data);
	}

	/**
	 * 加密
	 * 
	 * @param data
	 *            待加密数据
	 * @param key
	 *            密钥
	 * @return byte[] 加密数据
	 * @throws Exception
	 */
	public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
		// 加入BouncyCastleProvider支持
		Security.addProvider(new BouncyCastleProvider());
		// 还原密钥
		Key k = toKey(key);
		// 实例化
		Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
		// 初始化,设置为加密模式
		cipher.init(Cipher.ENCRYPT_MODE, k);
		// 执行操作
		return cipher.doFinal(data);
	}

	/**
	 * 生成密钥 <br>
	 * 
	 * @return byte[] 二进制密钥
	 * @throws Exception
	 */
	public static byte[] initKey() throws Exception {
		// 加入BouncyCastleProvider支持
		Security.addProvider(new BouncyCastleProvider());
		// 实例化
		KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
		// 初始化
		kg.init(128);
		// 生成秘密密钥
		SecretKey secretKey = kg.generateKey();
		// 获得密钥的二进制编码形式
		return secretKey.getEncoded();
	}
}

2、testNG测试

import static org.testng.Assert.assertEquals;

import org.apache.commons.codec.binary.Base64;
import org.testng.annotations.Test;

/**
 * @author alan 2018年11月16日
 */
public class IDEACoderTest {
	@Test
	public final void test() throws Exception {

		String inputStr = "IDEA";
		byte[] inputData = inputStr.getBytes();
		System.err.println("原文:\t" + inputStr);

		// 初始化密钥
		byte[] key = IDEACoder.initKey();
		System.err.println("密钥:\t" + Base64.encodeBase64String(key));

		// 加密
		inputData = IDEACoder.encrypt(inputData, key);
		System.err.println("加密后:\t" + Base64.encodeBase64String(inputData));

		// 解密
		byte[] outputData = IDEACoder.decrypt(inputData, key);
		String outputStr = new String(outputData);
		System.err.println("解密后:\t" + outputStr);

		// 校验
		assertEquals(inputStr, outputStr);
	}
}

5、PBE

1)、介绍

PBE(Password Based Encryption)基于密码加密算法是一种基于密码的加密算法,其特点是密码(password)由用户自己保管,采用随机数(加盐)杂凑多重加密等方法保证数据的安全性。PBE没有密钥,其密码(password)代替了密钥,为了增加密码的安全性,采用了加盐的处理方式。PBE是对称加密算法的综合性算法,常见的算法有PBEWithMD5AndDES,该算法是使用了MD5和DES构建PBE算法。

2)、应用场景

PBE算法通常用于需要用户输入口令的场合,例如保护用户数据。

3)、示例

以下是jdk实现示例

1、实现源码

import java.security.Key;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

/**
 * @author alan 2018年11月16日
 */
public class PBECoder {
	/**
	 * Java 6 支持以下任意一种算法
	 * 
	 * <pre>
	 * PBEWithMD5AndDES 
	 * PBEWithMD5AndTripleDES 
	 * PBEWithSHA1AndDESede
	 * PBEWithSHA1AndRC2_40
	 * </pre>
	 */
	public static final String ALGORITHM = "PBEWithMD5AndTripleDES";

	/**
	 * 盐初始化<br>
	 * 盐长度必须为8字节
	 * 
	 * @return byte[] 盐
	 * @throws Exception
	 */
	public static byte[] initSalt() throws Exception {
		SecureRandom random = new SecureRandom();
		return random.generateSeed(8);
	}

	/**
	 * 转换密钥
	 * 
	 * @param password 密码
	 * @return Key 密钥
	 * @throws Exception
	 */
	private static Key toKey(String password) throws Exception {
		// 密钥材料转换
		PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
		// 实例化
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
		// 生成密钥
		SecretKey secretKey = keyFactory.generateSecret(keySpec);
		return secretKey;
	}

	/**
	 * 加密
	 * 
	 * @param data     数据
	 * @param password 密码
	 * @param salt     盐
	 * @return byte[] 加密数据
	 * @throws Exception
	 */
	public static byte[] encrypt(byte[] data, String password, byte[] salt) throws Exception {
		// 转换密钥
		Key key = toKey(password);
		// 实例化PBE参数材料
		PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
		// 实例化
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		// 初始化
		cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
		// 执行操作
		return cipher.doFinal(data);
	}

	/**
	 * 解密
	 * 
	 * @param data     数据
	 * @param password 密码
	 * @param salt     盐
	 * @return byte[] 解密数据
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] data, String password, byte[] salt) throws Exception {
		// 转换密钥
		Key key = toKey(password);
		// 实例化PBE参数材料
		PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
		// 实例化
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		// 初始化
		cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
		// 执行操作
		return cipher.doFinal(data);
	}
}

2、testNG测试

import static org.testng.Assert.assertEquals;

import org.apache.commons.codec.binary.Base64;
import org.testng.annotations.Test;

/**
 * @author alan 2018年11月16日
 */
public class PBECoderTest {
	@Test
	public void test() throws Exception {
		String inputStr = "PBE";
		System.err.println("原文:" + inputStr);
		byte[] input = inputStr.getBytes();

		String pwd = "alanchan";
		System.err.println("密码:\t" + pwd);

		// 初始化盐
		byte[] salt = PBECoder.initSalt();
		System.err.println("盐:\t" + Base64.encodeBase64String(salt));

		// 加密
		byte[] data = PBECoder.encrypt(input, pwd, salt);
		System.err.println("加密后:\t" + Base64.encodeBase64String(data));

		// 解密
		byte[] output = PBECoder.decrypt(data, pwd, salt);
		String outputStr = new String(output);
		System.err.println("解密后:\t" + outputStr);

		// 校验
		assertEquals(inputStr, outputStr);
	}
}

以上,简单的介绍了对称加密的5种常见算法的使用示例,并给出推荐的应用示例。