对称加密算法:指用一个秘钥进行加密和解密。加密就是接收秘钥和原文,返回密文。解密就是接收秘钥和密文,返回原文。对称加密算法中的秘钥是一个自己给定的、固定长度(16字节)的。
常见的对称加密算法有:DES,AES,IDEA
AES算法常见的工作模式是:ECB和CBC.
1、AES算法+ECB工作模式(安全性低):同一个秘钥和原文只会生成一个密文。
在加密过程中,需要自定义函数encrypt进行加密处理;在加密过程中,需要自定义函数decrypt进行解密处理。在加密/解密的过程中,需要创建Cipher对象.传入加密使用的算法,工作模式,填充模式。
public class Demo01 {
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();
//调用自定义的函数encrypt,传入秘钥和原文字节数组
byte[] encrypted = encrypt(key, data);
//输出,调用Base64类,将加密内容(字节数组)编码成字符串
System.out.println("Encrypted(加密内容): " + Base64.getEncoder().encodeToString(encrypted));
// 解密:
byte[] decrypted = decrypt(key, encrypted);
//System.out.println(decrypted.length);
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 keySec = new SecretKeySpec(key,"AES");
// 初始化秘钥:设置加密模式ENCRYPT_
cipher.init(Cipher.ENCRYPT_MODE, keySec);
// 根据原始内容(字节),进行加密
return cipher.doFinal(input);
}
// 解密:
public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 创建密码对象,需要传入算法/工作模式/填充模式
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// 根据key的字节内容,"恢复"秘钥对象
SecretKey keySec = new SecretKeySpec(key,"AES");
// 初始化秘钥:设置解密模式DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE, keySec);
// 根据原始内容(字节),进行解密
return cipher.doFinal(input);
}
}
2、AES加密+CBC工作模式(安全性较高):同一个秘钥和原文,因为IV参数的随机产生,所以每次生成的密文都不一样。
CBC工作模式比ECB工作模式多了个参数,需要生成一个16字节的随机数作为IV参数。与密钥和原文一起进行加密处理生成密文。
//AES+CBC
public class Demo02 {
public static void main(String[] args) throws Exception {
// 原文:
String message = "Hello world!";
System.out.println("Message(原始信息): " + message);
// 256位密钥 = 32 bytes Key:
byte[] key = "1234567890ascfvgedcfth623fg5634f".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 {
// 设置算法/工作模式CBC/填充方式
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 恢复秘钥对象
SecretKey keySec = new SecretKeySpec(key,"AES");
// CBC模式需要生成一个16 bytes的initialization vector:
SecureRandom sr = SecureRandom.getInstanceStrong();
//生成16个字节的随机数
byte[] iv = sr.generateSeed(16);
System.out.println("iv字节数组(内容):"+Arrays.toString(iv));
System.out.println("iv字节数组(长度):"+iv.length);
//随机数封装成IVParameterSpec参数对象
IvParameterSpec ivps = new IvParameterSpec(iv);
// 初始化秘钥:操作模式、秘钥、IV参数
cipher.init(Cipher.ENCRYPT_MODE, keySec,ivps);
// 加密
byte[] data = cipher.doFinal(input);
// IV不需要保密,把IV和密文一起返回:
//先将IV放进数组,因为IV的长度固定
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];
//iv
System.arraycopy(input,0,iv,0,16);
//密文
System.arraycopy(input,16,data,0,data.length);
System.out.println(Arrays.toString(iv));
// 解密:
// 设置算法/工作模式CBC/填充方式
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 根据key的字节内容,"恢复"秘钥对象
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
// 根据iv的字节内容,"恢复"IVParameterSpec对象
IvParameterSpec ivps = new IvParameterSpec(iv);
// 初始化秘钥:操作模式、秘钥、IV参数
cipher.init(Cipher.DECRYPT_MODE, keySpec,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;
}
}