Jasypt 配置文件加密

Jasypt 配置文件加密,第1张

參考文献

Git地址: GitHub - ulisesbocchio/jasypt-spring-boot: Jasypt integration for Spring boot

原理:spring boot使用jasypt加密原理解析_const伐伐的博客-CSDN博客_stringencryptor

国密:SM4国密算法java实现 - SimonHu1993 - 博客园

使用:jasypt库的使用_hornsey2012的博客-CSDN博客_jasypt使用

国密算法:GitHub - xjfuuu/SM2_SM3_SM4Encrypt: 基于Java语言的国密SM2/SM3/SM4算法库 , 包含加密/解密、签名/验签、摘要算法的实现代码和测试方法 。

SpringBoot系列9-使用jasypt自定义stater运行时动态传入加密密码_猿份哥的博客-CSDN博客

工作随笔——jasypt-spring-boot使用 - 爱自己 - 博客园

spring加载流程:SpringBoot启动流程分析(六):IoC容器依赖注入 - 超级小小黑 - 博客园

1. Jasypt库的使用 1.1 简介

Jasypt是一个Java简易加密库,用于加密配置文件中的敏感信息,如数据库密码。jasypt库与springboot集成,在实际开发中非常方便。

1.2 添加依赖

    com.github.ulisesbocchio
    jasypt-spring-boot-starter
    2.1.0
jasypt版本springboot版本
2.1.0   2.1.0
1.5    1.4.2
1.5    1.5.3
1.8    1.4.2

注意:根据spring boot版本选择对应的jasypt版本

1.3 配置使用

将加密后的配置信息使用ENC函数,添加到配置文件中,应用启动加载配置文件时,会自动解密。

Jasypt默认使用的算法为PBEWithMD5AndDES,该算法需要一个加密密钥,可以在应用启动时指定。也可以直接写入配置文件,安全性稍差。

jasypt:
  encryptor:
    password: password

注意:这里指定加密密钥为password

1.4 测试示例 1.4.1 使用加密函数加密配置文件
public static void main(String[] args) {
        // 创建加密对象,默认 PBEWithMD5AndDES
        BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
        // 加密所需的密钥
        textEncryptor.setPassword("password");
        // 加密后的数据(数据库的用户名或密码)
        String encData = textEncryptor.encrypt("Password@1");
        // 解密后的数据(原数据)
        String decData = textEncryptor.decrypt(encData);
        System.out.println("encData: " + encData);
        System.out.println("decData: " + decData);
    }

输出:

encData: rJIqHYPSHc0EPesm650srg==
decData: root
1.4.2 添加加密后的属性配置

在配置文件中加入加密后的属性配置信息,我们加密了字符串root,使用的加密密钥为password,添加到application.yml文件中。

datasource:
  master:
    url: jdbc:mysql://127.0.0.1:3306/jeecg-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
    username: root
    password: ENC(r7PD0+haO/ALC+txojmG/A==)
    driver-class-name: com.mysql.cj.jdbc.Driver
2. 使用自定义加密器进行加密解密 2.1  SM4算法加密器代码案例 2.1.1 创建SM4算法加密器接口
package org.jeecg.config.jasypt.encryption.sm4;

import org.jasypt.encryption.StringEncryptor;
/**
* @Description SM4算法加密器接口
* @date 2022/3/7 14:25
* @Version 1.0
* @Author gezongyang
*/
public interface SM4StringEncryptor extends StringEncryptor {
}
2.1.2 创建SM4算法加密器
package org.jeecg.config.jasypt.encryption.sm4;
import lombok.extern.slf4j.Slf4j;
import org.jasypt.commons.CommonUtils;
import org.jeecg.common.util.security.sm4.SM4Utils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
* @Description 国密Sm4 算法加密器
* @date 2022/3/7 14:17
* @Version 1.0
* @Author gezongyang
*/
@Slf4j
@Component("sM4ECBStringEncryptor")
public class SM4ECBStringEncryptor implements SM4StringEncryptor {

    @Override
    public String encrypt(String msg) {
        String secretKey = System.getProperty("secretKey");
        CommonUtils.validateNotNull(msg, "msg cannot be set null");
        CommonUtils.validateNotNull(secretKey, "secretKey config not be set");
        try {
            log.info("加密前配置信息:{}",msg);
            SM4Utils sm4 = new SM4Utils();
            sm4.secretKey = secretKey;
            sm4.hexString = true;
            msg = sm4.encryptData_ECB(msg);
            log.info("加密后配置信息:{}", msg);
        } catch (Exception e) {
            log.error("配置信息加密失败,{}",e.getStackTrace());
        }
        return msg;
    }

    @Override
    public String decrypt(String msg) {
        String secretKey = System.getProperty("secretKey");
        CommonUtils.validateNotNull(msg, "msg cannot be set null");
        CommonUtils.validateNotNull(secretKey, "secretKey config not be set");
        try {
            log.info("解密前配置信息:{}",msg);
            SM4Utils sm4 = new SM4Utils();
            sm4.secretKey = secretKey;
            sm4.hexString = true;
            msg = sm4.decryptData_ECB(msg);
            log.info("解密后配置信息:{}", msg);
        } catch (Exception e) {
            log.error("配置信息解密失败,{}",e.getStackTrace());
        }
        return msg;
    }
}

注意:

① 是加密器在spring IOC 中注册的名称,在使用jasypt加密,解密配置文件时,会需要指定加密器的名称

② 这里通过获取虚拟机选项的值,来动态获取启动时指定的secretKey

2.1.2 在配置文件中指定自定义加密器
jasypt:
  encryptor:
    bean: sM4ECBStringEncryptor
2.1.3 在启动命令中配置JVM参数
java -DsecretKey=64EC7C763AB7BF64E2D75FF83A319918 -jar xxx.jar
2.2 自定义加密器测试 2.2.1 使用SM4算法加密工具类生成密文
public static void main(String[] args) throws IOException {
        String txt = "root";
        SM4Utils sm43 = new SM4Utils();
        sm4.secretKey = "64EC7C763AB7BF64E2D75FF83A319918";
        sm4.hexString = true;
        String secText = sm4.encryptData_ECB(txt);
        System.out.println("->" + secText + "<-");
}

执行结果:

22ffdacdb8c5d1665aa0024b3b69cecb
2.2.2 在启动参数中配置JVM参数
-DsecretKey=64EC7C763AB7BF64E2D75FF83A319918

 2.2.3 修改配置文件中需要加密的信息
datasource:
  master:
    url: jdbc:mysql://127.0.0.1:3306/jeecg-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
    username: root
    password: ENC(22ffdacdb8c5d1665aa0024b3b69cecb)
    driver-class-name: com.mysql.cj.jdbc.Driver

注意:需要将生成的密钥串用ENC()括起来,这样Jasypt就会知道这个配置是密文加密的,需要进行解密。

2.2.4 启动项目,解密日志打印正常则成功
2022-03-08 14:55:45.127 [main] INFO  c.u.j.encryptor.DefaultLazyEncryptor:30 - Found Custom Encryptor Bean org.jeecg.config.jasypt.encryption.sm4.SM4ECBStringEncryptor@288728e with name: sM4ECBStringEncryptor
2022-03-08 14:55:45.129 [main] INFO  o.j.c.jasypt.encryption.sm4.SM4ECBStringEncryptor:45 - 解密前配置信息:22ffdacdb8c5d1665aa0024b3b69cecb
2022-03-08 14:55:45.136 [main] INFO  o.j.c.jasypt.encryption.sm4.SM4ECBStringEncryptor:50 - 解密后配置信息:root
2.3 SM4加密工具代码 2.3.1  SM4 类
package org.jeecg.common.util.security.sm4;
import org.jeecg.common.util.Util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;


public class SM4 {
    public static final int SM4_ENCRYPT = 1;
    public static final int SM4_DECRYPT = 0;
    private long GET_ULONG_BE(byte[] b, int i) {
        long n = (long) (b[i] & 0xff) << 24 | (long) ((b[i + 1] & 0xff) << 16) | (long) ((b[i + 2] & 0xff) << 8) | (long) (b[i + 3] & 0xff) & 0xffffffffL;
        return n;
    }

    private void PUT_ULONG_BE(long n, byte[] b, int i) {
        b[i] = (byte) (int) (0xFF & n >> 24);
        b[i + 1] = (byte) (int) (0xFF & n >> 16);
        b[i + 2] = (byte) (int) (0xFF & n >> 8);
        b[i + 3] = (byte) (int) (0xFF & n);
    }

    private long SHL(long x, int n) {
        return (x & 0xFFFFFFFF) << n;
    }

    private long ROTL(long x, int n) {
        return SHL(x, n) | x >> (32 - n);
    }

    private void SWAP(long[] sk, int i) {
        long t = sk[i];
        sk[i] = sk[(31 - i)];
        sk[(31 - i)] = t;
    }

    public static final byte[] SboxTable = {(byte) 0xd6, (byte) 0x90, (byte) 0xe9, (byte) 0xfe,
            (byte) 0xcc, (byte) 0xe1, 0x3d, (byte) 0xb7, 0x16, (byte) 0xb6,
            0x14, (byte) 0xc2, 0x28, (byte) 0xfb, 0x2c, 0x05, 0x2b, 0x67,
            (byte) 0x9a, 0x76, 0x2a, (byte) 0xbe, 0x04, (byte) 0xc3,
            (byte) 0xaa, 0x44, 0x13, 0x26, 0x49, (byte) 0x86, 0x06,
            (byte) 0x99, (byte) 0x9c, 0x42, 0x50, (byte) 0xf4, (byte) 0x91,
            (byte) 0xef, (byte) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43,
            (byte) 0xed, (byte) 0xcf, (byte) 0xac, 0x62, (byte) 0xe4,
            (byte) 0xb3, 0x1c, (byte) 0xa9, (byte) 0xc9, 0x08, (byte) 0xe8,
            (byte) 0x95, (byte) 0x80, (byte) 0xdf, (byte) 0x94, (byte) 0xfa,
            0x75, (byte) 0x8f, 0x3f, (byte) 0xa6, 0x47, 0x07, (byte) 0xa7,
            (byte) 0xfc, (byte) 0xf3, 0x73, 0x17, (byte) 0xba, (byte) 0x83,
            0x59, 0x3c, 0x19, (byte) 0xe6, (byte) 0x85, 0x4f, (byte) 0xa8,
            0x68, 0x6b, (byte) 0x81, (byte) 0xb2, 0x71, 0x64, (byte) 0xda,
            (byte) 0x8b, (byte) 0xf8, (byte) 0xeb, 0x0f, 0x4b, 0x70, 0x56,
            (byte) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (byte) 0xd1,
            (byte) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (byte) 0x87,
            (byte) 0xd4, 0x00, 0x46, 0x57, (byte) 0x9f, (byte) 0xd3, 0x27,
            0x52, 0x4c, 0x36, 0x02, (byte) 0xe7, (byte) 0xa0, (byte) 0xc4,
            (byte) 0xc8, (byte) 0x9e, (byte) 0xea, (byte) 0xbf, (byte) 0x8a,
            (byte) 0xd2, 0x40, (byte) 0xc7, 0x38, (byte) 0xb5, (byte) 0xa3,
            (byte) 0xf7, (byte) 0xf2, (byte) 0xce, (byte) 0xf9, 0x61, 0x15,
            (byte) 0xa1, (byte) 0xe0, (byte) 0xae, 0x5d, (byte) 0xa4,
            (byte) 0x9b, 0x34, 0x1a, 0x55, (byte) 0xad, (byte) 0x93, 0x32,
            0x30, (byte) 0xf5, (byte) 0x8c, (byte) 0xb1, (byte) 0xe3, 0x1d,
            (byte) 0xf6, (byte) 0xe2, 0x2e, (byte) 0x82, 0x66, (byte) 0xca,
            0x60, (byte) 0xc0, 0x29, 0x23, (byte) 0xab, 0x0d, 0x53, 0x4e, 0x6f,
            (byte) 0xd5, (byte) 0xdb, 0x37, 0x45, (byte) 0xde, (byte) 0xfd,
            (byte) 0x8e, 0x2f, 0x03, (byte) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b,
            0x51, (byte) 0x8d, 0x1b, (byte) 0xaf, (byte) 0x92, (byte) 0xbb,
            (byte) 0xdd, (byte) 0xbc, 0x7f, 0x11, (byte) 0xd9, 0x5c, 0x41,
            0x1f, 0x10, 0x5a, (byte) 0xd8, 0x0a, (byte) 0xc1, 0x31,
            (byte) 0x88, (byte) 0xa5, (byte) 0xcd, 0x7b, (byte) 0xbd, 0x2d,
            0x74, (byte) 0xd0, 0x12, (byte) 0xb8, (byte) 0xe5, (byte) 0xb4,
            (byte) 0xb0, (byte) 0x89, 0x69, (byte) 0x97, 0x4a, 0x0c,
            (byte) 0x96, 0x77, 0x7e, 0x65, (byte) 0xb9, (byte) 0xf1, 0x09,
            (byte) 0xc5, 0x6e, (byte) 0xc6, (byte) 0x84, 0x18, (byte) 0xf0,
            0x7d, (byte) 0xec, 0x3a, (byte) 0xdc, 0x4d, 0x20, 0x79,
            (byte) 0xee, 0x5f, 0x3e, (byte) 0xd7, (byte) 0xcb, 0x39, 0x48};

    public static final int[] FK = {0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc};

    public static final int[] CK = {0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
            0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
            0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
            0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
            0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
            0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
            0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
            0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279};

    private byte sm4Sbox(byte inch) {
        int i = inch & 0xFF;
        byte retVal = SboxTable[i];
        return retVal;
    }

    private long sm4Lt(long ka) {
        long bb = 0L;
        long c = 0L;
        byte[] a = new byte[4];
        byte[] b = new byte[4];
        PUT_ULONG_BE(ka, a, 0);
        b[0] = sm4Sbox(a[0]);
        b[1] = sm4Sbox(a[1]);
        b[2] = sm4Sbox(a[2]);
        b[3] = sm4Sbox(a[3]);
        bb = GET_ULONG_BE(b, 0);
        c = bb ^ ROTL(bb, 2) ^ ROTL(bb, 10) ^ ROTL(bb, 18) ^ ROTL(bb, 24);
        return c;
    }

    private long sm4F(long x0, long x1, long x2, long x3, long rk) {
        return x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk);
    }

    private long sm4CalciRK(long ka) {
        long bb = 0L;
        long rk = 0L;
        byte[] a = new byte[4];
        byte[] b = new byte[4];
        PUT_ULONG_BE(ka, a, 0);
        b[0] = sm4Sbox(a[0]);
        b[1] = sm4Sbox(a[1]);
        b[2] = sm4Sbox(a[2]);
        b[3] = sm4Sbox(a[3]);
        bb = GET_ULONG_BE(b, 0);
        rk = bb ^ ROTL(bb, 13) ^ ROTL(bb, 23);
        return rk;
    }

    private void sm4_setkey(long[] SK, byte[] key) {
        long[] MK = new long[4];
        long[] k = new long[36];
        int i = 0;
        MK[0] = GET_ULONG_BE(key, 0);
        MK[1] = GET_ULONG_BE(key, 4);
        MK[2] = GET_ULONG_BE(key, 8);
        MK[3] = GET_ULONG_BE(key, 12);
        k[0] = MK[0] ^ (long) FK[0];
        k[1] = MK[1] ^ (long) FK[1];
        k[2] = MK[2] ^ (long) FK[2];
        k[3] = MK[3] ^ (long) FK[3];
        for (; i < 32; i++) {
            k[(i + 4)] = (k[i] ^ sm4CalciRK(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^ (long) CK[i]));
            SK[i] = k[(i + 4)];
        }
    }

    private void sm4_one_round(long[] sk, byte[] input, byte[] output) {
        int i = 0;
        long[] ulbuf = new long[36];
        ulbuf[0] = GET_ULONG_BE(input, 0);
        ulbuf[1] = GET_ULONG_BE(input, 4);
        ulbuf[2] = GET_ULONG_BE(input, 8);
        ulbuf[3] = GET_ULONG_BE(input, 12);
        while (i < 32) {
            ulbuf[(i + 4)] = sm4F(ulbuf[i], ulbuf[(i + 1)], ulbuf[(i + 2)], ulbuf[(i + 3)], sk[i]);
            i++;
        }
        PUT_ULONG_BE(ulbuf[35], output, 0);
        PUT_ULONG_BE(ulbuf[34], output, 4);
        PUT_ULONG_BE(ulbuf[33], output, 8);
        PUT_ULONG_BE(ulbuf[32], output, 12);
    }
    //修改了填充模式,为模式
    private byte[] padding(byte[] input, int mode) {
        if (input == null) {
            return null;
        }


        byte[] ret = (byte[]) null;
        if (mode == SM4_ENCRYPT) {
            //填充:hex必须是32的整数倍填充 ,填充的是80  00 00 00
            int p = 16 - input.length % 16;
            String inputHex = Util.byteToHex(input)+ "80";
            StringBuffer stringBuffer =new StringBuffer(inputHex);
            for (int i = 0; i  0; length -= 16) {
            byte[] in = new byte[16];
            byte[] out = new byte[16];
            bins.read(in);
            sm4_one_round(ctx.sk, in, out);
            bous.write(out);
        }


        byte[] output = bous.toByteArray();
        if (ctx.isPadding && ctx.mode == SM4_DECRYPT) {
            output = padding(output, SM4_DECRYPT);
        }
        bins.close();
        bous.close();
        return output;
    }


    public byte[] sm4_crypt_cbc(SM4_Context ctx, byte[] iv, byte[] input) throws Exception {
        if (iv == null || iv.length != 16) {
            throw new Exception("iv error!");
        }


        if (input == null) {
            throw new Exception("input is null!");
        }


        if (ctx.isPadding && ctx.mode == SM4_ENCRYPT) {
            input = padding(input, SM4_ENCRYPT);
        }


        int i = 0;
        int length = input.length;
        ByteArrayInputStream bins = new ByteArrayInputStream(input);
        ByteArrayOutputStream bous = new ByteArrayOutputStream();
        if (ctx.mode == SM4_ENCRYPT) {
            for (; length > 0; length -= 16) {
                byte[] in = new byte[16];
                byte[] out = new byte[16];
                byte[] out1 = new byte[16];


                bins.read(in);
                for (i = 0; i < 16; i++) {
                    out[i] = ((byte) (in[i] ^ iv[i]));
                }
                sm4_one_round(ctx.sk, out, out1);
                System.arraycopy(out1, 0, iv, 0, 16);
                bous.write(out1);
            }
        } else {
            byte[] temp = new byte[16];
            for (; length > 0; length -= 16) {
                byte[] in = new byte[16];
                byte[] out = new byte[16];
                byte[] out1 = new byte[16];


                bins.read(in);
                System.arraycopy(in, 0, temp, 0, 16);
                sm4_one_round(ctx.sk, in, out);
                for (i = 0; i < 16; i++) {
                    out1[i] = ((byte) (out[i] ^ iv[i]));
                }
                System.arraycopy(temp, 0, iv, 0, 16);
                bous.write(out1);
            }
        }

        byte[] output = bous.toByteArray();
        if (ctx.isPadding && ctx.mode == SM4_DECRYPT) {
            output = padding(output, SM4_DECRYPT);
        }
        bins.close();
        bous.close();
        return output;
    }
}
2.3.3  SM4Utils工具类
package org.jeecg.common.util.security.sm4;


import org.apache.commons.codec.binary.Base64;
import org.jeecg.common.util.Util;


import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class SM4Utils {

    public String secretKey = "";
    public String iv = "";
    public boolean hexString = false;

    public SM4Utils() {
    }

    /**
     * SM4以ECB模式加密数据
     * @param plainText
     * @return
     */
    public String encryptData_ECB(String plainText) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_ENCRYPT;

            byte[] keyBytes;
            if (hexString) {
                keyBytes = Util.hexStringToBytes(secretKey);
            } else {
                //keyBytes = secretKey.getBytes();
                keyBytes = Util.hexStringToBytes(secretKey);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4_crypt_ecb(ctx, plainText.getBytes("UTF-8"));
            return Util.byteToHex(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * SM4 以ECB模式解密数据
     * @param cipherText
     * @return
     */
    public String decryptData_ECB(String cipherText) {
        try {
            byte[] encrypted = Util.hexToByte(cipherText);
            cipherText= Base64.encodeBase64String(encrypted);;
            //cipherText = new BASE64Encoder().encode(encrypted);
            if (cipherText != null && cipherText.trim().length() > 0) {
                Pattern p = Pattern.compile("\\s*|\t|\r|\n");
                Matcher m = p.matcher(cipherText);
                cipherText = m.replaceAll("");
            }

            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_DECRYPT;

            byte[] keyBytes;
            if (hexString) {
                keyBytes = Util.hexStringToBytes(secretKey);
            } else {
                keyBytes = secretKey.getBytes();
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            byte[] decrypted = sm4.sm4_crypt_ecb(ctx, Base64.decodeBase64(cipherText));
            //byte[] decrypted = sm4.sm4_crypt_ecb(ctx, new BASE64Decoder().decodeBuffer(cipherText));
            return new String(decrypted, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * SM4 以CBC模式加密数据
     * @param plainText
     * @return
     */
    public String encryptData_CBC(String plainText) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_ENCRYPT;

            byte[] keyBytes;
            byte[] ivBytes;
            if (hexString) {
                keyBytes = Util.hexStringToBytes(secretKey);
                ivBytes = Util.hexStringToBytes(iv);
            } else {
                keyBytes = secretKey.getBytes();
                ivBytes = iv.getBytes();
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, plainText.getBytes("UTF-8"));
            return Util.byteToHex(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * SM4 以CCB模式解密数据
     * @param cipherText
     * @return
     */
    public String decryptData_CBC(String cipherText) {
        try {
            byte[] encrypted = Util.hexToByte(cipherText);
            cipherText= Base64.encodeBase64String(encrypted);;
            //cipherText = new BASE64Encoder().encode(encrypted);
            if (cipherText != null && cipherText.trim().length() > 0) {
                Pattern p = Pattern.compile("\\s*|\t|\r|\n");
                Matcher m = p.matcher(cipherText);
                cipherText = m.replaceAll("");
            }
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_DECRYPT;

            byte[] keyBytes;
            byte[] ivBytes;
            if (hexString) {
                keyBytes = Util.hexStringToBytes(secretKey);
                ivBytes = Util.hexStringToBytes(iv);
            } else {
                keyBytes = secretKey.getBytes();
                ivBytes = iv.getBytes();
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            //byte[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, new BASE64Decoder().decodeBuffer(cipherText));
            byte[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, Base64.decodeBase64(cipherText));
            /*String text = new String(decrypted, "UTF-8");
            return text.substring(0,text.length()-1);*/
            return new String(decrypted, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
3. jasypt 运行原理解析 3.1 Jasypt 如何工作

1)它注册了一个 Spring post processor,该处理器装饰 Spring Environment 中包含的所有 PropertySource 对象,因此它们是“加密感知”的,并检测何时按照 jasypt 的属性约定对属性进行加密。

package com.ulisesbocchio.jasyptspringboot.configuration;


import com.ulisesbocchio.jasyptspringboot.EncryptablePropertyFilter;
import com.ulisesbocchio.jasyptspringboot.EncryptablePropertyResolver;
import com.ulisesbocchio.jasyptspringboot.annotation.EncryptablePropertySource;
import com.ulisesbocchio.jasyptspringboot.annotation.EncryptablePropertySources;
import com.ulisesbocchio.jasyptspringboot.wrapper.EncryptableEnumerablePropertySourceWrapper;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.context.ApplicationContextException;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;


public class EncryptablePropertySourceBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered {
    private static final Logger log = LoggerFactory.getLogger(EncryptablePropertySourceBeanFactoryPostProcessor.class);
    private ConfigurableEnvironment env;

    public EncryptablePropertySourceBeanFactoryPostProcessor(ConfigurableEnvironment env) {
        this.env = env;
    }

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        ResourceLoader ac = new DefaultResourceLoader();
        MutablePropertySources propertySources = this.env.getPropertySources();
        Stream encryptablePropertySourcesMetadata = this.getEncryptablePropertySourcesMetadata(beanFactory);
        EncryptablePropertyResolver propertyResolver = (EncryptablePropertyResolver)beanFactory.getBean("lazyEncryptablePropertyResolver", EncryptablePropertyResolver.class);
        EncryptablePropertyFilter propertyFilter = (EncryptablePropertyFilter)beanFactory.getBean("lazyEncryptablePropertyFilter", EncryptablePropertyFilter.class);
        List loaders = this.initPropertyLoaders();
        encryptablePropertySourcesMetadata.forEach((eps) -> {
            this.loadEncryptablePropertySource(eps, this.env, ac, propertyResolver, propertyFilter, propertySources, loaders);
        });
    }

    private List initPropertyLoaders() {
        return SpringFactoriesLoader.loadFactories(PropertySourceLoader.class, this.getClass().getClassLoader());
    }

    /**
     * 加载加密属性源
     * @param encryptablePropertySource
     * @param env
     * @param resourceLoader
     * @param resolver 属性解析器
     * @param propertyFilter 属性过滤器
     * @param propertySources 属性源
     * @param loaders
     * @throws BeansException
     */
    private void loadEncryptablePropertySource(AnnotationAttributes encryptablePropertySource, ConfigurableEnvironment env, ResourceLoader resourceLoader, EncryptablePropertyResolver resolver, EncryptablePropertyFilter propertyFilter, MutablePropertySources propertySources, List loaders) throws BeansException {
        try {
            PropertySource ps = this.createPropertySource(encryptablePropertySource, env, resourceLoader, resolver, propertyFilter, loaders);
            propertySources.addLast(ps);
            log.info("Created Encryptable Property Source '{}' from locations: {}", ps.getName(), Arrays.asList(encryptablePropertySource.getStringArray("value")));
        } catch (Exception var9) {
            throw new ApplicationContextException("Exception Creating PropertySource", var9);
        }
    }


    /**
     * 包装PropertySource 为 EncryptableEnumerablePropertySourceWrapper
     * @param attributes
     * @param environment
     * @param resourceLoader
     * @param resolver
     * @param propertyFilter
     * @param loaders
     * @return
     * @throws Exception
     */
    private PropertySource createPropertySource(AnnotationAttributes attributes, ConfigurableEnvironment environment, ResourceLoader resourceLoader, EncryptablePropertyResolver resolver, EncryptablePropertyFilter propertyFilter, List loaders) throws Exception {
        String name = this.generateName(attributes.getString("name"));
        String[] locations = attributes.getStringArray("value");
        boolean ignoreResourceNotFound = attributes.getBoolean("ignoreResourceNotFound");
        CompositePropertySource compositePropertySource = new CompositePropertySource(name);
        Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
        String[] var11 = locations;
        int var12 = locations.length;


        for(int var13 = 0; var13 < var12; ++var13) {
            String location = var11[var13];
            String resolvedLocation = environment.resolveRequiredPlaceholders(location);
            Resource resource = resourceLoader.getResource(resolvedLocation);
            if (!resource.exists()) {
                if (!ignoreResourceNotFound) {
                    throw new IllegalStateException(String.format("Encryptable Property Source '%s' from location: %s Not Found", name, resolvedLocation));
                }


                log.info("Ignoring NOT FOUND Encryptable Property Source '{}' from locations: {}", name, resolvedLocation);
            } else {
                String actualName = name + "#" + resolvedLocation;
                this.loadPropertySource(loaders, resource, actualName).ifPresent((psources) -> {
                    psources.forEach(compositePropertySource::addPropertySource);
                });
            }
        }


        return new EncryptableEnumerablePropertySourceWrapper(compositePropertySource, resolver, propertyFilter);
    }


    private String generateName(String name) {
        return !StringUtils.isEmpty(name) ? name : "EncryptedPropertySource#" + System.currentTimeMillis();
    }


    private Stream getEncryptablePropertySourcesMetadata(ConfigurableListableBeanFactory beanFactory) {
        Stream source = this.getBeanDefinitionsForAnnotation(beanFactory, EncryptablePropertySource.class);
        Stream sources = this.getBeanDefinitionsForAnnotation(beanFactory, EncryptablePropertySources.class).flatMap((map) -> {
            return Arrays.stream((AnnotationAttributes[])((AnnotationAttributes[])map.get("value")));
        });
        return Stream.concat(source, sources);
    }


    private Stream getBeanDefinitionsForAnnotation(ConfigurableListableBeanFactory bf, Class annotation) {
        Stream var10000 = Arrays.stream(bf.getBeanNamesForAnnotation(annotation));
        bf.getClass();
        return var10000.map(bf::getBeanDefinition).filter((bd) -> {
            return bd instanceof AnnotatedBeanDefinition;
        }).map((bd) -> {
            return (AnnotatedBeanDefinition)bd;
        }).map(AnnotatedBeanDefinition::getMetadata).filter((md) -> {
            return md.hasAnnotation(annotation.getName());
        }).map((md) -> {
            return (AnnotationAttributes)md.getAnnotationAttributes(annotation.getName());
        });
    }


    private Optional>> loadPropertySource(List loaders, Resource resource, String sourceName) throws IOException {
        return Optional.of(resource).filter(this::isFile).map((res) -> {
            return (List)loaders.stream().filter((loader) -> {
                return this.canLoadFileExtension(loader, resource);
            }).findFirst().map((loader) -> {
                return this.load(loader, sourceName, resource);
            }).orElse((Object)null);
        });
    }


    private List> load(PropertySourceLoader loader, String sourceName, Resource resource) {
        try {
            return loader.load(sourceName, resource);
        } catch (Throwable var5) {
            throw var5;
        }
    }


    private boolean canLoadFileExtension(PropertySourceLoader loader, Resource resource) {
        return Arrays.stream(loader.getFileExtensions()).anyMatch((extension) -> {
            return resource.getFilename().toLowerCase().endsWith("." + extension.toLowerCase());
        });
    }


    private boolean isFile(Resource resource) {
        return resource != null && resource.exists() && StringUtils.hasText(StringUtils.getFilenameExtension(resource.getFilename()));
    }


    public int getOrder() {
        return 2147483647;
    }
}

2)它定义了一个默认的 StringEncryptor,可以通过常规属性、系统属性或命令行参数进行配置。

package com.ulisesbocchio.jasyptspringboot.encryptor;

import com.ulisesbocchio.jasyptspringboot.util.Functional;
import com.ulisesbocchio.jasyptspringboot.util.Singleton;
import java.util.Optional;
import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.env.Environment;

public class DefaultLazyEncryptor implements StringEncryptor {
    private static final Logger log = LoggerFactory.getLogger(DefaultLazyEncryptor.class);
    private final Singleton singleton;

    public DefaultLazyEncryptor(Environment e, String customEncryptorBeanName, BeanFactory bf) {
        this.singleton = new Singleton(() -> {
            Optional var10000 = Optional.of(customEncryptorBeanName);
            bf.getClass();
            return (StringEncryptor)var10000.filter(bf::containsBean).map((name) -> {
                return (StringEncryptor)bf.getBean(name);
            }).map(Functional.tap((bean) -> {
                log.info("Found Custom Encryptor Bean {} with name: {}", bean, customEncryptorBeanName);
            })).orElseGet(() -> {
                log.info("String Encryptor custom Bean not found with name '{}'. Initializing Default String Encryptor", customEncryptorBeanName);
                return this.createDefault(e);
            });
        });
    }

    public DefaultLazyEncryptor(Environment e) {
        this.singleton = new Singleton(() -> {
            return this.createDefault(e);
        });
    }

    private StringEncryptor createDefault(Environment e) {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword(getRequiredProperty(e, "jasypt.encryptor.password"));
        config.setAlgorithm(getProperty(e, "jasypt.encryptor.algorithm", "PBEWithMD5AndDES"));
        config.setKeyObtentionIterations(getProperty(e, "jasypt.encryptor.keyObtentionIterations", "1000"));
        config.setPoolSize(getProperty(e, "jasypt.encryptor.poolSize", "1"));
        config.setProviderName(getProperty(e, "jasypt.encryptor.providerName", (String)null));
        config.setProviderClassName(getProperty(e, "jasypt.encryptor.providerClassName", (String)null));
        config.setSaltGeneratorClassName(getProperty(e, "jasypt.encryptor.saltGeneratorClassname", "org.jasypt.salt.RandomSaltGenerator"));
        config.setStringOutputType(getProperty(e, "jasypt.encryptor.stringOutputType", "base64"));
        encryptor.setConfig(config);
        return encryptor;
    }

    private static String getProperty(Environment environment, String key, String defaultValue) {
        if (!propertyExists(environment, key)) {
            log.info("Encryptor config not found for property {}, using default value: {}", key, defaultValue);
        }


        return environment.getProperty(key, defaultValue);
    }

    private static boolean propertyExists(Environment environment, String key) {
        return environment.getProperty(key) != null;
    }

    private static String getRequiredProperty(Environment environment, String key) {
        if (!propertyExists(environment, key)) {
            throw new IllegalStateException(String.format("Required Encryption configuration property missing: %s", key));
        } else {
            return environment.getProperty(key);
        }
    }

    public String encrypt(String message) {
        return ((StringEncryptor)this.singleton.get()).encrypt(message);
    }

    public String decrypt(String encryptedMessage) {
        return ((StringEncryptor)this.singleton.get()).decrypt(encryptedMessage);
    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/734411.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-27
下一篇 2022-04-27

发表评论

登录后才能评论

评论列表(0条)

保存