• java-信息安全(十九)加密工具Jasypt


    一、概述

      Jasypt 这个Java类包为开发人员提供一种简单的方式来为项目增加加密功能,包括:密码Digest认证,文本和对象加密,集成 hibernate,Spring Security(Acegi)来增强密码管理。

      Jasypt是一个Java库,可以使开发者不需太多操作来给Java项目添加基本加密功能,而且不需要知道加密原理。

      根据Jasypt文档,该技术可用于加密任务与应用程序,例如加密密码、敏感信息和数据通信、创建完整检查数据的sums. 其他性能包括高安全性、基于标准的加密技术、可同时单向和双向加密的加密密码、文本、数字和二进制文件。Jasypt也可以与Acegi Security整合也即Spring Security。Jasypt亦拥有加密应用配置的集成功能,而且提供一个开放的API从而任何一个Java Cryptography Extension都可以使用Jasypt。

      Jasypt还符合RSA标准的基于密码的加密,并提供了无配置加密工具以及新的、高可配置标准的加密工具。

        1、该开源项目可用于加密任务与应用程序,例如加密密码、敏感信息和数据通信

        2、还包括高安全性、基于标准的加密技术、可同时单向和双向加密的加密密码、文本、数字和二进制文件。

        3、Jasypt还符合RSA标准的基于密码的加密,并提供了无配置加密工具以及新的、高可配置标准的加密工具。

        4、加密属性文件(encryptable properties files)、Spring work集成、加密Hibernate数据源配置、新的命令行工具、URL加密的Apache wicket集成以及升级文档。

        5、Jasypt也可以与Acegi Security整合也即Spring Security。Jasypt亦拥有加密应用配置的集成功能,而且提供一个开放的API从而任何一个Java Cryptography Extension都可以使用Jasypt。

    二、使用

    2.1、jar使用

    shell下jar使用

    Maven下载好的jar包加密Mavenorgjasyptjasypt1.9.3jasypt-1.9.3.jar

    java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI password=G0CvDz7oJn6 algorithm=PBEWithMD5AndDES input=root

    input:你要解密的字符串(这里是上面生成的密文)

    password:口令(加密过程一样的字符串,现在知道这个有什么用了吧)

    algorithm:加密算法(输入加密过程一样的算法)

    OUTPUT:下面的字符串就是生成的明文,可以那来对比加密前的字符串

    2.2、代码方式1-原生

    2.2.1、加密解密-文本原生使用

            <dependency>
                <groupId>org.jasypt</groupId>
                <artifactId>jasypt</artifactId>
                <version>1.9.3</version>
            </dependency>

    示例

    public class BasicTextEncryptorTest {
        BasicTextEncryptor textEncryptor;
    
        @Before
        public void setUp() {
            textEncryptor = new BasicTextEncryptor();
            textEncryptor.setPassword("EbfYkitulv73I2p0mXI50JMXoaxZTKJ7");
        }
    
        @Test
        public void encrypt() {
            // 加密
            System.out.println(textEncryptor.encrypt("root@1234"));
            //TJetNWzmC4os1CCb+gHtz+5MpL9NFMML
            //KCTSu/Dv1elE1A/ZyppCHgJAAwKiez/p
        }
    
        @Test
        public void decyptPwd() {
            // 解密
    //        root@1234
            System.out.println(textEncryptor.decrypt("TJetNWzmC4os1CCb+gHtz+5MpL9NFMML"));
    
    //        root@1234
            System.out.println(textEncryptor.decrypt("KCTSu/Dv1elE1A/ZyppCHgJAAwKiez/p"));
        }
    }

    2.2.2、单向散列

      一般在做用户认证的时候,通常会使用MD5做简单的散列,然后登录时必须MD5值实现。同样的需求,也可以使用Jasypt来实现。

      BasicPasswordEncryptor

        @Test
        public void encrypt() {
            BasicPasswordEncryptor textEncryptor = new BasicPasswordEncryptor();
            String encryptPassword = textEncryptor.encryptPassword("EbfYkitulv73I2p0mXI50JMXoaxZTKJ7");
            System.out.println(encryptPassword);
            boolean checkPassword = textEncryptor.checkPassword("EbfYkitulv73I2p0mXI50JMXoaxZTKJ7", encryptPassword);
            System.out.println(checkPassword);
        }

    2.2.3、多线程加解密

      在多核机器上运行时,我们希望并行处理解密处理。为了获得良好的性能,我们可以使用PooledPBEStringEncryptor setPoolSize() API来创建一个解密线程池。它们中的每一个都可以由不同的线程并行使用:

    PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
    encryptor.setPoolSize(4);
    encryptor.setPassword("some-random-data");
    encryptor.setAlgorithm("PBEWithMD5AndTripleDES");

      最好将池大小设置为等于机器的核心数。加密和解密的代码与以前的代码相同。

    2.3、代码方式2-springboot结合

      配置文件参看:005-Spring Boot配置分析-配置文件application、Environment、PropertySource、@Value、EnvironmentPostProcessor、Profiles

      源码地址:https://github.com/ulisesbocchio/jasypt-spring-boot

    pom

            <dependency>
                <groupId>com.github.ulisesbocchio</groupId>
                <artifactId>jasypt-spring-boot-starter</artifactId>
                <version>3.0.1</version>
            </dependency>

    增加JasyptConfig 配置类

    @Configuration
    public class JasyptConfig {
    
        @Bean("jasyptStringEncryptor")
        public StringEncryptor stringEncryptor() {
            PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
            SimpleStringPBEConfig config = new SimpleStringPBEConfig();
            config.setPassword("EbfYkitulv73I2p0mXI50JMXoaxZTKJ7");
    //        config.setAlgorithm("PBEWithMD5AndDES");//默认配置
    //        config.setKeyObtentionIterations("1000");//默认配置
            config.setPoolSize("4");
    //        config.setProviderName("SunJCE");//默认配置
    //        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");//默认配置
    //        config.setStringOutputType("base64");//默认配置
            encryptor.setConfig(config);
            return encryptor;
        }
    }

    配置文件的写入和Spring XML的基本类似。application.yml相当于applicationContext.xml,security.properties就是要进行属性替换的配置文件。

    application.properties

    spring.datasource.url=jdbc:mysql://localhost:3306/abc?useSSL=false
    spring.datasource.username=root
    spring.datasource.password=${jdbc.password}

    security.properties

    jdbc.password=ENC(TJetNWzmC4os1CCb+gHtz+5MpL9NFMML)

    启动类增加

    @SpringBootApplication
    @EnableEncryptableProperties
    @PropertySource(value = {"classpath:security.properties"},ignoreResourceNotFound = false)
    public class SpringRunnerMain {
        public static void main(String[] args) {
            SpringApplication.run(SpringRunnerMain.class, args);
        }
    }

    2.4、关于这个口令的配置方式

      jasypt的作者建议是把这个盐值放在系统属性、命令行或是环境变量来使用,而不是放在配置文件

      还有种常用方式,直接配置方式(这样口令就暴露在这个配置文件里面,不建议);密文使用ENC(……),密钥放在代码中,配置分开

    1、启动命令

      jar: 命令:java -Djasypt.encryptor.password=jasypt -jar xxx.jar

      war:到Tomcat的bin目录下,打开文件catalina.bat/catalina.sh,添加如下参数,然后保存:window:set JAVA_OPTS="-Djasypt.encryptor.password=jasypt"  , Linux:JAVA_OPTS="-Djasypt.encryptor.password=jasypt"

    或者直接在tomcat bin 目录新建setenv.bat setenv.sh

    文件内容如下

    Windows:set JAVA_OPTS="-Djasypt.encryptor.password=jasypt"

    Linux:export JAVA_OPTS="-Djasypt.encryptor.password=jasypt"

    程序会默认使用。

    2、获取环境变量

            Properties properties = System.getProperties();
            Set<Object> objects = properties.keySet();
            for (Object object : objects) {
                System.out.println("key:" + object + "---:" + properties.get(object));
            }
    
            Map<String, String> getenv = System.getenv();
            for (Map.Entry<String, String> entry : getenv.entrySet()) {
                System.out.println(entry.getKey() + "---:" + entry.getValue());
            }

    三、核心类库说明

    3.1、加密工具类【以文本text为例】

    普通文本实现了如下三种方式

      

    以及参看Strong,AES,只是算法不一致

      BasicTextEncryptor→PBEWithMD5AndDES

      StrongTextEncryptor→PBEWithMD5AndTripleDES

      AES256TextEncryptor→PBEWithHMACSHA512AndAES_256

    主要是【参看BasicTextEncryptor】

    public final class BasicTextEncryptor implements TextEncryptor {
        private final StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
    
        public BasicTextEncryptor() {
            this.encryptor.setAlgorithm("PBEWithMD5AndDES");
        }
    
        public void setPassword(String password) {
            this.encryptor.setPassword(password);
        }
    
        public void setPasswordCharArray(char[] password) {
            this.encryptor.setPasswordCharArray(password);
        }
    
        public String encrypt(String message) {
            return this.encryptor.encrypt(message);
        }
    
        public String decrypt(String encryptedMessage) {
            return this.encryptor.decrypt(encryptedMessage);
        }
    }

    更多pbe算法可以参看:java-信息安全(三)-PBE加密算法

    参看上述工具类编写方式,以及上述PBE加密算法,编写:PBEWITHSHA1ANDRC4_128 工具类:RC128TextEncryptor

    public class RC128TextEncryptor implements TextEncryptor {
        private final StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
    
        public RC128TextEncryptor() {
            this.encryptor.setAlgorithm("PBEWITHSHA1ANDRC4_128");
        }
    
        public void setPassword(String password) {
            this.encryptor.setPassword(password);
        }
    
        public void setPasswordCharArray(char[] password) {
            this.encryptor.setPasswordCharArray(password);
        }
    
        public String encrypt(String message) {
            return this.encryptor.encrypt(message);
        }
    
        public String decrypt(String encryptedMessage) {
            return this.encryptor.decrypt(encryptedMessage);
        }
    }
    View Code

    测试:

    public class RC128TextEncryptorTest {
    
        RC128TextEncryptor textEncryptor;
    
        @Before
        public void setUp() {
            textEncryptor = new RC128TextEncryptor();
            textEncryptor.setPassword("EbfYkitulv73I2p0mXI50JMXoaxZTKJ7");
        }
    
        @Test
        public void encrypt() {
            // 加密
            System.out.println(textEncryptor.encrypt("root@1234"));
            //zjhmIP38jmvob56qyNevHjs=
            //iMX2aR70CkLGdtlAdhe2XKI=
        }
    
        @Test
        public void decyptPwd() {
            // 解密
    //        root@1234
            System.out.println(textEncryptor.decrypt("zjhmIP38jmvob56qyNevHjs="));
    
    //        root@1234
            System.out.println(textEncryptor.decrypt("iMX2aR70CkLGdtlAdhe2XKI="));
        }
    }
    View Code

    综上所述,所有算法核心是调用:StandardPBEStringEncryptor 

    3.2、StandardPBEStringEncryptor说明

    public final class StandardPBEStringEncryptor implements PBEStringCleanablePasswordEncryptor {
        private static final String MESSAGE_CHARSET = "UTF-8";
        private static final String ENCRYPTED_MESSAGE_CHARSET = "US-ASCII";
        public static final String DEFAULT_STRING_OUTPUT_TYPE = "base64";
        private StringPBEConfig stringPBEConfig = null;
        private String stringOutputType = "base64";
        private boolean stringOutputTypeBase64 = true;
        private boolean stringOutputTypeSet = false;
        private final StandardPBEByteEncryptor byteEncryptor;
        private final Base64 base64;
    
        public StandardPBEStringEncryptor() {
            this.byteEncryptor = new StandardPBEByteEncryptor();
            this.base64 = new Base64();
        }
    
        private StandardPBEStringEncryptor(StandardPBEByteEncryptor standardPBEByteEncryptor) {
            this.byteEncryptor = standardPBEByteEncryptor;
            this.base64 = new Base64();
        }
    
        public synchronized void setConfig(PBEConfig config) {
            this.byteEncryptor.setConfig(config);
            if (config != null && config instanceof StringPBEConfig) {
                this.stringPBEConfig = (StringPBEConfig)config;
            }
    
        }
    
        public void setAlgorithm(String algorithm) {
            this.byteEncryptor.setAlgorithm(algorithm);
        }
    
        public void setPassword(String password) {
            this.byteEncryptor.setPassword(password);
        }
    
        public void setPasswordCharArray(char[] password) {
            this.byteEncryptor.setPasswordCharArray(password);
        }
    
        public void setKeyObtentionIterations(int keyObtentionIterations) {
            this.byteEncryptor.setKeyObtentionIterations(keyObtentionIterations);
        }
    
        public void setSaltGenerator(SaltGenerator saltGenerator) {
            this.byteEncryptor.setSaltGenerator(saltGenerator);
        }
    
        public void setIvGenerator(IvGenerator ivGenerator) {
            this.byteEncryptor.setIvGenerator(ivGenerator);
        }
    
        public void setProviderName(String providerName) {
            this.byteEncryptor.setProviderName(providerName);
        }
    
        public void setProvider(Provider provider) {
            this.byteEncryptor.setProvider(provider);
        }
    
        public synchronized void setStringOutputType(String stringOutputType) {
            CommonUtils.validateNotEmpty(stringOutputType, "String output type cannot be set empty");
            if (this.isInitialized()) {
                throw new AlreadyInitializedException();
            } else {
                this.stringOutputType = CommonUtils.getStandardStringOutputType(stringOutputType);
                this.stringOutputTypeSet = true;
            }
        }
    
        synchronized StandardPBEStringEncryptor[] cloneAndInitializeEncryptor(int size) {
            StandardPBEByteEncryptor[] byteEncryptorClones = this.byteEncryptor.cloneAndInitializeEncryptor(size);
            this.initializeSpecifics();
            StandardPBEStringEncryptor[] clones = new StandardPBEStringEncryptor[size];
            clones[0] = this;
    
            for(int i = 1; i < size; ++i) {
                clones[i] = new StandardPBEStringEncryptor(byteEncryptorClones[i]);
                if (CommonUtils.isNotEmpty(this.stringOutputType)) {
                    clones[i].setStringOutputType(this.stringOutputType);
                }
            }
    
            return clones;
        }
    
        public boolean isInitialized() {
            return this.byteEncryptor.isInitialized();
        }
    
        public synchronized void initialize() {
            if (!this.isInitialized()) {
                this.initializeSpecifics();
                this.byteEncryptor.initialize();
            }
    
        }
    
        private void initializeSpecifics() {
            if (this.stringPBEConfig != null) {
                String configStringOutputType = this.stringPBEConfig.getStringOutputType();
                this.stringOutputType = !this.stringOutputTypeSet && configStringOutputType != null ? configStringOutputType : this.stringOutputType;
            }
    
            this.stringOutputTypeBase64 = "base64".equalsIgnoreCase(this.stringOutputType);
        }
    
        public String encrypt(String message) {
            if (message == null) {
                return null;
            } else {
                if (!this.isInitialized()) {
                    this.initialize();
                }
    
                try {
                    byte[] messageBytes = message.getBytes("UTF-8");
                    byte[] encryptedMessage = this.byteEncryptor.encrypt(messageBytes);
                    String result = null;
                    if (this.stringOutputTypeBase64) {
                        encryptedMessage = this.base64.encode(encryptedMessage);
                        result = new String(encryptedMessage, "US-ASCII");
                    } else {
                        result = CommonUtils.toHexadecimal(encryptedMessage);
                    }
    
                    return result;
                } catch (EncryptionInitializationException var5) {
                    throw var5;
                } catch (EncryptionOperationNotPossibleException var6) {
                    throw var6;
                } catch (Exception var7) {
                    throw new EncryptionOperationNotPossibleException();
                }
            }
        }
    
        public String decrypt(String encryptedMessage) {
            if (encryptedMessage == null) {
                return null;
            } else {
                if (!this.isInitialized()) {
                    this.initialize();
                }
    
                try {
                    byte[] encryptedMessageBytes = null;
                    byte[] encryptedMessageBytes;
                    if (this.stringOutputTypeBase64) {
                        encryptedMessageBytes = encryptedMessage.getBytes("US-ASCII");
                        encryptedMessageBytes = this.base64.decode(encryptedMessageBytes);
                    } else {
                        encryptedMessageBytes = CommonUtils.fromHexadecimal(encryptedMessage);
                    }
    
                    byte[] message = this.byteEncryptor.decrypt(encryptedMessageBytes);
                    return new String(message, "UTF-8");
                } catch (EncryptionInitializationException var4) {
                    throw var4;
                } catch (EncryptionOperationNotPossibleException var5) {
                    throw var5;
                } catch (Exception var6) {
                    throw new EncryptionOperationNotPossibleException();
                }
            }
        }
    }
    View Code

    这里涉及了具体加密解密实现逻辑。

    直接初始化调用

    public class StandardPBEStringEncryptorTest {
        StandardPBEStringEncryptor textEncryptor;
    
        @Before
        public void setUp() {
            textEncryptor = new StandardPBEStringEncryptor();
    //        textEncryptor.setAlgorithm("");//自行指定
            textEncryptor.setPassword("EbfYkitulv73I2p0mXI50JMXoaxZTKJ7");
        }
    
        @Test
        public void encrypt() {
            // 加密
            System.out.println(textEncryptor.encrypt("root@1234"));
            //Han0rFt6K2jhvrK5swPpD/ctoUMPckIO
            //upkr4Rc6bhmpUXhdRoT9qqkhiSfEhTvS
        }
    
        @Test
        public void decyptPwd() {
            // 解密
    //        root@1234
            System.out.println(textEncryptor.decrypt("Han0rFt6K2jhvrK5swPpD/ctoUMPckIO"));
    //        root@1234
            System.out.println(textEncryptor.decrypt("upkr4Rc6bhmpUXhdRoT9qqkhiSfEhTvS"));
        }
    }
    View Code

    3.3、上述2.3使用池化方式

     
  • 相关阅读:
    java.lang.ClassNotFoundException: org.jaxen.JaxenException
    hdu 4882 ZCC Loves Codefires(贪心)
    C++ STL 源代码学习(之deque篇)
    算法导论学习笔记(2)-归并排序
    机器学习方法:回归(一):线性回归Linear regression
    HDU 2028 Lowest Common Multiple Plus
    C++11新特性应用--实现延时求值(std::function和std::bind)
    大数减法
    hive 运行sqlclient异常
    Oracle 12c agent install for windows
  • 原文地址:https://www.cnblogs.com/bjlhx/p/12229296.html
Copyright © 2020-2023  润新知