Java 常用加密算法(二)---对称加密(DES/3DES(T
2017-08-27 本文已影响84人
_凌浩雨
Java 常用加密算法(二)---对称加密(DES/3DES(TripleDES)/AES)
基于“对称密钥”的加密算法主要有DES、3DES(TripleDES)、AES、RC2、RC4、RC5和Blowfish等。
代码中用到的Base64与BouncyCastleProvider的jar包可在本文末尾下载源码,从源码获取jar包。
- DES
DES算法全称为Data Encryption Standard,即数据加密算法,它是IBM公司于1975年研究成功并公开发表的。DES算法的入口参数有三个:Key、Data、Mode。其中Key为8个字节共64位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密。
五种分组模式:EBC模式、CBC模式、CFB模式、OFB模式、CTR模式。
其中CTR 模式被广泛用于 ATM 网络安全和 IPSec应用中,相对于其它模式而言,CRT模式具有如下特点:
■硬件效率:允许同时处理多块明文 / 密文。
■ 软件效率:允许并行计算,可以很好地利用 CPU 流水等并行技术。
■ 预处理:算法和加密盒的输出不依靠明文和密文的输入,因此如果有足够的保证安全的存储器,加密算法将仅仅是一系列异或运算,这将极大地提高吞吐量。
■ 随机访问:第 i 块密文的解密不依赖于第 i-1 块密文,提供很高的随机访问能力
■ 可证明的安全性:能够证明 CTR 至少和其他模式一样安全(CBC, CFB, OFB, ...)
■ 简单性:与其它模式不同,CTR模式仅要求实现加密算法,但不要求实现解密算法。对于 AES 等加/解密本质上不同的算法来说,这种简化是巨大的。
■ 无填充,可以高效地作为流式加密使用。
在Java进行DES、3DES和AES三种对称加密算法时,常采用的是NoPadding(不填充)、Zeros填充(0填充)、PKCS5Padding填充。
示例:
/**
* DES加密工具类
* @author mazaiting
*/
public class DESUtil {
/**
* 算法名称
*/
public static final String KEY_ALGORITHM = "DES";
/**
* 算法名称/加密模式/填充方式
* DES的四种工作模式:ECB(电子密码本)、CBC(加密分组链接)、
* CFB(加密反馈模式)、OFB(输出反馈)
* 当前无填充的情况:
* 加密数据必须为8的倍数,密钥输入必须为16的倍数
* 使用
String source = "abcdefgh";// 为8位的倍数
String key = "A1B2C3D4E5F60708";// 为16位的倍数
String encryptData = DESUtil.encrypt(source, key);
System.out.println("加密后: " + encryptData);
String decryptData = DESUtil.decrypt(encryptData, key);
System.out.println("解密后: " + decryptData);
*/
public static final String CIPHER_ALGORITHM_DES_ECB_NOPADDING = "DES/ECB/NoPadding";
/**
* DES/CBC/PKCS5Padding
* PKCS5Padding填充时:
* 加密数据无位数控制,密钥输入必须为16的倍数
* 使用
String source = "abcdefgh";// 无需控制位数
String key = "A1B2C3D4E5F60708";// 为16位的倍数
String encryptData = DESUtil.encrypt(source, key);
System.out.println("加密后: " + encryptData);
String decryptData = DESUtil.decrypt(encryptData, key);
System.out.println("解密后: " + decryptData);
*/
public static final String CIPHER_ALGORITHM_DES_ECB_PKCS5_PADDING = "DES/ECB/PKCS5Padding";
/**
* 加密数据
* @param data 待加密的数据--8位
* @param key 密钥--16位
* @return 加密后的数据
*/
public static String encrypt(String data, String key) {
try {
// 获得一个密钥
Key deskey = keyGenerator(key);
// 实例化一个Cipher(密码)对象,用于完成加密操作
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_DES_ECB_PKCS5_PADDING);
SecureRandom random = new SecureRandom();
// 初始化Cipher对象,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, deskey, random);
byte[] bytes = data.getBytes();
// 执行加密操作
byte[] results = cipher.doFinal(bytes);
return Base64.encodeBase64String(results);
} catch (InvalidKeyException e) {
return "无效KEY"; // 无效KEY
} catch (NoSuchAlgorithmException e) {
return "无效算法名称"; // 无效算法名称
} catch (InvalidKeySpecException e) {
return "无效KeySpec"; // 无效KeySpec
} catch (NoSuchPaddingException e) {
return "无效算法名称"; // 无效算法名称
} catch (IllegalBlockSizeException e) {
return "无效字节"; // 无效字节
} catch (BadPaddingException e) {
return "解析异常"; // 解析异常
}
}
/**
* 解密数据
* @param data 待解密数据
* @param key 密钥
* @return 解密后的数据
*/
public static String decrypt(String data, String key) {
try {
Key desKey = keyGenerator(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_DES_ECB_PKCS5_PADDING);
// 初始化Cipher对象,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, desKey);
// 执行解密操作
byte[] decBytes = cipher.doFinal(Base64.decodeBase64(data));
return new String(decBytes,"UTF-8");
} catch (InvalidKeyException e) {
return "无效KEY"; // 无效KEY
} catch (NoSuchAlgorithmException e) {
return "无效算法名称"; // 无效算法名称
} catch (InvalidKeySpecException e) {
return "无效KeySpec"; // 无效KeySpec
} catch (NoSuchPaddingException e) {
return "无效算法名称"; // 无效算法名称
} catch (IllegalBlockSizeException e) {
return "无效字节"; // 无效字节
} catch (BadPaddingException e) {
return "解析异常"; // 解析异常
} catch (UnsupportedEncodingException e) {
return "编码异常"; // 编码异常
}
}
/**
* 生成密钥key对象
* @param key 密钥字符串
* @return 密钥对象
* @throws InvalidKeyException 无效的key
* @throws NoSuchAlgorithmException 算法名称未发现
* @throws InvalidKeySpecException 无效的KeySpec
*/
private static Key keyGenerator(String key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
byte[] input = hexString2Bytes(key);
DESKeySpec desKey = new DESKeySpec(input);
// 创建一个密钥工厂,然后用它把DESKeySpec转化
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
// 获得一个密钥
SecretKey secretKey = keyFactory.generateSecret(desKey);
return secretKey;
}
/**
* 从十六进制字符串到字节数组转化
* @param key 密钥
*/
private static byte[] hexString2Bytes(String key) {
byte[] b = new byte[key.length()/2];
int j = 0;
for (int i = 0; i < b.length; i++) {
char c0 = key.charAt(j++);
char c1 = key.charAt(j++);
// c0做b[i]的高字节,c1做低字节
b[i] = (byte) ((parse(c0)<<4)|parse(c1));
}
return b;
}
/**
* 将字符转换为int值
* @param c 要转化的字符
* @return ASCII码值
*/
private static int parse(char c) {
if (c >= 'a') {
return (c - 'a' + 10) & 0x0f;
}
if (c >= 'A') {
return (c - 'A' + 10) & 0x0f;
}
return (c - '0') & 0x0f;
}
}
- 3-DES
3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它相当于是对每个数据块应用三次DES加密算法。由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解;3DES即是设计用来提供一种相对简单的方法,即通过增加DES的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法。
示例:
/**
* 3-DES加密工具类
* @author mazaiting
*/
public class ThreeDESUtil {
/**
* 算法名称
*/
public static final String KEY_ALGORITHM = "desede";
/**
* 算法名称/加密模式/填充方式
*
String source = "abcdefgh"; // 无填充情况下,长度必须为8的倍数
String key = "6C4E60E55552386C759569836DC0F83869836DC0F838C0F7";// 长度必须大于等于48
System.out.println(key.length());
String encryptData = ThreeDESUtil.tDesEncryptCBC(source, key);
System.out.println("加密后: " + encryptData);
String decryptData = ThreeDESUtil.tDesDecryptCBC(encryptData, key);
System.out.println("解密后: " + decryptData);
*/
public static final String CIPHER_ALGORITHM = "desede/CBC/NoPadding";
/**
* IvParameterSpec参数
*/
public static final byte[] keyiv = { 1, 2, 3, 4, 5, 6, 7, 8 };
/**
* CBC加密
* @param data 明文
* @param key 密钥
* @return Base64编码的密文
*/
public static String tDesEncryptCBC(String data, String key){
try {
// 添加一个安全提供者
Security.addProvider(new BouncyCastleProvider());
// 获得密钥
Key desKey = keyGenerator(key);
// 获取密码实例
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
IvParameterSpec ips = new IvParameterSpec(keyiv);
// 初始化密码
cipher.init(Cipher.ENCRYPT_MODE, desKey, ips);
// 执行加密
byte[] bytes = cipher.doFinal(data.getBytes("UTF-8"));
return Base64.encodeBase64String(bytes);
} catch (InvalidKeyException e) {
return "无效KEY"; // 无效KEY
} catch (NoSuchAlgorithmException e) {
return "无效算法名称"; // 无效算法名称
} catch (InvalidKeySpecException e) {
return "无效KeySpec"; // 无效KeySpec
} catch (NoSuchPaddingException e) {
return "无效算法名称"; // 无效算法名称
} catch (IllegalBlockSizeException e) {
return "无效字节"; // 无效字节
} catch (BadPaddingException e) {
return "解析异常"; // 解析异常
} catch (UnsupportedEncodingException e) {
return "编码异常"; // 编码异常
} catch (InvalidAlgorithmParameterException e) {
return "摘要参数异常"; // 摘要参数异常
}
}
/**
* CBC解密
* @param data Base64编码的密文
* @param key 密钥
* @return
*/
public static String tDesDecryptCBC(String data, String key) {
try {
Key desKey = keyGenerator(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
IvParameterSpec ips = new IvParameterSpec(keyiv);
cipher.init(Cipher.DECRYPT_MODE, desKey, ips);
byte[] bytes = cipher.doFinal(Base64.decodeBase64(data));
return new String(bytes, "UTF-8");
} catch (InvalidKeyException e) {
return "无效KEY"; // 无效KEY
} catch (NoSuchAlgorithmException e) {
return "无效算法名称"; // 无效算法名称
} catch (InvalidKeySpecException e) {
return "无效KeySpec"; // 无效KeySpec
} catch (NoSuchPaddingException e) {
return "无效算法名称"; // 无效算法名称
} catch (IllegalBlockSizeException e) {
return "无效字节"; // 无效字节
} catch (BadPaddingException e) {
return "解析异常"; // 解析异常
} catch (UnsupportedEncodingException e) {
return "编码异常"; // 编码异常
} catch (InvalidAlgorithmParameterException e) {
return "摘要参数异常"; // 摘要参数异常
}
}
/**
* 生成密钥key对象
* @param key 密钥字符串
* @return 密钥对象
* @throws InvalidKeyException 无效的key
* @throws NoSuchAlgorithmException 算法名称未发现
* @throws InvalidKeySpecException 无效的KeySpec
*/
private static Key keyGenerator(String key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
byte[] input = hexString2Bytes(key);
DESedeKeySpec desKey = new DESedeKeySpec(input);
// 创建一个密钥工厂,然后用它把DESKeySpec转化
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
// 获得一个密钥
SecretKey secretKey = keyFactory.generateSecret(desKey);
return secretKey;
}
/**
* 从十六进制字符串到字节数组转化
* @param key 密钥
*/
private static byte[] hexString2Bytes(String key) {
byte[] b = new byte[key.length()/2];
int j = 0;
for (int i = 0; i < b.length; i++) {
char c0 = key.charAt(j++);
char c1 = key.charAt(j++);
// c0做b[i]的高字节,c1做低字节
b[i] = (byte) ((parse(c0)<<4)|parse(c1));
}
return b;
}
/**
* 将字符转换为int值
* @param c 要转化的字符
* @return ASCII码值
*/
private static int parse(char c) {
if (c >= 'a') {
return (c - 'a' + 10) & 0x0f;
}
if (c >= 'A') {
return (c - 'A' + 10) & 0x0f;
}
return (c - '0') & 0x0f;
}
}
- AES加密
AES是分组密钥,算法输入128位数据,密钥长度也是128位。
/**
* AES加密工具类
* <p>
* 使用:
* String source = "mazaiting";
* String key = "123456";
* <p>
* String encryptString = AesUtil.encrypt(source, key);
* System.out.println("加密后: " + encryptString);
* <p>
* String decryptString = AesUtil.decrypt(encryptString, key);
* System.out.println("解密后: " + decryptString);
* 需要依赖:compile 'commons-codec:commons-codec:1.11'
* @author mazaiting
*/
public class AesUtil {
/**
* 算法名称
*/
private static final String KEY_ALGORITHM = "AES";
/**
* 算法
*/
private static final String CIPHER_ALGORITHM = "AES";
/**
* 加密数据
*
* @param data 待加密内容
* @param key 加密的密钥
* @return 加密后的数据
*/
public static String encrypt(String data, String key) {
try {
// 获得密钥
Key deskey = keyGenerator(key);
// 实例化一个密码对象
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
// 密码初始化
cipher.init(Cipher.ENCRYPT_MODE, deskey);
// 执行加密
byte[] bytes = cipher.doFinal(data.getBytes("UTF-8"));
// 返回Base64编码后的字符串
return Base64.encodeBase64String(bytes);
} catch (NoSuchAlgorithmException e) {
return "加密名称异常"; // 获取加密名称异常
} catch (UnsupportedEncodingException e) {
return "未知编码格式"; // 未知编码格式
} catch (InvalidKeyException e) {
return "无效Key"; // 无效Key
} catch (NoSuchPaddingException e) {
return "无效密码算法"; // 无效密码算法
} catch (IllegalBlockSizeException e) {
return "无效字节"; // 无效字节
} catch (BadPaddingException e) {
return "解析异常"; // 解析异常
}
}
/**
* 解密数据
*
* @param data 待解密的内容
* @param key 解密的密钥
* @return 解密后的文字
*/
public static String decrypt(String data, String key) {
try {
// 生成密钥
Key kGen = keyGenerator(key);
// 实例化密码对象
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
// 初始化密码对象
cipher.init(Cipher.DECRYPT_MODE, kGen);
// 执行解密
byte[] bytes = cipher.doFinal(Base64.decodeBase64(data));
// 返回解密后的字符串
return new String(bytes, "UTF-8");
} catch (NoSuchAlgorithmException e) {
return "加密名称异常"; // 获取加密名称异常
} catch (UnsupportedEncodingException e) {
return "未知编码格式"; // 未知编码格式
} catch (InvalidKeyException e) {
return "无效Key"; // 无效Key
} catch (NoSuchPaddingException e) {
return "无效密码算法"; // 无效密码算法
} catch (IllegalBlockSizeException e) {
return "无效字节"; // 无效字节
} catch (BadPaddingException e) {
return "解析异常"; // 解析异常
}
}
/**
* 获取密钥
*
* @param key 密钥字符串
* @return 返回一个密钥
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
*/
private static Key keyGenerator(String key) throws NoSuchAlgorithmException, UnsupportedEncodingException {
KeyGenerator kGen = KeyGenerator.getInstance(KEY_ALGORITHM);
kGen.init(128, new SecureRandom(hexString2Bytes(key)));
SecretKey secretKey = kGen.generateKey();
byte[] encoded = secretKey.getEncoded();
return new SecretKeySpec(encoded, KEY_ALGORITHM);
}
/**
* 从十六进制字符串到字节数组转化
*
* @param key 密钥
*/
private static byte[] hexString2Bytes(String key) {
byte[] b = new byte[key.length() / 2];
int j = 0;
for (int i = 0; i < b.length; i++) {
char c0 = key.charAt(j++);
char c1 = key.charAt(j++);
// c0做b[i]的高字节,c1做低字节
b[i] = (byte) ((parse(c0) << 4) | parse(c1));
}
return b;
}
/**
* 将字符转换为int值
*
* @param c 要转化的字符
* @return ASCII码值
*/
private static int parse(char c) {
if (c >= 'a') {
return (c - 'a' + 10) & 0x0f;
}
if (c >= 'A') {
return (c - 'A' + 10) & 0x0f;
}
return (c - '0') & 0x0f;
}
}