第八章 对称加密算法--AES
注意:本节内容主要参考自《Java加密与解密的艺术(第2版)》第7章“初等加密算法--对称加密算法”
8.1、AES
特点:
- 密钥建立时间短、灵敏性好、内存需求低(不管怎样,反正就是好)
- 最常用的对称加密算法
8.2、实现方式
- JDK(密钥长度有128,192,256三种选法,提供PKCS5Padding的填充模式)
- Bouncy Castle(密钥长度有128,192,256三种选法,提供PKCS7Padding的填充模式)
8.2.1、基于JDK或BC的AES实现(工作模式为ECB)
package com.util.aes;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* 基于JDK或BC的AES算法,工作模式采用ECB
*/
public class AESJDK {
private static final String ENCODING = "UTF-8";
private static final String KEY_ALGORITHM = "AES";//产生密钥的算法
private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//加解密算法 格式:算法/工作模式/填充模式 注意:ECB不使用IV参数
/**
* 产生密钥
*/
public static byte[] getKey() throws NoSuchAlgorithmException{
Security.addProvider(new BouncyCastleProvider());//在BC中用,JDK下去除
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
keyGenerator.init(256);//初始化密钥长度,128,192,256(选用192和256的时候需要配置无政策限制权限文件--JDK6)
SecretKey key =keyGenerator.generateKey();//产生密钥
return key.getEncoded();
}
/**
* 还原密钥:二进制字节数组转换为Java对象
*/
public static Key toKey(byte[] keyByte){
return new SecretKeySpec(keyByte, KEY_ALGORITHM);
}
/**
* AES加密
* @param data 带加密数据
* @param keyByte 密钥
*/
public static byte[] encrypt(String data, byte[] keyByte) throws InvalidKeyException,
NoSuchAlgorithmException,
InvalidKeySpecException,
NoSuchPaddingException,
IllegalBlockSizeException,
BadPaddingException,
UnsupportedEncodingException,
NoSuchProviderException,
InvalidAlgorithmParameterException{
Key key = toKey(keyByte);//还原密钥
//Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);//JDK下用
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");//BC下用
cipher.init(Cipher.ENCRYPT_MODE, key);//设置加密模式并且初始化key
return cipher.doFinal(data.getBytes(ENCODING));
}
/**
* AES加密,并转为16进制字符串或Base64编码字符串
*/
public static String encryptAESHex(String data, byte[] keyByte) throws InvalidKeyException,
NoSuchAlgorithmException,
InvalidKeySpecException,
NoSuchPaddingException,
IllegalBlockSizeException,
BadPaddingException,
UnsupportedEncodingException,
NoSuchProviderException,
InvalidAlgorithmParameterException {
byte[] encodedByte = encrypt(data, keyByte);
//return new String(Hex.encode(encodedByte));//借助BC
//return new String(org.apache.commons.codec.binary.Hex.encodeHexString(encodedByte));//借助CC
return Base64.encodeBase64String(encodedByte);//借助CC的Base64编码
}
/**
* AES解密
* @param data 待解密数据为字节数组
* @param keyByte 密钥
*/
public static byte[] decrypt(byte[] data, byte[] keyByte) throws InvalidKeyException,
NoSuchAlgorithmException,
InvalidKeySpecException,
NoSuchPaddingException,
IllegalBlockSizeException,
BadPaddingException,
UnsupportedEncodingException,
NoSuchProviderException,
InvalidAlgorithmParameterException {
Key key = toKey(keyByte);//还原密钥
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");//BC下用
//Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);//JDK下用
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(data);
}
/**
* AES解密
* @param data 待解密数据为字符串
* @param keyByte 密钥
*/
public static byte[] decrypt(String data, byte[] keyByte) throws InvalidKeyException,
NoSuchAlgorithmException,
InvalidKeySpecException,
NoSuchPaddingException,
IllegalBlockSizeException,
BadPaddingException,
UnsupportedEncodingException,
NoSuchProviderException,
InvalidAlgorithmParameterException {
Key key = toKey(keyByte);//还原密钥
//Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);//JDK下用
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");//BC下用
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(Base64.decodeBase64(data));//注意data不可以直接采用data.getByte()方法转化为字节数组,否则会抛异常
}
/**
* 测试
*/
public static void main(String[] args) throws NoSuchAlgorithmException,
InvalidKeyException,
InvalidKeySpecException,
NoSuchPaddingException,
IllegalBlockSizeException,
BadPaddingException,
UnsupportedEncodingException,
NoSuchProviderException,
InvalidAlgorithmParameterException {
String data = "找一个好姑娘做老婆是我的梦 想!";
/*************测试encrypt()、decrypt()**************/
System.out.println("原文-->"+data);
byte[] keyByte = AESJDK.getKey();
System.out.println("密钥-->"+Base64.encodeBase64String(keyByte));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
byte[] encodedByte = AESJDK.encrypt(data, keyByte);
System.out.println("加密后-->"+encodedByte);
byte[] encodedByte2 = AESJDK.encrypt(data, keyByte);
System.out.println("加密后-->"+encodedByte2);
byte[] decodedByte = AESJDK.decrypt(encodedByte, keyByte);
System.out.println("解密后-->"+decodedByte);
for(int i=0;i<encodedByte.length;i++){
System.out.println(encodedByte[i]==encodedByte2[i]);
}
/*************测试encryptAESHex()、decrypt()**************/
System.out.println("原文-->"+data);
byte[] keyByte3 = AESJDK.getKey();
System.out.println("密钥-->"+Base64.encodeBase64String(keyByte3));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
String encodedStr = AESJDK.encryptAESHex(data, keyByte3);
System.out.println("加密后-->"+encodedStr);
String encodedByte4 = AESJDK.encryptAESHex(data, keyByte3);
System.out.println("加密后-->"+encodedByte4);
byte[] decodedByte3 = AESJDK.decrypt(Base64.decodeBase64(encodedStr), keyByte3);
System.out.println("解密Byte[]后-->"+decodedByte3);
byte[] decodedByte4 = AESJDK.decrypt(encodedStr, keyByte3);
System.out.println("解密String后-->"+decodedByte4);
}
}
注意点:
- 本文JDK版本采用的是1.6(也是当下企业常用的版本)
- 基于JDK或是基于BC去实现查看代码中注释即可
- 想使用BC下,需要在生成密钥的地方加上Security.addProvider(new BouncyCastleProvider());(这与书中不同,可能JDK7不需要加)
- 密钥初始化长度可以为128,192,256,其中在选用192和256的时候需要配置无政策限制权限文件,具体方法文末会讲。(这与书中不同,可能JDK7下192不需要配置那个文件)
这个类具体在实际中使用的方式见"Java企业项目开发实践"《第六章 企业项目开发--cookie》,具体链接如下:
http://www.cnblogs.com/java-zhao/p/5128393.html
8.2.2、基于BC的AES实现(工作模式为CTR)(这个类在我后边的使用中有点问题,以后有时间再来解决,如果要用AES算法的话,用上边那种就好)
package com.util.aes;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* 基于BC的AES算法,工作模式采用CTR
*/
public class AESBC {
private static final String ENCODING = "UTF-8";
private static final String KEY_ALGORITHM = "AES";//产生密钥的算法
private static final String CIPHER_ALGORITHM = "AES/CTR/PKCS7Padding";//加解密算法 格式:算法/工作模式/填充模式 注意:ECB不使用IV参数,CTR使用
private static final byte[] IV = "zhaojigangzhaoji".getBytes();//注意:这里需要是十六个字符,用于CTR
/**
* 产生密钥
*/
public static byte[] getKey() throws NoSuchAlgorithmException{
Security.addProvider(new BouncyCastleProvider());//加入BCProvider
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
keyGenerator.init(256);//初始化密钥长度,128,192,256(选用192和256的时候需要配置无政策限制权限文件--JDK6)
SecretKey key =keyGenerator.generateKey();//产生密钥
return key.getEncoded();
}
/**
* 还原密钥:二进制字节数组转换为Java对象
*/
public static Key toKey(byte[] keyByte){
return new SecretKeySpec(keyByte, KEY_ALGORITHM);
}
/**
* AES加密
* @param data 带加密数据
* @param keyByte 密钥
*/
public static byte[] encrypt(String data, byte[] keyByte) throws InvalidKeyException,
NoSuchAlgorithmException,
InvalidKeySpecException,
NoSuchPaddingException,
IllegalBlockSizeException,
BadPaddingException,
UnsupportedEncodingException,
NoSuchProviderException,
InvalidAlgorithmParameterException{
Key key = toKey(keyByte);//还原密钥
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");//使用BC
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV));//设置加密模式并且初始化key,加入IV用于BC下的CTR
return cipher.doFinal(data.getBytes(ENCODING));
}
/**
* AES加密,并转为16进制字符串或Base64编码字符串
*/
public static String encryptAESHex(String data, byte[] keyByte) throws InvalidKeyException,
NoSuchAlgorithmException,
InvalidKeySpecException,
NoSuchPaddingException,
IllegalBlockSizeException,
BadPaddingException,
UnsupportedEncodingException,
NoSuchProviderException,
InvalidAlgorithmParameterException {
byte[] encodedByte = encrypt(data, keyByte);
//return new String(Hex.encode(encodedByte));//借助BC
//return new String(org.apache.commons.codec.binary.Hex.encodeHexString(encodedByte));//借助CC
return Base64.encodeBase64String(encodedByte);//借助CC的Base64编码
}
/**
* AES解密
* @param data 待解密数据为字节数组
* @param keyByte 密钥
*/
public static byte[] decrypt(byte[] data, byte[] keyByte) throws InvalidKeyException,
NoSuchAlgorithmException,
InvalidKeySpecException,
NoSuchPaddingException,
IllegalBlockSizeException,
BadPaddingException,
UnsupportedEncodingException,
NoSuchProviderException,
InvalidAlgorithmParameterException {
Key key = toKey(keyByte);//还原密钥
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV));//设置加密模式并且初始化key,加入IV用于BC下的CTR
return cipher.doFinal(data);
}
/**
* AES解密
* @param data 待解密数据为字符串
* @param keyByte 密钥
*/
public static byte[] decrypt(String data, byte[] keyByte) throws InvalidKeyException,
NoSuchAlgorithmException,
InvalidKeySpecException,
NoSuchPaddingException,
IllegalBlockSizeException,
BadPaddingException,
UnsupportedEncodingException,
NoSuchProviderException,
InvalidAlgorithmParameterException {
Key key = toKey(keyByte);//还原密钥
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV));//设置加密模式并且初始化key,加入IV用于BC下的CTR
return cipher.doFinal(Base64.decodeBase64(data));
}
/**
* 测试
*/
public static void main(String[] args) throws NoSuchAlgorithmException,
InvalidKeyException,
InvalidKeySpecException,
NoSuchPaddingException,
IllegalBlockSizeException,
BadPaddingException,
UnsupportedEncodingException,
NoSuchProviderException,
InvalidAlgorithmParameterException {
String data = "找一个好姑娘做老婆是我的梦 想!";
/*************测试encrypt()、decrypt()**************/
System.out.println("原文-->"+data);
byte[] keyByte = AESBC.getKey();
System.out.println("密钥-->"+Base64.encodeBase64String(keyByte));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
byte[] encodedByte = AESBC.encrypt(data, keyByte);
System.out.println("加密后-->"+encodedByte);
byte[] encodedByte2 = AESBC.encrypt(data, keyByte);
System.out.println("加密后-->"+encodedByte2);
byte[] decodedByte = AESBC.decrypt(encodedByte, keyByte);
System.out.println("解密后-->"+decodedByte);
for(int i=0;i<encodedByte.length;i++){
System.out.println(encodedByte[i]==encodedByte2[i]);
}
/*************测试encryptAESHex()、decrypt()**************/
System.out.println("原文-->"+data);
byte[] keyByte3 = AESBC.getKey();
System.out.println("密钥-->"+Base64.encodeBase64String(keyByte3));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
String encodedStr = AESBC.encryptAESHex(data, keyByte3);
System.out.println("加密后-->"+encodedStr);
String encodedByte4 = AESBC.encryptAESHex(data, keyByte3);
System.out.println("加密后-->"+encodedByte4);
byte[] decodedByte3 = AESBC.decrypt(Base64.decodeBase64(encodedStr), keyByte3);
System.out.println("解密Byte[]后-->"+decodedByte3);
byte[] decodedByte4 = AESBC.decrypt(encodedStr, keyByte3);
System.out.println("解密String后-->"+decodedByte4);
}
}
注意点:
- CTR是AES最常使用的工作模式
- 在CTR模式下需要加入IV参数(必须是一个16位的自己数组,例如:byte[] IV = "zhaojigangzhaoji".getBytes()),这是ECB模式所不需要的。
- IV参数用于cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV))
附:无政策限制权限文件配置方法:
第一步:下载配置文件压缩包
http://download.csdn.net/download/rzg813/8069407
第二步:用压缩包中下边选中的文件去覆盖%JAVA_HOME%\jre\lib\security和%JRE_HOME%\lib\security下相应的包即可。

第八章 对称加密算法--AES的更多相关文章
- JAVA的对称加密算法AES——加密和解密
出自: http://blog.csdn.net/hongtashan11/article/details/6599645 http://www.cnblogs.com/liunanjava/p/42 ...
- DES、3DES、AES、PBE对称加密算法实现及应用
1.对称加密算法概述 对称加密算法是应用较早的加密算法,技术成熟.在对称加密算法中,数据发信方将明文和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去.收信方收到密文后,若想解读原文 ...
- 常用加密算法的Java实现总结(二) ——对称加密算法DES、3DES和AES
1.对称加密算法 1.1 定义 对称加密算法是应用较早的加密算法,技术成熟.在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yue)一起经过特殊加密算法处理后,使其变成复杂的加密密文发 ...
- Java 加密解密 对称加密算法 非对称加密算法 MD5 BASE64 AES RSA
版权声明:本文为博主原创文章,未经博主允许不得转载. [前言] 本文简单的介绍了加密技术相关概念,最后总结了java中现有的加密技术以及使用方法和例子 [最简单的加密] 1.简单的概念 明文:加密前的 ...
- Java 加密 AES 对称加密算法
版权声明:本文为博主原创文章,未经博主允许不得转载. [AES] 一种对称加密算法,DES的取代者. 加密相关文章见:Java 加密解密 对称加密算法 非对称加密算法 MD5 BASE64 AES R ...
- 对称加密算法DES,3重DES,TDEA,Blowfish,RC5,IDEA,AES。
对称加密算法:DES,3重DES,TDEA,Blowfish,RC5,IDEA,AES. 1.对称加密算法 1.1 定义 对称加密算法是应用较早的加密算法,技术成熟.在对称加密算法中,数据发信方将明文 ...
- java-信息安全(二)-对称加密算法DES,3DES,AES,Blowfish,RC2,RC4
概述 信息安全基本概念: DES(Data Encryption Standard,数据加密标准) 3DES(Triple DES,三重数据加密算法(TDEA,Triple Data Encrypti ...
- 对称加密算法DES、3DES和AES 原理总结(转载)
1.对称加密算法 1.1 定义 对称加密算法是应用较早的加密算法,技术成熟.在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yue)一起经过特殊加密算法处理后,使其变成复杂的加密密文发 ...
- DES/3DES/AES 三种对称加密算法实现
1. 简单介绍 3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称.它相当于是对每个数据块应用三次DES ...
随机推荐
- 洛谷P3557 GRA-Tower Defense Game [POI2013] 构造
正解:构造 解题报告: 传送门 话说这题我理解题意理解了好久TT一直没懂那个,k的意义是什么,,,后来才明白,可能k就是没有意义的趴 (upd:好像明白辣,k是用来保证这么做是对的QwQ 然后就直接港 ...
- TortoiseGit密钥的配置(转)
add by zhj:说到密钥,就不得不提非对称加密.目前使用最广泛的非对称加密算法是rsa,它是美国三位科学家于1977年发明的. 一对密钥对有两个密钥,其中一个为私钥,一个为公钥,两者没有什么区别 ...
- iOS中textbox文本框清除圆角
在iOS.Mac safari中,所有的textbox, select, checkbox都会被强制美化为圆角.但在特殊情况下需要清除圆角时发现iOS中使用以下传统的css无效: border-rad ...
- 自定义Metrics:让Prometheus监控你的应用程序
前言 Prometheus社区提供了大量的官方以及第三方Exporters,可以满足Prometheus的采纳者快速实现对关键业务,以及基础设施的监控需求. 如上所示,一个简单的应用以及环境架构.一般 ...
- java map.entry
我希望要一个ArrayList<Entry>,类似C++中的pair, 但是Map.Entry是个接口,不能实例化,可以像下面这样写 HashMap<Integer, Integer ...
- glob.glob()、os.path.split()函数、global和nonlocal关键字
1. glob.glob() glob模块是Python最简单的模块之一, 内容非常少, 用它可以查找符合特定规则的文件路径名, 查找文件时只会用到三个匹配符: * :匹配0个或多个字符 ? : 匹配 ...
- 筛选DataTable中的数据
DataTable dt = bll.GetTable(); //查询数据 DataTable newdt = new DataTable(); //一个新的table来保存筛选的记录 newdt = ...
- js模拟电梯操作
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- VS2010/MFC编程入门之四十三(MFC常用类:CTime类和CTimeSpan类)
上一节中鸡啄米讲了MFC常用类CString类的用法,本节继续讲另外两个MFC常用类-日期和时间类CTime类和CTimeSpan类. 日期和时间类简介 CTime类的对象表示的时间是基于格林威治标准 ...
- 519. Random Flip Matrix(Fisher-Yates洗牌算法)
1. 问题 给定一个全零矩阵的行和列,实现flip函数随机把一个0变成1并返回索引,实现rest函数将所有数归零. 2. 思路 拒绝采样 (1)先计算矩阵的元素个数(行乘以列),记作n,那么[0, n ...