数据签名、加密是前后端开发经常需要使用到的技术,应用场景包括不限于用户登入、数据交易、信息通讯等,不同的应用场景也会需要使用到不同的签名加密算法,或者需要搭配不一样的 签名加密算法来达到业务目标。常用的加密算法有:
- 对称加密算法;
- 非对称加密算法;
- 哈希算法,加盐哈希算法(单向加密);
- 数字签名。
使用加密签名算法,可以达到下面的安全目标:
- 保密性:防止用户的数据被读取;
- 数据完整性:防止数据被篡改;
- 身份验证:确保数据发自特定的一方。
对称加密
对称加密算法加密和解密时使用同一把秘钥。操作比较简单,加密速度快,秘钥简单。经常在消息发送方需要加密大量数据时使用。缺点是风险都在这个秘钥上面,一旦被窃取,信息会暴露。所以安全级别不够高。常用对称加密算法有DES,3DES,AES等。在jdk中也都有封装。
DES
DES的秘钥为8个字节,64个bit位。(不适应当今分布式开放网络对数据加密安全性的要求)在Java进行DES、3DES和AES三种对称加密算法时,常采用的是NoPadding(不填充)、Zeros填充(0填充)、PKCS5Padding填充。
一个DES的列子:
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.security.Key;
import java.security.SecureRandom;
import java.util.Base64;
public class DESUtil {
//算法名称
public static final String KEY_ALGORITHM = "DES";
//算法名称/加密模式/填充方式
//DES共有四种工作模式-->> ECB:电子密码本模式、 CBC:加密分组链接模式、CFB:加密反馈模式、OFB:输出反馈模式
//在Java进行DES、3DES和AES三种对称加密算法时,常采用的是NoPadding(不填充)、Zeros填充(0填充)、PKCS5Padding填充。
//不同的工作模式下,初始化Cipher的代码不一样
public static final String CIPHER_ALGORITHM = "DES/ECB/NoPadding";
private static SecretKey keyGenerator(String hexKeyStr) throws Exception {
byte input[] = hexString2Bytes(hexKeyStr);
DESKeySpec desKey = new DESKeySpec(input);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
SecretKey securekey = keyFactory.generateSecret(desKey);
return securekey;
}
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;
}
//从十六进制字符串到字节数组转换
public static byte[] hexString2Bytes(String hexstr) {
byte[] b = new byte[hexstr.length() / 2];
int j = 0;
for (int i = 0; i < b.length; i++) {
char c0 = hexstr.charAt(j++);
char c1 = hexstr.charAt(j++);
b[i] = (byte) ((parse(c0) << 4) | parse(c1));
}
return b;
}
/**
* 加密数据
* @param data 待加密数据
* @param hexKeyStr 密钥
* @return 加密后的数据
*/
public static String encrypt(String data, String hexKeyStr) throws Exception {
Key deskey = keyGenerator(hexKeyStr);
// 实例化Cipher对象,它用于完成实际的加密操作
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
SecureRandom random = new SecureRandom();
// 初始化Cipher对象,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, deskey, random);
byte[] results = cipher.doFinal(data.getBytes());
// 执行加密操作。加密后的结果通常都会用Base64编码进行传输
return Base64.getEncoder().encodeToString(results);
}
/**
* 解密数据
* @param data 待解密数据
* @param hexKeyStr 密钥
* @return 解密后的数据
*/
public static String decrypt(String data, String hexKeyStr) throws Exception {
Key deskey = keyGenerator(hexKeyStr);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
//初始化Cipher对象,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, deskey);
// 执行解密操作
return new String(cipher.doFinal(Base64.getDecoder().decode(data)));
}
//Des秘钥采用64bit为,8个字节,如果使用字符串则太短,一般使用16进制的字符串(长度16位,大于16为会截取前16位)
public static void main(String[] args) throws Exception {
//模拟3DES的过程
String source = "amigoxie";
System.out.println("原文: " + source);
String key = "A1B2C3D4E5F60708";
String ke2 = "A1B2C3D4E5F60709";
String ke3 = "A1B2C3D4E5F6070A";
String encryptData1 = encrypt(source, key);
String encryptData2 = decrypt(encryptData1,ke2);
String encryptData3 = encrypt(encryptData2,ke3);
System.out.println("加密后: " + encryptData3);
String dencryptData1 = decrypt(encryptData3,ke3);
String dencryptData2 = encrypt(dencryptData1,ke2);
String dencryptData3 = decrypt(dencryptData2,key);
System.out.println("解密后: " + dencryptData3);
//String decryptData = decrypt(encryptData, key);
//System.out.println("解密后: " + decryptData);
}
}
3DES
3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它相当于是对每个数据块应用三次DES加密算法。由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解;3DES即是设计用来提供一种相对简单的方法,即通过增加DES的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法。
其具体实现如下:设Ek()和Dk()代表DES算法的加密和解密过程,K代表DES算法使用的密钥,P代表明文,C代表密文,这样:
3DES加密过程为:C=Ek3(Dk2(Ek1(P)))
3DES解密过程为:P=Dk1(EK2(Dk3(C)))
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import java.security.Key;
import java.util.Base64;
public class ThreeDESUtil {
// 算法名称
public static final String KEY_ALGORITHM = "DESEDE";
// 算法名称/加密模式/填充方式
public static final String CIPHER_ALGORITHM = "DESEDE/ECB/NoPadding";
private static SecretKey keyGenerator(String hexKeyStr) throws Exception {
byte input[] = HexString2Bytes(hexKeyStr);
DESedeKeySpec keySpec = new DESedeKeySpec(input);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
SecretKey secretKey = keyFactory.generateSecret(keySpec);
return secretKey;
}
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;
}
// 从十六进制字符串到字节数组转换
public static byte[] HexString2Bytes(String hexstr) {
byte[] b = new byte[hexstr.length() / 2];
int j = 0;
for (int i = 0; i < b.length; i++) {
char c0 = hexstr.charAt(j++);
char c1 = hexstr.charAt(j++);
b[i] = (byte) ((parse(c0) << 4) | parse(c1));
}
return b;
}
public static String encrypt(String data, String hexKeyStr) throws Exception {
Key deskey = keyGenerator(hexKeyStr);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, deskey);
byte[] results = cipher.doFinal(data.getBytes())