文章内容
一、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的尚待研究),填充值的算法都是一样的:填充值=块大小 – (数据长度%块大小)
如上面的例子:
1 2 3 | {22,22,22,22} 填充值 = 8 -(4%8)= 4 {22,22,22,22,4,4,4,4} |
二、AES工具类
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | 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模式加密
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 | /** * 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)); } |
运行结果:
1 2 3 | ------------------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模式解密
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | /** * 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)); } |
运行结果:
1 2 3 | ------------------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> |
格式化结果如下:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | < 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模式加密
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 | /** * 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)); } |
运行结果:
1 2 3 | ------------------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模式解密
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | /** * 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)); } |
运行结果:
1 2 3 | ------------------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"}} |
格式化后结果如下:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | { "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工具类是差不多的,主要在于算法,密钥规范,工作模式的不同。