对称加密算法
对称加密算法就是传统的用一个密钥进行加密和解密。
加密:接收密码和明文然后输出密文
解密:接收密码和密文然后输出明文
常见的对称加密算法:
算法 | 密钥长度 |
| 填充模式 | ||
DES | 56/64 | ECB/CBC/PCBC/CTR/... | NoPadding/PKCS5Padding/... | ||
AES | 128/192/256 | ECB/CBC/PCBC/CTR/... | NoPadding/PKCS5Padding/PKCS7Padding/... | ||
IDEA |
|
| PKCS5Padding/PKCS7Padding/... |
使用AES加密
两种常见的工作模式ECB,CBC
ECB模式
需要一个固定长度的密钥(128位(bit),16个字节(byte)),固定的明文会生成固定的密文。
public class ECB {
public static void main(String[] args) throws GeneralSecurityException {
// 原文:
String message = "天生我材必有用飞流直下三千尺";
System.out.println("Message(原始信息): " + message);
// 128位密钥 = 16 bytes Key:
byte[] key = "1234567890abcdef".getBytes();
// 加密:
byte[] data = message.getBytes();
byte[] encrypted = encrypt(key, data);
System.out.println("Encrypted(加密内容): " + Base64.getEncoder().encodeToString(encrypted));
// 解密:
byte[] decrypted = decrypt(key, encrypted);
System.out.println("Decrypted(解密内容): " + new String(decrypted));
}
// 加密:
public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 创建密码对象,需要传入算法/工作模式/填充模式
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// 根据key的字节内容,"恢复"秘钥对象
SecretKey keySe = new SecretKeySpec(key,"AES");
// 初始化秘钥:设置加密模式ENCRYPT_
cipher.init(Cipher.ENCRYPT_MODE, keySe);
// 根据原始内容(字节),进行加密
return cipher.doFinal(input);
}
// 解密:
public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 创建密码对象,需要传入算法/工作模式/填充模式
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// 根据key的字节内容,"恢复"秘钥对象
SecretKey keySe = new SecretKeySpec(key,"AES");
// 初始化秘钥:设置解密模式DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE,keySe);
// 根据原始内容(字节),进行解密
return cipher.doFinal(input);
}
}
ECB 模式是最简单的 AES 加密模式,这种一对一的加密方式会导致安全性降低。更好应该用CBC模式。
CBC模式
其实就是在ECB模式的基础上加了一个随机数作为 IV 参数,这样对于同一份明文,每次生成的密文都不同。每次运行结果输出的数组也会不一样。
public class CBC {
public static void main(String[] args) throws GeneralSecurityException {
// 原文:
String message = "天生我材必有用飞流直下三千尺";
System.out.println("Message(原始信息): " + message);
// 256位密钥 =32 bytes Key:
byte[] key = "1234567890abcdef1234567890abcdef".getBytes();
// 加密:
byte[] data = message.getBytes();
byte[] encrypted = encrypt(key, data);
System.out.println("Encrypted(加密内容): " + Base64.getEncoder().encodeToString(encrypted));
// 解密:
byte[] decrypted = decrypt(key, encrypted);
System.out.println("Decrypted(解密内容): " + new String(decrypted));
}
// 加密:
public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 创建密码对象,需要传入算法/工作模式/填充模式
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 根据key的字节内容,"恢复"秘钥对象
SecretKey keySe = new SecretKeySpec(key,"AES");
// CBC模式需要生成一个16 bytes的initialization vector
SecureRandom sr = SecureRandom.getInstanceStrong();
byte[] iv = sr.generateSeed(16); // 生成16个字节的随机数
System.out.println(Arrays.toString(iv));
IvParameterSpec ivps = new IvParameterSpec(iv);
// 初始化秘钥:设置加密模式,密钥,IV参数
cipher.init(Cipher.ENCRYPT_MODE, keySe,ivps);
// 加密
byte[] data = cipher.doFinal(input);
// 根据原始内容(字节),进行加密
return join(iv,data);
}
// 解密:
public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 把input分割成iv和密文
byte[] iv = new byte[16];
byte[] data = new byte[input.length-16];
//源数组,源数组要复制的起始位置 ,目标数组,目标数组复制的起始位置,复制的长度
System.arraycopy(input, 0, iv, 0, 16);
System.arraycopy(input, 16, data, 0, data.length);
System.out.println(Arrays.toString(iv));
// 解密
// 创建密码对象,需要传入算法/工作模式/填充模式
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 根据key的字节内容,"恢复"秘钥对象
SecretKey keySe = new SecretKeySpec(key,"AES");
IvParameterSpec ivps = new IvParameterSpec(iv);
// 初始化秘钥:设置解密模式DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE,keySe,ivps);
// 根据原始内容(字节),进行解密
return cipher.doFinal(data);
}
public static byte[] join(byte[] bs1,byte[] bs2) {
byte[] r = new byte[bs1.length+bs2.length];
//源数组,源数组要复制的起始位置 ,目标数组,目标数组复制的起始位置,复制的长度
System.arraycopy(bs1, 0, r, 0, bs1.length);
System.arraycopy(bs2, 0, r, bs1.length, bs2.length);
return r;
}
}