|
@@ -0,0 +1,318 @@
|
|
|
+package com.hrsk.cloud.eg.domain.common.utils;
|
|
|
+
|
|
|
+import org.apache.commons.codec.binary.Base64;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import javax.crypto.Cipher;
|
|
|
+import javax.crypto.spec.IvParameterSpec;
|
|
|
+import javax.crypto.spec.SecretKeySpec;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author zhangyy
|
|
|
+ * @version 1.0
|
|
|
+ * @description: PrivacyAesUtil 个人信息 加密方法
|
|
|
+ * @date 2024/8/26 17:58
|
|
|
+ */
|
|
|
+public class PrivacyAesUtil {
|
|
|
+
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(PrivacyAesUtil.class);
|
|
|
+ private static byte[] Keys = {0x41, 0x72, 0x65, 0x79, 0x6F, 0x75, 0x6D, 0x79, 0x53, 0x6E, 0x6F, 0x77, 0x6D, 0x61, 0x6E, 0x3F};
|
|
|
+
|
|
|
+ private final static String AesDecKey = "47FC4124CF94E070";
|
|
|
+
|
|
|
+ private final static String AesDecIv = "ovOh2xYoRdfATob6";
|
|
|
+
|
|
|
+ public final static String RESULT = "result";
|
|
|
+ public final static String SALT = "salt";
|
|
|
+
|
|
|
+
|
|
|
+ public static String encryptCBCPKCS5(String sSrc, String sKey,String ivKey) throws Exception {
|
|
|
+ if (sKey == null) {
|
|
|
+ System.out.print("Key为空null");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ // 判断Key是否为16位
|
|
|
+ if (sKey.length() != 16) {
|
|
|
+ System.out.print("Key长度不是16位");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ byte[] raw = sKey.getBytes("utf-8");
|
|
|
+ SecretKeySpec keySpec = new SecretKeySpec(raw, "AES");
|
|
|
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式"
|
|
|
+ IvParameterSpec iv = new IvParameterSpec(ivKey.getBytes());//使用CBC模式,需要一个向量iv,可增加加密算法的强度
|
|
|
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
|
|
|
+ byte[] encrypted = cipher.doFinal(sSrc.getBytes());
|
|
|
+ return encode(encrypted);//此处使用BASE64做转码功能,同时能起到2次加密的作用。
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String decryptAESCbc(String data, String key, String iv) throws Exception {
|
|
|
+ try {
|
|
|
+
|
|
|
+ byte[] encrypted1 = decode(data);
|
|
|
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
|
|
+ SecretKeySpec keyspace = new SecretKeySpec(key.getBytes(), "AES");
|
|
|
+ IvParameterSpec specie = new IvParameterSpec(iv.getBytes());
|
|
|
+
|
|
|
+ cipher.init(Cipher.DECRYPT_MODE, keyspace, specie);
|
|
|
+
|
|
|
+ byte[] original = cipher.doFinal(encrypted1);
|
|
|
+ String originalString = new String(original);
|
|
|
+ return originalString.trim();
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("decryptAESCbc fail",e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param data 明文
|
|
|
+ * @param key 密钥,长度16
|
|
|
+ * @return 密文
|
|
|
+ * AES算法加密明文
|
|
|
+ */
|
|
|
+ public static String encryptAES(String data, String key, String iv) throws Exception {
|
|
|
+ try {
|
|
|
+ Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
|
|
+// String iv = "0000000000000000";
|
|
|
+ int blockSize = cipher.getBlockSize();
|
|
|
+ byte[] dataBytes = data.getBytes();
|
|
|
+ int plaintextLength = dataBytes.length;
|
|
|
+
|
|
|
+ if (plaintextLength % blockSize != 0) {
|
|
|
+ plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
|
|
|
+ }
|
|
|
+
|
|
|
+ byte[] plaintext = new byte[plaintextLength];
|
|
|
+ System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
|
|
|
+
|
|
|
+ SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
|
|
|
+ IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
|
|
|
+
|
|
|
+ cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
|
|
|
+ byte[] encrypted = cipher.doFinal(plaintext);
|
|
|
+
|
|
|
+ return encode(encrypted).trim();
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("encryptAES fail",e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param data 密文
|
|
|
+ * @param key 密钥,长度16
|
|
|
+ * @return 明文
|
|
|
+ * AES算法解密密文
|
|
|
+ */
|
|
|
+ public static String decryptAES(String data, String key, String iv) throws Exception {
|
|
|
+ try {
|
|
|
+
|
|
|
+ byte[] encrypted1 = decode(data);
|
|
|
+ Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
|
|
+ SecretKeySpec keyspace = new SecretKeySpec(key.getBytes(), "AES");
|
|
|
+ IvParameterSpec specie = new IvParameterSpec(iv.getBytes());
|
|
|
+
|
|
|
+ cipher.init(Cipher.DECRYPT_MODE, keyspace, specie);
|
|
|
+
|
|
|
+ byte[] original = cipher.doFinal(encrypted1);
|
|
|
+ String originalString = new String(original);
|
|
|
+ return originalString.trim();
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("decryptAES fail ",e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 编码
|
|
|
+ *
|
|
|
+ * @param byteArray
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static String encode(byte[] byteArray) {
|
|
|
+ return new String(new Base64().encode(byteArray));
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 解码
|
|
|
+ *
|
|
|
+ * @param base64EncodedString
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static byte[] decode(String base64EncodedString) {
|
|
|
+ return new Base64().decode(base64EncodedString);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 用于手机号。身份证号等长于4位的字符串类型加密 用原字符串后四位进行加密 身份证结果44位,手机号结果24位
|
|
|
+ * @param sourceStr 待加密字符串
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static Map<String, String> encryptNum(String sourceStr) {
|
|
|
+ String key = "47FC4124CF94";
|
|
|
+ String iv = "rffgzmz2fedyts9s";
|
|
|
+ Map<String, String> resultMap = new HashMap<>();
|
|
|
+ if(StringUtils.isEmpty(sourceStr) || "null".equals(sourceStr)){
|
|
|
+ return resultMap;
|
|
|
+ }
|
|
|
+ if(sourceStr.length()<4){
|
|
|
+ resultMap.put(PrivacyAesUtil.SALT, "1234");
|
|
|
+ resultMap.put(PrivacyAesUtil.RESULT, encryptSortNum(sourceStr));
|
|
|
+ return resultMap;
|
|
|
+ }
|
|
|
+ String subStr = sourceStr.substring(sourceStr.length()-4,sourceStr.length());
|
|
|
+ subStr = subStr.replaceAll("(x|X)", "A").replaceAll("[^0-9aA]", "B");
|
|
|
+
|
|
|
+ key += subStr;
|
|
|
+ String resultStr = "";
|
|
|
+ try {
|
|
|
+ resultStr = encryptCBCPKCS5(sourceStr, key, AesDecIv);
|
|
|
+ }catch (Exception e){
|
|
|
+ System.out.println(key);
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ resultMap.put(PrivacyAesUtil.SALT, subStr);
|
|
|
+ resultMap.put(PrivacyAesUtil.RESULT, resultStr);
|
|
|
+ return resultMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 4位以下的字符串类型加密 用固定key进行加密
|
|
|
+ * @param sourceStr 待加密字符串
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static String encryptSortNum(String sourceStr) {
|
|
|
+ String key = "47FC4124CF941234";
|
|
|
+ String iv = "rffgzmz2fedyts9s";
|
|
|
+ String resultStr = "";
|
|
|
+ try {
|
|
|
+ resultStr = encryptCBCPKCS5(sourceStr, key, AesDecIv);
|
|
|
+ }catch (Exception e){
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return resultStr;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将加密后信息及加密盐放入待加密map
|
|
|
+ * @param map
|
|
|
+ * @param keyName
|
|
|
+ * @param keySaltName
|
|
|
+ */
|
|
|
+ public static void encFillMap(Map map, String keyName, String keySaltName){
|
|
|
+ if(null == map || map.isEmpty()){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if(StringUtils.isEmpty(String.valueOf(map.get(keyName))) || null == map.get(keyName)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Map<String, String> encResultMap = PrivacyAesUtil.encryptNum(String.valueOf(map.get(keyName)));
|
|
|
+ map.put(keyName, encResultMap.get(PrivacyAesUtil.RESULT));
|
|
|
+ map.put(keySaltName, encResultMap.get(PrivacyAesUtil.SALT));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将查询结果解密放到待解密map中
|
|
|
+ * @param map
|
|
|
+ * @param keyName
|
|
|
+ * @param keySaltName
|
|
|
+ */
|
|
|
+ public static void decFillMap(Map map, String keyName, String keySaltName){
|
|
|
+ if(null == map || map.isEmpty() || StringUtils.isEmpty(String.valueOf(map.get(keyName))) || StringUtils.isEmpty(String.valueOf(map.get(keySaltName)))){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ map.put(keyName, decryptNum(String.valueOf(map.get(keyName)), String.valueOf(map.get(keySaltName))));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 对应encryptNum 及 encryptSortNum函数的解密
|
|
|
+ * @param sourceStr 待解密字符串
|
|
|
+ * @param salt 盐
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static String decryptNum(String sourceStr, String salt) {
|
|
|
+ if("null".equals(sourceStr)){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if(StringUtils.isEmpty(sourceStr)||StringUtils.isEmpty(salt) || "null".equals(salt)){
|
|
|
+ return sourceStr;
|
|
|
+ }
|
|
|
+ String key = "47FC4124CF94"+salt;
|
|
|
+ String resultStr = "";
|
|
|
+ try{
|
|
|
+ resultStr = decryptAESCbc(sourceStr, key, AesDecIv);
|
|
|
+ }catch (Exception e){
|
|
|
+ log.warn("解密出错源{},",sourceStr);
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(resultStr)){
|
|
|
+ if (sourceStr.length() == 11 && sourceStr.startsWith("1") && sourceStr.endsWith(salt)){
|
|
|
+ return sourceStr;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return resultStr;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void main(String[] args){
|
|
|
+ Map<String, Object> testMap = new HashMap<>();
|
|
|
+ testMap.put("mobile","18190742697");
|
|
|
+ PrivacyAesUtil.encFillMap(testMap, "mobile", "mobileSalt");
|
|
|
+ System.out.println(testMap);
|
|
|
+ String rtn = String.valueOf(testMap.get("mobile"));
|
|
|
+ System.out.println("rtn:"+rtn);
|
|
|
+ System.out.println(PrivacyAesUtil.decryptNum(rtn, String.valueOf(testMap.get("mobileSalt"))));
|
|
|
+ try {
|
|
|
+ System.out.println(PrivacyAesUtil.decryptNum("Hhn8PDX1wLDtfcgmXc8PXA==", "1199"));
|
|
|
+ System.out.println("--------------------------------------");
|
|
|
+ System.out.println(PrivacyAesUtil.encryptAES("M/n254m1qm5z1YTw6C3Flg==", "47FC4124CF946428", AesDecIv));
|
|
|
+ }catch (Exception e){
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String encryptEcb5(String sSrc, String sKey) {
|
|
|
+ if (sKey == null) {
|
|
|
+ return null;
|
|
|
+ }// 判断 Key 是否为 16 位
|
|
|
+ if (sKey.length() != 16) {
|
|
|
+ if(sKey.length()!=32){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ byte[] raw = sKey.getBytes("utf-8");
|
|
|
+ SecretKeySpec skySpec = new SecretKeySpec(raw, "AES"); // "算法/模式/补码方式"
|
|
|
+ Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
|
|
+ cipher.init(Cipher.ENCRYPT_MODE, skySpec);
|
|
|
+ byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8")); // 此处使用 BASE64 做转码功能,同时能起到 2 次加密的作用。
|
|
|
+ return Base64.encodeBase64String(encrypted);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String decryptEcb5(String sSrc, String sKey) throws Exception {
|
|
|
+ if (sKey == null) {
|
|
|
+ return null;
|
|
|
+ }// 判断 Key 是否为 16 位
|
|
|
+ if (sKey.length() != 16) {
|
|
|
+ if(sKey.length()!=32){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ byte[] raw = sKey.getBytes("utf-8");
|
|
|
+ SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); // "算法/模式/补码方式"
|
|
|
+ Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
|
|
+ cipher.init(Cipher.DECRYPT_MODE, skeySpec);
|
|
|
+ byte[] encrypted = cipher.doFinal(Base64.decodeBase64(sSrc)); // 此处使用 BASE64 做转码功能,同时能起到 2 次加密的作用。
|
|
|
+ return new String(encrypted);
|
|
|
+ }
|
|
|
+}
|