先贴代码:重要的参数都有注释,自己摸索的,有不对的地方大家指正
import java.security.Key; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESedeKeySpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; /** * * @ClassName: DESUtil * @Description: 加解密工具类 * @author: panpan * @date: 2019年1月29日 下午5:01:48 * */ public class AESUtil { private static final String CHARSET_NAME = "UTF-8"; public static String encode(String plainText, String key, String vi) { try { // 根据字符串key生成 Cipher 初始化使用的 secretKey SecretKey secretKey = new SecretKeySpec(key.getBytes(CHARSET_NAME),"AES"); // 获取Cipher实例,指定加密方法、加密模式、补位模式 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 加密器初始化,参数分别是: 加密器编码模式(加密或解密)、秘钥、加密向量 cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(vi.getBytes())); // cipher 可以 add 但是最终需要使用 doFinal结束,返回byte[],这里通过base64编码成字符串 return java.util.Base64.getEncoder().encodeToString(cipher.doFinal(plainText.getBytes(CHARSET_NAME))); } catch (Exception e) { throw new RuntimeException(e); } } public static String decode(String encryptText, String key, String vi) { try { SecretKey secretKey = new SecretKeySpec(key.getBytes(CHARSET_NAME),"AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(vi.getBytes())); return new String(cipher.doFinal(java.util.Base64.getDecoder().decode(encryptText)), CHARSET_NAME); } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) { String vi = "f4CAHEW85Daszbwi"; // 16字节加密向量 String message = "Uibn1aICzX"; // 任意大小需要加密的文字 String key = "JvOybH9j7Qs0wSxi"; // 128bit、16字节秘钥 String encryptedCode = encode(message,key,vi); System.out.println(encryptedCode); String decryptedCode = decode(encryptedCode,key,vi); System.out.println(decryptedCode); } }
接着放参考资料:
首先第一位的是 JAVA API:
http://www.matools.com/api/java8
需要注意的是,获取Cipher实例时,可以选择很多加密模式,这是写这个工具类的核心。
1、加密方法有: AES、DES、DESede、RSA
2、加密模式有: CBC、ECB,这两种是JDK中提供的实例有的,如果你需要写其他的加密模式,如:CFB、OFB
可以参考这篇文章的原理:
https://blog.csdn.net/sunqiujing/article/details/75065218
当然,想要demo的话,这里有一个CFB的例子:
https://download.csdn.net/download/langeldep/9749421
3、最后一个参数: Padding or not: 是否补位,这个初次接触加密的童鞋可能有点懵,说实话今早我刚刚看到这个的时候也有点懵逼,后来参考了 https://blog.csdn.net/sunqiujing/article/details/75065218 这篇文章讲述的原理,有点明白了,其实AES、DES在加密时,是以 8 bit 作为一个单元的,如果不满 8 bit,如果你选择了 PKCS5Padding,则会给你补位,CFB中那位老哥写的demo,使用的是 NoPadding,但是自己在代码了撸了补位的操作,具体为什么他不使用工具里自带的补位,没有细细研究。
4、还有一点,括号中的数字,说的是你的 加密key需要的位数,也是 AES加密快的大小
引用一个图
比如我使用 AES/CBC/PKCS5Padding,官方文档中说要 128 bit,即 key需要 128/8 = 16 字符的字符串,
如果你的位数不满 16 位,就会报以下错误:
java.lang.RuntimeException: java.security.InvalidKeyException: Invalid AES key length: 17 bytes
接下来的一个核心,是Cipher加密器的初始化:
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(vi.getBytes()));
1、加密器模式: ENCRYPT_MODE是加密 DECRYPT_MODE是解密
2、 secretKey 是秘钥,当然你不能直接把直接放字符串秘钥,得使用JAVA提供的秘钥生成器,并制定加密方式,因为不同加密方式,使用的key构成是不一样的,并且秘钥的大小也不同,重点需要特别注意。
3、 加密向量,注意 上面代码里采用的 AES/CBC/PKCS5Padding 需要 16字节128bit的加密向量,否则则会报错:
java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long
加密向量干啥用的嘞? 大家可以回想一下大学学得 线性代数,加密的每个明文模块、秘钥模块、密文模块其实都是一个矩阵,这里的加密向量其实和线代里的向量应该是一致的。
再借用一张图
大概原理差不多是: 明文矩阵 X 秘钥矩阵 X 基础向量 = 明文矩阵
这篇文章写得很详细,大家可以看一下
https://blog.csdn.net/wufaliang003/article/details/79619027
嗯嗯,总算对对称加密的几种方法有了个大概了解,做一篇文章,mark一下,也是分享经验,有不对的地方大家评论