上面一篇文章介绍了使用DES方式进行加解密(DES方式加解密的简单介绍),我们说了DES由于使用8个字节(64bit)密钥进行加解密,所以安全性不够(当然这里的不够都是相对的),所以现在使用了密钥更多的AES方式进行对称加密提高安全性,AES加密方式的全称是Advanced Encryption Standard,这里的Advanced当然是相对于DES来说的。AES加密根据其使用的密钥长度又细分成AES-128、AES-192和AES-256这三种AES加密方式,其中AES-128对应128bit密钥长度,AES-192对应192bit,AES-256对应256bit,从道理上说密钥长度越长,机密的安全等级就越高,但是密钥越长加解密对硬件的性能消耗就越厉害,所以这里以AES-128为例来讲解AES加密方式在Java中的实现(实际上实现了128加密,另外两种也就简单了)。
1、AES加密
我们这里还是先实现AES的字节方式加密
/**
* AES加密二进制数据
*
* @param data 二进制待加密数据
* @param key 二进制密钥
* @return 二进制加密后的数据
* @throws Exception
*/
public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
//构造密钥生成器,指定AES算法
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
//根据传入的密钥字节生成一个可信任的随机数据源
SecureRandom secureRandom = new SecureRandom(key);
//初始化一个128的密钥生成器
keyGenerator.init(128,secureRandom);
//生成一个原始的对称密钥
SecretKey originSecretKey = keyGenerator.generateKey();
//根据原始对称密钥生成一个AES密钥
byte[] raw = originSecretKey.getEncoded();
SecretKeySpec secretKey = new SecretKeySpec(raw,"AES");
//声明一个Cipher对象
Cipher cipher = Cipher.getInstance("AES");
//使用密钥初始化cipher
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
//进行解密操作,实际上执行的还是Cipher的doFinal方法
return cipher.doFinal(data);
}
代码中对字节加密实现说的很详细了,这里提一下的就是由于这里使用了AES-128的加密方式,所以代码中的secretKey是16个字节(128bit)的,如果我们换成AES-192那么这里的secretKey就应该是24个字节。同时也要注意和DES实现加密一样,这里实际上的加密工作还是由Java中的Cipher类来完成的,我们所做的事情只不过是一些初始化的工作。
同样的,由于平时使用的都是针对字符串的加解密,所以这里得实现一个字符串的加密方法
/**
* 重载encrypt方法,使得数据源和密钥可使用字符串
*
* @param data 字符串数据源
* @param key 字符串密钥
* @return 返回字符串类型的
* @throws Exception
*/
public static String encrypt(String data, String key) throws Exception {
byte[] bt = encrypt(data.getBytes(), key.getBytes());
String str = Base64.encodeBase64URLSafeString(bt);
return str;
}
这里还是使用了Base64进行byte和String之间的转换,不能直接用new String(bytes)方式来转换,具体原因见DES那篇文章。
2、AES解密
同样的,这里来实现AES的字节解密方式
/**
* AES解密二进制数据
*
* @param data AES机密过的二进制数据
* @param key 用来解密的二进制密钥
* @return 返回解密后的数据
* @throws Exception
*/
public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
//构造密钥生成器,指定AES算法
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
//根据传入的密钥字节生成一个可信任的随机数据源
SecureRandom secureRandom = new SecureRandom(key);
//初始化一个128的密钥生成器
keyGenerator.init(128,secureRandom);
//生成一个原始的对称密钥
SecretKey originSecretKey = keyGenerator.generateKey();
//根据原始对称密钥生成一个AES密钥
byte[] raw = originSecretKey.getEncoded();
SecretKeySpec secretKey = new SecretKeySpec(raw,"AES");
//声明一个Cipher对象
Cipher cipher = Cipher.getInstance("AES");
/***到这里的字节解密代码都和机密代码一样***/
//使用密钥初始化cipher,这里和加密操作的唯一区别是设置的MODE不一样
cipher.init(Cipher.DECRYPT_MODE, secretKey);
//进行解密操作,实际上执行的还是Cipher的doFinal方法
return cipher.doFinal(data);
}
看的出来,这里的字节解密方法实现和加密方法实现只有cipher.init代码设置的Mode方式不一样而已,最后还是通过Cipher类来进行的解密操作。
这里还是来实现一个针对字符串的解密方式
/**
* 重载decrypt方法,输入加密过的数据源和密钥输出解密后的字符串
* @param data 加密后的字符串数据源
* @param key 用来加密的字符串密钥
* @return 解密后的字符串
* @throws Exception
*/
public static String decrypt(String data, String key) throws Exception {
byte[] buf = Base64.decodeBase64(data);
byte[] bt = decrypt(buf, key.getBytes());
return new String(bt);
}
到这里AES方式在Java中实现加解密的功能就算完成了,至于AES加解密的详情这里就细究了,毕竟DES的实现原理博主都觉得一时半会搞不定更不用说更加复杂的AES了。有了加解密方法,小伙伴们就很容易实现自己的AesUtil工具类了,不过在android中请记得用android.util.Base64的对应方法来处理Byte和String。
下面是我的详细使用代码,base64编码和二进制十六进制转换两种方式。
注:Base64 key定义为16位字符,十六进制的key字母范围是a-f.
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
/**
* @author x_san3
* Description: 加解密
*/
public class AESUtil {
private static String algorithm = "AES";
private static String key = "abcdefghijklm123";
public static void main(String[] args) throws Exception {
String data = "654321";
/*String secretKey = "abcdefabcdefabcdefabcdefabcdef09";
String enStr = AESUtil.encrypt(data, secretKey);
System.out.println("加密后:" + enStr);
String deStr = AESUtil.decrypt(enStr, secretKey);
System.out.println("解密后:" + deStr);*/
String ciphertext = AESUtil.encrypt(data);
System.out.println("加密后:" + ciphertext);
String deStr = AESUtil.decrypt(ciphertext);
System.out.println("解密后:" + deStr);
}
/**
* Description: 加密
* @param secret
* @return 加密后的值
* @throws Exception
*/
public static String encrypt(String data) throws Exception {
// Cipher负责完成加密或解密工作,生成Cipher对象,指定其支持的算法
Cipher cipher = Cipher.getInstance(algorithm);
// 生成特定的密钥
SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
// 根据密钥,对Cipher对象进行初始化,ENCRYPT_MODE表示加密模式
cipher.init(Cipher.ENCRYPT_MODE, skey);
byte[] result = cipher.doFinal(data.getBytes());
// org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString(result);
return Base64.getEncoder().encodeToString(result);
}
/**
* Description: 解密
* @param ciphertext
* @return 解密后的值
* @throws Exception
*/
public static String decrypt(String ciphertext) throws Exception {
//byte[] old = org.apache.commons.codec.binary.Base64.decodeBase64(ciphertext);
byte[] ciphertextByte = Base64.getDecoder().decode(ciphertext);
// Cipher负责完成加密或解密工作,生成Cipher对象,指定其支持的算法
Cipher cipher = Cipher.getInstance(algorithm);
// 生成特定的密钥
SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
// 根据密钥,对Cipher对象进行初始化,ENCRYPT_MODE表示加密模式
cipher.init(Cipher.DECRYPT_MODE, skey);
byte[] result = cipher.doFinal(ciphertextByte);
return new String(result);
}
/*
* 加密
*/
public static String encrypt(String data, String secretKey) throws Exception {
byte[] key = hexStr2Byte(secretKey);
SecretKeySpec sKey = new SecretKeySpec(key, algorithm);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, sKey);
byte[] encrypted = cipher.doFinal(data.getBytes());
return byte2HexStr(encrypted);
}
/*
* 解密
*/
public static String decrypt(String ciphertext, String secretKey) throws Exception {
byte[] tmp = hexStr2Byte(ciphertext);
byte[] key = hexStr2Byte(secretKey);
SecretKeySpec sKey = new SecretKeySpec(key, algorithm);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, sKey);
byte[] decrypted = cipher.doFinal(tmp);
return new String(decrypted);
}
/*
* 转为二进制
*/
private static byte[] hexStr2Byte(String secret_key) {
if (secret_key.length() < 1)
return null;
byte[] encrypted = new byte[secret_key.length() / 2];
for (int i = 0; i < secret_key.length() / 2; i++) {
int high = Integer.parseInt(secret_key.substring(i * 2, i * 2 + 1), 16);//偶数位
int low = Integer.parseInt(secret_key.substring(i * 2 + 1, i * 2 + 2), 16);//奇数位
encrypted[i] = (byte) (high * 16 + low);
}
return encrypted;
}
/*
* 转为十六进制
*/
private static String byte2HexStr(byte buf[]) {
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10)
strbuf.append("0");
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}
}
---------------------------------------------欢迎关注公众号(生活不止有代码)-------------------------------------------------------