AES简介
AES最一种常见的对称加密算法,对称加密算法也就是加密和解密用相同的密钥。
具体的加密流程如下图:
下面简单介绍下各个部分的作用与意义:
- 明文P
没有经过加密的数据。
- 密钥K
用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。密钥为接收方与发送方协商产生,但不可以直接在网络上传输,否则会导致密钥泄漏,通常是通过非对称加密算法加密密钥,然后再通过网络传输给对方,或者直接面对面商量密钥。密钥是绝对不可以泄漏的,否则会被攻击者还原密文,窃取机密数据。
- AES加密函数
设AES加密函数为E,则 C = E(K, P),其中P为明文,K为密钥,C为密文。也就是说,把明文P和密钥K作为加密函数的参数输入,则加密函数E会输出密文C。
- 密文C
经加密函数处理后的数据
- AES解密函数
设AES解密函数为D,则 P = D(K, C),其中C为密文,K为密钥,P为明文。也就是说,把密文C和密钥K作为解密函数的参数输入,则解密函数会输出明文P。
在这里简单介绍下对称加密算法与非对称加密算法的区别。
- 对称加密算法
加密和解密用到的密钥是相同的,这种加密方式加密速度非常快,适合经常发送数据的场合。缺点是密钥的传输比较麻烦。
- 非对称加密算法
加密和解密用的密钥是不同的,这种加密方式是用数学上的难解问题构造的,通常加密解密的速度比较慢,适合偶尔发送数据的场合。优点是密钥传输方便。常见的非对称加密算法为RSA、ECC和EIGamal。
AES使用
语言:java
jdk版本:1.7
算法:AEC
密钥长度:32 也就是AES-256
AES为分组密码,分组密码也就是把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文。在AES标准规范中,密钥的长度可以使用128位、192位、256位。(每个字节8位)
AES | 使用的密钥长度 |
---|---|
AES-128 | 16 |
AES-192 | 24 |
AES-256 | 32 |
加密模式:ECB
电码本模式(Electronic Codebook Book (ECB),这种模式是将整个明文分成若干段相同的小段,然后对每一小段进行加密。
填充模式:PKCS7Padding
在分组加密算法中,我们首先要将原文进行分组,然后每个分组进行加密,然后组装密文。
其中有一步是分组。如何分组?
假设我们现在的数据长度是24字节,BlockSize是8字节,那么很容易分成3组,一组8字节;
因为加密算法的需求,明文字节必须按照block进行填充对齐,才能方便进行加密运算。
考虑过一个问题没,如果现有的待加密数据不是BlockSize的整数倍,那该如何分组?
例如,有一个17字节的数据,BlockSize是8字节,怎么分组?
我们可以对原文进行填充(padding),将其填充到8字节的整数倍!
加密结果编码方式:Base64
环境准备
JAVA实现“AES/ECB/PKCS7Padding”对称加解密,尤其是 AES256的加解密需要注意两点:
- 技术出口限制,国内的JDK 默认不支持;
Java本身限制密钥的长度最多128位,而AES256需要的密钥长度是256位,因此需要到Java官网上下载一个Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files。
解决出口限制问题,下载以下两个包替换jdk安装路径下: jre\lib\security 的同名文件
JDK8 jar包下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
JDK7 jar包下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
JDK6 jar包下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html
把里面的两个jar包:local_policy.jar 和 US_export_policy.jar 替换掉原来jdk安装目录\jre\lib\security 下的两个jar包接可以了
- PKCS7Padding JAVA默认不支持PKCS7Padding填充模式,需借助第三方提供者。
一般的JRE(如Oracle JRE、OpenJRE)里面只有"AES/ECB/PKCS5Padding"算法,没有"AES/ECB/PKCS7Padding"算法。、故我们需要引入BouncyCastle的库,并给Cipher.getInstance方法传入参数"BC"来指定Java使用这个库里的加/解密算法。
maven工程pom.xml文件中添加以下配置:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15</artifactId>
<version>1.44</version>
</dependency>其Jar包的下载地址:http://www.bouncycastle.org/download/bcprov-jdk15on-160.jar
java 代码
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class CryptAES {
public static boolean initialized = false;
public static final String ALGORITHM = "AES/ECB/PKCS7Padding";
/**
* @param String data 要被加密的字符串
* @param String key 加/解密要用的长度为32的字节数组(256位)密钥
* @return String 加密后数据
* @throws Exception
*/
public static String Aes256Encode(String data, String key) {
initialize();
byte[] result = null;
try {
Cipher cipher = Cipher.getInstance(ALGORITHM, "BC");
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
result = cipher.doFinal(data.getBytes("UTF-8"));
} catch (Exception e) {
e.printStackTrace();
}
return Base64.encodeBase64String(result);
}
/**
* @param String dataEncode 要被解密的数据(加密后的数据)
* @param String key 加/解密要用的长度为32的字节数组(256位)密钥
* @return String 解密后的字符串
*/
public static String Aes256Decode(String dataEncode, String key) {
initialize();
String result = null;
try {
Cipher cipher = Cipher.getInstance(ALGORITHM, "BC");
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] decoded = cipher.doFinal(Base64.decodeBase64(dataEncode));
result = new String(decoded, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static void initialize() {
if (initialized)
return;
Security.addProvider(new BouncyCastleProvider());
initialized = true;
}
public static void main(String[] args) {
String key = "12345678901234567890123456789012";
String data = "abc";
String aes256Encode = Aes256Encode(data, key);
System.out.println("加密前数据:" + data);
System.out.println("加密后数据:" + aes256Encode);
System.out.println();
String aes256Decode = Aes256Decode(aes256Encode, key);
System.out.println("解密前数据:" + aes256Encode);
System.out.println("解密后数据:" + aes256Decode);
}
}
输出结果:
加密前数据:abc
加密后数据:q2tSoCKKcbz8RCMso+R2QA==
解密前数据:q2tSoCKKcbz8RCMso+R2QA==
解密后数据:abc