1.测试类中创建一个密钥库
记得先创建resources/secretkey
@Test
public void t() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
try {
// 使用默认的密钥库类型,例如 "JKS", "PKCS12" 等
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
// 通过指定算法,指定提供者来构造KeyGenerator对象
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
String password = "testalias123";
SecureRandom secureRandom = new SecureRandom(password.getBytes(StandardCharsets.UTF_8));
// 初始化KeyGenerator对象,通过指定大小和随机源的方式产生
keyGen.init(128, secureRandom);
// 生成秘钥
Key key = keyGen.generateKey();
// testalias为别名,testalias123为其密码
keyStore.setKeyEntry("testalias", key, "testalias123".toCharArray(), null);
// testkeystore123密钥库密码
keyStore.store(new FileOutputStream("src/main/resources/secretkey/testalias.keystore"), "testkeystore123".toCharArray());
} catch (Exception ex) {
ex.printStackTrace();
}
}
2.工具类
package com.example.utils;
import javax.crypto.*;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
public class AESEncryptionUtils {
private static final String AES = "AES";
/**
* 获取密钥
*
* @return 密钥
* @throws Exception
*/
public static SecretKey getAESKey() throws Exception {
KeyStore keyStore = KeyStore.getInstance("JCEKS");
char[] password = "testalias123".toCharArray();
try (FileInputStream fis = new FileInputStream("src/main/resources/secretKey/testalias.keystore")) {
keyStore.load(fis, password);
}
KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore.getEntry("testalias", new KeyStore.PasswordProtection(password));
SecretKey secretKey = secretKeyEntry.getSecretKey();
return secretKey;
}
/**
* 文本加密
*
* @param plainData 待加密文本
* @param secretKey 密钥
* @return 加密后的字符串
* @throws Exception
*/
public static String encrypt(String plainData, SecretKey secretKey) throws Exception {
Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedBytes = cipher.doFinal(plainData.getBytes(StandardCharsets.UTF_8));
// 转换为Base64编码的字符串,以便于传输和存储
return Base64.getEncoder().encodeToString(encryptedBytes);
}
/**
* 日期时间加密
*
* @param plainData 待加密日期时间
* @param secretKey 密钥
* @return 加密后的字符串
* @throws Exception
*/
public static String encrypt(LocalDateTime plainData, SecretKey secretKey) throws Exception {
Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String dateStr = plainData.format(fmt);
byte[] encryptedBytes = cipher.doFinal(dateStr.getBytes(StandardCharsets.UTF_8));
// 转换为Base64编码的字符串,以便于传输和存储
return Base64.getEncoder().encodeToString(encryptedBytes);
}
/**
* 数字加密
*
* @param plainData 待加密数字
* @param secretKey 密钥
* @return 加密后的字符串
* @throws Exception
*/
public static String encrypt(int plainData, SecretKey secretKey) throws Exception {
Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] numberBytes = ByteBuffer.allocate(Integer.BYTES).putInt(plainData).array();
byte[] encryptedBytes = cipher.doFinal(numberBytes);
// 转换为Base64编码的字符串,以便于传输和存储
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public static String encrypt(long plainData, SecretKey secretKey) throws Exception {
Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] numberBytes = ByteBuffer.allocate(Long.BYTES).putLong(plainData).array();
byte[] encryptedBytes = cipher.doFinal(numberBytes);
// 转换为Base64编码的字符串,以便于传输和存储
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public static String encrypt(double plainData, SecretKey secretKey) throws Exception {
Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] numberBytes = ByteBuffer.allocate(Double.BYTES).putDouble(plainData).array();
byte[] encryptedBytes = cipher.doFinal(numberBytes);
// 转换为Base64编码的字符串,以便于传输和存储
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public static String encrypt(float plainData, SecretKey secretKey) throws Exception {
Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] numberBytes = ByteBuffer.allocate(Float.BYTES).putFloat(plainData).array();
byte[] encryptedBytes = cipher.doFinal(numberBytes);
// 转换为Base64编码的字符串,以便于传输和存储
return Base64.getEncoder().encodeToString(encryptedBytes);
}
/**
* 文本解密
*
* @param cipherData 待解密文本
* @param secretKey 密钥
* @return 解密文本
* @throws Exception
*/
public static String decryptStr(String cipherData, SecretKey secretKey) throws Exception {
byte[] decryptedBytes = getDecryptedBytes(cipherData, secretKey);
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
/**
* 日期时间解密
*
* @param cipherData 待解密日期时间
* @param secretKey 密钥
* @return 解密日期时间
* @throws Exception
*/
public static LocalDateTime decryptLocalDateTime(String cipherData, SecretKey secretKey) throws Exception {
byte[] decryptedBytes = getDecryptedBytes(cipherData, secretKey);
String dateTimeStr = new String(decryptedBytes, StandardCharsets.UTF_8);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return LocalDateTime.parse(dateTimeStr, fmt);
}
/**
* 数字解密
*
* @param cipherData 加密后的字符串
* @param secretKey 密钥
* @return 解密后的数字
* @throws Exception
*/
public static int decryptInt(String cipherData, SecretKey secretKey) throws Exception {
byte[] decryptedBytes = getDecryptedBytes(cipherData, secretKey);
return ByteBuffer.wrap(decryptedBytes).getInt();
}
public static long decryptLong(String cipherData, SecretKey secretKey) throws Exception {
byte[] decryptedBytes = getDecryptedBytes(cipherData, secretKey);
return ByteBuffer.wrap(decryptedBytes).getLong();
}
public static double decryptDouble(String cipherData, SecretKey secretKey) throws Exception {
byte[] decryptedBytes = getDecryptedBytes(cipherData, secretKey);
return ByteBuffer.wrap(decryptedBytes).getDouble();
}
public static float decryptFloat(String cipherData, SecretKey secretKey) throws Exception {
byte[] decryptedBytes = getDecryptedBytes(cipherData, secretKey);
return ByteBuffer.wrap(decryptedBytes).getFloat();
}
private static byte[] getDecryptedBytes(String cipherData, SecretKey secretKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] encryptedBytes = Base64.getDecoder().decode(cipherData);
return cipher.doFinal(encryptedBytes);
}
}
3.测试类中编写测试代码
@Test
public void test() throws Exception {
String plainText = "helloWorld";
// 获取AES密钥
SecretKey aesKey = AESEncryptionUtils.getAESKey();
// 加密浮点数
String encryptedText = AESEncryptionUtils.encrypt(1.23D, aesKey);
System.out.println("Encrypted Text: " + encryptedText);
// 解密浮点数
System.out.println("Decrypted Text: " + AESEncryptionUtils.decryptDouble(encryptedText, aesKey));
// 加密长整型数
String a = AESEncryptionUtils.encrypt(324892478L, aesKey);
System.out.println("Encrypted Text: " + a);
// 解密长整型数(使用错误的解密方法会得到错误的结果,即使使用decryptDouble来解密long类型也是会出现错误解密结果的)
System.out.println("Decrypted Text: " + AESEncryptionUtils.decryptLong(a, aesKey));
}
个人感悟:
- 密钥库作用在于避免明文方式把密钥写入代码,可能会被反编译,用密钥库就不存在这个问题。
- 创建密钥库的过程在测试里面创建了,实际上这部分代码后续也不会被打包进去,也不存在创建信息的泄露(也可以控制台创建,这里只提供代码创建)
- 上述代码可以在存入数据库前根据数据类型来进行不同的加密与解密。也可以直接就只用String的加密解密方法,每次处理前把不同类型数据转换成字符串在加密就行了,解密同理。写成不同类型只是个人感觉会不会这样效率高一些,毕竟数值与字符串的转换在数据量大的情况下还是一个消耗
以上仅个人体会,本人还处于学习阶段。如有错误,恳请指正