1977年l月数据加密标准DES(Data Encryption Standard)正式向社会公布,它是世界上第一个公认的实用分组密码算法标准。但DES在经过20年的实践应用后,现在已被认为是不可靠的。1997年1月2日美国国家标准和技术研究所(NSIT)发布了高级加密标准(AES—FIPS)的研发计划,并于同年9月12日正式发布了征集候选算法公告[18],希望确定一种保护敏感信息的公开、免费并且全球通用的算法作为AES,以代替DES。在征集公告中,NSIT对算法的基本要求是:算法必须是私钥体制的分组密码,支持128位分组长度和128、192、256 bits密钥长度。
经过三轮遴选,Rjindael最终胜出。2000年10月2日,NIST宣布采用Rjindael算法作为新一代高级加密标准。2001年11月26日联邦信息处理标准出版社发布了正式的AES标准即FIPS PUBS 197,其中制定的标准生效时间为2002年5月26日。
Rnjidael算法是一种可变分组长度和密钥长度的迭代型分组密码,它的分组长度和密钥长度均可独立地指定为128、192、256 bits,它以其安全性和多方面的优良性能,成为AES的最佳选择。Rjindael算法能抵抗现在的所有己知密码攻击,它在广泛的计算环境中的硬件和软件实现性能都表现得非常优秀,它的密钥建立时间极短且灵活性强,它极低的内存要求使其非常适合在存储器受限的环境中使用,并且表现出很好的性能[19]。
算法的实现方案:目前AES算法 实现研究主要分为软件实现和硬件实现两个方向。软件实现是在微机上的编程实现,它具有实现容易、可移植性强、成本低廉、易于升级等优点;它的缺点是需要庞大的操作系统和大量硬件资源的支持。由于通用CPU主频的不断提高,现在的软件实现也能达到相当高的速度。
AES的实现算法的Java细节如下表所示:
AES算法
算法 | 密钥长度 | 密钥长度默认值 | 工作模式 | 填充方式 | 备注 |
AES | 128、 192、 256 |
128 | ECB、CBC、PCBC、 CTR、CTS、CFB、 CFB8至CFB128、 OFB、OFB8OFB128 | NoPadding、 PKCS5Padding、 ISO1012Padding | Java 6实现若使用256位密 钥需要获得无政策限制文件 (Unlimited Strength Jurisdiction Policy Files) |
同上 | 同上 | 同上 | PKCS7Padding、 ZeroBytePadding | Bouncy Castle实现 |
/*
* Copyright 2013 WeCode authors
*
* Licensed under the WeCode, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License from ydonghao2@gmail.com
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wecode.security.algorithes;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
/**
* AES安全编码组件,Bouncy Castle 256字长密钥
*
* @author ydonghao2
* @version 2.0 使用Commons Codec提供Base64算法对密钥进行封装和解包
*
*/
public abstract class AESCoder {
// 密钥算法
public static final String KEY_ALGORITHM = "AES";
/**
* 加密/解密算法 /工作方式 / 填充方式 Bouncy Castle支持PKCS7Padding填充方式
*/
public static final String CIPTHER_ALGORITHM = "AES/ECB/PKCS7Padding";
/**
* 转换密钥
*
* @param key二进制密钥
* @return Key 密钥
* @throws Exception
*/
private static Key toKey(byte[] key) throws Exception {
// 实例化AES密钥材料
SecretKey secretKey = new SecretKeySpec(key, KEY_ALGORITHM);
return secretKey;
}
/**
* 解密
*
* @param data
* 待解密数据
* @param key
* 密钥
* @return byte[]解密数据
* @throws Exception
*/
public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
// 还原密钥
Key k = toKey(key);
/**
* 实例化
*
*/
Cipher cipher = Cipher.getInstance(CIPTHER_ALGORITHM, "BC");
// 初始化
cipher.init(Cipher.DECRYPT_MODE, k);
// 执行操作
return cipher.doFinal(data);
}
/**
* 解密
*
* @param data
* 待解密数据
* @param key
* 密钥
* @return byte[]解密数据
* @throws Exception
*/
public static byte[] decrypt(byte[] data, String key) throws Exception {
return decrypt(data, getKey(key));
}
/**
* 加密
*
* @param data
* 待加密数据
* @param key
* 密钥
* @return byte[] 加密数据
* @throws Exception
*/
public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
// 还原密钥
Key k = toKey(key);
/**
* 实例化
*/
Cipher cipher = Cipher.getInstance(CIPTHER_ALGORITHM, "BC");
// 初始化,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, k);
// 执行操作
return cipher.doFinal(data);
}
/**
* 加密
*
* @param data
* 待加密数据
* @param key
* 密钥
* @return byte[] 加密数据
* @throws Exception
*/
public static byte[] encrypt(byte[] data, String key) throws Exception {
return encrypt(data, getKey(key));
}
/**
* 生成密钥
*
* @return byte[] 二进制密钥
* @throws Exception
*/
public static byte[] initKey() throws Exception {
// 实例化
KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
// AES要求密钥长度为256位
kg.init(256);
// 生成密钥
SecretKey secretKey = kg.generateKey();
// 获取密钥的二进制编码形式
return secretKey.getEncoded();
}
/**
* 初始化密钥
* @return String Base64编码密钥
* @throws Exception
*/
public static String initKeyString() throws Exception {
return Base64.encodeBase64String(initKey());
}
/**
* 获取密钥
* @param key 密钥
* @return byte[] 密钥
* @throws Exception
*/
public static byte[] getKey(String key) throws Exception {
return Base64.decodeBase64(key);
}
/**
* 摘要处理
* @param data 待摘要数据
* @return 摘要字符串
*/
public static String shaHex(byte[] data) {
return DigestUtils.md5Hex(data);
}
/**
* 验证
* @param data 待摘要数据
* @param messageDigest 摘要字符串
* @return 验证结果
*/
public static boolean validate(byte[] data, String messageDigest) {
return messageDigest.equals(shaHex(data));
}
}
关于本系统的AES具体实现主要代码和说明如下:
public abstract classAESCoder extends java.lang.Object
AES安全编码组件,Bouncy Castle 256字长密钥
版本: 2.0 使用Commons Codec提供Base64算法对密钥进行封装和解包
密钥算法
这里指定我们在此次用的密钥算法,方便后面的SecretKey的实例化。
public static final String KEY_ALGORITHM = "AES";
加密/解密算法 /工作方式 / 填充方式 ,Java 6支持PKcs5Padding填充方式,Bouncy Castle支持PKCS7Padding填充方式,本系统采用Bouncy CastlePKCS7Padding方式
public static final String CIPTHER_ALGORITHM ="AES/ECB/PKCS7Padding";
转换密钥
参数:
key- 二进制密钥,
返回:
Key- 密钥。
抛出:
java.lang.Exception
SecretKey在javax.crypto.SecretKey包中。SecretKey接口是对称密钥顶层接口。DES、AES等多种对称密码算法密钥均可通过该接口提供。通常使用的SecretKey接口的实现类SecretKeySpec(javax.crypto.spec.SecretkeySpec)。本系统这里使用SecretKey是进行密钥转换,将二进制的key密钥转换成Key类型的密钥。
private static Key toKey(byte[] key) throws Exception {
// 实例化AES密钥材料
SecretKey secretKey = new SecretKeySpec(key,KEY_ALGORITHM);
return secretKey;
}
解密方法
参数:
data- 待解密数据
key- 密钥
返回:
byte[]解密数据
抛出:
java.lang.Exception
Cipher类是一个引擎类,它通过getInstance()工厂方法来实例化对象。此处通过上面的CIPTHER_ALGORITHM说明:使用的算法是AES算法,工作模式是ECB,填充方式是PKCS7Padding。不同的算法支持不同的工作模式及填充方式。“BC”是指Bouncy Castle。
Cipher中有着了如下两个常量:
//用于将Cipher对象进行初始化为解密常量。
public final static intDECRYPT_MODE;
//用于将Cipher对象初始化为加密模式常量。
public final static intENCRYPT_MODE;
通过这两个常量来完成用于加密或是解密的初始化。
init(Cipher.DECRYPT_MODE,k)则是运用了DECRYPT_MODE变量初始化了解密算法。
此次的解密操作不需要多次更新数据,因此可以直接执行public final byte[] doFinal(byte[]input),将解密的数据保存在data中。
public static byte[] decrypt(byte[] data, byte[] key) throwsException {
// 还原密钥
Key k = toKey(key);
Cipher cipher = Cipher.getInstance(CIPTHER_ALGORITHM,"BC");
// 初始化
cipher.init(Cipher.DECRYPT_MODE, k);
// 执行操作
return cipher.doFinal(data);
}
解密方法
参数:
data- 待解密数据
key- 密钥
返回:
byte[]解密数据
抛出:
java.lang.Exception
这个重载方法建的目的是为了在网络中传输密钥,在后面的加密方法中也有同样的重载方法所以在后面不再累述。
public static byte[] decrypt(byte[] data, String key) throwsException {
return decrypt(data, getKey(key));
}
加密方法
参数:
data- 待加密数据
key- 密钥
返回:
byte[]加密数据
抛出:
java.lang.Exception
init(Cipher.ENCRYPT_MODE,k)则是运用了ENCRYPT_MODE变量初始化了加密算法。
此次的加密操作不需要多次更新数据,因此可以直接执行public final byte[] doFinal(byte[]input),将加密的数据保存在data中。
public static byte[] encrypt(byte[] data, byte[] key) throwsException {
// 还原密钥
Key k = toKey(key);
Cipher cipher = Cipher.getInstance(CIPTHER_ALGORITHM,"BC");
// 初始化,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, k);
// 执行操作
return cipher.doFinal(data);
}
生成密钥
返回:
byte[]二进制密钥
抛出:
java.lang.Exception
在这里本系统AES要求密钥长度为256位。KeyGenerator类用来生成密钥。称为秘密密钥生成器。KeyGenerator类通过如下方法获得实例化:
public static final KeyGeneratorgetInstance(String algorithm)
返回生成指定算法的秘密密钥的KeyGenerator对象。
public static byte[] initKey() throws Exception {
// 实例化
KeyGenerator kg =KeyGenerator.getInstance(KEY_ALGORITHM);
kg.init(256);
// 生成密钥
SecretKey secretKey = kg.generateKey();
// 获取密钥的二进制编码形式
return secretKey.getEncoded();
}
AESCoderTest.java,测试AESCoder.java封装类
/*
* Copyright 2013 WeCode authors
*
* Licensed under the WeCode, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License from ydonghao2@gmail.com
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wecode.security.algorithes;
import static org.junit.Assert.*;
import org.apache.commons.codec.binary.Base64;
import org.junit.Test;
/**
* AES安全组件校验
* @author ydonghao2
* @version 2.0
*/
public class AESCoderTest {
/**
* 测试
*/
//@Test
public static void main(String[] args) throws Exception {
String inputStr = "AES";
byte[] inputData = inputStr.getBytes();
System.err.println("原文:" + inputStr);
//初始化密钥
byte[] key = AESCoder.initKey();
System.err.println("密钥:" + Base64.encodeBase64String(key));
//加密
inputData = AESCoder.encrypt(inputData, key);
System.out.println("加密后:" + Base64.encodeBase64String(inputData));
//解密
byte[] outputData = AESCoder.decrypt(inputData, key);
String outputStr = new String(outputData);
System.out.println("解密后:" + outputStr);
//校验
assertEquals(inputStr, outputStr);
}
}