增加加密算法
This commit is contained in:
121
pom.xml
121
pom.xml
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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"
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
@@ -26,11 +26,7 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter</artifactId>
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- <dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
|
||||||
<!– <optional>true</optional>–>
|
|
||||||
</dependency>-->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
@@ -39,6 +35,11 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-aop</artifactId>
|
<artifactId>spring-boot-starter-aop</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- boot 官方推荐模板引擎-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.guava</groupId>
|
<groupId>com.google.guava</groupId>
|
||||||
<artifactId>guava</artifactId>
|
<artifactId>guava</artifactId>
|
||||||
@@ -64,7 +65,11 @@
|
|||||||
<artifactId>commons-codec</artifactId>
|
<artifactId>commons-codec</artifactId>
|
||||||
<version>1.10</version>
|
<version>1.10</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!--<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
|
<version>1.64</version>
|
||||||
|
</dependency>-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
@@ -78,7 +83,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.hutool</groupId>
|
<groupId>cn.hutool</groupId>
|
||||||
<artifactId>hutool-core</artifactId>
|
<artifactId>hutool-all</artifactId>
|
||||||
<version>4.0.3</version>
|
<version>4.0.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
@@ -86,46 +91,84 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- java web防控包-->
|
<!-- java web防控包-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.owasp.esapi</groupId>
|
<groupId>org.owasp.esapi</groupId>
|
||||||
<artifactId>esapi</artifactId>
|
<artifactId>esapi</artifactId>
|
||||||
<version>2.2.0.0</version>
|
<version>2.2.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
<profiles>
|
||||||
|
<!--
|
||||||
|
dev 开发环境
|
||||||
|
test 测试环境
|
||||||
|
prod 生产环境
|
||||||
|
-->
|
||||||
|
<profile>
|
||||||
|
<id>dev</id>
|
||||||
|
<activation>
|
||||||
|
<activeByDefault>true</activeByDefault>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<profiles.active>dev</profiles.active>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>test</id>
|
||||||
|
<properties>
|
||||||
|
<profiles.active>test</profiles.active>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>prod</id>
|
||||||
|
<properties>
|
||||||
|
<profiles.active>prod</profiles.active>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
<build>
|
<build>
|
||||||
|
<finalName>${project.artifactId}-${project.version}-${profiles.active}</finalName>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
<resource>
|
||||||
|
<directory>${project.basedir}/profiles/${profiles.active}</directory>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<!-- 加入该配置,使用maven package,依赖jar不会打包在项目最终jar文件内
|
<!-- 加入该配置,使用maven package,依赖jar不会打包在项目最终jar文件内
|
||||||
启动jar 加入参数 -Dthin.root=. -jar
|
启动jar 加入参数 -Dthin.root=. -jar-->
|
||||||
-->
|
<groupId>org.springframework.boot.experimental</groupId>
|
||||||
<groupId>org.springframework.boot.experimental</groupId>
|
<artifactId>spring-boot-thin-layout</artifactId>
|
||||||
<artifactId>spring-boot-thin-layout</artifactId>
|
<version>1.0.12.RELEASE</version>
|
||||||
<version>1.0.12.RELEASE</version>
|
</dependency>
|
||||||
</dependency>
|
</dependencies>
|
||||||
</dependencies>
|
</plugin>
|
||||||
</plugin>
|
<plugin>
|
||||||
<plugin>
|
<!-- 加入该配置,maven package执行时会在target目录整理好依赖包 -->
|
||||||
<!-- 加入该配置,maven package执行时会在target目录整理好依赖包 -->
|
<groupId>org.springframework.boot.experimental</groupId>
|
||||||
<groupId>org.springframework.boot.experimental</groupId>
|
<artifactId>spring-boot-thin-maven-plugin</artifactId>
|
||||||
<artifactId>spring-boot-thin-maven-plugin</artifactId>
|
<version>1.0.12.RELEASE</version>
|
||||||
<version>1.0.12.RELEASE</version>
|
<executions>
|
||||||
<executions>
|
<execution>
|
||||||
<execution>
|
<id>resolve</id>
|
||||||
<id>resolve</id>
|
<goals>
|
||||||
<goals>
|
<goal>resolve</goal>
|
||||||
<goal>resolve</goal>
|
</goals>
|
||||||
</goals>
|
<inherited>false</inherited>
|
||||||
<inherited>false</inherited>
|
</execution>
|
||||||
</execution>
|
</executions>
|
||||||
</executions>
|
</plugin>
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|||||||
5
profiles/dev/application-dev.properties
Normal file
5
profiles/dev/application-dev.properties
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
server.port=9999
|
||||||
|
|
||||||
|
|
||||||
|
logging.path=d://logs
|
||||||
|
|
||||||
2
profiles/prod/application-prod.properties
Normal file
2
profiles/prod/application-prod.properties
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
server.port=8080
|
||||||
|
logging.path=./logs
|
||||||
2
profiles/test/application-test.properties
Normal file
2
profiles/test/application-test.properties
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
server.port=8080
|
||||||
|
logging.path=./logs
|
||||||
@@ -7,7 +7,7 @@ import org.springframework.context.annotation.ComponentScan;
|
|||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@ServletComponentScan("com.taoyuanx.securitydemo.web")
|
@ServletComponentScan("com.taoyuanx.securitydemo.web")
|
||||||
class SecurityDemoApplication {
|
public class SecurityDemoApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(SecurityDemoApplication.class, args);
|
SpringApplication.run(SecurityDemoApplication.class, args);
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ package com.taoyuanx.securitydemo.config;
|
|||||||
|
|
||||||
import com.taoyuanx.securitydemo.security.ratelimit.AbstractRateLimiter;
|
import com.taoyuanx.securitydemo.security.ratelimit.AbstractRateLimiter;
|
||||||
import com.taoyuanx.securitydemo.security.ratelimit.RedisRateLimiter;
|
import com.taoyuanx.securitydemo.security.ratelimit.RedisRateLimiter;
|
||||||
|
import com.taoyuanx.securitydemo.utils.RSAUtil;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@@ -10,6 +13,10 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,7 +27,7 @@ import java.util.List;
|
|||||||
@Data
|
@Data
|
||||||
@ConfigurationProperties("application.config")
|
@ConfigurationProperties("application.config")
|
||||||
@Configuration
|
@Configuration
|
||||||
public class GlobalConfig {
|
public class GlobalConfig implements InitializingBean {
|
||||||
@Autowired
|
@Autowired
|
||||||
Environment environment;
|
Environment environment;
|
||||||
|
|
||||||
@@ -36,6 +43,15 @@ public class GlobalConfig {
|
|||||||
|
|
||||||
private String systemFileFormat;
|
private String systemFileFormat;
|
||||||
|
|
||||||
|
private String rsaP12Path;
|
||||||
|
private String rsaP12Password;
|
||||||
|
|
||||||
|
private PublicKey publicKey;
|
||||||
|
private PrivateKey privateKey;
|
||||||
|
private Certificate certificate;
|
||||||
|
|
||||||
|
private String publickKeyBase64;
|
||||||
|
|
||||||
public String getConfig(String configKey) {
|
public String getConfig(String configKey) {
|
||||||
return environment.getProperty(configKey);
|
return environment.getProperty(configKey);
|
||||||
}
|
}
|
||||||
@@ -54,4 +70,17 @@ public class GlobalConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
//证书初始化
|
||||||
|
KeyStore keyStore = RSAUtil.getKeyStore(rsaP12Path, rsaP12Password);
|
||||||
|
publicKey = RSAUtil.getPublicKey(keyStore);
|
||||||
|
privateKey = RSAUtil.getPrivateKey(keyStore, rsaP12Password);
|
||||||
|
certificate = RSAUtil.getCertificate(keyStore);
|
||||||
|
publickKeyBase64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCejQE9rKg8v5TuaS9tODR9QNPg\n" +
|
||||||
|
"P9MDhtyIFmKLmQTu2an/pEW18XWXEKi04ORYfwr7BjAJ9HMWspGRg8rbSjbethud\n" +
|
||||||
|
"QnJUDtrqHNDYzJ1HhQT7sngGvpuH9ME7ZW4yZcMDS7/i5tQSps31JmGI+ULZg1cv\n" +
|
||||||
|
"G5A/SbSqiE5PXSfIhQIDAQAB";
|
||||||
|
Base64.encodeBase64String(certificate.getEncoded());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package com.taoyuanx.securitydemo.controller;
|
||||||
|
|
||||||
|
import cn.hutool.crypto.Mode;
|
||||||
|
import cn.hutool.crypto.Padding;
|
||||||
|
import cn.hutool.crypto.symmetric.AES;
|
||||||
|
import com.taoyuanx.securitydemo.common.Result;
|
||||||
|
import com.taoyuanx.securitydemo.common.ResultBuilder;
|
||||||
|
import com.taoyuanx.securitydemo.config.GlobalConfig;
|
||||||
|
import com.taoyuanx.securitydemo.exception.ServiceException;
|
||||||
|
|
||||||
|
import com.taoyuanx.securitydemo.utils.*;
|
||||||
|
import com.taoyuanx.securitydemo.vo.EncryptForm;
|
||||||
|
import org.apache.commons.codec.binary.Hex;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.security.interfaces.RSAPrivateKey;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dushitaoyuan
|
||||||
|
* @desc 加密控制器
|
||||||
|
* @date 2020/1/15
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("crypt")
|
||||||
|
public class CryptController {
|
||||||
|
@Autowired
|
||||||
|
GlobalConfig globalConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务端公钥获取
|
||||||
|
*/
|
||||||
|
@GetMapping("serverPub")
|
||||||
|
@ResponseBody
|
||||||
|
public String serverPub() {
|
||||||
|
return globalConfig.getPublickKeyBase64();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务端公钥获取
|
||||||
|
*/
|
||||||
|
@GetMapping("cryptPage")
|
||||||
|
public String cryptPage(Model model, HttpServletRequest request) {
|
||||||
|
model.addAttribute("serverPub", globalConfig.getPublickKeyBase64());
|
||||||
|
String serverRandom = RandomCodeUtil.getRandCode(16);
|
||||||
|
request.getSession().setAttribute("serverRandom", serverRandom);
|
||||||
|
model.addAttribute("serverRandom", serverRandom);
|
||||||
|
String iv=RandomCodeUtil.getRandCode(16);
|
||||||
|
model.addAttribute("iv", iv);
|
||||||
|
request.getSession().setAttribute("iv", iv);
|
||||||
|
return "crypt";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接受加密请求
|
||||||
|
*/
|
||||||
|
@PostMapping("reciveEncrypt")
|
||||||
|
@ResponseBody
|
||||||
|
public Result reciveEncrypt(EncryptForm encryptForm, HttpServletRequest request) throws Exception {
|
||||||
|
Object serverRandom = request.getSession().getAttribute("serverRandom");
|
||||||
|
if (!(Objects.nonNull(encryptForm.getServerRandom()) && encryptForm.getServerRandom().equals(serverRandom))) {
|
||||||
|
throw new ServiceException("非法请求");
|
||||||
|
}
|
||||||
|
String dataHash = encryptForm.getDataHash();
|
||||||
|
//解密aes对称密码
|
||||||
|
String clientAesEncodePassword = RSAUtil.decryptByPrivateKey(encryptForm.getClientAesEncodePassword(), (RSAPrivateKey) globalConfig.getPrivateKey());
|
||||||
|
byte[] clientAesIv = request.getSession().getAttribute("iv").toString().getBytes("UTF-8");
|
||||||
|
String aesMode = "AES/CBC/PKCS5Padding";
|
||||||
|
//解密数据
|
||||||
|
String data = null;
|
||||||
|
try {
|
||||||
|
AES aes = new AES(Mode.CBC, Padding.PKCS5Padding, clientAesEncodePassword.getBytes("UTF-8"), clientAesIv);
|
||||||
|
byte[] bytes = Hex.decodeHex(encryptForm.getEncodeData().toCharArray());
|
||||||
|
data = new String(aes.decrypt(bytes), "UTF-8");
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ServiceException("解密失败");
|
||||||
|
}
|
||||||
|
String hash = HashUtil.hash(data, HashUtil.SHA256, HashUtil.HEX);
|
||||||
|
if (!hash.equals(encryptForm.getDataHash())) {
|
||||||
|
throw new ServiceException("数据hash不匹配");
|
||||||
|
}
|
||||||
|
return ResultBuilder.success("ok");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ public class ServiceException extends RuntimeException {
|
|||||||
this.errorCode=errorCode;
|
this.errorCode=errorCode;
|
||||||
}
|
}
|
||||||
public Integer getErrorCode(){
|
public Integer getErrorCode(){
|
||||||
return getErrorCode();
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
135
src/main/java/com/taoyuanx/securitydemo/utils/HashUtil.java
Normal file
135
src/main/java/com/taoyuanx/securitydemo/utils/HashUtil.java
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
package com.taoyuanx.securitydemo.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 都市桃源
|
||||||
|
* 数据摘要工具类
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
import org.apache.commons.codec.binary.Hex;
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
|
||||||
|
public class HashUtil {
|
||||||
|
//hash字符类型 base64 和hex
|
||||||
|
public static final String HEX = "hex";
|
||||||
|
public static final String BASE64 = "base64";
|
||||||
|
|
||||||
|
//hash算法类型 md5,sha256,sha1
|
||||||
|
public static final String MD5 = "md5";
|
||||||
|
public static final String SHA256 = "sha256";
|
||||||
|
public static final String SHA1 = "sha1";
|
||||||
|
|
||||||
|
public static byte[] hash(String content, String hashType) throws Exception {
|
||||||
|
if (null == content || "".equals(content)) {
|
||||||
|
throw new Exception("hash 内容为空");
|
||||||
|
}
|
||||||
|
return doHash(content.getBytes(), hashType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static byte[] hash(byte[] content, String hashType) throws Exception {
|
||||||
|
if (null == content || "".equals(content)) {
|
||||||
|
throw new Exception("hash 内容为空");
|
||||||
|
}
|
||||||
|
return doHash(content, hashType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param content hash内容
|
||||||
|
* @param hashType hash类型
|
||||||
|
* @param stringType 编码类型 base64 和 hex
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static String hash(String content, String hashType, String stringType) throws Exception {
|
||||||
|
if (null == content || "".equals(content)) {
|
||||||
|
throw new Exception("hash 内容为空");
|
||||||
|
}
|
||||||
|
return bytes2Str(doHash(content.getBytes(), hashType), stringType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String hash(byte[] content, String hashType, String stringType) throws Exception {
|
||||||
|
if (null == content || content.length == 0) {
|
||||||
|
throw new Exception("hash 内容为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes2Str(doHash(content, hashType), stringType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String hash(InputStream content, String hashType, String stringType) throws Exception {
|
||||||
|
if (null == content) {
|
||||||
|
throw new Exception("hash 内容为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes2Str(doHash(content, hashType), stringType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String bytes2Str(byte[] bytes, String stringType) {
|
||||||
|
switch (stringType) {
|
||||||
|
case HEX:
|
||||||
|
return Hex.encodeHexString(bytes);
|
||||||
|
case BASE64:
|
||||||
|
return Base64.encodeBase64String(bytes);
|
||||||
|
default:
|
||||||
|
return Base64.encodeBase64String(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String bytesToAscllString(byte[] bytes) {
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
for (byte b : bytes) {
|
||||||
|
buf.append((char) b);
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] doHash(byte[] content, String hashType) {
|
||||||
|
switch (hashType) {
|
||||||
|
case MD5:
|
||||||
|
return DigestUtils.getMd5Digest().digest(content);
|
||||||
|
case SHA256:
|
||||||
|
return DigestUtils.getSha256Digest().digest(content);
|
||||||
|
case SHA1:
|
||||||
|
return DigestUtils.getSha1Digest().digest(content);
|
||||||
|
default:
|
||||||
|
return DigestUtils.getMd5Digest().digest(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] doHash(InputStream content, String hashType) throws IOException {
|
||||||
|
byte[] buffer = new byte[1024 * 1024 * 4];
|
||||||
|
MessageDigest digest = null;
|
||||||
|
switch (hashType) {
|
||||||
|
case MD5:
|
||||||
|
digest = DigestUtils.getMd5Digest();
|
||||||
|
break;
|
||||||
|
case SHA256:
|
||||||
|
digest = DigestUtils.getSha256Digest();
|
||||||
|
break;
|
||||||
|
case SHA1:
|
||||||
|
digest = DigestUtils.getSha1Digest();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
digest = DigestUtils.getMd5Digest();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int len = -1;
|
||||||
|
while ((len = content.read(buffer, 0, 1024)) != -1) {
|
||||||
|
digest.update(buffer, 0, len);
|
||||||
|
}
|
||||||
|
content.close();
|
||||||
|
return digest.digest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
System.out.println(hash("1", MD5, HEX));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package com.taoyuanx.securitydemo.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dushitaoyuan
|
||||||
|
* @date 2019/1/7 18:34
|
||||||
|
* @desc 帮助类
|
||||||
|
**/
|
||||||
|
public class HelperUtil {
|
||||||
|
private static final String CLASSPATH_PREFIX = "classpath:";
|
||||||
|
|
||||||
|
public static boolean isEmpty(String str) {
|
||||||
|
return str == null || str.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getExtension(String fileName) {
|
||||||
|
return fileName.substring(fileName.lastIndexOf(".")+1).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InputStream getInputStream(String filePath) throws FileNotFoundException {
|
||||||
|
if (filePath.startsWith(CLASSPATH_PREFIX)) {
|
||||||
|
return HelperUtil.class.getResourceAsStream(filePath.replaceFirst(CLASSPATH_PREFIX, ""));
|
||||||
|
} else {
|
||||||
|
return new FileInputStream(filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] subarray(byte[] array, int startIndexInclusive, int endIndexExclusive) {
|
||||||
|
if (array == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (startIndexInclusive < 0) {
|
||||||
|
startIndexInclusive = 0;
|
||||||
|
}
|
||||||
|
if (endIndexExclusive > array.length) {
|
||||||
|
endIndexExclusive = array.length;
|
||||||
|
}
|
||||||
|
int newSize = endIndexExclusive - startIndexInclusive;
|
||||||
|
if (newSize <= 0) {
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] subarray = new byte[newSize];
|
||||||
|
System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
|
||||||
|
return subarray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] addAll(byte[] array1, byte... array2) {
|
||||||
|
if (array1 == null) {
|
||||||
|
return clone(array2);
|
||||||
|
} else if (array2 == null) {
|
||||||
|
return clone(array1);
|
||||||
|
}
|
||||||
|
byte[] joinedArray = new byte[array1.length + array2.length];
|
||||||
|
System.arraycopy(array1, 0, joinedArray, 0, array1.length);
|
||||||
|
System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
|
||||||
|
return joinedArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] clone(byte[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return array.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
278
src/main/java/com/taoyuanx/securitydemo/utils/RSAUtil.java
Normal file
278
src/main/java/com/taoyuanx/securitydemo/utils/RSAUtil.java
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
package com.taoyuanx.securitydemo.utils;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.CipherInputStream;
|
||||||
|
import javax.crypto.CipherOutputStream;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.io.*;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.Signature;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.security.interfaces.RSAPrivateKey;
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
public final class RSAUtil {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(RSAUtil.class);
|
||||||
|
public static final String KEYSTORE_TYPE_P12 = "PKCS12";
|
||||||
|
public static final String KEYSTORE_TYPE_JKS = "JKS";
|
||||||
|
public static final String ENCRYPT_TYPE_RSA = "RSA";
|
||||||
|
public static final String DEFAILT_SIGN_ALGORITHM = "MD5withRSA";
|
||||||
|
public static final String CERT_TYPE_X509 = "X.509";
|
||||||
|
|
||||||
|
public static KeyStore getKeyStore(String filePath, String keyPassword) throws Exception {
|
||||||
|
return getKeyStore(HelperUtil.getInputStream(filePath), keyPassword, guessKeyStoreType(filePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyStore getKeyStore(InputStream inputStream, String keyPassword, String keyStoreType) throws Exception {
|
||||||
|
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
|
||||||
|
keyStore.load(inputStream, keyPassword.toCharArray());
|
||||||
|
return keyStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String guessKeyStoreType(String filePath) {
|
||||||
|
String ext = HelperUtil.getExtension(filePath);
|
||||||
|
if (ext.equals("p12") || ext.equals("pfx")) {
|
||||||
|
return KEYSTORE_TYPE_P12;
|
||||||
|
}
|
||||||
|
if (ext.equals("jks")) {
|
||||||
|
return KEYSTORE_TYPE_JKS;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RSAPublicKey getPublicKey(KeyStore keyStore) throws Exception {
|
||||||
|
String key_aliases = null;
|
||||||
|
Enumeration<String> enumeration = keyStore.aliases();
|
||||||
|
if (enumeration.hasMoreElements()) {
|
||||||
|
key_aliases = enumeration.nextElement();
|
||||||
|
RSAPublicKey publicKey = (RSAPublicKey) keyStore.getCertificate(key_aliases).getPublicKey();
|
||||||
|
return publicKey;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Certificate getCertificate(KeyStore keyStore) throws Exception {
|
||||||
|
String key_aliases = null;
|
||||||
|
Enumeration<String> enumeration = keyStore.aliases();
|
||||||
|
key_aliases = enumeration.nextElement();
|
||||||
|
if (keyStore.isKeyEntry(key_aliases)) {
|
||||||
|
Certificate certificate = keyStore.getCertificate(key_aliases);
|
||||||
|
return certificate;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RSAPrivateKey getPrivateKey(KeyStore keyStore, String keyPassword) throws Exception {
|
||||||
|
String key_aliases = null;
|
||||||
|
Enumeration<String> enumeration = keyStore.aliases();
|
||||||
|
key_aliases = enumeration.nextElement();
|
||||||
|
if (keyStore.isKeyEntry(key_aliases)) {
|
||||||
|
RSAPrivateKey privateKey = (RSAPrivateKey) keyStore.getKey(key_aliases, keyPassword.toCharArray());
|
||||||
|
return privateKey;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String encryptByPublicKey(String data, RSAPublicKey publicKey) throws Exception {
|
||||||
|
return Base64.encodeBase64URLSafeString(encryptByPublicKey(Base64.decodeBase64(data), publicKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] encryptByPublicKey(byte[] data, RSAPublicKey publicKey) throws Exception {
|
||||||
|
if (null == publicKey) {// 如果公钥为空,采用系统公钥
|
||||||
|
throw new Exception("rsa publicKey is null");
|
||||||
|
}
|
||||||
|
Cipher cipher = Cipher.getInstance(ENCRYPT_TYPE_RSA);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||||
|
// 模长
|
||||||
|
int key_len = publicKey.getModulus().bitLength() / 8;
|
||||||
|
// 加密数据长度 <= 模长-11,如果明文长度大于模长-11则要分组加密
|
||||||
|
key_len -= 11;
|
||||||
|
byte[] dataReturn = null;
|
||||||
|
for (int i = 0; i < data.length; i += key_len) {
|
||||||
|
byte[] doFinal = cipher.doFinal(HelperUtil.subarray(data, i, i + key_len));
|
||||||
|
dataReturn = HelperUtil.addAll(dataReturn, doFinal);
|
||||||
|
}
|
||||||
|
return dataReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 私钥解密
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @param privateKey
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey) throws Exception {
|
||||||
|
return new String(decryptByPrivateKey(Base64.decodeBase64(data), privateKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static byte[] decryptByPrivateKey(byte[] data, RSAPrivateKey privateKey) throws Exception {
|
||||||
|
if (null == privateKey) {
|
||||||
|
throw new Exception("rsa privateKey is null");
|
||||||
|
}
|
||||||
|
Cipher cipher = Cipher.getInstance(ENCRYPT_TYPE_RSA);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||||
|
// 模长
|
||||||
|
int key_len = privateKey.getModulus().bitLength() / 8;
|
||||||
|
// 分组解密
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream(data.length);
|
||||||
|
// 如果密文长度大于模长则要分组解密
|
||||||
|
for (int i = 0; i < data.length; i += key_len) {
|
||||||
|
byte[] doFinal = cipher.doFinal(HelperUtil.subarray(data, i, i + key_len));
|
||||||
|
out.write(doFinal, 0, doFinal.length);
|
||||||
|
}
|
||||||
|
return out.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void encryptByPublicKey(InputStream data, RSAPublicKey publicKey, OutputStream encodeStream) throws Exception {
|
||||||
|
if (null == publicKey) {
|
||||||
|
throw new Exception("rsa publicKey is null");
|
||||||
|
}
|
||||||
|
Cipher cipher = Cipher.getInstance(ENCRYPT_TYPE_RSA);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||||
|
CipherInputStream cipherInputStream = new CipherInputStream(data, cipher);
|
||||||
|
int buffSize = 4 << 20;
|
||||||
|
byte[] buf = new byte[buffSize];
|
||||||
|
int len = 0;
|
||||||
|
while ((len = cipherInputStream.read(buf)) != -1) {
|
||||||
|
encodeStream.write(buf, 0, len);
|
||||||
|
}
|
||||||
|
cipherInputStream.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void decryptByPrivateKey(InputStream data, RSAPrivateKey privateKey, OutputStream decodeStream) throws Exception {
|
||||||
|
if (null == privateKey) {
|
||||||
|
throw new Exception("rsa privateKey is null");
|
||||||
|
}
|
||||||
|
Cipher cipher = Cipher.getInstance(ENCRYPT_TYPE_RSA);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||||
|
CipherOutputStream cipherOutputStream = new CipherOutputStream(decodeStream, cipher);
|
||||||
|
int buffSize = 4 << 20;
|
||||||
|
byte[] buf = new byte[buffSize];
|
||||||
|
int len = 0;
|
||||||
|
while ((len = data.read(buf)) != -1) {
|
||||||
|
cipherOutputStream.write(buf, 0, len);
|
||||||
|
}
|
||||||
|
cipherOutputStream.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 签名
|
||||||
|
*
|
||||||
|
* @param data 签名内容
|
||||||
|
* @param signAlgorithm 签名
|
||||||
|
* @param privateKey 签名私钥
|
||||||
|
* @return 签名值
|
||||||
|
*/
|
||||||
|
public static byte[] sign(byte[] data, String signAlgorithm, RSAPrivateKey privateKey) throws Exception {
|
||||||
|
if (null == privateKey) {
|
||||||
|
throw new Exception("rsa privateKey is null");
|
||||||
|
}
|
||||||
|
if (HelperUtil.isEmpty(signAlgorithm)) {
|
||||||
|
signAlgorithm = DEFAILT_SIGN_ALGORITHM;
|
||||||
|
}
|
||||||
|
Signature signture = Signature.getInstance(signAlgorithm);
|
||||||
|
signture.initSign(privateKey);
|
||||||
|
signture.update(data);
|
||||||
|
return signture.sign();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param data 签名原文内容
|
||||||
|
* @param sign 签名值
|
||||||
|
* @param publicKey 验签公钥
|
||||||
|
* @param signAlgorithm 签名算法 MD5withRSA,SHA1withRSA,SHA256withRSA
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean vefySign(byte[] data, byte[] sign, String signAlgorithm, PublicKey publicKey) {
|
||||||
|
try {
|
||||||
|
if (null == sign || sign.length == 0 || null == data || data.length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (null == publicKey) {
|
||||||
|
throw new Exception("rsa publicKey is null");
|
||||||
|
}
|
||||||
|
if (HelperUtil.isEmpty(signAlgorithm)) {
|
||||||
|
signAlgorithm = DEFAILT_SIGN_ALGORITHM;
|
||||||
|
}
|
||||||
|
Signature signature = Signature.getInstance(signAlgorithm);
|
||||||
|
signature.initVerify(publicKey);
|
||||||
|
signature.update(data);
|
||||||
|
return signature.verify(sign);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("验签异常{}", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String sign(String data, String signAlgorithm, RSAPrivateKey privateKey) throws Exception {
|
||||||
|
return Base64.encodeBase64URLSafeString(sign(data.getBytes(), signAlgorithm, privateKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean vefySign(String data, String signvalue, X509Certificate cert) {
|
||||||
|
try {
|
||||||
|
if (HelperUtil.isEmpty(data) || HelperUtil.isEmpty(signvalue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (null == cert) {
|
||||||
|
throw new Exception("rsa X509Certificate is null");
|
||||||
|
}
|
||||||
|
return vefySign(data.getBytes(), Base64.decodeBase64(signvalue), cert.getSigAlgName(), cert.getPublicKey());
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("验签异常{}", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static X509Certificate readPublicKeyCer(InputStream publicInput) throws Exception {
|
||||||
|
CertificateFactory certificatefactory = CertificateFactory.getInstance(CERT_TYPE_X509);
|
||||||
|
X509Certificate cert = (X509Certificate) certificatefactory.generateCertificate(publicInput);
|
||||||
|
return cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PublicKey readPublicKey(File fileInputStream) {
|
||||||
|
try {
|
||||||
|
return RSAUtil.readPublicKeyCer(new FileInputStream(fileInputStream)).getPublicKey();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("读取公钥失败", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取pem格式公钥
|
||||||
|
*
|
||||||
|
* @param certPemString pem字符串
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static PublicKey readPublicKeyPEM(String certPemString) {
|
||||||
|
try {
|
||||||
|
return RSAUtil.readPublicKeyCer(new ByteArrayInputStream(certPemString.getBytes("UTF-8"))).getPublicKey();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("读取公钥失败", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.taoyuanx.securitydemo.utils;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dushitaoyuan
|
||||||
|
* @desc 随机码
|
||||||
|
* @date 2020/1/3
|
||||||
|
*/
|
||||||
|
public class RandomCodeUtil {
|
||||||
|
/**
|
||||||
|
* 随机生成字符
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static char[] rand_str = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
|
||||||
|
't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
|
||||||
|
|
||||||
|
public static String getRandCode(int len) {
|
||||||
|
StringBuilder pwd = new StringBuilder(len);
|
||||||
|
Random r = new Random();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
pwd.append(rand_str[r.nextInt(rand_str.length)]);
|
||||||
|
}
|
||||||
|
return pwd.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/main/java/com/taoyuanx/securitydemo/vo/EncryptForm.java
Normal file
21
src/main/java/com/taoyuanx/securitydemo/vo/EncryptForm.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package com.taoyuanx.securitydemo.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dushitaoyuan
|
||||||
|
* @desc 加密请求表单
|
||||||
|
* @date 2020/1/15
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class EncryptForm {
|
||||||
|
//服务端随机数
|
||||||
|
private String serverRandom;
|
||||||
|
//服务端公钥加密后的aes对称密钥
|
||||||
|
private String clientAesEncodePassword;
|
||||||
|
//加密后的数据
|
||||||
|
private String encodeData;
|
||||||
|
//数据hash
|
||||||
|
private String dataHash;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
server.port=8080
|
|
||||||
#数据库连接池
|
#数据库连接池
|
||||||
#spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
|
#spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
|
||||||
#spring.datasource.username:root
|
#spring.datasource.username:root
|
||||||
@@ -12,7 +12,7 @@ server.port=8080
|
|||||||
#spring.datasource.timeBetweenEvictionRunsMillis=60000
|
#spring.datasource.timeBetweenEvictionRunsMillis=60000
|
||||||
#spring.datasource.filters=wall
|
#spring.datasource.filters=wall
|
||||||
|
|
||||||
|
spring.profiles.active=@profiles.active@
|
||||||
|
|
||||||
spring.redis.database=2
|
spring.redis.database=2
|
||||||
spring.redis.host=192.168.30.211
|
spring.redis.host=192.168.30.211
|
||||||
@@ -40,5 +40,17 @@ application.config.file-storage-dir=G:/temp
|
|||||||
#系统文件访问地址,参见fileHandler
|
#系统文件访问地址,参见fileHandler
|
||||||
application.config.systemFileFormat=http://localhost:${server.port}/api/file
|
application.config.systemFileFormat=http://localhost:${server.port}/api/file
|
||||||
|
|
||||||
|
#rsa p12 路径及密码
|
||||||
|
application.config.rsaP12-path=d://client.p12
|
||||||
|
application.config.rsaP12-password=123456
|
||||||
|
|
||||||
|
#thymeleaf \u6A21\u677F\u5F15\u64CE\u914D\u7F6E
|
||||||
|
spring.thymeleaf.enabled=true
|
||||||
|
spring.thymeleaf.encoding=UTF-8
|
||||||
|
spring.thymeleaf.cache=false
|
||||||
|
spring.thymeleaf.suffix=.html
|
||||||
|
|
||||||
logging.level.org.springframework=INFO
|
logging.level.org.springframework=INFO
|
||||||
|
|
||||||
|
|
||||||
|
logging.path=./logs
|
||||||
|
|||||||
BIN
src/main/resources/certs/client.p12
Normal file
BIN
src/main/resources/certs/client.p12
Normal file
Binary file not shown.
21
src/main/resources/certs/client_cert.cer
Normal file
21
src/main/resources/certs/client_cert.cer
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDizCCAnOgAwIBAgIGAW+nseYzMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQG
|
||||||
|
EwJDTjELMAkGA1UECAwCQkoxCzAJBgNVBAcMAkJKMRIwEAYDVQQKDAnmoYPmupDk
|
||||||
|
uaExEjAQBgNVBAsMCeahg+a6kOS5oTESMBAGA1UEAwwJ5qGD5rqQ5LmhMSMwIQYJ
|
||||||
|
KoZIhvcNAQkBFhRsaWFuZ2xlaV9senhAMTYzLmNvbTAgFw0yMDAxMTQxNjAwMDBa
|
||||||
|
GA8yMDU3MDExNDE2MDAwMFowfDELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkJKMQsw
|
||||||
|
CQYDVQQHDAJCSjEVMBMGA1UECgwMdGFveXVhbnguY29tMRUwEwYDVQQLDAx0YW95
|
||||||
|
dWFueC5jb20xJTAjBgkqhkiG9w0BCQEWFmR1c2hpdGFveXVhbkBnbWFpbC5jb20w
|
||||||
|
gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJ6NAT2sqDy/lO5pL204NH1A0+A/
|
||||||
|
0wOG3IgWYouZBO7Zqf+kRbXxdZcQqLTg5Fh/CvsGMAn0cxaykZGDyttKNt62G51C
|
||||||
|
clQO2uoc0NjMnUeFBPuyeAa+m4f0wTtlbjJlwwNLv+Lm1BKmzfUmYYj5QtmDVy8b
|
||||||
|
kD9JtKqITk9dJ8iFAgMBAAGjgYcwgYQwHwYDVR0jBBgwFoAUh6OitnPZb0BV6swl
|
||||||
|
cLTxEcy+OkMwHQYDVR0OBBYEFFuy+UxzJzqVtodEp66TeZi20AOXMA8GA1UdDwEB
|
||||||
|
/wQFAwMH/4AwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwkGCCsGAQUFBwMSMA8GA1Ud
|
||||||
|
EwQIMAYBAf8CAQAwDQYJKoZIhvcNAQELBQADggEBAAAmbo7QgtCrbaGMUUbMWD2U
|
||||||
|
lbJiCxRFgoad4jkUQq/YrWYJZa0oMYWjRhKUuQKJ+KXz2HdMtwChi2RwzHzAdLda
|
||||||
|
2l3Pqg9U2XLoS4FxPRt4LwXQKDlIUYRwrBRH/beT5JUK5xcRRQR78uNT6luccL3T
|
||||||
|
hzUBYB1/rqREIpqHS1D1eV/DiFfhiFUn2GtcxV4vN+uOz2KvY0rh6li132wp9zZK
|
||||||
|
loLJfygKKNzPhiegAYu6M9+0q/CVXyNudr19BbbmP1SjNeA4WF/gjYB3ilrRDbDY
|
||||||
|
MMzDsKhkqOU42oYOdsjWuN9ZwZqAKys73EuD/DEMEqPfmRVpeGdy9GH/1IPZwto=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
15
src/main/resources/certs/client_pri.pem
Normal file
15
src/main/resources/certs/client_pri.pem
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIICWwIBAAKBgQCejQE9rKg8v5TuaS9tODR9QNPgP9MDhtyIFmKLmQTu2an/pEW1
|
||||||
|
8XWXEKi04ORYfwr7BjAJ9HMWspGRg8rbSjbethudQnJUDtrqHNDYzJ1HhQT7sngG
|
||||||
|
vpuH9ME7ZW4yZcMDS7/i5tQSps31JmGI+ULZg1cvG5A/SbSqiE5PXSfIhQIDAQAB
|
||||||
|
An9e3vgwL07zTvQXXyYOnzlz7HR1A1Vm3C3MyQ+ub9TD0tiMgaFoFtv9c1QIPN7M
|
||||||
|
SI3nWgP1ztQO1ijEfwKSLHQWswMTTuE+yMOMHvKpK9qcOr/u34TR1bKVuL0PqUaa
|
||||||
|
C3nkBklM/F/Wg4qTqtGSMRA2rBrcPdiRG2Z/fUXGTTKpAkEA2oTvk96hKQ1uO6Hx
|
||||||
|
2D2aocaXs/ri8sTgrqNTYXfYPHO3r8To7/PsW00adDmf9eXARQP4Jk8DoTJzTDG/
|
||||||
|
3iZ1OQJBALm+4qAVmePBEHJrH7AGWkZGAFo05nwtTNuRDYjJ7qsy79v4UOKq9zb0
|
||||||
|
UmxOrHh8M7pom3Vs5JyPBRaPCtF4Ga0CQQCfeccy/pZVVJTvdlf+/a6dhEbwthft
|
||||||
|
HxvuuAnBJ2qra7RR1f4+KKGFXHcC/Y8tMVipxaTTqHS4rw4QPHqPkTeZAkEAkrUN
|
||||||
|
JGnLUZNk3Sp1Lb/mv4h8sMMFpODWyrln2jm8U+X4g2I+6LkmZ3ZUP41oNgXLiZkj
|
||||||
|
6HxomKtx1l6GqenVRQJAZ3hQDWBTYYZYoR13q++Zzy91dPZkK+CGMytgAEU+OpNf
|
||||||
|
J835Xn/ecvF94F/eflzrxHLIA0Wafc5iC8pOrRwETg==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
6
src/main/resources/certs/client_pub.pem
Normal file
6
src/main/resources/certs/client_pub.pem
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCejQE9rKg8v5TuaS9tODR9QNPg
|
||||||
|
P9MDhtyIFmKLmQTu2an/pEW18XWXEKi04ORYfwr7BjAJ9HMWspGRg8rbSjbethud
|
||||||
|
QnJUDtrqHNDYzJ1HhQT7sngGvpuH9ME7ZW4yZcMDS7/i5tQSps31JmGI+ULZg1cv
|
||||||
|
G5A/SbSqiE5PXSfIhQIDAQAB
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
2
src/main/resources/certs/readme.txt
Normal file
2
src/main/resources/certs/readme.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
证书类型为[RSA]p12 alias:taoyuanx-client
|
||||||
|
p12 密码:123456
|
||||||
136
src/main/resources/logback-spring.xml
Normal file
136
src/main/resources/logback-spring.xml
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<configuration scan="true" scanPeriod="10 seconds">
|
||||||
|
<springProperty name="LOG_HOME" source="logging.path" defaultValue="./logs"/>
|
||||||
|
<property name="LOG_PREFIX" value="seed-boot"/>
|
||||||
|
|
||||||
|
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
|
||||||
|
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
|
||||||
|
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
|
||||||
|
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
|
||||||
|
|
||||||
|
|
||||||
|
<!--输出到控制台-->
|
||||||
|
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||||
|
<level>info</level>
|
||||||
|
</filter>
|
||||||
|
<encoder>
|
||||||
|
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_HOME}/debug/${LOG_PREFIX}.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_HOME}/debug/${LOG_PREFIX}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||||
|
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||||
|
<maxFileSize>100MB</maxFileSize>
|
||||||
|
</timeBasedFileNamingAndTriggeringPolicy>
|
||||||
|
<maxHistory>15</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>debug</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_HOME}/info/${LOG_PREFIX}.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_HOME}/info/${LOG_PREFIX}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||||
|
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||||
|
<maxFileSize>100MB</maxFileSize>
|
||||||
|
</timeBasedFileNamingAndTriggeringPolicy>
|
||||||
|
<maxHistory>15</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>info</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_HOME}/warn/${LOG_PREFIX}.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_HOME}/warn/${LOG_PREFIX}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||||
|
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||||
|
<maxFileSize>100MB</maxFileSize>
|
||||||
|
</timeBasedFileNamingAndTriggeringPolicy>
|
||||||
|
<maxHistory>15</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>warn</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
|
||||||
|
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${LOG_HOME}/error/${LOG_PREFIX}.log</file>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${LOG_HOME}/error/${LOG_PREFIX}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||||
|
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||||
|
<maxFileSize>100MB</maxFileSize>
|
||||||
|
</timeBasedFileNamingAndTriggeringPolicy>
|
||||||
|
<maxHistory>15</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>ERROR</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<springProfile name="dev">
|
||||||
|
<root level="DEBUG">
|
||||||
|
<appender-ref ref="CONSOLE"/>
|
||||||
|
</root>
|
||||||
|
</springProfile>
|
||||||
|
<springProfile name="prod,test">
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="DEBUG_FILE"/>
|
||||||
|
<appender-ref ref="INFO_FILE"/>
|
||||||
|
<appender-ref ref="WARN_FILE"/>
|
||||||
|
<appender-ref ref="ERROR_FILE"/>
|
||||||
|
</root>
|
||||||
|
</springProfile>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</configuration>
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<configuration debug="false">
|
|
||||||
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径 -->
|
|
||||||
<property name="LOG_HOME" value="./logs" />
|
|
||||||
<!-- 控制台输出 -->
|
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
|
||||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
|
||||||
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
|
|
||||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} -
|
|
||||||
%msg%n</pattern>
|
|
||||||
</encoder>
|
|
||||||
</appender>
|
|
||||||
<!-- 按照每天生成日志文件 -->
|
|
||||||
<appender name="FILE"
|
|
||||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
|
||||||
<!--日志文件输出的文件名 -->
|
|
||||||
<FileNamePattern>${LOG_HOME}/cert.log.%d{yyyy-MM-dd}.log
|
|
||||||
</FileNamePattern>
|
|
||||||
<!--日志文件保留天数 -->
|
|
||||||
<MaxHistory>30</MaxHistory>
|
|
||||||
</rollingPolicy>
|
|
||||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
|
||||||
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
|
|
||||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} -
|
|
||||||
%msg%n</pattern>
|
|
||||||
|
|
||||||
</encoder>
|
|
||||||
<!--日志文件最大的大小 -->
|
|
||||||
<triggeringPolicy
|
|
||||||
class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
|
|
||||||
<MaxFileSize>10MB</MaxFileSize>
|
|
||||||
</triggeringPolicy>
|
|
||||||
</appender>
|
|
||||||
<!-- 日志输出级别 -->
|
|
||||||
<root level="DEBUG">
|
|
||||||
<appender-ref ref="STDOUT" />
|
|
||||||
</root>
|
|
||||||
|
|
||||||
|
|
||||||
</configuration>
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
//全局定义变量和全局函数
|
//全局定义变量和全局函数
|
||||||
|
|
||||||
var apiBaseUrl = "http://localhost:8080/"
|
var apiBaseUrl = "http://localhost:9999/"
|
||||||
var staticBaseUrl = "http://localhost:8080/"
|
var staticBaseUrl = "http://localhost:9999/"
|
||||||
|
|
||||||
function getApiUrl(path) {
|
function getApiUrl(path) {
|
||||||
return apiBaseUrl + path;
|
return apiBaseUrl + path;
|
||||||
|
|||||||
35
src/main/resources/static/js/crypt/aes.js
Normal file
35
src/main/resources/static/js/crypt/aes.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
CryptoJS v3.1.2
|
||||||
|
code.google.com/p/crypto-js
|
||||||
|
(c) 2009-2013 by Jeff Mott. All rights reserved.
|
||||||
|
code.google.com/p/crypto-js/wiki/License
|
||||||
|
*/
|
||||||
|
var CryptoJS=CryptoJS||function(u,p){var d={},l=d.lib={},s=function(){},t=l.Base={extend:function(a){s.prototype=this;var c=new s;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
|
||||||
|
r=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=p?c:4*a.length},toString:function(a){return(a||v).stringify(this)},concat:function(a){var c=this.words,e=a.words,j=this.sigBytes;a=a.sigBytes;this.clamp();if(j%4)for(var k=0;k<a;k++)c[j+k>>>2]|=(e[k>>>2]>>>24-8*(k%4)&255)<<24-8*((j+k)%4);else if(65535<e.length)for(k=0;k<a;k+=4)c[j+k>>>2]=e[k>>>2];else c.push.apply(c,e);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
|
||||||
|
32-8*(c%4);a.length=u.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],e=0;e<a;e+=4)c.push(4294967296*u.random()|0);return new r.init(c,a)}}),w=d.enc={},v=w.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++){var k=c[j>>>2]>>>24-8*(j%4)&255;e.push((k>>>4).toString(16));e.push((k&15).toString(16))}return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j+=2)e[j>>>3]|=parseInt(a.substr(j,
|
||||||
|
2),16)<<24-4*(j%8);return new r.init(e,c/2)}},b=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++)e.push(String.fromCharCode(c[j>>>2]>>>24-8*(j%4)&255));return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j++)e[j>>>2]|=(a.charCodeAt(j)&255)<<24-8*(j%4);return new r.init(e,c)}},x=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(b.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return b.parse(unescape(encodeURIComponent(a)))}},
|
||||||
|
q=l.BufferedBlockAlgorithm=t.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=x.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,e=c.words,j=c.sigBytes,k=this.blockSize,b=j/(4*k),b=a?u.ceil(b):u.max((b|0)-this._minBufferSize,0);a=b*k;j=u.min(4*a,j);if(a){for(var q=0;q<a;q+=k)this._doProcessBlock(e,q);q=e.splice(0,a);c.sigBytes-=j}return new r.init(q,j)},clone:function(){var a=t.clone.call(this);
|
||||||
|
a._data=this._data.clone();return a},_minBufferSize:0});l.Hasher=q.extend({cfg:t.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){q.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,e){return(new a.init(e)).finalize(b)}},_createHmacHelper:function(a){return function(b,e){return(new n.HMAC.init(a,
|
||||||
|
e)).finalize(b)}}});var n=d.algo={};return d}(Math);
|
||||||
|
(function(){var u=CryptoJS,p=u.lib.WordArray;u.enc.Base64={stringify:function(d){var l=d.words,p=d.sigBytes,t=this._map;d.clamp();d=[];for(var r=0;r<p;r+=3)for(var w=(l[r>>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+0.75*v<p;v++)d.push(t.charAt(w>>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join("")},parse:function(d){var l=d.length,s=this._map,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w<
|
||||||
|
l;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();
|
||||||
|
(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<<j|b>>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<<j|b>>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<<j|b>>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<<j|b>>>32-j)+n}for(var t=CryptoJS,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({_doReset:function(){this._hash=new w.init([1732584193,4023233417,2562383102,271733878])},
|
||||||
|
_doProcessBlock:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this._hash.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]),
|
||||||
|
f=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f,
|
||||||
|
m,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m,
|
||||||
|
E,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},_doFinalize:function(){var b=this._data,n=b.words,a=8*this._nDataBytes,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/
|
||||||
|
4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this._process();b=this._hash;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b._hash=this._hash.clone();return b}});t.MD5=v._createHelper(r);t.HmacMD5=v._createHmacHelper(r)})(Math);
|
||||||
|
(function(){var u=CryptoJS,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length<q;){n&&s.update(n);var n=s.update(d).finalize(r);s.reset();for(var a=1;a<p;a++)n=s.finalize(n),s.reset();b.concat(n)}b.sigBytes=4*q;return b}});u.EvpKDF=function(d,l,p){return s.create(p).compute(d,
|
||||||
|
l)}})();
|
||||||
|
CryptoJS.lib.Cipher||function(u){var p=CryptoJS,d=p.lib,l=d.Base,s=d.WordArray,t=d.BufferedBlockAlgorithm,r=p.enc.Base64,w=p.algo.EvpKDF,v=d.Cipher=t.extend({cfg:l.extend(),createEncryptor:function(e,a){return this.create(this._ENC_XFORM_MODE,e,a)},createDecryptor:function(e,a){return this.create(this._DEC_XFORM_MODE,e,a)},init:function(e,a,b){this.cfg=this.cfg.extend(b);this._xformMode=e;this._key=a;this.reset()},reset:function(){t.reset.call(this);this._doReset()},process:function(e){this._append(e);return this._process()},
|
||||||
|
finalize:function(e){e&&this._append(e);return this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(e){return{encrypt:function(b,k,d){return("string"==typeof k?c:a).encrypt(e,b,k,d)},decrypt:function(b,k,d){return("string"==typeof k?c:a).decrypt(e,b,k,d)}}}});d.StreamCipher=v.extend({_doFinalize:function(){return this._process(!0)},blockSize:1});var b=p.mode={},x=function(e,a,b){var c=this._iv;c?this._iv=u:c=this._prevBlock;for(var d=0;d<b;d++)e[a+d]^=
|
||||||
|
c[d]},q=(d.BlockCipherMode=l.extend({createEncryptor:function(e,a){return this.Encryptor.create(e,a)},createDecryptor:function(e,a){return this.Decryptor.create(e,a)},init:function(e,a){this._cipher=e;this._iv=a}})).extend();q.Encryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize;x.call(this,e,a,c);b.encryptBlock(e,a);this._prevBlock=e.slice(a,a+c)}});q.Decryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize,d=e.slice(a,a+c);b.decryptBlock(e,a);x.call(this,
|
||||||
|
e,a,c);this._prevBlock=d}});b=b.CBC=q;q=(p.pad={}).Pkcs7={pad:function(a,b){for(var c=4*b,c=c-a.sigBytes%c,d=c<<24|c<<16|c<<8|c,l=[],n=0;n<c;n+=4)l.push(d);c=s.create(l,c);a.concat(c)},unpad:function(a){a.sigBytes-=a.words[a.sigBytes-1>>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a,
|
||||||
|
this,b&&b.words)},_doProcessBlock:function(a,b){this._mode.processBlock(a,b)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var b=this._process(!0)}else b=this._process(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684,
|
||||||
|
1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})},
|
||||||
|
decrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this._parse(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},_parse:function(a,b){return"string"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d,
|
||||||
|
b.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this._parse(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}();
|
||||||
|
(function(){for(var u=CryptoJS,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8,
|
||||||
|
16,32,64,128,27,54],d=d.AES=p.extend({_doReset:function(){for(var a=this._key,c=a.words,d=a.sigBytes/4,a=4*((this._nRounds=d+6)+1),e=this._keySchedule=[],j=0;j<a;j++)if(j<d)e[j]=c[j];else{var k=e[j-1];j%d?6<d&&4==j%d&&(k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this._invKeySchedule=[];for(d=0;d<a;d++)j=a-d,k=d%4?e[j]:e[j-4],c[d]=4>d||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>>
|
||||||
|
8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this._doCryptBlock(a,b,this._keySchedule,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this._doCryptBlock(a,c,this._invKeySchedule,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},_doCryptBlock:function(a,b,c,d,e,j,l,f){for(var m=this._nRounds,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r<m;r++)var q=d[g>>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t=
|
||||||
|
d[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p._createHelper(d)})();
|
||||||
1
src/main/resources/static/js/crypt/jsencrypt.min.js
vendored
Normal file
1
src/main/resources/static/js/crypt/jsencrypt.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
src/main/resources/static/js/jquery.serializeObject.min.js
vendored
Normal file
1
src/main/resources/static/js/jquery.serializeObject.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
$.fn.serializeObject=function(){"use strict";var a={},b=function(b,c){var d=a[c.name];"undefined"!=typeof d&&d!==null?$.isArray(d)?d.push(c.value):a[c.name]=[d,c.value]:a[c.name]=c.value};return $.each(this.serializeArray(),b),a};
|
||||||
111
src/main/resources/templates/crypt.html
Normal file
111
src/main/resources/templates/crypt.html
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>加密例子</title>
|
||||||
|
<script src="/js/crypt/core-min.js"></script>
|
||||||
|
<script src="/js/crypt/enc-base64-min.js"></script>
|
||||||
|
<script src="/js/crypt/sha256-min.js"></script>
|
||||||
|
<script src="/js/crypt/aes.js"></script>
|
||||||
|
<script src="/js/jquery-2.1.1.min.js"></script>
|
||||||
|
<script src="/js/common/system.js"></script>
|
||||||
|
<script src="/js/jquery.serializeObject.min.js"></script>
|
||||||
|
<script src="/js/crypt/jsencrypt.min.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<input name="serverPub" type="hidden" th:value="${serverPub}">
|
||||||
|
<input id="iv" name="iv" type="hidden" th:value="${iv}">
|
||||||
|
<form id="encodeForm" action="" method="post">
|
||||||
|
<input name="serverRandom" type="hidden" th:value="${serverRandom}">
|
||||||
|
<input name="clientAesEncodePassword" type="hidden" value="">
|
||||||
|
<input name="encodeData" type="hidden" value="">
|
||||||
|
<input name="dataHash" type="hidden" value="">
|
||||||
|
<button onclick="encryptSubmit()">提交</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function encryptSubmit() {
|
||||||
|
var clientAesPassword = randomStr(16);
|
||||||
|
var serverPub = $("input[name='serverPub']").val();
|
||||||
|
var encodePassword = encryptPublicKey(serverPub, clientAesPassword);
|
||||||
|
var data = "123456";
|
||||||
|
var encodeData = encrypt(data, clientAesPassword);
|
||||||
|
$("#encodeForm input[name='clientAesEncodePassword']").val(encodePassword);
|
||||||
|
$("#encodeForm input[name='encodeData']").val(encodeData);
|
||||||
|
$("#encodeForm input[name='dataHash']").val(hashData(data));
|
||||||
|
var encodeFormData = $("#encodeForm").serializeObject();
|
||||||
|
console.log(encodeFormData)
|
||||||
|
jQuery.support.cors = true;
|
||||||
|
$.ajax({
|
||||||
|
type: 'post',
|
||||||
|
url: getApiUrl("crypt/reciveEncrypt"),
|
||||||
|
data: encodeFormData,
|
||||||
|
dataType: 'json',
|
||||||
|
traditional: true,
|
||||||
|
async: false,
|
||||||
|
xhrFields: {
|
||||||
|
withCredentials: true
|
||||||
|
}
|
||||||
|
}).success(function (result) {
|
||||||
|
if (result.success == 1) {
|
||||||
|
alert("登录成功");
|
||||||
|
} else {
|
||||||
|
alert(result.msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function randomStr(len) {
|
||||||
|
var x = "0123456789qwertyuioplkjhgfdsazxcvbnm";
|
||||||
|
var tmp = "";
|
||||||
|
for (var i = 0; i < len; i++) {
|
||||||
|
tmp += x.charAt(Math.ceil(Math.random() * 100000000) % x.length);
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
function encryptPublicKey(publicKeyBase64, data) {
|
||||||
|
var encrypt = new JSEncrypt();
|
||||||
|
encrypt.setPublicKey(publicKeyBase64);
|
||||||
|
var data = encrypt.encrypt(data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
var iv = CryptoJS.enc.Utf8.parse($("#iv").val());
|
||||||
|
|
||||||
|
|
||||||
|
//Aes 加解密
|
||||||
|
function decrypt(data, aesKey) {
|
||||||
|
var key = CryptoJS.enc.Utf8.parse(aesKey);
|
||||||
|
var decryptData = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(data));
|
||||||
|
var decrypt = CryptoJS.AES.decrypt(decryptData, key, {
|
||||||
|
iv: iv,
|
||||||
|
mode: CryptoJS.mode.CBC,
|
||||||
|
padding: CryptoJS.pad.Pkcs7
|
||||||
|
});
|
||||||
|
var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
|
||||||
|
return decryptedStr.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function encrypt(data, aesKey) {
|
||||||
|
var key = CryptoJS.enc.Utf8.parse(aesKey)
|
||||||
|
var encrypted = CryptoJS.AES.encrypt(data, key, {
|
||||||
|
iv: iv,
|
||||||
|
mode: CryptoJS.mode.CBC,
|
||||||
|
padding: CryptoJS.pad.Pkcs7
|
||||||
|
});
|
||||||
|
return encrypted.ciphertext.toString(CryptoJS.enc.Hex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// hash
|
||||||
|
function hashData(data) {
|
||||||
|
return CryptoJS.SHA256(data).toString(CryptoJS.enc.Hex)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
44
src/test/java/com/taoyuanx/securitydemo/CertTest.java
Normal file
44
src/test/java/com/taoyuanx/securitydemo/CertTest.java
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package com.taoyuanx.securitydemo;
|
||||||
|
|
||||||
|
import com.taoyuanx.securitydemo.utils.HashUtil;
|
||||||
|
import com.taoyuanx.securitydemo.utils.HelperUtil;
|
||||||
|
import com.taoyuanx.securitydemo.utils.RSAUtil;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.interfaces.RSAPrivateKey;
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dushitaoyuan
|
||||||
|
* @date 2020/1/15
|
||||||
|
*/
|
||||||
|
public class CertTest {
|
||||||
|
@Test
|
||||||
|
public void rsaTest() throws Exception {
|
||||||
|
|
||||||
|
|
||||||
|
KeyStore keyStore = RSAUtil.getKeyStore("d://client.p12", "123456");
|
||||||
|
RSAPublicKey publicKey = RSAUtil.getPublicKey(keyStore);
|
||||||
|
RSAUtil.getPrivateKey(keyStore, "123456");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rsaDecodeFileTest() throws Exception {
|
||||||
|
|
||||||
|
KeyStore keyStore = RSAUtil.getKeyStore("d://client.p12", "123456");
|
||||||
|
RSAPublicKey publicKey = RSAUtil.getPublicKey(keyStore);
|
||||||
|
RSAPrivateKey privateKey = RSAUtil.getPrivateKey(keyStore, "123456");
|
||||||
|
String srcFile = "d://demo.pdf", encodeFile = "d://demo_encode.pdf", decodeFile = "d://demo_decode.pdf";
|
||||||
|
String fileHash = HashUtil.hash(new FileInputStream(srcFile), HashUtil.MD5, HashUtil.HEX);
|
||||||
|
RSAUtil.encryptByPublicKey(new FileInputStream(srcFile), publicKey, new FileOutputStream(encodeFile));
|
||||||
|
RSAUtil.decryptByPrivateKey(new FileInputStream(encodeFile), privateKey, new FileOutputStream(decodeFile));
|
||||||
|
|
||||||
|
String fileEncodeHash = HashUtil.hash(new FileInputStream(decodeFile), HashUtil.MD5, HashUtil.HEX);
|
||||||
|
System.out.println(fileHash.equals(fileEncodeHash));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user