文章内容
一、AES简介
密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准高级加密标准。
对称加密算法也就是加密和解密用相同的密钥,具体的加解密流程如下:
1、ECB模式
ECB(Electronic Codebook,电码本)模式是分组密码的一种最基本的工作模式。在该模式下,待处理信息被分为大小合适的分组,然后分别对每一分组独立进行加密或解密处理。
1)ECB特点
- 操作简单
- 利于实现并行处理(由于其分组的独立性)
- 能防止误差传播
- 可能对明文进行主动攻击(不能隐藏明文)
2)ECB加密过程
将数据按照8个字节一段进行DES加密得到一段8个字节的密文或者明文,最后一段不足8个字节,按照需求补足8个字节进行计算,之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。
2、CBC模式
CBC指的是密码分组链接(Cipher-block chaining)的简称。在CBC模式中,每个明文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有明文块。同时,为了保证每条消息的唯一性,在第一个块中需要使用初始化向量。
1)CBC特点
- 不容易主动攻击,是SSL、IPSec的标准,安全性好于ECB
- 加密过程是串行的,无法被并行化
- 存在误差传递
- 需要初始化向量IV
2)CBC加密过程
- 1. 首先将数据按照8个字节一组进行分组得到D1D2D3…Dn(若数据不是8的整数倍,用指定的PADDING数据补位)
- 2. 第一组数据D1与初始化向量I异或后的结果进行DES加密得到第一组密文C1
- 3. 第二组数据D2与第一组的加密结果C1异或以后的结果进行DES加密,得到第二组密文C2
- 4. 之后的数据以此类推,得到Cn
- 5. 按顺序连为C1C2C3…Cn即为加密结果。
3、填充(PADDING)
- NoPadding: 加密内容不足8位用0补足8位, Cipher类不提供补位功能,需自己实现代码给加密内容添加0, 如{36,36,36,0,0,0,0,0}
- PKCS5Padding: 加密内容不足8位用余位数补足8位, 如{22,22,22,22,4,4,4,4}或者{28,28,28,28,28,3,3,3}刚好8位补8位8
在PKCS5Padding中,明确定义Block的大小是8位,而在PKCS7Padding定义中,对于块的大小是不确定的,可以在1-255之间(块长度超出255的尚待研究),填充值的算法都是一样的:填充值=块大小 – (数据长度%块大小)
如上面的例子:
{22,22,22,22}
填充值 = 8 -(4%8)= 4
{22,22,22,22,4,4,4,4}
二、AES工具类
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
/**
* Aes工具类
**/public class AesUtil {
private static final String ALGORITHM = "AES";
private static final String AES_CBC_PADDING = "AES/CBC/PKCS5Padding";//AES/CBC/PKCS7Padding
private static final String AES_ECB_PADDING = "AES/ECB/PKCS5Padding";//AES/ECB/PKCS7Padding
/**
* 也可以通过这种方式获取密钥
*
* @param key
* @return
*/ private static SecretKey getSecretKey(byte[] key) {
try {
//获取指定的密钥生成器
KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM);
//加密强随机数
SecureRandom secureRandom = new SecureRandom();
secureRandom.setSeed(key);
//这里可以是128、192、256、越大越安全
keyGen.init(256, secureRandom);
return keyGen.generateKey();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("AES获取密钥出现错误,算法异常");
}
}
/**
* Aes加密(CBC工作模式)
*
* @param key 密钥,key长度必须大于等于 3*8 = 24,并且是8的倍数
* @param keyIv 初始化向量,keyIv长度必须等于16
* @param data 明文
* @return 密文
* @throws Exception
*/ public static byte[] encodeByCBC(byte[] key, byte[] keyIv, byte[] data)
throws Exception {
//获取SecretKey对象,也可以使用getSecretKey()方法
Key secretKey = new SecretKeySpec(key, ALGORITHM);
//获取指定转换的密码对象Cipher(参数:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(AES_CBC_PADDING);
//创建向量参数规范也就是初始化向量
IvParameterSpec ips = new IvParameterSpec(keyIv);
//用密钥和一组算法参数规范初始化此Cipher对象(加密模式)
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ips);
//执行加密操作
return cipher.doFinal(data);
}
/**
* Aes加密(ECB工作模式)
*
* @param key 密钥,key长度必须大于等于 3*8 = 24,并且是8的倍数
* @param keyIv 初始化向量,keyIv长度必须等于16
* @param data 密文
* @return 明文
* @throws Exception
*/ public static byte[] decodeByCBC(byte[] key, byte[] keyIv, byte[] data)
throws Exception {
//获取SecretKey对象,也可以使用getSecretKey()方法
Key secretKey = new SecretKeySpec(key, ALGORITHM);
//获取指定转换的密码对象Cipher(参数:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(AES_CBC_PADDING);
//创建向量参数规范也就是初始化向量
IvParameterSpec ips = new IvParameterSpec(keyIv);
//用密钥和一组算法参数规范初始化此Cipher对象(加密模式)
cipher.init(Cipher.DECRYPT_MODE, secretKey, ips);
//执行加密操作
return cipher.doFinal(data);
}
/**
* Aes加密(ECB工作模式),不要IV
*
* @param key 密钥,key长度必须大于等于 3*8 = 24,并且是8的倍数
* @param data 明文
* @return 密文
* @throws Exception
*/ public static byte[] encodeByECB(byte[] key, byte[] data) throws Exception {
//获取SecretKey对象,也可以使用getSecretKey()方法
SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);
//获取指定转换的密码对象Cipher(参数:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(AES_ECB_PADDING);
//用密钥和一组算法参数规范初始化此Cipher对象(加密模式)
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
//执行加密操作
return cipher.doFinal(data);
}
/**
* Aes解密(ECB工作模式),不要IV
*
* @param key 密钥,key长度必须大于等于 3*8 = 24,并且是8的倍数
* @param data 密文
* @return 明文
* @throws Exception
*/ public static byte[] decodeByECB(byte[] key, byte[] data) throws Exception {
//获取SecretKey对象,也可以使用getSecretKey()方法
SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);
//获取指定转换的密码对象Cipher(参数:算法/工作模式/填充模式)
Cipher cipher = Cipher.getInstance(AES_ECB_PADDING);
//用密钥和一组算法参数规范初始化此Cipher对象(加密模式)
cipher.init(Cipher.DECRYPT_MODE, secretKey);
//执行加密操作
return cipher.doFinal(data);
}
}
三、实践
- AES加密key的长度至少为24位并且是8的倍数
- AES里CBC模式的加解密初始化向量的长度为16
- AES里加解密的时候密钥要保持一致
1、AES之ECB模式加密
/**
* AES加密之ECB加密
* 此处单元测试的注解是采用:org.junit.Test
* @throws Exception
*/@Test
public void ecbEncode() throws Exception {
System.out.println("------------------AES加密之ECB加密转base64------------------");
//key的长度至少为24位并且是8的倍数(比如32,40等等)
String aesKey = "ee1b7d9ca0b7d10d2cd27f35d34bb412";
String plainText = "<root><out_refund_no>20180608163757915497</out_refund_no><out_trade_no>15070411211528250141228</out_trade_no><refund_account>REFUND_SOURCE_RECHARGE_FUNDS</refund_account><refund_fee>1</refund_fee><refund_id>50000607002018060805036784330</refund_id><refund_recv_accout>支付用户零钱</refund_recv_accout><refund_request_source>API</refund_request_source><refund_status>SUCCESS</refund_status><settlement_refund_fee>1</settlement_refund_fee><settlement_total_fee>1</settlement_total_fee><success_time>2018-06-08 16:38:05</success_time><total_fee>1</total_fee><transaction_id>4200000129201806063432463966</transaction_id></root>";
System.out.println("ECB加密原始数据:" + plainText);
byte[] key = aesKey.getBytes(StandardCharsets.UTF_8);
byte[] data = plainText.getBytes(StandardCharsets.UTF_8);
//ECB模式加密
byte[] encode = AesUtil.encodeByECB(key, data);
System.out.println("ECB加密后转Base64的数据:" + Base64.getEncoder().encodeToString(encode));
}
运行结果:
------------------AES加密之ECB加密转base64------------------
ECB加密原始数据:<root><out_refund_no>20180608163757915497</out_refund_no><out_trade_no>15070411211528250141228</out_trade_no><refund_account>REFUND_SOURCE_RECHARGE_FUNDS</refund_account><refund_fee>1</refund_fee><refund_id>50000607002018060805036784330</refund_id><refund_recv_accout>支付用户零钱</refund_recv_accout><refund_request_source>API</refund_request_source><refund_status>SUCCESS</refund_status><settlement_refund_fee>1</settlement_refund_fee><settlement_total_fee>1</settlement_total_fee><success_time>2018-06-08 16:38:05</success_time><total_fee>1</total_fee><transaction_id>4200000129201806063432463966</transaction_id></root>
ECB加密后转Base64的数据:vuQrpYy7xHB63Ha2s8dQdp9GX96XLUJknNebiHzQZpZq9GAe/drIFiCW+TwcCUy93TdN8vMOoGHn7G5jcB1azuNyHjCqR8rYELFR1BvD9j15IR31i3GjSw4U3Y+1LqLohC7q4Gajv4FvC9SNSa4xXpAuV0vARWjZOlSJHYQ9rvG89RK8alYFKrQZDBcMAx+knA7nrJ4LkLpPub6d9rRgon9hK2BVQbVIE1JqJnP6oJGq9gxhEyCg5j/c7PU+gTUvaOlCaByxKjCaVqrCAN1o3SNpjr8HgAIKC7qLpvr6twvnQ2UpIvG81HVeS3w8R/XHS8HO4SX81iPG5G/Y2SV8udCheA8Rh8EXxetibz4USoFRRf6vUebRuHaNhyp9NP5VzJ8+KDh1ySGXoBc1JKKi/s/R2rFzp4mHWtKcL3F0wIgAIJu2KVwI5nzy/zZJLXb4SKLBM5TQrkWt1l1qOeIpGTG6xlgGTjvPTa/+Au+VGYwqN+fUEojyruojlFFwkglYBASLQak0lVJRhOp+9fsrX8oSSHGl0a4NqWNSN1gyASGY1vL3yG0l+vVcjHaj+m9Ac04C0LzdT9zP2Pp1ImpzjTd2xed4X3DCcSJN8DB7JaWLe2iffe807aYz6VVVWDMKTcPpYoIqbX2tHGDO+6AyKHRN6QwBlbyUsSTd30N49GnDTfALcY7mMU374jr8dOfd2ciUDBgAsvFN4vPisn7LH4HH0HQfdiVbnCSZuUA0/NTjq2Jy5WAaY5Kkrh2i5TIg7d6LC1StBI1JPV/9PYGXAIXBSZVR57pz9zstekW2aHKmnlIvwzn2mSvmllH0iboxb0zyoxqZPzMgUO7pS3Ym7g==
2、AES之ECB模式解密
/**
* AES加密之ECB解密
* 此处单元测试的注解是采用:org.junit.Test
* @throws Exception
*/@Test
public void ecbDecode() throws Exception {
System.out.println("------------------AES加密之ECB解密------------------");
//和加密时密钥一样
String aesKey = "ee1b7d9ca0b7d10d2cd27f35d34bb412";
//base64编码后的字符串
String plainText = "vuQrpYy7xHB63Ha2s8dQdp9GX96XLUJknNebiHzQZpZq9GAe/drIFiCW+TwcCUy93TdN8vMOoGHn7G5jcB1azuNyHjCqR8rYELFR1BvD9j15IR31i3GjSw4U3Y+1LqLohC7q4Gajv4FvC9SNSa4xXpAuV0vARWjZOlSJHYQ9rvG89RK8alYFKrQZDBcMAx+knA7nrJ4LkLpPub6d9rRgon9hK2BVQbVIE1JqJnP6oJGq9gxhEyCg5j/c7PU+gTUvaOlCaByxKjCaVqrCAN1o3SNpjr8HgAIKC7qLpvr6twvnQ2UpIvG81HVeS3w8R/XHS8HO4SX81iPG5G/Y2SV8udCheA8Rh8EXxetibz4USoFRRf6vUebRuHaNhyp9NP5VzJ8+KDh1ySGXoBc1JKKi/s/R2rFzp4mHWtKcL3F0wIgAIJu2KVwI5nzy/zZJLXb4SKLBM5TQrkWt1l1qOeIpGTG6xlgGTjvPTa/+Au+VGYwqN+fUEojyruojlFFwkglYBASLQak0lVJRhOp+9fsrX8oSSHGl0a4NqWNSN1gyASGY1vL3yG0l+vVcjHaj+m9Ac04C0LzdT9zP2Pp1ImpzjTd2xed4X3DCcSJN8DB7JaWLe2iffe807aYz6VVVWDMKTcPpYoIqbX2tHGDO+6AyKHRN6QwBlbyUsSTd30N49GnDTfALcY7mMU374jr8dOfd2ciUDBgAsvFN4vPisn7LH4HH0HQfdiVbnCSZuUA0/NTjq2Jy5WAaY5Kkrh2i5TIg7d6LC1StBI1JPV/9PYGXAIXBSZVR57pz9zstekW2aHKmnlIvwzn2mSvmllH0iboxb0zyoxqZPzMgUO7pS3Ym7g==";
System.out.println("ECB解密原始数据:" + plainText);
//因为原始字符串经过base64编码后的字符串
byte[] key = aesKey.getBytes(StandardCharsets.UTF_8);
byte[] data = Base64.getDecoder().decode(plainText);
//ECB模式解密
byte[] decodeStr = AesUtil.decodeByECB(key, data);
System.out.println("ECB解密后转字符串数据:" + new String(decodeStr, StandardCharsets.UTF_8));
}
运行结果:
------------------AES加密之ECB解密------------------
ECB解密原始数据:vuQrpYy7xHB63Ha2s8dQdp9GX96XLUJknNebiHzQZpZq9GAe/drIFiCW+TwcCUy93TdN8vMOoGHn7G5jcB1azuNyHjCqR8rYELFR1BvD9j15IR31i3GjSw4U3Y+1LqLohC7q4Gajv4FvC9SNSa4xXpAuV0vARWjZOlSJHYQ9rvG89RK8alYFKrQZDBcMAx+knA7nrJ4LkLpPub6d9rRgon9hK2BVQbVIE1JqJnP6oJGq9gxhEyCg5j/c7PU+gTUvaOlCaByxKjCaVqrCAN1o3SNpjr8HgAIKC7qLpvr6twvnQ2UpIvG81HVeS3w8R/XHS8HO4SX81iPG5G/Y2SV8udCheA8Rh8EXxetibz4USoFRRf6vUebRuHaNhyp9NP5VzJ8+KDh1ySGXoBc1JKKi/s/R2rFzp4mHWtKcL3F0wIgAIJu2KVwI5nzy/zZJLXb4SKLBM5TQrkWt1l1qOeIpGTG6xlgGTjvPTa/+Au+VGYwqN+fUEojyruojlFFwkglYBASLQak0lVJRhOp+9fsrX8oSSHGl0a4NqWNSN1gyASGY1vL3yG0l+vVcjHaj+m9Ac04C0LzdT9zP2Pp1ImpzjTd2xed4X3DCcSJN8DB7JaWLe2iffe807aYz6VVVWDMKTcPpYoIqbX2tHGDO+6AyKHRN6QwBlbyUsSTd30N49GnDTfALcY7mMU374jr8dOfd2ciUDBgAsvFN4vPisn7LH4HH0HQfdiVbnCSZuUA0/NTjq2Jy5WAaY5Kkrh2i5TIg7d6LC1StBI1JPV/9PYGXAIXBSZVR57pz9zstekW2aHKmnlIvwzn2mSvmllH0iboxb0zyoxqZPzMgUO7pS3Ym7g==
ECB解密后转字符串数据:<root><out_refund_no>20180608163757915497</out_refund_no><out_trade_no>15070411211528250141228</out_trade_no><refund_account>REFUND_SOURCE_RECHARGE_FUNDS</refund_account><refund_fee>1</refund_fee><refund_id>50000607002018060805036784330</refund_id><refund_recv_accout>支付用户零钱</refund_recv_accout><refund_request_source>API</refund_request_source><refund_status>SUCCESS</refund_status><settlement_refund_fee>1</settlement_refund_fee><settlement_total_fee>1</settlement_total_fee><success_time>2018-06-08 16:38:05</success_time><total_fee>1</total_fee><transaction_id>4200000129201806063432463966</transaction_id></root>
格式化结果如下:
<root>
<out_refund_no>20180608163757915497</out_refund_no>
<out_trade_no>15070411211528250141228</out_trade_no>
<refund_account>REFUND_SOURCE_RECHARGE_FUNDS</refund_account>
<refund_fee>1</refund_fee>
<refund_id>50000607002018060805036784330</refund_id>
<refund_recv_accout>支付用户零钱</refund_recv_accout>
<refund_request_source>API</refund_request_source>
<refund_status>SUCCESS</refund_status>
<settlement_refund_fee>1</settlement_refund_fee>
<settlement_total_fee>1</settlement_total_fee>
<success_time>2018-06-08 16:38:05</success_time>
<total_fee>1</total_fee>
<transaction_id>4200000129201806063432463966</transaction_id>
</root>
3、AES之CBC模式加密
/**
* AES加密之CBC加密转base64
* 此处单元测试的注解是采用:org.junit.Test
* @throws Exception
*/@Test
public void cbcEncode() throws Exception {
System.out.println("------------------AES加密之CBC加密转base64------------------");
String desKey = "4c1ab02124f0941fbc01f902be421843";
//初始化向量的长度为16
String keyIv = "12345678abcdefgh";
String plainText = "{"txncode":"QueryInvoice","instid":"10000006","mchntid":"100000060000001","netid":"040000280001","posid":"040000280001","oprid":"wtsd001","serialNo":"04000028000121052148281221","postTime":"2021-06-03 00:08:00","responsecode":"000000","responsedesc":"成功","messageList":{"code":"03702170021109363363","viewUrl":"https://www.chinaeinv.com/p.jspa?c=15E38CA48E906F7985CF","pdfUnsignedUrl":"https://www.chinaeinv.com/pdf.jspa?c=15E38CA48E906F7985CF","generateTime":"2021-05-21 17:46:29","totalAmount":"50"}}";
System.out.println("CBC加密原始数据:" + plainText);
byte[] key = desKey.getBytes(StandardCharsets.UTF_8);
byte[] data = plainText.getBytes(StandardCharsets.UTF_8);
byte[] encode = AesUtil.encodeByCBC(key, keyIv.getBytes(StandardCharsets.UTF_8), data);
System.out.println("CBC加密后转Base64的数据:" + Base64.getEncoder().encodeToString(encode));
}
运行结果:
------------------AES加密之CBC加密转base64------------------
CBC加密原始数据:{"txncode":"QueryInvoice","instid":"10000006","mchntid":"100000060000001","netid":"040000280001","posid":"040000280001","oprid":"wtsd001","serialNo":"04000028000121052148281221","postTime":"2021-06-03 00:08:00","responsecode":"000000","responsedesc":"成功","messageList":{"code":"03702170021109363363","viewUrl":"https://www.chinaeinv.com/p.jspa?c=15E38CA48E906F7985CF","pdfUnsignedUrl":"https://www.chinaeinv.com/pdf.jspa?c=15E38CA48E906F7985CF","generateTime":"2021-05-21 17:46:29","totalAmount":"50"}}
CBC加密后转Base64的数据:KRdou0k/HC1jdHlddMJBPI18jjsu9djXZpd99dkKFbyawP59uPDqTGknoLD01fv1/KTVYe5oSzqMsK2DH+QFvQKT86ieJsOxyB5CRLvrcp780hdBwW1RvxEZYqarXhpOLskLdjbTo1L9BJht4gA8HuDw3w9gMx/HcZeUiESVDt2ihspLrDAMyj7OwU2pdE+3o/O3V++BcpIdUHsPcqB02kSWlPiEBfsl5xZvm0P9rmlfPPTTP754L+Hc/s4vOAMoWCOZtBljfojDHdhRqr6iLoAr1ZtNrz51Ph8Sz7P94wm/0RrFQDpvJd9m2f5Ph3m3zjHHlFXv3GXMDZjcrshjxemyyZ+7nIXmbcjWLDOo9AGoH/33FE0JGs9jS+XtaaTnNNsw9thJmjDuIe4QQEyBOQemvkxf15bg1q3O+jxorh4/WL2+TuK6i8ybhJIadcSn1w5pQj97NRQjZNvFMg+VdlqgvEDaGebwFDXqU/k8tlmnTF/5UhnI4T4aimut4jJVL/ktBulUbKjsdPLJIHi6hJuUZboYr1p+ExDlxhZqKnJ/rV9eyhRQKWT65yrYzZ2p1nRhiG/7a7BavsFof2prvbpUOwa9nMYHEwtvJoDjoJF/8t3fr7KaPHQ/+IMo7DOL/pG8iUQKm0AHYazyFH7DDOBbTq0O+Y5vC7iTD1gB1Lc=
4、AES之CBC模式解密
/**
* AES加密之CBC解密
* 此处单元测试的注解是采用:org.junit.Test
* @throws Exception
*/@Test
public void cbcDecode() throws Exception {
System.out.println("------------------AES加密之CBC解密------------------");
//和加密时密钥一样
String desKey = "4c1ab02124f0941fbc01f902be421843";
String plainText = "KRdou0k/HC1jdHlddMJBPI18jjsu9djXZpd99dkKFbyawP59uPDqTGknoLD01fv1/KTVYe5oSzqMsK2DH+QFvQKT86ieJsOxyB5CRLvrcp780hdBwW1RvxEZYqarXhpOLskLdjbTo1L9BJht4gA8HuDw3w9gMx/HcZeUiESVDt2ihspLrDAMyj7OwU2pdE+3o/O3V++BcpIdUHsPcqB02kSWlPiEBfsl5xZvm0P9rmlfPPTTP754L+Hc/s4vOAMoWCOZtBljfojDHdhRqr6iLoAr1ZtNrz51Ph8Sz7P94wm/0RrFQDpvJd9m2f5Ph3m3zjHHlFXv3GXMDZjcrshjxemyyZ+7nIXmbcjWLDOo9AGoH/33FE0JGs9jS+XtaaTnNNsw9thJmjDuIe4QQEyBOQemvkxf15bg1q3O+jxorh4/WL2+TuK6i8ybhJIadcSn1w5pQj97NRQjZNvFMg+VdlqgvEDaGebwFDXqU/k8tlmnTF/5UhnI4T4aimut4jJVL/ktBulUbKjsdPLJIHi6hJuUZboYr1p+ExDlxhZqKnJ/rV9eyhRQKWT65yrYzZ2p1nRhiG/7a7BavsFof2prvbpUOwa9nMYHEwtvJoDjoJF/8t3fr7KaPHQ/+IMo7DOL/pG8iUQKm0AHYazyFH7DDOBbTq0O+Y5vC7iTD1gB1Lc=";
String keyIv = "12345678abcdefgh";
System.out.println("CBC解密原始数据:" + plainText);
byte[] key = desKey.getBytes(StandardCharsets.UTF_8);
//因为结果时
byte[] data = Base64.getDecoder().decode(plainText);
byte[] decodeStr = AesUtil.decodeByCBC(key, keyIv.getBytes(StandardCharsets.UTF_8), data);
System.out.println("CBC解密后转字符串数据:" + new String(decodeStr, StandardCharsets.UTF_8));
}
运行结果:
------------------AES加密之CBC解密------------------
CBC解密原始数据:KRdou0k/HC1jdHlddMJBPI18jjsu9djXZpd99dkKFbyawP59uPDqTGknoLD01fv1/KTVYe5oSzqMsK2DH+QFvQKT86ieJsOxyB5CRLvrcp780hdBwW1RvxEZYqarXhpOLskLdjbTo1L9BJht4gA8HuDw3w9gMx/HcZeUiESVDt2ihspLrDAMyj7OwU2pdE+3o/O3V++BcpIdUHsPcqB02kSWlPiEBfsl5xZvm0P9rmlfPPTTP754L+Hc/s4vOAMoWCOZtBljfojDHdhRqr6iLoAr1ZtNrz51Ph8Sz7P94wm/0RrFQDpvJd9m2f5Ph3m3zjHHlFXv3GXMDZjcrshjxemyyZ+7nIXmbcjWLDOo9AGoH/33FE0JGs9jS+XtaaTnNNsw9thJmjDuIe4QQEyBOQemvkxf15bg1q3O+jxorh4/WL2+TuK6i8ybhJIadcSn1w5pQj97NRQjZNvFMg+VdlqgvEDaGebwFDXqU/k8tlmnTF/5UhnI4T4aimut4jJVL/ktBulUbKjsdPLJIHi6hJuUZboYr1p+ExDlxhZqKnJ/rV9eyhRQKWT65yrYzZ2p1nRhiG/7a7BavsFof2prvbpUOwa9nMYHEwtvJoDjoJF/8t3fr7KaPHQ/+IMo7DOL/pG8iUQKm0AHYazyFH7DDOBbTq0O+Y5vC7iTD1gB1Lc=
CBC解密后转字符串数据:{"txncode":"QueryInvoice","instid":"10000006","mchntid":"100000060000001","netid":"040000280001","posid":"040000280001","oprid":"wtsd001","serialNo":"04000028000121052148281221","postTime":"2021-06-03 00:08:00","responsecode":"000000","responsedesc":"成功","messageList":{"code":"03702170021109363363","viewUrl":"https://www.chinaeinv.com/p.jspa?c=15E38CA48E906F7985CF","pdfUnsignedUrl":"https://www.chinaeinv.com/pdf.jspa?c=15E38CA48E906F7985CF","generateTime":"2021-05-21 17:46:29","totalAmount":"50"}}
格式化后结果如下:
{
"txncode": "QueryInvoice",
"instid": "10000006",
"mchntid": "100000060000001",
"netid": "040000280001",
"posid": "040000280001",
"oprid": "wtsd001",
"serialNo": "04000028000121052148281221",
"postTime": "2021-06-03 00:08:00",
"responsecode": "000000",
"responsedesc": "成功",
"messageList": {
"code": "03702170021109363363",
"viewUrl": "https://www.chinaeinv.com/p.jspa?c=15E38CA48E906F7985CF",
"pdfUnsignedUrl": "https://www.chinaeinv.com/pdf.jspa?c=15E38CA48E906F7985CF",
"generateTime": "2021-05-21 17:46:29",
"totalAmount": "50"
}
}
从以上格式化的结果和最开始结果,可以看到数据实现了加密和解密并保护了数据的完整性。微信其实也使用到了AES加密方式。
四、总结
本文简单编写了一个AesUtil工具类,包含了CBC和ECB两种模式,整体上和DES工具类是差不多的,主要在于算法,密钥规范,工作模式的不同。