目录
- 前言
- 代码加密(AES)
- sql解密
前言
在一些项目中,客户要求一方面把一些敏感信息进行加密存储到数据库中,另一方面又需要通过加密的信息进行查询,这时就需要在sql对加密的字段进行解密后再进行查询。
代码加密(AES)
AesFieldUtils.java
package com.hw.common.utils;import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.regex.Matcher;
import java.util.regex.Pattern;@Slf4j
public class AesFieldUtils {/*** 加密算法*/private final String KEY_ALGORITHM = "AES";/*** 算法/模式/补码方式*/private final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";/*** 编码格式*/private final String CODE = "utf-8";/*** base64验证规则*/private static final String BASE64_RULE = "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)=?$";/*** 正则验证对象*/private static final Pattern PATTERN = Pattern.compile(BASE64_RULE);/*** 加解密 密钥key*/private String key/*** @param content 加密字符串* @return 加密结果*/public String encrypt(String content) {return encrypt(content, key);}/*** 加密** @param content 加密参数* @param key 加密key* @return 结果字符串*/public String encrypt(String content, String key) {//判断如果已经是base64加密字符串则返回原字符串if (isBase64(content)) {return content;}// 为了安全起见,暂时不加密,需要时再放开//return content;byte[] encrypted = encrypt2bytes(content, key);if (null == encrypted || encrypted.length < 1) {log.error("加密字符串[{}]转字节为null", content);return null;}return Base64Utils.encodeToString(encrypted);}/*** @param content 加密字符串* @param key 加密key* @return 返回加密字节*/public byte[] encrypt2bytes(String content, String key) {try {byte[] raw = key.getBytes(CODE);SecretKeySpec secretKeySpec = new SecretKeySpec(raw, KEY_ALGORITHM);Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);return cipher.doFinal(content.getBytes(CODE));} catch (Exception e) {log.error("failed to encrypt: {} of {}", content, e);return null;}}/*** @param content 加密字符串* @return 返回加密结果*/public String decrypt(String content) {try {return decrypt(content, key);} catch (Exception e) {log.error("failed to decrypt: {}, e: {}", content, e);return null;}}/*** 解密** @param content 解密字符串* @param key 解密key* @return 解密结果*/public String decrypt(String content, String key) throws Exception {//不是base64格式字符串则不进行解密if (!isBase64(content)) {return content;}// 为了安全起见,暂时不加密解密,需要时再放开//return content;return decrypt(Base64Utils.decodeFromString(content), key);}/*** @param content 解密字节* @param key 解密key* @return 返回解密内容*/public String decrypt(byte[] content, String key) throws Exception {if (key == null) {log.error("AES key should not be null");return null;}byte[] raw = key.getBytes(CODE);SecretKeySpec keySpec = new SecretKeySpec(raw, KEY_ALGORITHM);Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);cipher.init(Cipher.DECRYPT_MODE, keySpec);try {byte[] original = cipher.doFinal(content);return new String(original, CODE);} catch (Exception e) {log.error("failed to decrypt content: {}/ key: {}, e: {}", content, key, e);return null;}}/*** 判断是否为 base64加密** @param str 参数* @return 结果*/public static boolean isBase64(String str) {Matcher matcher = PATTERN.matcher(str);return matcher.matches();}public static void main(String[] args) {AesFieldUtils aesFieldUtils = new AesFieldUtils();String reuslt = aesFieldUtils.encrypt("13809449025","qwertyuiopasdfgh");System.out.println(reuslt);}}
加密的密文:dcAJ143U+AkxbvOwRctnVg==
sql解密
mysql 使用 AES_DECRYPT(crypt_str,key_str) 进行解密,第一个参数crypt_str加密的字符串,第二个参数key_str 密钥,需和代码加密时的密钥保持一致。
SELECT AES_DECRYPT(FROM_BASE64('dcAJ143U+AkxbvOwRctnVg=='), 'qwertyuiopasdfgh') AS '解密结果';