对称加密
概述:对称加密算法就是传统的用一个密码加密和解密,在软件开发中,常用的对称加密算法有:
算法 | 密钥长度 | 工作模式 | 填充模式 |
DES | 56/64 | ECB/CBC/PCBC/... | NopPadding/PKCS5Padding/... |
AES | 128/192/256 | ECB/CBC/PCBC/... | NopPadding/PKCS5Padding//PKCS7Padding/... |
IDEA | 128 | ECB | PKCS5Padding//PKCS7Padding/... |
密钥的长度直接决定加密强度,而工作模式和填充模式可以看成是对对称加密算法的参数和格式选择。Java标准库提供的算法实现并不包括所有的工作模式和填充模式。但是我们通常只需要挑选常用的使用就可以了 。DES算法由于密钥过短,可以在短时间内暴力破解,所以现在已经不安全了。
使用AES加密
AES算法是目前应用最广泛的加密算法,比较常见的工作模式是ECB和CBC。
ECB模式:
package com.impudent.Test03;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class Demo02 {
public static void main(String[] args) throws Exception {
//原文
String message="Hello,World!";
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 NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
//创建密码对象,需要传入算法/工具模式/填充模式
Cipher cipher=Cipher.getInstance("AES/ECB/PKCS5Padding");
//根据key的字节内容,“恢复”密钥对象
SecretKey Keyspec=new SecretKeySpec(key, "AES");
//初始化密钥:设置加密模式ENCRYPT_MODE
cipher.init(Cipher.ENCRYPT_MODE, Keyspec);
//根据原始内容进行加密
return cipher.doFinal(input);
}
//解密
public static byte[] decrypt(byte[] key,byte[] input) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
//创建密码对象,需要传入算法/工具模式/填充模式
Cipher cipher=Cipher.getInstance("AES/ECB/PKCS5Padding");
//根据key字节内容,“恢复”密钥对象
SecretKey keyspec=new SecretKeySpec(key, "AES");
//初始化密钥:设置解密模式DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE, keyspec);
//根据原始内容进行解密
return cipher.doFinal(input);
}
}
CBC模式:ECB模式是最简单的AES加密模式,它只需要一个固定长度的密钥,固定的明文会生成固定的密文,这种一对一的加密模式会导致安全性降低,更好的方式是通过CBC模式,它需要一个随机数作为IV参数,这样对于同一份明文,每次产生的密文都不同。
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Demo03 {
public static void main(String[] args) throws Exception {
//原文
String message="Hello,World!";
System.out.println("Message: "+message);
//128位密钥=16 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 NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
//创建密码对象,需要传入算法/工具模式/填充模式
Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
//根据key的字节内容,“恢复”密钥对象
SecretKey Keyspec=new SecretKeySpec(key, "AES");
//CBC模式需要生成一个16 bytes的initialization vector
SecureRandom sr=SecureRandom.getInstanceStrong();
byte[] iv=sr.generateSeed(16);
System.out.println(Arrays.toString(iv));
IvParameterSpec ivps=new IvParameterSpec(iv);
//初始化密钥:设置加密模式ENCRYPT_MODE
cipher.init(Cipher.ENCRYPT_MODE, Keyspec,ivps);
//加密
byte[] data= cipher.doFinal(input);
//IV不需要保密,把IV和密文一起返回
return join(iv,data);
}
//解密
public static byte[] decrypt(byte[] key,byte[] input) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
//把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");
SecretKey keyspec=new SecretKeySpec(key, "AES");
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;
}
}