【AES对称加密 KeyStore使用 EhCache 使用】

AES对称加密 及 KeyStore 数据存储与读取,EhCache 存储信息

  • AES 对称加解密
  • KEYSTORE 存储读取信息
  • KEYSTORE 存储读取秘钥信息
  • 相关导入
  • EhCache使用

AES 对称加解密

/**
     * AES 对称加密、解密测试
     */
    public static void aesTest() {
        String plainText = "TCBJ-SECRET-KEY-ENCODE-DECODE-TEST";
        try {
            // 生成秘钥
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(128);
            SecretKey secretKey =  keyGenerator.generateKey();

            /**
             * todo
             * 根据业务保存秘钥,秘钥一旦变化旧的内容无法解密
             */

            // 加密
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] encrypted = cipher.doFinal(plainText.getBytes());

            // 解密
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            byte[] decrypted = cipher.doFinal(encrypted);

            System.out.println("输入:" + plainText);
            System.out.println("加密结果:" + new String(encrypted));
            System.out.println(decrypted);
            System.out.println("解密结果:" + new String(decrypted));

        } catch (Exception e) {
            System.out.println("AES 加解密异常");
        }
    }

KEYSTORE 存储读取信息

此处的keystore文件是用命令生成的,密码在命令中就定义了
不想用命令生成也可以在代码中直接生成
具体执行路径:JDK安装目录的 /bin 下 打开cmd 窗口
jceks 记得写对

keytool -genkey -alias csdn -keypass 123456 -keyalg RSA -keysize 1024 -validity 3650 -keystore D:/keyStore/test.keystore -storepass 888999 -storetype jceks

存储普通数据

/**
     * keystore 文件秘钥存储测试
     */
    public static void keyStoreTest() {
        FileInputStream inputStream = null ;
        OutputStream outputStream = null;
        try {
            // 读取 keyStore 文件转换为 keyStore 密钥库对象
            inputStream = new FileInputStream("D:\\keyStore\\test.keystore");
            // 设置证书类型 jceks
            KeyStore keyStore = KeyStore.getInstance("jceks");
            // 设置密钥库密码——获取keystore信息所需的密码
            String storepass = "888999";
            keyStore.load(inputStream,storepass.toCharArray());
            inputStream.close();


            // 加载keystore,就可以读取keystore现有条目、或者写入新条目
            // 别名——创建文件指定好的别名及密码
            String alias = "csdn";
            // 别名密码,指定别名条目的密码——私钥密码
            String keypass = "123456";
            KeyStore.ProtectionParameter parameter = new KeyStore.PasswordProtection(keypass.toCharArray());
            KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias,parameter);
            PrivateKey myPrivateKey = entry.getPrivateKey();
            System.out.println("获取到的私钥是:" + myPrivateKey.toString());

            // 设置秘钥信息别名 desPws 及 访问密码 decrp pws ,写入存储信息 desPwd
            String desPwd = "我是存储在 keystore 中的 AES 加密解密用的秘钥4.0";
            String password = "decryp pws";
            SecretKey mySecretKey = new SecretKeySpec(desPwd.getBytes(),"JKS");
            KeyStore.SecretKeyEntry skEntry = new KeyStore.SecretKeyEntry(mySecretKey);
            keyStore.setEntry("desPws", skEntry, new KeyStore.PasswordProtection(password.toCharArray()));
            // 将 keystore 存储到指定输出流,并用密码保护完整性
            outputStream = new FileOutputStream("D:\\keyStore\\test.keystore");
            keyStore.store(outputStream,storepass.toCharArray());
            outputStream.close();
        } catch (Exception e) {
            // todo 存储 keyStore 文件失败
        } finally {
            try {
                if (outputStream !=  null) {
                    outputStream.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                // todo 关闭文件流失败
            }
        }
    }

读取普通数据

/**
     * keystore 文件秘钥提取测试
     */
    public static void keyStoreDecodeTest() {
        String storepass = "888999";
        try {
            FileInputStream inputStream = null;
            // 读取keystore文件转换为 keystore 密钥库对象
            inputStream = new FileInputStream("D:\\keyStore\\test.keystore");
            // 设置证书类型
            KeyStore keyStore = KeyStore.getInstance("jceks");
            // 使用密钥库密码访问
            keyStore.load(inputStream,storepass.toCharArray());
            inputStream.close();

            // 根据别名,从 证书获取密码并解密
            // keystore.getKey 返回与给定别名关联的秘钥,并用给定密码来恢复他
            String password = "decryp pws";
            Key key = keyStore.getKey("desPws",password.toCharArray());
            // key.getEncode 返回基本编码格式的秘钥,如果秘钥不支持编码,返回null
            // 注意这里存储的是字符串,所以要根据 encode 转化,如果存储的是 SecretKey 直接 key 的值就是了
            System.out.println("从证书中获取的秘钥为:" + new String(key.getEncoded()));
        } catch (Exception e) {
            // todo 异常处理
        }
    }

KEYSTORE 存储读取秘钥信息

这里跟存储、读取普通数据其实差不多,多了一个生成 keystore 文件步骤而已
读取的时候 key 直接就是对应存储的 secretKey了

    /**
     * AES 秘钥对象 SecretKey 存储 KeyStore 中
     */
    public static void saveSecretKey2KeyStore() {
        try {
            // 生成秘钥
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(128);
            SecretKey secretKey =  keyGenerator.generateKey();
            KeyStore keyStore = KeyStore.getInstance("jceks");
            keyStore.load(null,null);
            System.out.println("保存的秘钥:" + secretKey);
            // 可以存字符串也可以存对象
            KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry(secretKey);
            // 设置条目名称及密码
            String entryPwd = "abc";
            keyStore.setEntry("test",secretKeyEntry,new KeyStore.PasswordProtection(entryPwd.toCharArray()));
            FileOutputStream outputStream = new FileOutputStream("D:\\keyStore\\test2.keystore");
            // 设置文件访问密码
            String storepwd = "123456";
            keyStore.store(outputStream,storepwd.toCharArray());
            outputStream.close();
        } catch (Exception e) {
            // todo
        }
    }
   /**
     * 从 KeyStore 获取 AES 秘钥对象 SecretKey
     */
    public static void getSecretKeyFromKeyStore() {
        try {
            String storepass = "123456";
            FileInputStream inputStream = new FileInputStream("D:\\keyStore\\test2.keystore");
            KeyStore keyStore1 = KeyStore.getInstance("jceks");
            keyStore1.load(inputStream,storepass.toCharArray());
            inputStream.close();
            String password = "abc";
            Key key = keyStore1.getKey("test",password.toCharArray());
            SecretKey keyValue = (SecretKey) key;
            System.out.println("获取到的秘钥:" + keyValue);
        } catch (Exception e) {
            // todo
        }
    }

相关导入

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.PrivateKey;

EhCache使用

  • 依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
        </dependency>
  • application.properties 配置

spring.cache.type=ehcache
spring.cache.ehcache.config=classpath:ehcache.xml
  • ehcache.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false">
    <!--缓存存放路径-->
    <diskStore path="D:\\keyStore\\"/>
    <defaultCache maxElementsInMemory="10000"
                  eternal="false"
                  timeToIdleSeconds="60"
                  timeToLiveSeconds="60"
                  overflowToDisk="true"
                  maxElementsOnDisk="10000000"
                  diskPersistent="false"
                  diskExpiryThreadIntervalSeconds="120"
                  memoryStoreEvictionPolicy="LRU" />


    <!--缓存文件名,配置多个不同的缓存存放不同的数据-->
    <cache name="shortlinkPropertiesCache"
           maxElementsInMemory="10000"
           eternal="false"
           timeToIdleSeconds="150"
           timeToLiveSeconds="600"
           overflowToDisk="false"
           diskPersistent="false"
           diskExpiryThreadIntervalSeconds="1"
           memoryStoreEvictionPolicy="LRU" />


</ehcache>

        <!--
        要实现缓存的实体必须要序列化
        以下属性是必须的:
           name:                Cache的名称,必须是唯一的(ehcache会把这个cache放到HashMap)。
           iskStore :           指定数据存储位置,可指定磁盘中的文件夹位置
           defaultCache :       默认的管理策略
           maxElementsInMemory: 在内存中缓存的element的最大数目。
           maxElementsOnDisk:   在磁盘上缓存的element的最大数目,默认值为0,表示不限制。
           eternal:             设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,
                                 如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断。
           overflowToDisk:      如果内存中数据超过内存限制,是否要缓存到磁盘上。

        以下属性是可选的:
         timeToIdleSeconds:     对象空闲时间,指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问。
         timeToLiveSeconds:     对象存活时间,指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问。
         diskPersistent:        是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false。
         diskExpiryThreadIntervalSeconds:   对象检测线程运行时间间隔。标识对象状态的线程多长时间运行一次。
         diskSpoolBufferSizeMB:             DiskStore使用的磁盘大小,默认值30MB。每个cache使用各自的DiskStore。
         memoryStoreEvictionPolicy:         如果内存中数据超过内存限制,向磁盘缓存时的策略。默认值LRU,可选FIFOLFU。
         clearOnFlush:内存数量最大时是否清除。

        缓存的3 种清空策略 :
        FIFO ,first in first out (先进先出).

        LFULess Frequently Used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存。

        LRULeast Recently Used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。


        -->
  • 使用

import com.***.CacheTestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author: chen
 * @Date: 2023/7/18 10:09
 */
@RestController
public class test {

    private CacheTestService cacheTestService;
    private static final String SHORTLINKTXQ = "ShortLinkTXQ";

    @Autowired
    public test(CacheTestService cacheTestService) {
        this.cacheTestService = cacheTestService;
    }

    @PostMapping("/addCache")
    public void addCache(){
        String result = cacheTestService.addCache(SHORTLINKTXQ);
        System.out.println("结果:" + result);
    }


    @PostMapping("/deleteCache")
    public void deleteCache() {
        cacheTestService.deleteCache(SHORTLINKTXQ);
    }

}


import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

/**
 * @Author: chen
 * @Project: member-parent
 * @Date: 2023/7/18 10:38
 */
@Service
@Slf4j
public class CacheTestService {




    @Cacheable(value = "shortlinkPropertiesCache", key = "#code")
    public String addCache(String code) {
        //使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素
        // 如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中
        System.out.println("访问方法返回的数据");
        // 直接正常返回对象、对象集合都行,都可以直接存入缓存,不用可以转成JSON之类的String 数据
        return "缓存内容";

    }

    @CacheEvict(value = "shortlinkPropertiesCache", key = "#code")
    public void deleteCache(String code) {
        System.out.println("删除成功");
    }

    @CachePut(value = "shortlinkPropertiesCache", key = "#code")
    public void updateCache(String code) {
        //@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果
        // 而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中

    }
}

第一次调用接口(添加缓存)
在这里插入图片描述
第二次调用接口
【AES对称加密 KeyStore使用 EhCache 使用】_第1张图片
【AES对称加密 KeyStore使用 EhCache 使用】_第2张图片
调用删除缓存接口后,重新调用添加缓存接口
【AES对称加密 KeyStore使用 EhCache 使用】_第3张图片

你可能感兴趣的:(java)