소스 검색

examcloud-crypto-starter

deason 3 년 전
부모
커밋
e0b80b5597
29개의 변경된 파일1995개의 추가작업 그리고 0개의 파일을 삭제
  1. 55 0
      examcloud-starters/examcloud-crypto-starter/pom.xml
  2. 22 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/CryptoAutoConfiguration.java
  3. 48 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/CryptoProperties.java
  4. 20 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/Algorithm.java
  5. 20 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/CryptoConstant.java
  6. 15 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/CryptoException.java
  7. 117 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/CryptoGroup.java
  8. 52 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/CryptoHelper.java
  9. 52 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/CryptoItem.java
  10. 49 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/CryptoType.java
  11. 30 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/FieldPair.java
  12. 22 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/Key.java
  13. 20 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/KeyType.java
  14. 98 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/CryptoFactory.java
  15. 20 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/CryptoService.java
  16. 41 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/impl/AesCryptoService.java
  17. 30 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/impl/Base64CryptoService.java
  18. 41 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/impl/DesCryptoService.java
  19. 37 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/impl/Rc4CryptoService.java
  20. 61 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/impl/RsaCryptoService.java
  21. 41 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/impl/TripleDesCryptoService.java
  22. 173 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/utils/AesUtil.java
  23. 169 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/utils/DesUtil.java
  24. 145 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/utils/Rc4Util.java
  25. 253 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/utils/RsaUtil.java
  26. 169 0
      examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/utils/TripleDesUtil.java
  27. 2 0
      examcloud-starters/examcloud-crypto-starter/src/main/resources/META-INF/spring.factories
  28. 192 0
      examcloud-starters/examcloud-crypto-starter/src/test/java/cn/com/qmth/examcloud/starters/crypto/test/CryptoTest.java
  29. 1 0
      examcloud-starters/pom.xml

+ 55 - 0
examcloud-starters/examcloud-crypto-starter/pom.xml

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>examcloud-crypto-starter</artifactId>
+    <packaging>jar</packaging>
+
+    <parent>
+        <groupId>cn.com.qmth.examcloud.starters</groupId>
+        <artifactId>examcloud-starters</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-autoconfigure</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>${basedir}/src/main/resources</directory>
+                <includes>
+                    <include>**/*.*</include>
+                </includes>
+            </resource>
+        </resources>
+    </build>
+
+</project>

+ 22 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/CryptoAutoConfiguration.java

@@ -0,0 +1,22 @@
+package cn.com.qmth.examcloud.starters.crypto;
+
+import cn.com.qmth.examcloud.starters.crypto.service.CryptoFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableConfigurationProperties(CryptoProperties.class)
+public class CryptoAutoConfiguration {
+
+    private static final Logger log = LoggerFactory.getLogger(CryptoAutoConfiguration.class);
+
+    @Bean
+    public CryptoFactory cryptoFactory() {
+        log.info("cryptoFactory init...");
+        return new CryptoFactory();
+    }
+
+}

+ 48 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/CryptoProperties.java

@@ -0,0 +1,48 @@
+package cn.com.qmth.examcloud.starters.crypto;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.io.Serializable;
+
+/**
+ * 加、解密算法配置类
+ */
+@ConfigurationProperties(prefix = "examcloud.starters.crypto", ignoreUnknownFields = false)
+public class CryptoProperties implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String rsaPublicKey;
+
+    private String rsaPrivateKey;
+
+    /**
+     * 默认加密方案组合
+     */
+    private String[] groups;
+
+    public String getRsaPublicKey() {
+        return rsaPublicKey;
+    }
+
+    public void setRsaPublicKey(String rsaPublicKey) {
+        this.rsaPublicKey = rsaPublicKey;
+    }
+
+    public String getRsaPrivateKey() {
+        return rsaPrivateKey;
+    }
+
+    public void setRsaPrivateKey(String rsaPrivateKey) {
+        this.rsaPrivateKey = rsaPrivateKey;
+    }
+
+    public String[] getGroups() {
+        return groups;
+    }
+
+    public void setGroups(String[] groups) {
+        this.groups = groups;
+    }
+
+}

+ 20 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/Algorithm.java

@@ -0,0 +1,20 @@
+package cn.com.qmth.examcloud.starters.crypto.common;
+
+/**
+ * 算法
+ */
+public enum Algorithm {
+
+    AES,
+
+    DES,
+
+    TRIPLE_DES,
+
+    RC4,
+
+    RSA,
+
+    BASE64;
+
+}

+ 20 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/CryptoConstant.java

@@ -0,0 +1,20 @@
+package cn.com.qmth.examcloud.starters.crypto.common;
+
+/**
+ * 加、解密相关常量
+ */
+public interface CryptoConstant {
+
+    String TIMESTAMP = "timestamp";
+
+    String REQUEST_PARAM_ERROR = "请求参数错误!";
+
+    String ALGORITHM_INVALID = "算法无效!";
+
+    String KEY_ERROR = "密钥错误!";
+
+    String ENCRYPT_ERROR = "加密错误!";
+
+    String DECRYPT_ERROR = "解密错误!";
+
+}

+ 15 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/CryptoException.java

@@ -0,0 +1,15 @@
+package cn.com.qmth.examcloud.starters.crypto.common;
+
+public class CryptoException extends RuntimeException {
+
+    private static final long serialVersionUID = -8380685002388748754L;
+
+    public CryptoException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public CryptoException(String message) {
+        super(message);
+    }
+
+}

+ 117 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/CryptoGroup.java

@@ -0,0 +1,117 @@
+package cn.com.qmth.examcloud.starters.crypto.common;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 加、解密方案组合
+ */
+public class CryptoGroup {
+
+    private List<CryptoItem> items;
+
+    /**
+     * 构造方案组合
+     *
+     * @param combination 组合名称
+     */
+    public CryptoGroup(String combination) {
+        if (StringUtils.isEmpty(combination)) {
+            return;
+        }
+
+        items = new ArrayList<>();
+        for (int n = 0; n < combination.length(); n++) {
+            Character c = combination.charAt(n);
+
+            CryptoType type = CryptoType.findByName(c.toString());
+            if (type == null) {
+                throw new CryptoException(CryptoConstant.ALGORITHM_INVALID);
+            }
+
+            items.add(new CryptoItem(type));
+        }
+    }
+
+    /**
+     * 匹配算法的密钥值(特殊场景:所有算法都共用一个密码!!!)
+     *
+     * @param keyValue 密钥值
+     * @return
+     */
+    public CryptoGroup matchKeys(String keyValue) {
+        for (CryptoItem item : getItems()) {
+            Key key = new Key(keyValue, KeyType.COMMON);
+            item.setEncryptKey(key);
+            item.setDecryptKey(key);
+        }
+
+        return this;
+    }
+
+    /**
+     * 匹配某种算法的密钥值(适用加、解密密码都一样场景)
+     *
+     * @param algorithm 算法
+     * @param keyValue  密钥值
+     * @return
+     */
+    public CryptoGroup matchKeys(Algorithm algorithm, String keyValue) {
+        if (StringUtils.isEmpty(keyValue)) {
+            throw new CryptoException(CryptoConstant.KEY_ERROR);
+        }
+
+        Key key = new Key(keyValue, KeyType.COMMON);
+        for (CryptoItem item : getItems()) {
+            if (item.getType().getAlgorithm() == algorithm) {
+                item.setEncryptKey(key);
+                item.setDecryptKey(key);
+            }
+        }
+
+        return this;
+    }
+
+    /**
+     * 匹配某种算法的密钥值(适用加、解密密码不一样场景)
+     *
+     * @param algorithm  算法
+     * @param encryptKey 加密密钥值
+     * @param decryptKey 解密密钥值
+     * @return
+     */
+    public CryptoGroup matchKeys(Algorithm algorithm, Key encryptKey, Key decryptKey) {
+        if (encryptKey.getType() == null || StringUtils.isEmpty(encryptKey.getValue())
+                || decryptKey.getType() == null || StringUtils.isEmpty(decryptKey.getValue())) {
+            throw new CryptoException(CryptoConstant.KEY_ERROR);
+        }
+
+        for (CryptoItem item : getItems()) {
+            if (item.getType().getAlgorithm() == algorithm) {
+                item.setEncryptKey(encryptKey);
+                item.setDecryptKey(decryptKey);
+            }
+        }
+
+        return this;
+    }
+
+    public List<CryptoItem> getItems() {
+        if (items == null) {
+            items = new ArrayList<>();
+        }
+        return items;
+    }
+
+    public List<CryptoItem> getReverseItems() {
+        // 倒序
+        List<CryptoItem> list = new ArrayList<>();
+        for (int n = getItems().size() - 1; n >= 0; n--) {
+            list.add(getItems().get(n));
+        }
+        return list;
+    }
+
+}

+ 52 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/CryptoHelper.java

@@ -0,0 +1,52 @@
+package cn.com.qmth.examcloud.starters.crypto.common;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 加、解密相关辅助类
+ */
+public class CryptoHelper implements CryptoConstant {
+
+    private static final Logger log = LoggerFactory.getLogger(CryptoHelper.class);
+
+    public static long parseTimestamp(String timestamp) {
+        if (StringUtils.isEmpty(timestamp)) {
+            throw new CryptoException(REQUEST_PARAM_ERROR);
+        }
+
+        try {
+            return Long.parseLong(timestamp);
+        } catch (NumberFormatException e) {
+            log.error(e.getMessage());
+            throw new CryptoException(REQUEST_PARAM_ERROR);
+        }
+    }
+
+    public static void verifyTimestamp(long timestamp) {
+        long diff = System.currentTimeMillis() - timestamp;
+        if (Math.abs(diff) > 60L * 1000L) {
+            // 60秒内有效
+            throw new CryptoException(REQUEST_PARAM_ERROR);
+        }
+    }
+
+    public static String buildKey(FieldPair... pairs) {
+        StringBuilder params = new StringBuilder();
+
+        for (int n = 0; n < pairs.length; n++) {
+            FieldPair pair = pairs[n];
+            params.append(pair.getFieldName()).append("=").append(pair.getFieldValue());
+            if (n < pairs.length - 1) {
+                params.append("&");
+            }
+        }
+
+        String key = DigestUtils.md5Hex(params.toString());
+        log.info("Crypto key = {}, params = {}", key, params);
+        return key;
+    }
+
+}

+ 52 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/CryptoItem.java

@@ -0,0 +1,52 @@
+package cn.com.qmth.examcloud.starters.crypto.common;
+
+/**
+ * 加、解密方案项
+ */
+public class CryptoItem {
+
+    private CryptoType type;
+
+    private Key encryptKey;
+
+    private Key decryptKey;
+
+    public CryptoItem(CryptoType type, Key encryptKey, Key decryptKey) {
+        this.type = type;
+        this.encryptKey = encryptKey;
+        this.decryptKey = decryptKey;
+    }
+
+    public CryptoItem(CryptoType type) {
+        this.type = type;
+    }
+
+    public CryptoItem() {
+
+    }
+
+    public CryptoType getType() {
+        return type;
+    }
+
+    public void setType(CryptoType type) {
+        this.type = type;
+    }
+
+    public Key getEncryptKey() {
+        return encryptKey;
+    }
+
+    public void setEncryptKey(Key encryptKey) {
+        this.encryptKey = encryptKey;
+    }
+
+    public Key getDecryptKey() {
+        return decryptKey;
+    }
+
+    public void setDecryptKey(Key decryptKey) {
+        this.decryptKey = decryptKey;
+    }
+
+}

+ 49 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/CryptoType.java

@@ -0,0 +1,49 @@
+package cn.com.qmth.examcloud.starters.crypto.common;
+
+import cn.com.qmth.examcloud.starters.crypto.service.impl.*;
+
+/**
+ * 加、解密算法类型
+ */
+public enum CryptoType {
+
+    A(AesCryptoService.class, Algorithm.AES),
+
+    B(Base64CryptoService.class, Algorithm.BASE64),
+
+    C(Rc4CryptoService.class, Algorithm.RC4),
+
+    D(DesCryptoService.class, Algorithm.DES),
+
+    E(TripleDesCryptoService.class, Algorithm.TRIPLE_DES);
+
+    // RSA存在性能问题暂停使用
+    // R(RsaCryptoService.class, Algorithm.RSA);
+
+    private Class impl;
+
+    private Algorithm algorithm;
+
+    CryptoType(Class impl, Algorithm algorithm) {
+        this.impl = impl;
+        this.algorithm = algorithm;
+    }
+
+    public static CryptoType findByName(String name) {
+        for (CryptoType type : values()) {
+            if (type.name().equals(name)) {
+                return type;
+            }
+        }
+        return null;
+    }
+
+    public Class getImpl() {
+        return impl;
+    }
+
+    public Algorithm getAlgorithm() {
+        return algorithm;
+    }
+
+}

+ 30 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/FieldPair.java

@@ -0,0 +1,30 @@
+package cn.com.qmth.examcloud.starters.crypto.common;
+
+public class FieldPair {
+
+    private String fieldName;
+
+    private String fieldValue;
+
+    public FieldPair(String fieldName, String fieldValue) {
+        this.fieldName = fieldName;
+        this.fieldValue = fieldValue;
+    }
+
+    public String getFieldName() {
+        return fieldName;
+    }
+
+    public void setFieldName(String fieldName) {
+        this.fieldName = fieldName;
+    }
+
+    public String getFieldValue() {
+        return fieldValue;
+    }
+
+    public void setFieldValue(String fieldValue) {
+        this.fieldValue = fieldValue;
+    }
+
+}

+ 22 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/Key.java

@@ -0,0 +1,22 @@
+package cn.com.qmth.examcloud.starters.crypto.common;
+
+public class Key {
+
+    private String value;
+
+    private KeyType type;
+
+    public Key(String value, KeyType type) {
+        this.value = value;
+        this.type = type;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public KeyType getType() {
+        return type;
+    }
+
+}

+ 20 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/common/KeyType.java

@@ -0,0 +1,20 @@
+package cn.com.qmth.examcloud.starters.crypto.common;
+
+public enum KeyType {
+
+    /**
+     * 通用密钥
+     */
+    COMMON,
+
+    /**
+     * 公钥
+     */
+    PUBLIC,
+
+    /**
+     * 私钥
+     */
+    PRIVATE
+
+}

+ 98 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/CryptoFactory.java

@@ -0,0 +1,98 @@
+package cn.com.qmth.examcloud.starters.crypto.service;
+
+import cn.com.qmth.examcloud.starters.crypto.common.*;
+import cn.com.qmth.examcloud.starters.crypto.service.impl.*;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * 加、解密算法工厂类
+ */
+public class CryptoFactory {
+
+    private static final Logger log = LoggerFactory.getLogger(CryptoFactory.class);
+
+    public CryptoService getCryptoService(CryptoType type) {
+        if (type.getImpl() == AesCryptoService.class) {
+            return new AesCryptoService();
+        } else if (type.getImpl() == DesCryptoService.class) {
+            return new DesCryptoService();
+        } else if (type.getImpl() == TripleDesCryptoService.class) {
+            return new TripleDesCryptoService();
+        } else if (type.getImpl() == Rc4CryptoService.class) {
+            return new Rc4CryptoService();
+        } else if (type.getImpl() == RsaCryptoService.class) {
+            return new RsaCryptoService();
+        } else if (type.getImpl() == Base64CryptoService.class) {
+            return new Base64CryptoService();
+        }
+
+        throw new CryptoException(CryptoConstant.ALGORITHM_INVALID);
+    }
+
+    /**
+     * 按加密方案组合“顺序”依次加密
+     */
+    public String encrypt(CryptoGroup cryptoGroup, String str) {
+        return this.encrypt(cryptoGroup, str, false);
+    }
+
+    /**
+     * 按加密方案组合“顺序或倒序”依次加密
+     */
+    public String encrypt(CryptoGroup cryptoGroup, String str, boolean reverse) {
+        if (StringUtils.isEmpty(str)) {
+            log.warn("[encrypt] input is empty...");
+            throw new CryptoException(CryptoConstant.REQUEST_PARAM_ERROR);
+        }
+
+        List<CryptoItem> items;
+        if (reverse) {
+            // 倒序
+            items = cryptoGroup.getReverseItems();
+        } else {
+            items = cryptoGroup.getItems();
+        }
+
+        for (CryptoItem item : items) {
+            str = this.getCryptoService(item.getType()).encrypt(str, item.getEncryptKey());
+        }
+
+        return str;
+    }
+
+    /**
+     * 按加密方案组合“顺序”依次解密
+     */
+    public String decrypt(CryptoGroup cryptoGroup, String str) {
+        return this.decrypt(cryptoGroup, str, false);
+    }
+
+    /**
+     * 按加密方案组合“顺序或倒序”依次解密
+     */
+    public String decrypt(CryptoGroup cryptoGroup, String str, boolean reverse) {
+        if (StringUtils.isEmpty(str)) {
+            log.warn("[decrypt] input is empty...");
+            throw new CryptoException(CryptoConstant.REQUEST_PARAM_ERROR);
+        }
+
+        List<CryptoItem> items;
+        if (reverse) {
+            // 倒序
+            items = cryptoGroup.getReverseItems();
+        } else {
+            items = cryptoGroup.getItems();
+        }
+
+        for (CryptoItem item : items) {
+            str = this.getCryptoService(item.getType()).decrypt(str, item.getDecryptKey());
+        }
+
+        return str;
+    }
+
+}

+ 20 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/CryptoService.java

@@ -0,0 +1,20 @@
+package cn.com.qmth.examcloud.starters.crypto.service;
+
+import cn.com.qmth.examcloud.starters.crypto.common.Key;
+
+/**
+ * 加、解密算法服务类
+ */
+public interface CryptoService {
+
+    /**
+     * 加密
+     */
+    String encrypt(String str, Key key);
+
+    /**
+     * 解密
+     */
+    String decrypt(String str, Key key);
+
+}

+ 41 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/impl/AesCryptoService.java

@@ -0,0 +1,41 @@
+package cn.com.qmth.examcloud.starters.crypto.service.impl;
+
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoConstant;
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoException;
+import cn.com.qmth.examcloud.starters.crypto.common.Key;
+import cn.com.qmth.examcloud.starters.crypto.service.CryptoService;
+import cn.com.qmth.examcloud.starters.crypto.utils.AesUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * AES算法(默认不带向量)
+ */
+public class AesCryptoService implements CryptoService {
+
+    private static final Logger log = LoggerFactory.getLogger(AesCryptoService.class);
+
+    @Override
+    public String encrypt(String str, Key key) {
+        if (key == null || StringUtils.isEmpty(key.getValue())) {
+            throw new CryptoException(CryptoConstant.KEY_ERROR);
+        }
+
+        byte[] keyBytes = key.getValue().getBytes(StandardCharsets.UTF_8);
+        return AesUtil.encrypt(str, keyBytes, false);
+    }
+
+    @Override
+    public String decrypt(String str, Key key) {
+        if (key == null || StringUtils.isEmpty(key.getValue())) {
+            throw new CryptoException(CryptoConstant.KEY_ERROR);
+        }
+
+        byte[] keyBytes = key.getValue().getBytes(StandardCharsets.UTF_8);
+        return AesUtil.decrypt(str, keyBytes, false);
+    }
+
+}

+ 30 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/impl/Base64CryptoService.java

@@ -0,0 +1,30 @@
+package cn.com.qmth.examcloud.starters.crypto.service.impl;
+
+import cn.com.qmth.examcloud.starters.crypto.common.Key;
+import cn.com.qmth.examcloud.starters.crypto.service.CryptoService;
+import org.apache.commons.codec.binary.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * BASE64算法
+ */
+public class Base64CryptoService implements CryptoService {
+
+    private static final Logger log = LoggerFactory.getLogger(Base64CryptoService.class);
+
+    @Override
+    public String encrypt(String str, Key key) {
+        byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
+        return Base64.encodeBase64String(bytes);
+    }
+
+    @Override
+    public String decrypt(String str, Key key) {
+        byte[] bytes = Base64.decodeBase64(str);
+        return new String(bytes, StandardCharsets.UTF_8);
+    }
+
+}

+ 41 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/impl/DesCryptoService.java

@@ -0,0 +1,41 @@
+package cn.com.qmth.examcloud.starters.crypto.service.impl;
+
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoConstant;
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoException;
+import cn.com.qmth.examcloud.starters.crypto.common.Key;
+import cn.com.qmth.examcloud.starters.crypto.service.CryptoService;
+import cn.com.qmth.examcloud.starters.crypto.utils.DesUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * DES算法(默认不带向量)
+ */
+public class DesCryptoService implements CryptoService {
+
+    private static final Logger log = LoggerFactory.getLogger(DesCryptoService.class);
+
+    @Override
+    public String encrypt(String str, Key key) {
+        if (key == null || StringUtils.isEmpty(key.getValue())) {
+            throw new CryptoException(CryptoConstant.KEY_ERROR);
+        }
+
+        byte[] keyBytes = key.getValue().getBytes(StandardCharsets.UTF_8);
+        return DesUtil.encrypt(str, keyBytes, false);
+    }
+
+    @Override
+    public String decrypt(String str, Key key) {
+        if (key == null || StringUtils.isEmpty(key.getValue())) {
+            throw new CryptoException(CryptoConstant.KEY_ERROR);
+        }
+
+        byte[] keyBytes = key.getValue().getBytes(StandardCharsets.UTF_8);
+        return DesUtil.decrypt(str, keyBytes, false);
+    }
+
+}

+ 37 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/impl/Rc4CryptoService.java

@@ -0,0 +1,37 @@
+package cn.com.qmth.examcloud.starters.crypto.service.impl;
+
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoConstant;
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoException;
+import cn.com.qmth.examcloud.starters.crypto.common.Key;
+import cn.com.qmth.examcloud.starters.crypto.service.CryptoService;
+import cn.com.qmth.examcloud.starters.crypto.utils.Rc4Util;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * RC4算法
+ */
+public class Rc4CryptoService implements CryptoService {
+
+    private static final Logger log = LoggerFactory.getLogger(Rc4CryptoService.class);
+
+    @Override
+    public String encrypt(String str, Key key) {
+        if (key == null || StringUtils.isEmpty(key.getValue())) {
+            throw new CryptoException(CryptoConstant.KEY_ERROR);
+        }
+
+        return Rc4Util.encrypt(str, key.getValue());
+    }
+
+    @Override
+    public String decrypt(String str, Key key) {
+        if (key == null || StringUtils.isEmpty(key.getValue())) {
+            throw new CryptoException(CryptoConstant.KEY_ERROR);
+        }
+
+        return Rc4Util.decrypt(str, key.getValue());
+    }
+
+}

+ 61 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/impl/RsaCryptoService.java

@@ -0,0 +1,61 @@
+package cn.com.qmth.examcloud.starters.crypto.service.impl;
+
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoConstant;
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoException;
+import cn.com.qmth.examcloud.starters.crypto.common.Key;
+import cn.com.qmth.examcloud.starters.crypto.common.KeyType;
+import cn.com.qmth.examcloud.starters.crypto.service.CryptoService;
+import cn.com.qmth.examcloud.starters.crypto.utils.RsaUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+/**
+ * RSA算法
+ */
+public class RsaCryptoService implements CryptoService {
+
+    private static final Logger log = LoggerFactory.getLogger(RsaCryptoService.class);
+
+    @Override
+    public String encrypt(String str, Key key) {
+        if (key == null || StringUtils.isEmpty(key.getValue())) {
+            throw new CryptoException(CryptoConstant.KEY_ERROR);
+        }
+
+        if (KeyType.PRIVATE == key.getType()) {
+            RSAPrivateKey rsaPrivateKey = RsaUtil.getPrivateKey(key.getValue());
+            return RsaUtil.privateEncrypt(str, rsaPrivateKey);
+        }
+
+        if (KeyType.PUBLIC == key.getType()) {
+            RSAPublicKey rsaPublicKey = RsaUtil.getPublicKey(key.getValue());
+            return RsaUtil.publicEncrypt(str, rsaPublicKey);
+        }
+
+        throw new CryptoException(CryptoConstant.ENCRYPT_ERROR);
+    }
+
+    @Override
+    public String decrypt(String str, Key key) {
+        if (key == null || StringUtils.isEmpty(key.getValue())) {
+            throw new CryptoException(CryptoConstant.KEY_ERROR);
+        }
+
+        if (KeyType.PRIVATE == key.getType()) {
+            RSAPrivateKey rsaPrivateKey = RsaUtil.getPrivateKey(key.getValue());
+            return RsaUtil.privateDecrypt(str, rsaPrivateKey);
+        }
+
+        if (KeyType.PUBLIC == key.getType()) {
+            RSAPublicKey rsaPublicKey = RsaUtil.getPublicKey(key.getValue());
+            return RsaUtil.publicDecrypt(str, rsaPublicKey);
+        }
+
+        throw new CryptoException(CryptoConstant.DECRYPT_ERROR);
+    }
+
+}

+ 41 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/service/impl/TripleDesCryptoService.java

@@ -0,0 +1,41 @@
+package cn.com.qmth.examcloud.starters.crypto.service.impl;
+
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoConstant;
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoException;
+import cn.com.qmth.examcloud.starters.crypto.common.Key;
+import cn.com.qmth.examcloud.starters.crypto.service.CryptoService;
+import cn.com.qmth.examcloud.starters.crypto.utils.TripleDesUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * TripleDes算法(默认不带向量)
+ */
+public class TripleDesCryptoService implements CryptoService {
+
+    private static final Logger log = LoggerFactory.getLogger(TripleDesCryptoService.class);
+
+    @Override
+    public String encrypt(String str, Key key) {
+        if (key == null || StringUtils.isEmpty(key.getValue())) {
+            throw new CryptoException(CryptoConstant.KEY_ERROR);
+        }
+
+        byte[] keyBytes = key.getValue().getBytes(StandardCharsets.UTF_8);
+        return TripleDesUtil.encrypt(str, keyBytes, false);
+    }
+
+    @Override
+    public String decrypt(String str, Key key) {
+        if (key == null || StringUtils.isEmpty(key.getValue())) {
+            throw new CryptoException(CryptoConstant.KEY_ERROR);
+        }
+
+        byte[] keyBytes = key.getValue().getBytes(StandardCharsets.UTF_8);
+        return TripleDesUtil.decrypt(str, keyBytes, false);
+    }
+
+}

+ 173 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/utils/AesUtil.java

@@ -0,0 +1,173 @@
+package cn.com.qmth.examcloud.starters.crypto.utils;
+
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoConstant;
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoException;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/**
+ * AES加、解密
+ */
+public class AesUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(AesUtil.class);
+
+    /**
+     * 算法
+     */
+    private static final String ALGORITHM = "AES";
+
+    /**
+     * ECB模式
+     * 算法/模式/补码方式
+     */
+    private static final String ECB_PKCS5Padding = "AES/ECB/PKCS5Padding";
+
+    /**
+     * CBC模式
+     * 算法/模式/补码方式
+     */
+    private static final String CBC_PKCS5Padding = "AES/CBC/PKCS5Padding";
+
+    /**
+     * 默认密钥长度
+     */
+    private static final int DEFAULT_KEY_SIZE = 128;
+
+    /**
+     * 默认偏移向量字符串(长度必须16位,仅CBC模式下使用)
+     */
+    private static final String DEFAULT_IV = "@M#A$G%A^2&0*2(1";
+
+    /**
+     * 加密
+     */
+    public static String encrypt(String str, byte[] key) {
+        return encrypt(str, key, true);
+    }
+
+    /**
+     * 加密
+     */
+    public static String encrypt(String str, byte[] key, boolean cbcMode) {
+        if (StringUtils.isEmpty(str)) {
+            return "";
+        }
+
+        try {
+            SecretKey secretKey = initSecretKey(key);
+            if (log.isDebugEnabled()) {
+                log.debug("Key:" + new String(secretKey.getEncoded()));
+            }
+
+            Cipher cipher;
+            if (cbcMode) {
+                cipher = Cipher.getInstance(CBC_PKCS5Padding);
+                cipher.init(Cipher.ENCRYPT_MODE, secretKey, initIv(key));
+            } else {
+                cipher = Cipher.getInstance(ECB_PKCS5Padding);
+                cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+            }
+
+            byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
+            byte[] result = cipher.doFinal(bytes);
+
+            // return Base64.encodeBase64String(result);
+            return Hex.encodeHexString(result);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            throw new CryptoException(CryptoConstant.ENCRYPT_ERROR, e);
+        }
+    }
+
+    /**
+     * 解密
+     */
+    public static String decrypt(String str, byte[] key) {
+        return decrypt(str, key, true);
+    }
+
+    /**
+     * 解密
+     */
+    public static String decrypt(String str, byte[] key, boolean cbcMode) {
+        if (StringUtils.isEmpty(str)) {
+            return "";
+        }
+
+        try {
+            SecretKey secretKey = initSecretKey(key);
+            if (log.isDebugEnabled()) {
+                log.debug("Key:" + new String(secretKey.getEncoded()));
+            }
+
+            Cipher cipher;
+            if (cbcMode) {
+                cipher = Cipher.getInstance(CBC_PKCS5Padding);
+                cipher.init(Cipher.DECRYPT_MODE, secretKey, initIv(key));
+            } else {
+                cipher = Cipher.getInstance(ECB_PKCS5Padding);
+                cipher.init(Cipher.DECRYPT_MODE, secretKey);
+            }
+
+            // byte[] bytes = Base64.decodeBase64(str);
+            byte[] bytes = Hex.decodeHex(str);
+
+            byte[] result = cipher.doFinal(bytes);
+            return new String(result, StandardCharsets.UTF_8);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            throw new CryptoException(CryptoConstant.DECRYPT_ERROR, e);
+        }
+    }
+
+    /**
+     * 随机生成密钥
+     */
+    public static byte[] randomKey() {
+        try {
+            KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
+
+            // 密钥长度可选:128、192、256
+            // 其中192和256,需获得“无政策限制权限文件”,针对JDK版本对应覆盖local_policy.jar和US_export_policy.jar两个文件!
+            keyGenerator.init(DEFAULT_KEY_SIZE);
+
+            SecretKey secretKey = keyGenerator.generateKey();
+            return secretKey.getEncoded();
+        } catch (NoSuchAlgorithmException e) {
+            log.error(e.getMessage());
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static SecretKey initSecretKey(byte[] key) {
+        if (key.length == 16 || key.length == 24 || key.length == 32) {
+            // key长度范围为 16位 或 24位 或 32位
+            return new SecretKeySpec(key, ALGORITHM);
+        }
+
+        // 注:其它key长度时统一转为16位(长度不够时末尾补0,超出则截取)
+        byte[] newKey = Arrays.copyOf(key, 16);
+        return new SecretKeySpec(newKey, ALGORITHM);
+    }
+
+    public static IvParameterSpec initIv(byte[] key) {
+        byte[] ivBytes = DEFAULT_IV.getBytes(StandardCharsets.UTF_8);
+        // 生成新的向量值 = 默认向量值的前8位 + key值的前8位
+        // byte[] newKey = Arrays.copyOf(key, 16);
+        // System.arraycopy(newKey, 0, ivBytes, 8, Math.min(newKey.length, 8));
+        return new IvParameterSpec(ivBytes);
+    }
+
+}

+ 169 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/utils/DesUtil.java

@@ -0,0 +1,169 @@
+package cn.com.qmth.examcloud.starters.crypto.utils;
+
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoConstant;
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoException;
+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.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/**
+ * DES加、解密
+ */
+public class DesUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(DesUtil.class);
+
+    /**
+     * 算法
+     */
+    private static final String ALGORITHM = "DES";
+
+    /**
+     * ECB模式
+     * 算法/模式/补码方式
+     */
+    private static final String ECB_PKCS5Padding = "DES/ECB/PKCS5Padding";
+
+    /**
+     * CBC模式
+     * 算法/模式/补码方式
+     */
+    private static final String CBC_PKCS5Padding = "DES/CBC/PKCS5Padding";
+
+    /**
+     * 默认密钥长度
+     */
+    private static final int DEFAULT_KEY_SIZE = 56;
+
+    /**
+     * 默认偏移向量字符串(长度必须8位,仅CBC模式下使用)
+     */
+    private static final String DEFAULT_IV = "@M#A$G%A";
+
+    /**
+     * 加密
+     */
+    public static String encrypt(String str, byte[] key) {
+        return encrypt(str, key, true);
+    }
+
+    /**
+     * 加密
+     */
+    public static String encrypt(String str, byte[] key, boolean cbcMode) {
+        if (StringUtils.isEmpty(str)) {
+            return "";
+        }
+
+        try {
+            SecretKey secretKey = initSecretKey(key);
+            if (log.isDebugEnabled()) {
+                log.debug("Key:" + new String(secretKey.getEncoded()));
+            }
+
+            Cipher cipher;
+            if (cbcMode) {
+                cipher = Cipher.getInstance(CBC_PKCS5Padding);
+                cipher.init(Cipher.ENCRYPT_MODE, secretKey, initIv(key));
+            } else {
+                cipher = Cipher.getInstance(ECB_PKCS5Padding);
+                cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+            }
+
+            byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
+            byte[] result = cipher.doFinal(bytes);
+
+            // return Hex.encodeHexString(result);
+            return Base64.encodeBase64String(result);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            throw new CryptoException(CryptoConstant.ENCRYPT_ERROR, e);
+        }
+    }
+
+    /**
+     * 解密
+     */
+    public static String decrypt(String str, byte[] key) {
+        return decrypt(str, key, true);
+    }
+
+    /**
+     * 解密
+     */
+    public static String decrypt(String str, byte[] key, boolean cbcMode) {
+        if (StringUtils.isEmpty(str)) {
+            return "";
+        }
+
+        try {
+            SecretKey secretKey = initSecretKey(key);
+            if (log.isDebugEnabled()) {
+                log.debug("Key:" + new String(secretKey.getEncoded()));
+            }
+
+            Cipher cipher;
+            if (cbcMode) {
+                cipher = Cipher.getInstance(CBC_PKCS5Padding);
+                cipher.init(Cipher.DECRYPT_MODE, secretKey, initIv(key));
+            } else {
+                cipher = Cipher.getInstance(ECB_PKCS5Padding);
+                cipher.init(Cipher.DECRYPT_MODE, secretKey);
+            }
+
+            // byte[] bytes = Hex.decodeHex(str);
+            byte[] bytes = Base64.decodeBase64(str);
+
+            byte[] result = cipher.doFinal(bytes);
+            return new String(result, StandardCharsets.UTF_8);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            throw new CryptoException(CryptoConstant.DECRYPT_ERROR, e);
+        }
+    }
+
+    /**
+     * 随机生成密钥
+     */
+    public static byte[] randomKey() {
+        try {
+            KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
+
+            // 密钥长度可选:56
+            keyGenerator.init(DEFAULT_KEY_SIZE);
+
+            SecretKey secretKey = keyGenerator.generateKey();
+            return secretKey.getEncoded();
+        } catch (NoSuchAlgorithmException e) {
+            log.error(e.getMessage());
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static SecretKey initSecretKey(byte[] key) {
+        if (key.length == 8) {
+            // key长度范围为 8位
+            return new SecretKeySpec(key, ALGORITHM);
+        }
+
+        // 注:其它key长度时统一转为8位(长度不够时末尾补0,超出则截取)
+        byte[] newKey = Arrays.copyOf(key, 8);
+        return new SecretKeySpec(newKey, ALGORITHM);
+    }
+
+    public static IvParameterSpec initIv(byte[] key) {
+        byte[] ivBytes = DEFAULT_IV.getBytes(StandardCharsets.UTF_8);
+        return new IvParameterSpec(ivBytes);
+    }
+
+}

+ 145 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/utils/Rc4Util.java

@@ -0,0 +1,145 @@
+package cn.com.qmth.examcloud.starters.crypto.utils;
+
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoConstant;
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoException;
+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.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+/**
+ * RC4加、解密
+ */
+public class Rc4Util {
+
+    private static final Logger log = LoggerFactory.getLogger(Rc4Util.class);
+
+    /**
+     * 算法
+     */
+    private static final String ALGORITHM = "RC4";
+
+    /**
+     * 加密
+     */
+    public static String encrypt(String str, String key) {
+        if (StringUtils.isEmpty(str)) {
+            return "";
+        }
+
+        try {
+            SecretKey secretKey = initSecretKey(key);
+            if (log.isDebugEnabled()) {
+                log.debug("Key:" + new String(secretKey.getEncoded()));
+            }
+
+            Cipher cipher = Cipher.getInstance(ALGORITHM);
+            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+
+            byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
+            byte[] result = cipher.update(bytes);
+            // byte[] result = rc4Cipher(bytes, key);
+
+            return Base64.encodeBase64String(result);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new CryptoException(CryptoConstant.ENCRYPT_ERROR, e);
+        }
+    }
+
+    /**
+     * 解密
+     */
+    public static String decrypt(String str, String key) {
+        if (StringUtils.isEmpty(str)) {
+            return "";
+        }
+
+        try {
+            SecretKey secretKey = initSecretKey(key);
+            if (log.isDebugEnabled()) {
+                log.debug("Key:" + new String(secretKey.getEncoded()));
+            }
+
+            Cipher cipher = Cipher.getInstance(ALGORITHM);
+            cipher.init(Cipher.DECRYPT_MODE, secretKey);
+
+            byte[] bytes = Base64.decodeBase64(str);
+            byte[] result = cipher.update(bytes);
+            // byte[] result = rc4Cipher(bytes, key);
+
+            return new String(result, StandardCharsets.UTF_8);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new CryptoException(CryptoConstant.DECRYPT_ERROR, e);
+        }
+    }
+
+    public static SecretKey initSecretKey(String key) {
+        if (StringUtils.isEmpty(key)) {
+            throw new CryptoException(CryptoConstant.KEY_ERROR);
+        }
+
+        byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
+        if (keyBytes.length >= 5 && keyBytes.length <= 128) {
+            // key长度范围为 区间(5位,128位)
+            return new SecretKeySpec(keyBytes, ALGORITHM);
+        }
+
+        // 注:其它key长度时统一转为16位(长度不够时末尾补0,超出则截取)
+        byte[] newKey = Arrays.copyOf(keyBytes, 16);
+        return new SecretKeySpec(newKey, ALGORITHM);
+    }
+
+    private static byte[] rc4Cipher(byte[] data, String key) {
+        int xorIndex, x = 0, y = 0;
+        byte[] keyBytes = rc4Key(key);
+
+        byte[] result = new byte[data.length];
+        for (int i = 0; i < data.length; i++) {
+            x = (x + 1) & 0xff;
+            y = ((keyBytes[x] & 0xff) + y) & 0xff;
+
+            byte tmp = keyBytes[x];
+            keyBytes[x] = keyBytes[y];
+            keyBytes[y] = tmp;
+
+            xorIndex = ((keyBytes[x] & 0xff) + (keyBytes[y] & 0xff)) & 0xff;
+            result[i] = (byte) (data[i] ^ keyBytes[xorIndex]);
+        }
+
+        return result;
+    }
+
+    private static byte[] rc4Key(String key) {
+        if (StringUtils.isEmpty(key)) {
+            throw new CryptoException(CryptoConstant.KEY_ERROR);
+        }
+
+        byte[] result = new byte[256];
+        for (int i = 0; i < 256; i++) {
+            result[i] = (byte) i;
+        }
+
+        int index1 = 0, index2 = 0;
+        byte[] keyBytes = key.getBytes();
+        for (int i = 0; i < 256; i++) {
+            index2 = ((keyBytes[index1] & 0xff) + (result[i] & 0xff) + index2) & 0xff;
+
+            byte tmp = result[i];
+            result[i] = result[index2];
+            result[index2] = tmp;
+
+            index1 = (index1 + 1) % keyBytes.length;
+        }
+
+        return result;
+    }
+
+}

+ 253 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/utils/RsaUtil.java

@@ -0,0 +1,253 @@
+package cn.com.qmth.examcloud.starters.crypto.utils;
+
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoConstant;
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoException;
+import org.apache.commons.codec.binary.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import java.nio.charset.StandardCharsets;
+import java.security.*;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+
+/**
+ * RSA加、解密
+ */
+public class RsaUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(RsaUtil.class);
+
+    /**
+     * 算法
+     */
+    private static final String ALGORITHM = "RSA";
+
+    /**
+     * 签名算法
+     */
+    private static final String SIGN_ALGORITHM = "SHA1WithRSA";
+
+    /**
+     * 默认密钥长度
+     */
+    private static final int DEFAULT_KEY_SIZE = 1024;
+
+    /**
+     * RSA加密最大明文长度
+     * 注:RSA加密对明文的长度有限制,最大长度 = 密钥长度 - 11
+     * 即:1024位 / 8位 - 11 = 117(字节)
+     */
+    private static final int MAX_ENCRYPT_BLOCK = 117;
+
+    /**
+     * RSA解密最大密文长度
+     * 注:RSA解密对密文的长度有限制,RSA加密时内容字节不足时会使用填充模式
+     * 即:1024位 / 8位 = 128(字节)
+     */
+    private static final int MAX_DECRYPT_BLOCK = 128;
+
+    /**
+     * 公钥加密
+     */
+    public static String publicEncrypt(String str, RSAPublicKey publicKey) {
+        try {
+            Cipher cipher = Cipher.getInstance(ALGORITHM);
+            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+
+            byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
+            byte[] result = cipherResult(cipher, bytes, MAX_ENCRYPT_BLOCK);
+
+            return Base64.encodeBase64String(result);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            throw new CryptoException(CryptoConstant.ENCRYPT_ERROR, e);
+        }
+    }
+
+    /**
+     * 公钥解密
+     */
+    public static String publicDecrypt(String str, RSAPublicKey publicKey) {
+        try {
+            Cipher cipher = Cipher.getInstance(ALGORITHM);
+            cipher.init(Cipher.DECRYPT_MODE, publicKey);
+
+            byte[] bytes = Base64.decodeBase64(str);
+            byte[] result = cipherResult(cipher, bytes, MAX_DECRYPT_BLOCK);
+
+            return new String(result, StandardCharsets.UTF_8);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            throw new CryptoException(CryptoConstant.DECRYPT_ERROR, e);
+        }
+    }
+
+    /**
+     * 私钥加密
+     */
+    public static String privateEncrypt(String str, RSAPrivateKey privateKey) {
+        try {
+            Cipher cipher = Cipher.getInstance(ALGORITHM);
+            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
+
+            byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
+            byte[] result = cipherResult(cipher, bytes, MAX_ENCRYPT_BLOCK);
+
+            return Base64.encodeBase64String(result);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            throw new CryptoException(CryptoConstant.ENCRYPT_ERROR, e);
+        }
+    }
+
+    /**
+     * 私钥解密
+     */
+    public static String privateDecrypt(String str, RSAPrivateKey privateKey) {
+        try {
+            Cipher cipher = Cipher.getInstance(ALGORITHM);
+            cipher.init(Cipher.DECRYPT_MODE, privateKey);
+
+            byte[] bytes = Base64.decodeBase64(str);
+            byte[] result = cipherResult(cipher, bytes, MAX_DECRYPT_BLOCK);
+
+            return new String(result, StandardCharsets.UTF_8);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            throw new CryptoException(CryptoConstant.DECRYPT_ERROR, e);
+        }
+    }
+
+    /**
+     * 对数据分段加密或解密
+     */
+    private static byte[] cipherResult(Cipher cipher, byte[] bytes, int maxBlock)
+            throws IllegalBlockSizeException, BadPaddingException {
+        int strLength = bytes.length;
+        int offset = 0;
+
+        byte[] result = {}, cache;
+        while (strLength - offset > 0) {
+            if (strLength - offset > maxBlock) {
+                cache = cipher.doFinal(bytes, offset, maxBlock);
+                offset += maxBlock;
+            } else {
+                cache = cipher.doFinal(bytes, offset, strLength - offset);
+                offset = strLength;
+            }
+
+            result = Arrays.copyOf(result, result.length + cache.length);
+            System.arraycopy(cache, 0, result, result.length - cache.length, cache.length);
+        }
+
+        return result;
+    }
+
+    /**
+     * 私钥签名
+     */
+    public static String sign(String str, PrivateKey privateKey) {
+        try {
+            Signature signature = Signature.getInstance(SIGN_ALGORITHM);
+
+            signature.initSign(privateKey);
+            signature.update(str.getBytes(StandardCharsets.UTF_8));
+
+            byte[] result = signature.sign();
+            return Base64.encodeBase64String(result);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            throw new CryptoException("签名失败!", e);
+        }
+    }
+
+    /**
+     * 公钥验证签名
+     */
+    public static boolean verifySign(String str, String signStr, PublicKey publicKey) {
+        try {
+            Signature verifySign = Signature.getInstance(SIGN_ALGORITHM);
+
+            verifySign.initVerify(publicKey);
+            verifySign.update(str.getBytes(StandardCharsets.UTF_8));
+
+            byte[] bytes = Base64.decodeBase64(signStr);
+            return verifySign.verify(bytes);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            return false;
+        }
+    }
+
+    /**
+     * 随机生成公、私钥
+     */
+    public static KeyPair randomKey() {
+        try {
+            KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM);
+
+            // 密钥长度可选:1024、2048 ...
+            generator.initialize(DEFAULT_KEY_SIZE, new SecureRandom());
+
+            return generator.generateKeyPair();
+        } catch (NoSuchAlgorithmException e) {
+            log.error(e.getMessage());
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 获取RSA公钥
+     */
+    public static RSAPublicKey getPublicKey(String publicKeyStr) {
+        KeyFactory keyFactory;
+        try {
+            keyFactory = KeyFactory.getInstance(ALGORITHM);
+        } catch (NoSuchAlgorithmException e) {
+            log.error(e.getMessage());
+            throw new RuntimeException(e);
+        }
+
+        byte[] bytes = Base64.decodeBase64(publicKeyStr);
+        try {
+            // 通过X509编码的Key指令获得公钥对象
+            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
+            return (RSAPublicKey) keyFactory.generatePublic(keySpec);
+        } catch (InvalidKeySpecException e) {
+            log.error(e.getMessage());
+            throw new CryptoException(CryptoConstant.KEY_ERROR, e);
+        }
+    }
+
+    /**
+     * 获取RSA私钥
+     */
+    public static RSAPrivateKey getPrivateKey(String privateKeyStr) {
+        KeyFactory keyFactory;
+        try {
+            keyFactory = KeyFactory.getInstance(ALGORITHM);
+        } catch (NoSuchAlgorithmException e) {
+            log.error(e.getMessage());
+            throw new RuntimeException(e);
+        }
+
+        byte[] bytes = Base64.decodeBase64(privateKeyStr);
+        try {
+            // 通过PKCS8编码的Key指令获得私钥对象
+            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
+            return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
+        } catch (InvalidKeySpecException e) {
+            log.error(e.getMessage());
+            throw new CryptoException(CryptoConstant.KEY_ERROR, e);
+        }
+    }
+
+}

+ 169 - 0
examcloud-starters/examcloud-crypto-starter/src/main/java/cn/com/qmth/examcloud/starters/crypto/utils/TripleDesUtil.java

@@ -0,0 +1,169 @@
+package cn.com.qmth.examcloud.starters.crypto.utils;
+
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoConstant;
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoException;
+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.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/**
+ * TripleDes加、解密
+ */
+public class TripleDesUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(TripleDesUtil.class);
+
+    /**
+     * 算法
+     */
+    private static final String ALGORITHM = "DESede";
+
+    /**
+     * ECB模式
+     * 算法/模式/补码方式
+     */
+    private static final String ECB_PKCS5Padding = "DESede/ECB/PKCS5Padding";
+
+    /**
+     * CBC模式
+     * 算法/模式/补码方式
+     */
+    private static final String CBC_PKCS5Padding = "DESede/CBC/PKCS5Padding";
+
+    /**
+     * 默认密钥长度
+     */
+    private static final int DEFAULT_KEY_SIZE = 112;
+
+    /**
+     * 默认偏移向量字符串(长度必须8位,仅CBC模式下使用)
+     */
+    private static final String DEFAULT_IV = "@M#A$G%A";
+
+    /**
+     * 加密
+     */
+    public static String encrypt(String str, byte[] key) {
+        return encrypt(str, key, true);
+    }
+
+    /**
+     * 加密
+     */
+    public static String encrypt(String str, byte[] key, boolean cbcMode) {
+        if (StringUtils.isEmpty(str)) {
+            return "";
+        }
+
+        try {
+            SecretKey secretKey = initSecretKey(key);
+            if (log.isDebugEnabled()) {
+                log.debug("Key:" + new String(secretKey.getEncoded()));
+            }
+
+            Cipher cipher;
+            if (cbcMode) {
+                cipher = Cipher.getInstance(CBC_PKCS5Padding);
+                cipher.init(Cipher.ENCRYPT_MODE, secretKey, initIv(key));
+            } else {
+                cipher = Cipher.getInstance(ECB_PKCS5Padding);
+                cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+            }
+
+            byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
+            byte[] result = cipher.doFinal(bytes);
+
+            // return Hex.encodeHexString(result);
+            return Base64.encodeBase64String(result);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            throw new CryptoException(CryptoConstant.ENCRYPT_ERROR, e);
+        }
+    }
+
+    /**
+     * 解密
+     */
+    public static String decrypt(String str, byte[] key) {
+        return decrypt(str, key, true);
+    }
+
+    /**
+     * 解密
+     */
+    public static String decrypt(String str, byte[] key, boolean cbcMode) {
+        if (StringUtils.isEmpty(str)) {
+            return "";
+        }
+
+        try {
+            SecretKey secretKey = initSecretKey(key);
+            if (log.isDebugEnabled()) {
+                log.debug("Key:" + new String(secretKey.getEncoded()));
+            }
+
+            Cipher cipher;
+            if (cbcMode) {
+                cipher = Cipher.getInstance(CBC_PKCS5Padding);
+                cipher.init(Cipher.DECRYPT_MODE, secretKey, initIv(key));
+            } else {
+                cipher = Cipher.getInstance(ECB_PKCS5Padding);
+                cipher.init(Cipher.DECRYPT_MODE, secretKey);
+            }
+
+            // byte[] bytes = Hex.decodeHex(str);
+            byte[] bytes = Base64.decodeBase64(str);
+
+            byte[] result = cipher.doFinal(bytes);
+            return new String(result, StandardCharsets.UTF_8);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            throw new CryptoException(CryptoConstant.DECRYPT_ERROR, e);
+        }
+    }
+
+    /**
+     * 随机生成密钥
+     */
+    public static byte[] randomKey() {
+        try {
+            KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
+
+            // 密钥长度可选:112、168
+            keyGenerator.init(DEFAULT_KEY_SIZE);
+
+            SecretKey secretKey = keyGenerator.generateKey();
+            return secretKey.getEncoded();
+        } catch (NoSuchAlgorithmException e) {
+            log.error(e.getMessage());
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static SecretKey initSecretKey(byte[] key) {
+        if (key.length == 24) {
+            // key长度范围为 24位
+            return new SecretKeySpec(key, ALGORITHM);
+        }
+
+        // 注:其它key长度时统一转为24位(长度不够时末尾补0,超出则截取)
+        byte[] newKey = Arrays.copyOf(key, 24);
+        return new SecretKeySpec(newKey, ALGORITHM);
+    }
+
+    public static IvParameterSpec initIv(byte[] key) {
+        byte[] ivBytes = DEFAULT_IV.getBytes(StandardCharsets.UTF_8);
+        return new IvParameterSpec(ivBytes);
+    }
+
+}

+ 2 - 0
examcloud-starters/examcloud-crypto-starter/src/main/resources/META-INF/spring.factories

@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+cn.com.qmth.examcloud.starters.crypto.CryptoAutoConfiguration

+ 192 - 0
examcloud-starters/examcloud-crypto-starter/src/test/java/cn/com/qmth/examcloud/starters/crypto/test/CryptoTest.java

@@ -0,0 +1,192 @@
+package cn.com.qmth.examcloud.starters.crypto.test;
+
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoGroup;
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoHelper;
+import cn.com.qmth.examcloud.starters.crypto.common.CryptoItem;
+import cn.com.qmth.examcloud.starters.crypto.common.FieldPair;
+import cn.com.qmth.examcloud.starters.crypto.service.CryptoFactory;
+import cn.com.qmth.examcloud.starters.crypto.utils.*;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+public class CryptoTest {
+
+    @Before
+    public void init() {
+        Configurator.setRootLevel(Level.ALL);
+    }
+
+    @Test
+    public void demoTest() {
+        String str = "hello world, O(∩_∩)O哈哈~";
+
+        for (int n = 0; n < 1; n++) {
+            // str = str + "*";
+
+            // aesTest(str);
+            // desTest(str);
+            // tripleDesTest(str);
+            // rc4Test(str);
+            // rsaTest(str);
+            // otherTest(str);
+            cryptoGroupTest(str);
+        }
+    }
+
+    private void cryptoGroupTest(String str) {
+        String key = CryptoHelper.buildKey(
+                new FieldPair("key", "U_S_0_2"),
+                new FieldPair("token", "98ede2940ab84f448cb39568298b3d06"),
+                new FieldPair("timestamp", "1650364516803")
+        );
+
+        String combination = "ABCDE";
+        CryptoGroup cryptoGroup = new CryptoGroup(combination).matchKeys(key);
+        CryptoFactory cryptoFactory = new CryptoFactory();
+
+        // str = cryptoFactory.encrypt(cryptoGroup, str);
+        // System.out.println("加密结果:" + str);
+        // str = cryptoFactory.decrypt(cryptoGroup, str, true);
+        // System.out.println("解密结果:" + str);
+
+        System.out.println("\n---------- 按加密方案组合“顺序”依次加密 ----------");
+        for (CryptoItem item : cryptoGroup.getItems()) {
+            str = cryptoFactory.getCryptoService(item.getType()).encrypt(str, item.getEncryptKey());
+            System.out.println(String.format("%s-%s加密:%s\n", item.getType(), item.getType().getAlgorithm(), str));
+        }
+
+        System.out.println("\n---------- 按加密方案组合“倒序”依次解密 ----------");
+        for (CryptoItem item : cryptoGroup.getReverseItems()) {
+            str = cryptoFactory.getCryptoService(item.getType()).decrypt(str, item.getDecryptKey());
+            System.out.println(String.format("%s-%s解密:%s\n", item.getType(), item.getType().getAlgorithm(), str));
+        }
+    }
+
+    private void aesTest(String str) {
+        System.out.println("---------- AES ----------");
+
+        String key = "1234567890ABCDEF1234567890ABCDEF";
+        byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
+        // byte[] keyBytes = AesUtil.randomKey();
+
+        System.out.println("密钥:" + Hex.encodeHexString(AesUtil.initSecretKey(keyBytes).getEncoded()));
+        System.out.println("偏移向量:" + Hex.encodeHexString(AesUtil.initIv(keyBytes).getIV()));
+
+        String encryptData = AesUtil.encrypt(str, keyBytes, true);
+        System.out.println("加密串:" + encryptData);
+        String decryptData = AesUtil.decrypt(encryptData, keyBytes, true);
+        System.out.println("解密串:" + decryptData);
+
+        System.out.println("---------- AES ----------");
+    }
+
+    private void desTest(String str) {
+        System.out.println("---------- DES ----------");
+
+        String key = "12345678";
+        byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
+        // byte[] keyBytes = DesUtil.randomKey();
+
+        System.out.println("密钥:" + Hex.encodeHexString(DesUtil.initSecretKey(keyBytes).getEncoded()));
+        System.out.println("偏移向量:" + Hex.encodeHexString(DesUtil.initIv(keyBytes).getIV()));
+
+        String encryptData = DesUtil.encrypt(str, keyBytes, true);
+        System.out.println("加密串:" + encryptData);
+        String decryptData = DesUtil.decrypt(encryptData, keyBytes, true);
+        System.out.println("解密串:" + decryptData);
+
+        System.out.println("---------- DES ----------");
+    }
+
+    private void tripleDesTest(String str) {
+        System.out.println("---------- TripleDes ----------");
+
+        String key = "1234567890ABCDEF12345678";
+        byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
+        // byte[] keyBytes = TripleDesUtil.randomKey();
+
+        System.out.println("密钥:" + Hex.encodeHexString(TripleDesUtil.initSecretKey(keyBytes).getEncoded()));
+        System.out.println("偏移向量:" + Hex.encodeHexString(TripleDesUtil.initIv(keyBytes).getIV()));
+
+        String encryptData = TripleDesUtil.encrypt(str, keyBytes, true);
+        System.out.println("加密串:" + encryptData);
+        String decryptData = TripleDesUtil.decrypt(encryptData, keyBytes, true);
+        System.out.println("解密串:" + decryptData);
+
+        System.out.println("---------- TripleDes ----------");
+    }
+
+    private void rc4Test(String str) {
+        System.out.println("---------- RC4 ----------");
+
+        String key = "1234567890ABCDEF";
+        System.out.println("密钥:" + Hex.encodeHexString(Rc4Util.initSecretKey(key).getEncoded()));
+
+        String encryptData = Rc4Util.encrypt(str, key);
+        System.out.println("加密串:" + encryptData);
+        String decryptData = Rc4Util.decrypt(encryptData, key);
+        System.out.println("解密串:" + decryptData);
+
+        System.out.println("---------- RC4 ----------");
+    }
+
+    private void rsaTest(String str) {
+        System.out.println("---------- RSA ----------");
+
+        // KeyPair keyPair = RsaUtil.randomKey();
+        // PublicKey publicKey = keyPair.getPublic();
+        // PrivateKey privateKey = keyPair.getPrivate();
+        // String publicKeyStr = Base64.encodeBase64String(publicKey.getEncoded());
+        // String privateKeyStr = Base64.encodeBase64String(privateKey.getEncoded());
+
+        System.out.println("公钥:" + publicKeyStr);
+        System.out.println("私钥:" + privateKeyStr);
+
+        RSAPublicKey rsaPublicKey = RsaUtil.getPublicKey(publicKeyStr);
+        RSAPrivateKey rsaPrivateKey = RsaUtil.getPrivateKey(privateKeyStr);
+
+        String encryptData1 = RsaUtil.publicEncrypt(str, rsaPublicKey);
+        System.out.println("公钥加密串:" + encryptData1);
+        String decryptData1 = RsaUtil.privateDecrypt(encryptData1, rsaPrivateKey);
+        System.out.println("私钥解密串: " + decryptData1);
+
+        String encryptData2 = RsaUtil.privateEncrypt(str, rsaPrivateKey);
+        System.out.println("私钥加密串:" + encryptData2);
+        String decryptData2 = RsaUtil.publicDecrypt(encryptData2, rsaPublicKey);
+        System.out.println("公钥解密串: " + decryptData2);
+
+        String signStr = RsaUtil.sign(str, rsaPrivateKey);
+        System.out.println("私钥签名结果:" + signStr);
+        boolean signVerifyResult = RsaUtil.verifySign(str, signStr, rsaPublicKey);
+        System.out.println("公钥验证签名结果:" + signVerifyResult);
+
+        System.out.println("---------- RSA ----------");
+    }
+
+    private void otherTest(String str) {
+        System.out.println("---------- Base64 ----------");
+        String encode = Base64.encodeBase64String(str.getBytes(StandardCharsets.UTF_8));
+        System.out.println("Base64 编码: " + encode);
+        byte[] decode = Base64.decodeBase64(encode);
+        System.out.println("Base64 解码: " + new String(decode, StandardCharsets.UTF_8));
+        System.out.println("---------- Base64 ----------");
+
+        System.out.println("MD5: " + DigestUtils.md5Hex(str));
+        System.out.println("SHA1: " + DigestUtils.sha1Hex(str));
+        System.out.println("SHA256: " + DigestUtils.sha256Hex(str));
+    }
+
+    private static final String publicKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKWMG6iQOZpDBtLxk0qzFHwi+627vUcitGMqthtEMjLZvHbDovtRHpnNs1y9f0PO7LNZOE8LBY3CdWZaQfTg1pPJqV4DD0p4HicR0/5mbX+qqSTYqCbxF4s2nuIAgH2Z1rzlteRvbK6QxNZ+6UxtIqEdpIibBHPapimpwe6optRQIDAQAB";
+
+    private static final String privateKeyStr = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMpYwbqJA5mkMG0vGTSrMUfCL7rbu9RyK0Yyq2G0QyMtm8dsOi+1Eemc2zXL1/Q87ss1k4TwsFjcJ1ZlpB9ODWk8mpXgMPSngeJxHT/mZtf6qpJNioJvEXizae4gCAfZnWvOW15G9srpDE1n7pTG0ioR2kiJsEc9qmKanB7qim1FAgMBAAECgYEAukBgcfbUHYQIHzgPF2/MeKTBklnX1oEQXBkfr1thwOumTDXOiUM+La54CFiNev7rPpkeJGv3ppNekiQUocwSgnnIxyjo1pxjFx4GvCWwpId+XNMZjGGhx/7c2/J7CUgmLZ4+s13FvUThdUv5yMHyS7RwgoJENe5duDUiL86bQzECQQD/RU0PsiyLzbuayrA8t8dsgaQ1jDEJvcSQyqW7Rnqm25oApomCI9qktOaljw18SRd9CSQhLQaSZbKYSJxjpcCTAkEAyuy/lNP/ixp6p68vPjY10JrQYZqb5w7HOrkbWD/yzA+GCtT97mQc4hQabv7wBy7CMW1rJfWLYc1O823RL4s5xwJBAMq48H/8kZ/dHJXLTbaKhJdJRW05DmCcEhSiuodFa3ZDg8PsfduaObL/7wOf3afMLBkiP00RgtyUYwbI81m3cn0CQQCCMq6lTfQ7Cw1Bg4w7TUrwAjTLOwjmkjvP+K6Ly9P7i8ZEMu6OQxupDp77MoVNBnpAfmTuIQKCCNmsJHzAFYNHAkAyLxqSZySLsAU4GpJ0OnKTTwfzUhrp7Ln56olI63EloJSeomho8MASOVuHs/EkOgIg3Njnb0vKGigNbCiKjd1U";
+
+}

+ 1 - 0
examcloud-starters/pom.xml

@@ -13,6 +13,7 @@
 
     <modules>
         <module>examcloud-geetest-starter</module>
+        <module>examcloud-crypto-starter</module>
     </modules>
 
 </project>