对称加密就是采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,也称为单密钥加密。
比如:凯撒加密就可以认为是一种对称加密,将偏移量
看作密钥
,加密和解密都用的是相同的偏移量(密钥)
。
常见加密算法:
特点:
ECB : Electronic codebook, 电子密码本. 需要加密的消息按照块密码的块大小被分为数个块,并对每个块进行独立加密。
CBC : Cipher-block chaining, 密码块链接. 每个明文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有明文块。
优点 : 同样的原文生成的密文不一样。
缺点 : 串行处理数据,速度较慢。
当需要按块处理的数据, 数据长度不符合块处理需求时, 按照一定的方法填充满块长的规则,分为NoPadding
和PKCS5Padding
。
NoPadding:
PKCS5Padding:
注意:
加密模式和填充模式创建模式:
AES/CBC/NoPadding (128)
AES/CBC/PKCS5Padding (128)
AES/ECB/NoPadding (128)
AES/ECB/PKCS5Padding (128)
DES/CBC/NoPadding (56)
DES/CBC/PKCS5Padding (56)
DES/ECB/NoPadding (56)
DES/ECB/PKCS5Padding (56)
将对称加密的DES和AES进行封装处理,达到一套代码实现两种加密方式,结合了加密模式和填充模式的应用,代码可以直进行使用。。
代码实现:
public class SymmetryTest {
private final static String DES = "DES";
private final static String AES = "AES";
/**
* 设置为CBC加密模式,默认情况下ECB比CBC更高效
*/
private final static String CBC = "/CBC/PKCS5Padding";
public static void main(String[] args) {
// 对称加密 密文
String input = "key=85CD019515D14B91AD942787532314FF&startTime=1629431243245&endTime=1660967243244";
// DES加密算法,key的大小必须是8个字节
String desKey = "12345678";
// AES加密算法,key的大小必须是16个字节
String aesKey = "1234567812345678";
String encryptDes = encryptBySymmetry(input, desKey, SymmetryTest.DES, true);
System.out.println("DES加密:" + encryptDes);
String des = decryptBySymmetry(encryptDes, desKey, SymmetryTest.DES, true);
System.out.println("DES解密:" + des);
System.out.println("\n==============================================\n");
String encryptAes = encryptBySymmetry(input, aesKey, SymmetryTest.AES);
System.out.println("AES加密:" + encryptAes);
String aes = decryptBySymmetry(encryptAes, aesKey, SymmetryTest.AES);
System.out.println("AES解密:" + aes);
}
/**
* 对称加密
*
* @param input : 密文
* @param key : 密钥
* @param algorithm : 类型:DES、AES
* @return
*/
public static String encryptBySymmetry(String input, String key, String algorithm) {
return encryptBySymmetry(input, key, algorithm, false);
}
/**
* 对称解密
*
* @param input : 密文
* @param key : 密钥
* @param algorithm : 类型:DES、AES
* @return
*/
public static String decryptBySymmetry(String input, String key, String algorithm) {
return decryptBySymmetry(input, key, algorithm, false);
}
/**
* 对称加密数据
*
* @param input : 原文
* @param key : 密钥
* @param algorithm : 类型:DES、AES
* @param cbc : CBC加密模式:同样的原文生成的密文不一样,串行进行,加密使用CBC解密也需要CBC
* @return : 密文
* @throws Exception
*/
public static String encryptBySymmetry(String input, String key, String algorithm, Boolean cbc) {
try {
// 根据加密类型判断key字节数
checkAlgorithmAndKey(key, algorithm);
// CBC模式
String transformation = cbc ? algorithm + CBC : algorithm;
// 获取加密对象
Cipher cipher = Cipher.getInstance(transformation);
// 创建加密规则
// 第一个参数key的字节
// 第二个参数表示加密算法
SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
// ENCRYPT_MODE:加密模式
// DECRYPT_MODE: 解密模式
// 初始化加密模式和算法
// 默认采用ECB加密:同样的原文生成同样的密文,并行进行
// CBC加密:同样的原文生成的密文不一样,串行进行
if (cbc) {
// 使用CBC模式
IvParameterSpec iv = new IvParameterSpec(key.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, sks, iv);
} else {
cipher.init(Cipher.ENCRYPT_MODE, sks);
}
// 加密
byte[] bytes = cipher.doFinal(input.getBytes());
// 输出加密后的数据
return Base64.encode(bytes);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("加密失败!");
}
}
/**
* 对称解密
*
* @param input : 密文
* @param key : 密钥
* @param algorithm : 类型:DES、AES
* @param cbc : CBC加密模式:同样的原文生成的密文不一样,串行进行,加密使用CBC解密也需要CBC
* @throws Exception
* @return: 原文
*/
public static String decryptBySymmetry(String input, String key, String algorithm, Boolean cbc) {
try {
// 根据加密类型判断key字节数
checkAlgorithmAndKey(key, algorithm);
// CBC模式
String transformation = cbc ? algorithm + CBC : algorithm;
// 1,获取Cipher对象
Cipher cipher = Cipher.getInstance(transformation);
// 指定密钥规则
SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
// 默认采用ECB加密:同样的原文生成同样的密文
// CBC加密:同样的原文生成的密文不一样
if (cbc) {
// 使用CBC模式
IvParameterSpec iv = new IvParameterSpec(key.getBytes());
cipher.init(Cipher.DECRYPT_MODE, sks, iv);
} else {
cipher.init(Cipher.DECRYPT_MODE, sks);
}
// 3. 解密,上面使用的base64编码,下面直接用密文
byte[] bytes = cipher.doFinal(Base64.decode(input));
// 因为是明文,所以直接返回
return new String(bytes);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("解密失败!");
}
}
private static void checkAlgorithmAndKey(String key, String algorithm) {
// 根据加密类型判断key字节数
int length = key.getBytes().length;
boolean typeEnable = false;
if (DES.equals(algorithm)) {
typeEnable = length == 8;
} else if (AES.equals(algorithm)) {
typeEnable = length == 16;
} else {
throw new RuntimeException("加密类型不存在");
}
if (!typeEnable) {
throw new RuntimeException("加密Key错误");
}
}
}
效果: