Java使⽤AES-256加密
Java version: 1.8.0_151-b12
AES(Advanced Encryption Standard)加密算法属于对称加密算法,AES加密算法的安全性要⾼于DES和3DES, 所以AES已经成为了主要的对称加密算法.
AES的加密流程
要理解AES的加密流程, 会涉及到AES的五个关键词: 分组密码体制, Padding, 初始向量IV, 密钥, 加密模式.
分组密码体制: 所谓分组密码体制就是指将明⽂切成⼀段⼀段的来加密, 然后再把⼀段⼀段的密⽂拼起来形成最终密⽂的加密⽅
式. AES采⽤分组密码体制, 即AES加密会⾸先把明⽂切成⼀段⼀段的, ⽽且每段数据的长度要求必须是128位16个字节, 如果最后⼀段不够16个字节了, 就需要⽤Padding来把这段数据填满16个字节, 然后分别对每段数据进⾏加密, 最后再把每段加密数据拼起来形成最终的密⽂.
Padding: Padding就是⽤来把不满16个字节的分组数据填满16个字节⽤的, 它有三种模式PKCS5、PKC
S7和NOPADDING. PKCS5是指分组数据缺少⼏个字节, 就在数据的末尾填充⼏个字节的⼏, ⽐如缺少5个字节, 就在末尾填充5个字节的5. PKCS7是指分组数据缺少⼏个字节, 就在数据的末尾填充⼏个字节的0, ⽐如缺少7个字节, 就在末尾填充7个字节的0. NoPadding是指不需要填充, 也就是说数据的发送⽅肯定会保证最后⼀段数据也正好是16个字节. 那如果在PKCS5模式下, 最后⼀段数据的内容刚好就是16个16怎么办?
那解密端就不知道这⼀段数据到底是有效数据还是填充数据了, 因此对于这种情况, PKCS5模式会⾃动帮我们在最后⼀段数据后再添加16个字节的数据, ⽽且填充数据也是16个16, 这样解密段就能知道谁是有效数据谁是填充数据了. PKCS7最后⼀段数据的内容是16个0, 也是同样的道理. 解密端需要使⽤和加密端同样的Padding模式, 才能准确的识别有效数据和填充数据. 我们开发通常采⽤PKCS7 Padding模式.
初始向量IV: 初始向量IV的作⽤是使加密更加安全可靠, 我们使⽤AES加密时需要主动提供初始向量, ⽽且只需要提供⼀个初始向量就够了, 后⾯每段数据的加密向量都是前⾯⼀段的密⽂. 初始向量IV的长度规定为128位16个字节, 初始向量的来源为随机⽣成.
密钥: AES要求密钥的长度可以是128位16个字节、192位或者256位, 位数越⾼, 加密强度⾃然越⼤, 但是加密的效率⾃然会低⼀些, 因此要做好衡量. 我们开发通常采⽤128位16个字节的密钥, 我们使⽤AES
加密时需要主动提供密钥, ⽽且只需要提供⼀个密钥就够了, 每段数据加密使⽤的都是这⼀个密钥, 密钥来源为随机⽣成.
加密模式: AES⼀共有四种加密模式, 分别是ECB(电⼦密码本模式)、CBC(密码分组链接模式)、CFB、OFB, 我们⼀般使⽤的是CBC模式. 四种模式中除了ECB相对不安全之外, 其它三种模式的区别并没有那么⼤. ECB模式是最基本的加密模式, 即仅仅使⽤明⽂和密钥来加密数据, 相同的明⽂块会被加密成相同的密⽂块, 这样明⽂和密⽂的结构将是完全⼀样的, 就会更容易被破解, 相对来说不是那么安全, 因此很少使⽤. CBC模式则⽐ECB模式多了⼀个初始向量IV, 加密的时候, 第⼀个明⽂块会⾸先和初始向量IV做异或操作, 然后再经过密钥加密, 然后第⼀个密⽂块⼜会作为第⼆个明⽂块的加密向量来异或, 依次类推下去, 这样相同的明⽂块加密出的密⽂块就是不同的, 明⽂的结构和密⽂的结构也将是不同的, 因此更加安全, 我们常⽤的就是CBC加密模式.
说完 AES 加密流程, 下⾯说⼀说 Java 如何使⽤ AES 加密.
或许你⼀直使⽤ AES-128 加密没有任何问题, 但当你把密钥增加到32个字节的时候, 可能会遇到如下异常:
java.security.InvalidKeyException: Illegal key size
To solve that you have to go to , download the Unlimited Strength Jurisdiction Policy Files, unzip it, go to the <java-home>/lib/security directory,
and replace the two files local_policy.jar and US_export_policy.jar with the two files from the download.
Starting with Java 1.8.0_151 and 1.8.0_152 there is a new somewhat easier way to enable the unlimited strength jurisdiction policy for the JVM. Without
enabling this you cannot use AES-256. Since this version, it is no longer necessary to download the policy files from the Oracle website and install it. You
can now set the unlimited policy directly in your application with this one-liner:
Security.setProperty("crypto.policy", "unlimited");
In Java 1.8.0_162, the unlimited policy is enabled by default. You no longer need to install the policy file in the JRE or set the security property crypto.policy.
openjdk bugs:
Java 使⽤ AES-256 加密代码:
1/**
2 * @author xxx
3 * @date 2020-09-16 11:17
4 **/
5public class AES256Util {
6
7/**
8    * 密钥, 256位32个字节
9*/
10public static final String DEFAULT_SECRET_KEY = "uBdUx82vPHkDKb284d7NkjFoNcKWBuka";
11
12private static final String AES = "AES";
13
14/**
15    * 初始向量IV, 初始向量IV的长度规定为128位16个字节, 初始向量的来源为随机⽣成.
16*/
17private static final byte[] KEY_VI = "c558Gq0YQK2QUlMc".getBytes();
18
19/**
20    * 加密解密算法/加密模式/填充⽅式
21*/
22private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
23
24private static java.util.Base64.Encoder base64Encoder = java.Encoder();
25private static java.util.Base64.Decoder base64Decoder = java.Decoder();
26
27static {
28        java.security.Security.setProperty("crypto.policy", "unlimited");
29    }
30
31/**
32    * AES加密
33*/
34public static String encode(String key, String content) {
35try {
36            pto.SecretKey secretKey = pto.spec.Bytes(), AES);
37            pto.Cipher cipher = Instance(CIPHER_ALGORITHM);
38            cipher.pto.Cipher.ENCRYPT_MODE, secretKey, pto.spec.IvParameterSpec(KEY_VI)); 39
40// 获取加密内容的字节数组(这⾥要设置为utf-8)不然内容中如果有中⽂和英⽂混合中⽂就会解密为乱码
41byte[] byteEncode = Bytes(java.nio.charset.StandardCharsets.UTF_8);
42
43// 根据密码器的初始化⽅式加密
44byte[] byteAES = cipher.doFinal(byteEncode);
45
46// 将加密后的数据转换为字符串
deToString(byteAES);
48        } catch (Exception e) {
49            e.printStackTrace();
50        }
java源代码加密51return null;
52    }
53
54/**
55    * AES解密
56*/
57public static String decode(String key, String content) {
58try {
59            pto.SecretKey secretKey = pto.spec.Bytes(), AES);
60            pto.Cipher cipher = Instance(CIPHER_ALGORITHM);
61            cipher.pto.Cipher.DECRYPT_MODE, secretKey, pto.spec.IvParameterSpec(KEY_VI)); 62
63// 将加密并编码后的内容解码成字节数组
64byte[] byteContent = base64Decoder.decode(content);
65// 解密
66byte[] byteDecode = cipher.doFinal(byteContent);
67return new String(byteDecode, java.nio.charset.StandardCharsets.UTF_8);
68        } catch (Exception e) {
69            e.printStackTrace();
70        }
71return null;
72    }
73
74public static void main(String[] args) {
75        String dbPassword = "123456";
76        String encryptDbPwd = de(DEFAULT_SECRET_KEY, dbPassword);
77        System.out.println("encrypt: " + encryptDbPwd);
78
79        String decrypt = AES256Util.decode(DEFAULT_SECRET_KEY, encryptDbPwd);
80        System.out.println("decrypt:" + decrypt);
81    }
82
83 }
测试:
最后特别说明⼀下:
解密时⽤到的密钥, 初始向量IV, 加密模式, Padding模式必须和加密时的保持⼀致, 否则则会解密失败.

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。