新增utils和更改目录层级
This commit is contained in:
parent
8f84335d32
commit
c17cc727e7
17
dependeicnes/pom.xml
Normal file
17
dependeicnes/pom.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?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">
|
||||
<parent>
|
||||
<artifactId>zyjblogs-parent</artifactId>
|
||||
<groupId>cn.zyjblogs</groupId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>zyjblogs-dependencies</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>zyjblogs-cloud-dependencies</module>
|
||||
</modules>
|
||||
</project>
|
Binary file not shown.
16
pom.xml
16
pom.xml
@ -23,6 +23,12 @@
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<modules>
|
||||
<module>dependeicnes</module>
|
||||
<module>server</module>
|
||||
<module>stater</module>
|
||||
<module>utils</module>
|
||||
</modules>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License, Version 2.0</name>
|
||||
@ -281,11 +287,11 @@
|
||||
<!-- <artifactId>hutool-all</artifactId>-->
|
||||
<!-- <version>${hutool.version}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>${qrcode-zxing.version}</version>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.google.zxing</groupId>-->
|
||||
<!-- <artifactId>core</artifactId>-->
|
||||
<!-- <version>${qrcode-zxing.version}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
|
20
server/pom.xml
Normal file
20
server/pom.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?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>
|
||||
<parent>
|
||||
<artifactId>zyjblogs-cloud-dependencies</artifactId>
|
||||
<groupId>cn.zyjblogs</groupId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<artifactId>zyjblogs-server</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>zyjblogs-gateway</module>
|
||||
<module>zyjblogs-oauth</module>
|
||||
<module>zyjblogs-rbac</module>
|
||||
<module>zyjblogs-sms</module>
|
||||
</modules>
|
||||
</project>
|
26
stater/pom.xml
Normal file
26
stater/pom.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<?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">
|
||||
<parent>
|
||||
<artifactId>zyjblogs-parent</artifactId>
|
||||
<groupId>cn.zyjblogs</groupId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>zyjblogs-starter</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>zyjblogs-common-spring-boot-starter</module>
|
||||
<module>zyjblogs-feign-spring-boot-starter</module>
|
||||
<module>zyjblogs-minio-spring-boot-starter</module>
|
||||
<module>zyjblogs-mybatisplus-spring-boot-starter</module>
|
||||
<module>zyjblogs-oauth-spring-boot-starter</module>
|
||||
<module>zyjblogs-rabbitmq-spring-boot-starter</module>
|
||||
<module>zyjblogs-redis-spring-boot-starter</module>
|
||||
<module>zyjblogs-sms-spring-boot-starter</module>
|
||||
<module>zyjblogs-web-spring-boot-starter</module>
|
||||
</modules>
|
||||
</project>
|
@ -30,6 +30,11 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.zyjblogs</groupId>
|
||||
<artifactId>sm-crypto-utils</artifactId>
|
||||
<version>1.0.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
|
@ -1,5 +1,4 @@
|
||||
package cn.zyjblogs.starter.common.entity.constant;
|
||||
|
||||
public class CommonConstant {
|
||||
public static final Integer IS_DELETED = 1;
|
||||
public static final Integer NO_DELETED = 0;
|
||||
|
@ -1,5 +1,4 @@
|
||||
package cn.zyjblogs.starter.common.entity.constant;
|
||||
|
||||
/**
|
||||
* @author zhuyijun
|
||||
*/
|
||||
@ -7,7 +6,7 @@ public class CommonRedisKeyConstant {
|
||||
/**
|
||||
* 授权码
|
||||
*/
|
||||
public final static String AUTHORIZATION_CODE = "OAUTH:AUTHORIZATION_CODE";
|
||||
public static final String AUTHORIZATION_CODE = "OAUTH:AUTHORIZATION_CODE";
|
||||
/**
|
||||
* rsa
|
||||
*/
|
||||
|
@ -103,8 +103,4 @@ public enum MobileRegularExp {
|
||||
return isMobileNumber;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(MobileRegularExp.isMobileNumber("13476152541"));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
package cn.zyjblogs.starter.common.utils.crypto.sm;
|
||||
|
||||
public class SmException extends RuntimeException {
|
||||
public SmException() {
|
||||
}
|
||||
|
||||
public SmException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SmException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public SmException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public SmException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
@ -1,395 +0,0 @@
|
||||
package cn.zyjblogs.starter.common.utils.crypto.sm.sm2;
|
||||
|
||||
import cn.zyjblogs.starter.common.utils.crypto.sm.SmException;
|
||||
import org.bouncycastle.asn1.gm.GMNamedCurves;
|
||||
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
|
||||
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
|
||||
import org.bouncycastle.crypto.params.*;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
|
||||
import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Signature;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Base64;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 国密SM2非对称加密算法
|
||||
*/
|
||||
public class SM2 {
|
||||
|
||||
public static final String CRYPTO_NAME_SM2 = "sm2p256v1";
|
||||
private static byte SM2_CIPHER_FIRST_BIT = 4;
|
||||
|
||||
public enum EncodeType {
|
||||
UTF8,
|
||||
HEX,
|
||||
BASE64
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成SM2公私钥对
|
||||
* <p>
|
||||
* BC库使用的公钥=64个字节+1个字节(04标志位),BC库使用的私钥=32个字节
|
||||
* SM2秘钥的组成部分有 私钥D,公钥X,公钥Y, 他们都可以用长度为64的16进制的HEX串表示,
|
||||
* SM2公钥并不是直接由X+Y表示, 而是额外添加了一个头,当启用压缩时:公钥=有头+公钥X,即省略了公钥Y的部分
|
||||
*
|
||||
* @param compressed 是否压缩公钥(加密解密都使用BC库才能使用压缩)
|
||||
* @return SM2 HEX字符串格式秘钥对
|
||||
*/
|
||||
public static SM2KeyPair generateSm2Keys(boolean compressed) {
|
||||
|
||||
// 获取一条SM2曲线参数
|
||||
X9ECParameters sm2ECParameters = GMNamedCurves.getByName(CRYPTO_NAME_SM2);
|
||||
// 构造domain参数
|
||||
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
|
||||
|
||||
// 创建秘钥对生成器
|
||||
ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
|
||||
// 初始化生成器,带上随机数
|
||||
keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, new SecureRandom()));
|
||||
// 生成秘钥对
|
||||
AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
|
||||
|
||||
// 把公钥转换为椭圆点
|
||||
ECPublicKeyParameters publicKeyParameters = (ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic();
|
||||
ECPoint ecPoint = publicKeyParameters.getQ();
|
||||
|
||||
// 把公钥转换为HEX
|
||||
// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04,默认压缩公钥
|
||||
String publicKey = Hex.toHexString(ecPoint.getEncoded(compressed)).toUpperCase(Locale.ROOT);
|
||||
|
||||
// 把私钥转换为HEX
|
||||
ECPrivateKeyParameters privateKeyParameters = (ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate();
|
||||
BigInteger intPrivateKey = privateKeyParameters.getD();
|
||||
String privateKey = intPrivateKey.toString(16).toUpperCase(Locale.ROOT);
|
||||
|
||||
// 构造HEX秘钥对,并返回
|
||||
return new SM2KeyPair(publicKey, privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* SM2加密算法
|
||||
*
|
||||
* @param pubKey 公钥
|
||||
* @param data 待加密的数据
|
||||
* @return 密文,BC库产生的密文带由04标识符,与非BC库对接时需要去掉开头的04
|
||||
*/
|
||||
public static String encrypt(String pubKey, String data) {
|
||||
|
||||
// 按国密排序标准加密
|
||||
return encrypt(pubKey, data, SM2EngineExtend.CIPHER_MODE_NORM, EncodeType.UTF8, EncodeType.HEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* SM2加密算法
|
||||
*
|
||||
* @param pubKey 公钥
|
||||
* @param data 待加密的数据
|
||||
* @param cipherMode 密文排列方式0-C1C2C3;1-C1C3C2;
|
||||
* @return 密文,BC库产生的密文带由04标识符,与非BC库对接时需要去掉开头的04
|
||||
*/
|
||||
public static String encrypt(String pubKey, String data, int cipherMode, EncodeType inputType, EncodeType outType) {
|
||||
try {
|
||||
// 非压缩模式公钥对接放是128位HEX秘钥,需要为BC库加上“04”标记
|
||||
if (pubKey.length() == 128) {
|
||||
pubKey = "04" + pubKey;
|
||||
}
|
||||
// 获取一条SM2曲线参数
|
||||
X9ECParameters sm2ECParameters = GMNamedCurves.getByName(CRYPTO_NAME_SM2);
|
||||
// 构造ECC算法参数,曲线方程、椭圆曲线G点、大整数N
|
||||
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
|
||||
//提取公钥点
|
||||
ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(pubKey));
|
||||
// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
|
||||
ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
|
||||
|
||||
SM2EngineExtend sm2Engine = new SM2EngineExtend();
|
||||
// 设置sm2为加密模式
|
||||
sm2Engine.init(true, cipherMode, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));
|
||||
byte[] in;
|
||||
if (EncodeType.HEX.equals(inputType)) {
|
||||
in = Hex.decode(data);
|
||||
} else if (EncodeType.BASE64.equals(inputType)) {
|
||||
in = Base64.getDecoder().decode(data.getBytes(StandardCharsets.UTF_8));
|
||||
} else {
|
||||
in = data.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
byte[] arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);
|
||||
if (EncodeType.BASE64.equals(outType)) {
|
||||
byte[] base64Bytes = Base64.getEncoder().encode(arrayOfBytes);
|
||||
return new String(base64Bytes, StandardCharsets.UTF_8);
|
||||
} else if (EncodeType.HEX.equals(outType)) {
|
||||
return Hex.toHexString(arrayOfBytes).toUpperCase(Locale.ROOT);
|
||||
} else {
|
||||
return new String(arrayOfBytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new SmException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static byte[] addBitIfNeed(byte[] base64Decode) {
|
||||
byte first = base64Decode[0];
|
||||
if (first == SM2_CIPHER_FIRST_BIT) {
|
||||
return base64Decode;
|
||||
} else {
|
||||
byte[] finalByte = new byte[base64Decode.length + 1];
|
||||
finalByte[0] = SM2_CIPHER_FIRST_BIT;
|
||||
System.arraycopy(base64Decode, 0, finalByte, 1, base64Decode.length);
|
||||
return finalByte;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SM2解密算法
|
||||
*
|
||||
* @param priKey 私钥
|
||||
* @param cipherData 密文数据
|
||||
* @return 解密后的数据
|
||||
*/
|
||||
public static String decrypt(String priKey, String cipherData) {
|
||||
// // 按国密排序标准解密
|
||||
return decrypt(priKey, cipherData, SM2EngineExtend.CIPHER_MODE_NORM, EncodeType.HEX, EncodeType.UTF8);
|
||||
}
|
||||
|
||||
/**
|
||||
* SM2解密算法
|
||||
*
|
||||
* @param priKey 私钥
|
||||
* @param cipherData 密文数据
|
||||
* @param cipherMode 密文排列方式 0-C1C2C3;1-C1C3C2;
|
||||
* @return 解密后的数据
|
||||
*/
|
||||
public static String decrypt(String priKey, String cipherData, int cipherMode, EncodeType inputType, EncodeType outType) {
|
||||
|
||||
try {
|
||||
byte[] cipherDataByte;
|
||||
if (EncodeType.HEX.equals(inputType)) {
|
||||
// 使用BC库加解密时密文以04开头,传入的密文前面没有04则补上
|
||||
if (!cipherData.startsWith("04")) {
|
||||
cipherData = "04" + cipherData;
|
||||
}
|
||||
cipherDataByte = Hex.decode(cipherData);
|
||||
} else if (EncodeType.BASE64.equals(inputType)) {
|
||||
cipherDataByte = Base64.getDecoder().decode(cipherData);
|
||||
cipherDataByte = addBitIfNeed(cipherDataByte);
|
||||
} else {
|
||||
cipherDataByte = cipherData.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
//获取一条SM2曲线参数
|
||||
X9ECParameters sm2ECParameters = GMNamedCurves.getByName(CRYPTO_NAME_SM2);
|
||||
//构造domain参数
|
||||
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
|
||||
|
||||
BigInteger privateKeyD = new BigInteger(priKey, 16);
|
||||
ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);
|
||||
|
||||
SM2EngineExtend sm2Engine = new SM2EngineExtend();
|
||||
// 设置sm2为解密模式
|
||||
sm2Engine.init(false, cipherMode, privateKeyParameters);
|
||||
|
||||
byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
|
||||
if (EncodeType.HEX.equals(outType)) {
|
||||
return Hex.toHexString(arrayOfBytes).toUpperCase(Locale.ROOT);
|
||||
} else if (EncodeType.BASE64.equals(outType)) {
|
||||
byte[] base64Bytes = Base64.getEncoder().encode(arrayOfBytes);
|
||||
return new String(base64Bytes, StandardCharsets.UTF_8);
|
||||
} else {
|
||||
return new String(arrayOfBytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new SmException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 签名
|
||||
*
|
||||
* @param priKey 私钥
|
||||
* @param plainText 待签名文本
|
||||
* @return 签名
|
||||
*/
|
||||
public static String sign(String priKey, String plainText) {
|
||||
|
||||
try {
|
||||
// 构造提供器
|
||||
BouncyCastleProvider provider = new BouncyCastleProvider();
|
||||
// 获取一条SM2曲线参数
|
||||
X9ECParameters sm2ECParameters = GMNamedCurves.getByName(CRYPTO_NAME_SM2);
|
||||
// 构造椭圆参数规格
|
||||
ECParameterSpec ecParameterSpec = new ECParameterSpec(sm2ECParameters.getCurve(),
|
||||
sm2ECParameters.getG(), sm2ECParameters.getN(), sm2ECParameters.getH());
|
||||
// 创建Key工厂
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
|
||||
|
||||
// 创建签名对象
|
||||
Signature signature = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), provider);
|
||||
|
||||
// 将私钥HEX字符串转换为X值
|
||||
BigInteger bigInteger = new BigInteger(priKey, 16);
|
||||
// 生成SM2私钥
|
||||
BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) keyFactory.generatePrivate(new ECPrivateKeySpec(bigInteger,
|
||||
ecParameterSpec));
|
||||
|
||||
// 初始化为签名状态
|
||||
signature.initSign(bcecPrivateKey);
|
||||
// 传入签名字节
|
||||
signature.update(plainText.getBytes());
|
||||
|
||||
// 签名
|
||||
return Hex.toHexString(signature.sign()).toUpperCase(Locale.ROOT);
|
||||
} catch (Exception e) {
|
||||
throw new SmException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 验签
|
||||
*
|
||||
* @param pubKey 公钥
|
||||
* @param plainText 明文
|
||||
* @param signatureValue 签名
|
||||
* @return 验签结果
|
||||
*/
|
||||
public static boolean verify(String pubKey, String plainText, String signatureValue) {
|
||||
|
||||
// 非压缩模式公钥对接放是128位HEX秘钥,需要为BC库加上“04”标记
|
||||
if (pubKey.length() == 128) {
|
||||
pubKey = "04" + pubKey;
|
||||
}
|
||||
|
||||
try {
|
||||
// 构造提供器
|
||||
BouncyCastleProvider provider = new BouncyCastleProvider();
|
||||
|
||||
// 获取一条SM2曲线参数
|
||||
X9ECParameters sm2ECParameters = GMNamedCurves.getByName(CRYPTO_NAME_SM2);
|
||||
// 构造椭圆参数规格
|
||||
ECParameterSpec ecParameterSpec = new ECParameterSpec(sm2ECParameters.getCurve(),
|
||||
sm2ECParameters.getG(), sm2ECParameters.getN(), sm2ECParameters.getH());
|
||||
// 创建Key工厂
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
|
||||
|
||||
// 创建签名对象
|
||||
Signature signature = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), provider);
|
||||
|
||||
// 将公钥HEX字符串转换为椭圆曲线对应的点
|
||||
ECPoint ecPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(pubKey));
|
||||
BCECPublicKey bcecPublicKey = (BCECPublicKey) keyFactory.generatePublic(new ECPublicKeySpec(ecPoint, ecParameterSpec));
|
||||
|
||||
// 初始化为验签状态
|
||||
signature.initVerify(bcecPublicKey);
|
||||
signature.update(plainText.getBytes());
|
||||
|
||||
return signature.verify(Hex.decode(signatureValue));
|
||||
} catch (Exception e) {
|
||||
throw new SmException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 证书验签
|
||||
*
|
||||
* @param certStr 证书串
|
||||
* @param plaintext 签名原文
|
||||
* @param signValueStr 签名产生签名值 此处的签名值实际上就是 R和S的sequence
|
||||
* @return 证书验证结果
|
||||
*/
|
||||
public static boolean certVerify(String certStr, String plaintext, String signValueStr) {
|
||||
|
||||
try {
|
||||
// 构造提供器
|
||||
BouncyCastleProvider provider = new BouncyCastleProvider();
|
||||
|
||||
// 解析证书
|
||||
byte[] signValue = Hex.decode(signValueStr);
|
||||
CertificateFactory factory = new CertificateFactory();
|
||||
X509Certificate certificate = (X509Certificate) factory
|
||||
.engineGenerateCertificate(new ByteArrayInputStream(Hex.decode(certStr)));
|
||||
|
||||
// 验证签名
|
||||
Signature signature = Signature.getInstance(certificate.getSigAlgName(), provider);
|
||||
signature.initVerify(certificate);
|
||||
signature.update(plaintext.getBytes());
|
||||
|
||||
return signature.verify(signValue);
|
||||
} catch (Exception e) {
|
||||
throw new SmException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String data = "dPhq2XdoMcgD5m7M0I51SX7MkzMerWMcPdBdv/tX8B5jOyM28n+CcXUn721/9N0ELVgC2P0eBRn4jD04rPScJd5izcC7+xXT5LUwbV2S6wc0g2RC8nkuZITc4rdrACPvNxd18b6y";
|
||||
String pub = "0417f347d7fa08ae6ad9bf8ef6ac6c313810e05044290f7c18dc9b913b252603505cf7cdbf7ac7d88de508e78bbc2d74cb28c0a90724ed4b751cc69bdfe55b68de";
|
||||
String pri = "73d76cf4f553535d6ec45478fb1581baa0c83e166b347af10ab129966d3f187f";
|
||||
String key = "0123456789abcdeffedcba9876543210";
|
||||
try {
|
||||
String decrypt2 = SM2.decrypt(pri, "BCWhJJ0BFPt/RuhS37sk22/5GuemkzG7kt+CLwRSz34taiKPjc0TDoY959dCf7C2cZJ2uzLoqRmcH/pV7uWGhPzTIZmKM8wPpVIeuN616dNVm+5/YpaQfcawis6KpJOeeU4fcyrYf9wcawtkow==", 1, SM2.EncodeType.BASE64, SM2.EncodeType.UTF8);
|
||||
System.out.println("-------------");
|
||||
System.out.println(decrypt2);
|
||||
String encrypt1 = SM2.encrypt(pub, decrypt2);
|
||||
System.out.println("-------------");
|
||||
System.out.println(encrypt1);
|
||||
String decrypt3 = SM2.decrypt(pri, encrypt1);
|
||||
System.out.println("aaa:" + decrypt3);
|
||||
String decrypt4 = SM2.encrypt(pub, decrypt3, 1, SM2.EncodeType.UTF8, SM2.EncodeType.BASE64);
|
||||
System.out.println(decrypt4);
|
||||
System.out.println("-----------");
|
||||
String decrypt5 = SM2.decrypt(pri, decrypt4, 1, SM2.EncodeType.BASE64, SM2.EncodeType.BASE64);
|
||||
System.out.println(decrypt5);
|
||||
String decrypt5_1 = SM2.encrypt(pub, decrypt5, 1, SM2.EncodeType.BASE64, SM2.EncodeType.BASE64);
|
||||
System.out.println(decrypt5_1);
|
||||
String decrypt5_2 = SM2.decrypt(pri, decrypt5_1, 1, SM2.EncodeType.BASE64, SM2.EncodeType.BASE64);
|
||||
System.out.println(decrypt5_2);
|
||||
System.out.println(new String(Base64.getDecoder().decode(decrypt5)));
|
||||
String decrypt6 = SM2.encrypt(pub, decrypt5, 1, SM2.EncodeType.BASE64, SM2.EncodeType.HEX);
|
||||
System.out.println(decrypt6);
|
||||
System.out.println("-----------");
|
||||
String decrypt7 = SM2.decrypt(pri, decrypt6, 1, SM2.EncodeType.HEX, SM2.EncodeType.UTF8);
|
||||
System.out.println(decrypt7);
|
||||
String decrypt8 = SM2.decrypt(pri, data, 1, EncodeType.BASE64, SM2.EncodeType.UTF8);
|
||||
System.out.println(decrypt8);
|
||||
String datanew = "BPCv4lM/sVXzEJ7uFkXrvuKUVFS3EU9uCkV9vhgJQb92cY3FWfIa1M1UtYxkbfleEdiZHZooh5DV3HaakkYsCTbR/lKF4FC3ZplGGf9rCbCuovf7fFf5TJwX2m83qkNMTuW4o9QdjOQu4MiFtYbTMMTSb/0kNKHkrT8mCSY+6yLg7XIHmzepoGiWhQ2KB9diF066YzjKNDGbP3u9/zoQBCFKr190G7F6NH042kfLPRrpV3IkewJbNKGCCQ0SIvNJ475beYq5jpRbug2WOsR8qLEsPsIl7SPXh0ezB1hLwgmqFqM/B3QbobKP+lFmtbjjIumLgdGM9OzmG82TFZM3k0piIYQPS6JPHjR3nqrnxpwYxn2bKUifnrrrM8smyoa99BzJ4IPnZ7/3oxLwkRFnMee8oyMy1WCab0k5OKmAM/dk2weflyhXyY5mxGYHjdjpsj9ipOcKjqF6LKobMxSAOpn+pRfywvJr/CKE1dcq7k1gK/xZozQVqyENoM3BEyVEYfEUHrI1pxG8/2ugYYXIN4jX6XqR8COxnJOS8XuPi8Ukqsx/E3EwgWEbI3PvtRRaiI4RNWyc1oMyNDr8Al5caf67cUo2pasoF8IrUlZtePBEAmITHfzVm9sCfGz4eNw5b2a5YSLofCYX7R6C0b/+69uutyhmLb3Na9TOyseTEYJcf0pzO8DHdWZDTldH8+swARdulURCBR3AMs2ePDnfJwMcEyNt1jpacVDSRPIVhxOcgdeD3juaYpiEYdVTPBHv+RJoOi6pv87ZheeDejjpGUMLAGEC/P+SpGdG8IT7THEPw16/hNK/lzqAzmYa7lkAH2WycWbnaBed3bHJbJBNjP9DsBpAf3V/PGreXNWeD66g+gCQDhyOUdiWqoaEoCLA7nkOcQqEeDZNegQn5ZfU/cW4yW1sxfb3CNzqxJaA/qayon+BeCYmy3FpA0SIkAbA0/qTG7VWg4u4kAQBG+FZ+lJ9Eaj9JaFiCgqfQRBMEoLuVdH24UeRljIfRptuYDcPydCFRzDWhYqwguPeGluEb9JO8eESZ+waX48xtniMvxbQ0CzfDlMWJwO9EiPJyIj2b86/ibBfSq9vuWwSdeLLL2Jvjn5LB9cwzSU8yQzLgle9YGSC0sbQIMuyFHUhDUVyFTVPE3/bYpotuetoeQVMYvLe9H73825Q6PxY+CCMHb0Jqjva2JAf6emYGx1vb5MGoJzoxz/7lSxJ56I9yMfrwLMljToMSufcV+bhQYb6r468qtQ10eXlKom/I8ZqZIJHsIaZBxsxJe1UyxqGitasg55gqNLLDwv+6UmnvGT/B6g9bmfc363/gO5mQlJfZSlpUodZrXMCYZmNI1ZZFRQbu5aEdtL9M2lXeCnTJa2GDOqpbG5I3aWVcepUcCsx4375bJOo3g24dwhzTCyh7/dW9sPhqb3SSXb/l+JxFzUoBXzxQgpBzakwq1uGrCKYPkNfYrmxRej87ZGgQFGlCVjEUHwRhvnkLHTXeP2f3b8zCeu+6us=";
|
||||
String decrypt9 = SM2.decrypt(pri, datanew, 1, EncodeType.BASE64, SM2.EncodeType.UTF8);
|
||||
System.out.println(decrypt9);
|
||||
SM2KeyPair sm2KeyPair = generateSm2Keys(true);
|
||||
System.out.println("公钥\n" + sm2KeyPair.getPublicKey());
|
||||
System.out.println("私钥\n" + sm2KeyPair.getPrivateKey());
|
||||
String a = SM2.encrypt(sm2KeyPair.getPublicKey(), "好吃啊");
|
||||
System.out.println(a);
|
||||
System.out.println(SM2.decrypt(sm2KeyPair.getPrivateKey(), a));
|
||||
String data1 = "c4eba3e104f1858a4ad0eeea125537e80ad28d10e6b084c26a1c318dba4bec334bf246cdd3900bc35e20a2c8bf6948a050f5c9077b0617db7d98489c37f3cc8aebebf98a39c0f127e6d37a8ec31f3968f07c7a01b8d3e1a554d53b75de8ede6d50050d8a1c60e976e74829b0f32bc049edf7";
|
||||
System.out.println(SM2.decrypt("69A124C827FA42573FF1047368BA8428C04A04B5B947BBD202956CF1A78D1FB0", data1, 1, EncodeType.HEX, EncodeType.UTF8));
|
||||
String sign = SM2.sign("69A124C827FA42573FF1047368BA8428C04A04B5B947BBD202956CF1A78D1FB0", data1);
|
||||
System.out.println("私钥签名:\n" + sign);
|
||||
System.out.println(SM2.verify("032AB168CD73ED25824DB20B5F190C7C54971BC821450DEE0AC84C779CF3A9F897", data1, sign));
|
||||
String base64 = "BTcOfUO9+YxUeVl3nAkrebsu7H1scPwAppe0slpHLSMa4+2GhvW4ZTr++8AFT5pND3rcLtU76bzoIencvojqhvV8drMjGA6yPbp+6dg/KABNcE0SRwHhzNcTrf5SxTC4yI1TIuvo";
|
||||
String decrypt10 = SM2.decrypt(pri, base64, 1, SM2.EncodeType.BASE64, EncodeType.UTF8);
|
||||
System.out.println(decrypt10);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,293 +0,0 @@
|
||||
package cn.zyjblogs.starter.common.utils.crypto.sm.sm2;
|
||||
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
import org.bouncycastle.crypto.Digest;
|
||||
import org.bouncycastle.crypto.InvalidCipherTextException;
|
||||
import org.bouncycastle.crypto.digests.SM3Digest;
|
||||
import org.bouncycastle.crypto.params.*;
|
||||
import org.bouncycastle.math.ec.ECConstants;
|
||||
import org.bouncycastle.math.ec.ECFieldElement;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.BigIntegers;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class SM2EngineExtend {
|
||||
private final Digest digest;
|
||||
|
||||
/**
|
||||
* 是否为加密模式
|
||||
*/
|
||||
private boolean forEncryption;
|
||||
private ECKeyParameters ecKey;
|
||||
private ECDomainParameters ecParams;
|
||||
private int curveLength;
|
||||
private SecureRandom random;
|
||||
/**
|
||||
* 密文排序方式
|
||||
*/
|
||||
private int cipherMode;
|
||||
|
||||
/**
|
||||
* BC库默认排序方式-C1C2C3
|
||||
*/
|
||||
public static int CIPHER_MODE_BC = 0;
|
||||
/**
|
||||
* 国密标准排序方式-C1C3C2
|
||||
*/
|
||||
public static int CIPHER_MODE_NORM = 1;
|
||||
|
||||
public SM2EngineExtend() {
|
||||
this(new SM3Digest());
|
||||
}
|
||||
|
||||
public SM2EngineExtend(Digest digest) {
|
||||
this.digest = digest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置密文排序方式
|
||||
*
|
||||
* @param cipherMode 排序方式
|
||||
*/
|
||||
public void setCipherMode(int cipherMode) {
|
||||
this.cipherMode = cipherMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认初始化方法,使用国密排序标准
|
||||
*
|
||||
* @param forEncryption - 是否以加密模式初始化
|
||||
* @param param - 曲线参数
|
||||
*/
|
||||
public void init(boolean forEncryption, CipherParameters param) {
|
||||
init(forEncryption, CIPHER_MODE_NORM, param);
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认初始化方法,使用国密排序标准
|
||||
*
|
||||
* @param forEncryption 是否以加密模式初始化
|
||||
* @param cipherMode 加密数据排列模式:1-标准排序;0-BC默认排序
|
||||
* @param param 曲线参数
|
||||
*/
|
||||
public void init(boolean forEncryption, int cipherMode, CipherParameters param) {
|
||||
this.forEncryption = forEncryption;
|
||||
this.cipherMode = cipherMode;
|
||||
if (forEncryption) {
|
||||
ParametersWithRandom rParam = (ParametersWithRandom) param;
|
||||
|
||||
ecKey = (ECKeyParameters) rParam.getParameters();
|
||||
ecParams = ecKey.getParameters();
|
||||
|
||||
ECPoint s = ((ECPublicKeyParameters) ecKey).getQ().multiply(ecParams.getH());
|
||||
if (s.isInfinity()) {
|
||||
throw new IllegalArgumentException("invalid key: [h]Q at infinity");
|
||||
}
|
||||
|
||||
random = rParam.getRandom();
|
||||
} else {
|
||||
ecKey = (ECKeyParameters) param;
|
||||
ecParams = ecKey.getParameters();
|
||||
}
|
||||
|
||||
curveLength = (ecParams.getCurve().getFieldSize() + 7) / 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密或解密输入数据
|
||||
*
|
||||
* @param in 输入数据字节
|
||||
* @param inOff 偏移
|
||||
* @param inLen 长度
|
||||
* @return 解析后字节
|
||||
* @throws InvalidCipherTextException 异常
|
||||
*/
|
||||
public byte[] processBlock(byte[] in, int inOff, int inLen) throws InvalidCipherTextException {
|
||||
if (forEncryption) {
|
||||
// 加密
|
||||
return encrypt(in, inOff, inLen);
|
||||
} else {
|
||||
return decrypt(in, inOff, inLen);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密实现,根据cipherMode输出指定排列的结果,默认按标准方式排列
|
||||
*
|
||||
* @param in 输入数据字节
|
||||
* @param inOff 偏移
|
||||
* @param inLen 长度
|
||||
* @return 解析后字节
|
||||
*/
|
||||
private byte[] encrypt(byte[] in, int inOff, int inLen) {
|
||||
byte[] c2 = new byte[inLen];
|
||||
|
||||
System.arraycopy(in, inOff, c2, 0, c2.length);
|
||||
|
||||
byte[] c1;
|
||||
ECPoint kPB;
|
||||
do {
|
||||
BigInteger k = nextK();
|
||||
|
||||
ECPoint c1P = ecParams.getG().multiply(k).normalize();
|
||||
|
||||
c1 = c1P.getEncoded(false);
|
||||
|
||||
kPB = ((ECPublicKeyParameters) ecKey).getQ().multiply(k).normalize();
|
||||
|
||||
kdf(digest, kPB, c2);
|
||||
}
|
||||
while (notEncrypted(c2, in, inOff));
|
||||
|
||||
byte[] c3 = new byte[digest.getDigestSize()];
|
||||
|
||||
addFieldElement(digest, kPB.getAffineXCoord());
|
||||
digest.update(in, inOff, inLen);
|
||||
addFieldElement(digest, kPB.getAffineYCoord());
|
||||
|
||||
digest.doFinal(c3, 0);
|
||||
if (cipherMode == CIPHER_MODE_NORM) {
|
||||
return Arrays.concatenate(c1, c3, c2);
|
||||
}
|
||||
return Arrays.concatenate(c1, c2, c3);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密实现,默认按标准排列方式解密,解密时解出c2部分原文并校验c3部分
|
||||
*
|
||||
* @param in 输入数据字节
|
||||
* @param inOff 偏移
|
||||
* @param inLen 长度
|
||||
* @return 解析后字节
|
||||
* @throws InvalidCipherTextException
|
||||
*/
|
||||
private byte[] decrypt(byte[] in, int inOff, int inLen)
|
||||
throws InvalidCipherTextException {
|
||||
byte[] c1 = new byte[curveLength * 2 + 1];
|
||||
|
||||
System.arraycopy(in, inOff, c1, 0, c1.length);
|
||||
|
||||
ECPoint c1P = ecParams.getCurve().decodePoint(c1);
|
||||
|
||||
ECPoint s = c1P.multiply(ecParams.getH());
|
||||
if (s.isInfinity()) {
|
||||
throw new InvalidCipherTextException("[h]C1 at infinity");
|
||||
}
|
||||
|
||||
c1P = c1P.multiply(((ECPrivateKeyParameters) ecKey).getD()).normalize();
|
||||
|
||||
byte[] c2 = new byte[inLen - c1.length - digest.getDigestSize()];
|
||||
if (cipherMode == CIPHER_MODE_BC) {
|
||||
System.arraycopy(in, inOff + c1.length, c2, 0, c2.length);
|
||||
} else {
|
||||
// C1 C3 C2
|
||||
System.arraycopy(in, inOff + c1.length + digest.getDigestSize(), c2, 0, c2.length);
|
||||
}
|
||||
|
||||
kdf(digest, c1P, c2);
|
||||
|
||||
byte[] c3 = new byte[digest.getDigestSize()];
|
||||
|
||||
addFieldElement(digest, c1P.getAffineXCoord());
|
||||
digest.update(c2, 0, c2.length);
|
||||
addFieldElement(digest, c1P.getAffineYCoord());
|
||||
|
||||
digest.doFinal(c3, 0);
|
||||
|
||||
int check = 0;
|
||||
// 检查密文输入值C3部分和由摘要生成的C3是否一致
|
||||
if (cipherMode == CIPHER_MODE_BC) {
|
||||
for (int i = 0; i != c3.length; i++) {
|
||||
check |= c3[i] ^ in[c1.length + c2.length + i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i != c3.length; i++) {
|
||||
check |= c3[i] ^ in[c1.length + i];
|
||||
}
|
||||
}
|
||||
|
||||
clearBlock(c1);
|
||||
clearBlock(c3);
|
||||
|
||||
if (check != 0) {
|
||||
clearBlock(c2);
|
||||
throw new InvalidCipherTextException("invalid cipher text");
|
||||
}
|
||||
|
||||
return c2;
|
||||
}
|
||||
|
||||
private boolean notEncrypted(byte[] encData, byte[] in, int inOff) {
|
||||
for (int i = 0; i != encData.length; i++) {
|
||||
if (encData[i] != in[inOff]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void kdf(Digest digest, ECPoint c1, byte[] encData) {
|
||||
int ct = 1;
|
||||
int v = digest.getDigestSize();
|
||||
|
||||
byte[] buf = new byte[digest.getDigestSize()];
|
||||
int off = 0;
|
||||
|
||||
for (int i = 1; i <= ((encData.length + v - 1) / v); i++) {
|
||||
addFieldElement(digest, c1.getAffineXCoord());
|
||||
addFieldElement(digest, c1.getAffineYCoord());
|
||||
digest.update((byte) (ct >> 24));
|
||||
digest.update((byte) (ct >> 16));
|
||||
digest.update((byte) (ct >> 8));
|
||||
digest.update((byte) ct);
|
||||
|
||||
digest.doFinal(buf, 0);
|
||||
|
||||
if (off + buf.length < encData.length) {
|
||||
xor(encData, buf, off, buf.length);
|
||||
} else {
|
||||
xor(encData, buf, off, encData.length - off);
|
||||
}
|
||||
|
||||
off += buf.length;
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
|
||||
private void xor(byte[] data, byte[] kdfOut, int dOff, int dRemaining) {
|
||||
for (int i = 0; i != dRemaining; i++) {
|
||||
data[dOff + i] ^= kdfOut[i];
|
||||
}
|
||||
}
|
||||
|
||||
private BigInteger nextK() {
|
||||
int qBitLength = ecParams.getN().bitLength();
|
||||
|
||||
BigInteger k;
|
||||
do {
|
||||
k = new BigInteger(qBitLength, random);
|
||||
}
|
||||
while (k.equals(ECConstants.ZERO) || k.compareTo(ecParams.getN()) >= 0);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
private void addFieldElement(Digest digest, ECFieldElement v) {
|
||||
byte[] p = BigIntegers.asUnsignedByteArray(curveLength, v.toBigInteger());
|
||||
|
||||
digest.update(p, 0, p.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* clear possible sensitive data
|
||||
*/
|
||||
private void clearBlock(
|
||||
byte[] block) {
|
||||
Arrays.fill(block, (byte) 0);
|
||||
}
|
||||
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
package cn.zyjblogs.starter.common.utils.crypto.sm.sm2;
|
||||
|
||||
public class SM2KeyPair {
|
||||
/**
|
||||
* 公钥
|
||||
*/
|
||||
private String publicKey;
|
||||
/**
|
||||
* 私钥
|
||||
*/
|
||||
private String privateKey;
|
||||
|
||||
public SM2KeyPair(String publicKey, String privateKey) {
|
||||
this.publicKey = publicKey;
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
public SM2KeyPair() {
|
||||
}
|
||||
|
||||
public String getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public void setPublicKey(String publicKey) {
|
||||
this.publicKey = publicKey;
|
||||
}
|
||||
|
||||
public String getPrivateKey() {
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
public void setPrivateKey(String privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package cn.zyjblogs.starter.common.utils.crypto.sm.sm3;
|
||||
|
||||
import org.bouncycastle.crypto.digests.SM3Digest;
|
||||
import org.bouncycastle.crypto.macs.HMac;
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 国密SM3摘要算法
|
||||
*/
|
||||
public class SM3 {
|
||||
|
||||
public static String digest(String input) {
|
||||
// 创建摘要器
|
||||
SM3Digest sm3Digest = new SM3Digest();
|
||||
// 解析输入数据
|
||||
byte[] bytes = input.getBytes(StandardCharsets.UTF_8);
|
||||
// 构造输出数据缓冲区
|
||||
byte[] out = new byte[32];
|
||||
// 设置待摘要字节数据
|
||||
sm3Digest.update(bytes, 0, bytes.length);
|
||||
// 执行摘要
|
||||
sm3Digest.doFinal(out, 0);
|
||||
// 返回HEX字符串
|
||||
return Hex.toHexString(out).toUpperCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
|
||||
public static String hmac(String key, String data) {
|
||||
byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
|
||||
KeyParameter keyParameter = new KeyParameter(key.getBytes(StandardCharsets.UTF_8));
|
||||
SM3Digest digest = new SM3Digest();
|
||||
HMac mac = new HMac(digest);
|
||||
mac.init(keyParameter);
|
||||
mac.update(bytes, 0, bytes.length);
|
||||
byte[] out = new byte[32];
|
||||
mac.doFinal(out, 0);
|
||||
return Hex.toHexString(out).toUpperCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
public static boolean verify(String data, String hash) {
|
||||
String srcHash = digest(data);
|
||||
return hash.equals(srcHash);
|
||||
}
|
||||
|
||||
public static boolean verify(String key, String data, String hmac) {
|
||||
String srcHmac = hmac(key, data);
|
||||
return hmac.equals(srcHmac);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String a = SM3.digest("aaaa");
|
||||
System.out.println(a);
|
||||
System.out.println(verify("aaaa", a));
|
||||
}
|
||||
}
|
@ -1,209 +0,0 @@
|
||||
package cn.zyjblogs.starter.common.utils.crypto.sm.sm4;
|
||||
|
||||
import cn.zyjblogs.starter.common.utils.crypto.sm.SmException;
|
||||
import cn.zyjblogs.starter.common.utils.crypto.sm.sm3.SM3;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 国密SM4对称加密算法
|
||||
*/
|
||||
public class SM4 {
|
||||
// 算法
|
||||
private static final String SM4_ALGORITHM = "SM4";
|
||||
// 密钥长度128位
|
||||
private static final int DEFAULT_KEY_SIZE = 128;
|
||||
// 变换规则(CBC模式)
|
||||
private static final String TRANSFORMATION_CBC = "SM4/CBC/PKCS5Padding";
|
||||
// 变换规则(ECB模式)
|
||||
private static final String TRANSFORMATION_ECB = "SM4/ECB/PKCS5Padding";
|
||||
|
||||
// 追加提BC提供器
|
||||
static {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成默认Key
|
||||
*
|
||||
* @return key
|
||||
*/
|
||||
public static String generateKey() {
|
||||
return generateKey(DEFAULT_KEY_SIZE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成制定长度Key或vi
|
||||
*
|
||||
* @param keySize key 长度
|
||||
* @return key
|
||||
*/
|
||||
public static String generateKey(int keySize) {
|
||||
|
||||
try {
|
||||
// 创建Key生成器
|
||||
KeyGenerator kg = KeyGenerator.getInstance(SM4_ALGORITHM, BouncyCastleProvider.PROVIDER_NAME);
|
||||
|
||||
// 初始化
|
||||
kg.init(keySize, new SecureRandom());
|
||||
|
||||
// 生成Key
|
||||
byte[] encoded = kg.generateKey().getEncoded();
|
||||
|
||||
// 返回HEX字符串
|
||||
return Hex.toHexString(encoded).toUpperCase(Locale.ROOT);
|
||||
} catch (Exception e) {
|
||||
throw new SmException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 加密(CBC模式)
|
||||
*
|
||||
* @param keyHex 秘钥HEX字符串
|
||||
* @param planText 明文字符串
|
||||
* @param ivHex 向量HEX字符串
|
||||
* @return 加密后的HEX字符串
|
||||
*/
|
||||
public static String encrypt(String keyHex, String planText, String ivHex) {
|
||||
|
||||
try {
|
||||
// 创建加密对象
|
||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION_CBC);
|
||||
// 创建加密规则
|
||||
SecretKeySpec keySpec = new SecretKeySpec(Hex.decode(keyHex), SM4_ALGORITHM);
|
||||
// 创建IV向量
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(Hex.decode(ivHex));
|
||||
|
||||
// 初始化
|
||||
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
|
||||
|
||||
// 调用加密方法
|
||||
byte[] outputBytes = cipher.doFinal(planText.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
return Hex.toHexString(outputBytes).toUpperCase(Locale.ROOT);
|
||||
} catch (Exception e) {
|
||||
throw new SmException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密(CBC模式)
|
||||
*
|
||||
* @param keyHex 秘钥HEX字符串
|
||||
* @param cipherDataHex 密文的HEX字符串
|
||||
* @param ivHex 向量HEX字符串
|
||||
* @return 解密后的明文
|
||||
*/
|
||||
public static String decrypt(String keyHex, String cipherDataHex, String ivHex) {
|
||||
|
||||
try {
|
||||
// 创建加密对象
|
||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION_CBC);
|
||||
// 创建加密规则
|
||||
SecretKeySpec keySpec = new SecretKeySpec(Hex.decode(keyHex), SM4_ALGORITHM);
|
||||
// 创建IV向量
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(Hex.decode(ivHex));
|
||||
|
||||
// 初始化
|
||||
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
|
||||
// 调用加密方法
|
||||
byte[] outputBytes = cipher.doFinal(Hex.decode(cipherDataHex));
|
||||
|
||||
return new String(outputBytes, StandardCharsets.UTF_8);
|
||||
} catch (Exception e) {
|
||||
throw new SmException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密(ECB模式)
|
||||
*
|
||||
* @param keyHex 秘钥HEX字符串
|
||||
* @param planText 明文字符串
|
||||
* @return 加密后的HEX字符串
|
||||
*/
|
||||
public static String encrypt(String keyHex, String planText) {
|
||||
|
||||
try {
|
||||
// 创建加密对象
|
||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION_ECB);
|
||||
// 创建加密规则
|
||||
SecretKeySpec keySpec = new SecretKeySpec(Hex.decode(keyHex), SM4_ALGORITHM);
|
||||
|
||||
// 初始化
|
||||
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
|
||||
|
||||
// 调用加密方法
|
||||
byte[] outputBytes = cipher.doFinal(planText.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
return Hex.toHexString(outputBytes).toUpperCase(Locale.ROOT);
|
||||
} catch (Exception e) {
|
||||
throw new SmException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密(ECB模式)
|
||||
*
|
||||
* @param keyHex 秘钥HEX字符串
|
||||
* @param cipherDataHex 密文的HEX字符串
|
||||
* @return 解密后的明文
|
||||
*/
|
||||
public static String decrypt(String keyHex, String cipherDataHex) {
|
||||
|
||||
try {
|
||||
// 创建加密对象
|
||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION_ECB);
|
||||
// 创建加密规则
|
||||
SecretKeySpec keySpec = new SecretKeySpec(Hex.decode(keyHex), SM4_ALGORITHM);
|
||||
|
||||
// 初始化
|
||||
cipher.init(Cipher.DECRYPT_MODE, keySpec);
|
||||
|
||||
// 调用加密方法
|
||||
byte[] outputBytes = cipher.doFinal(Hex.decode(cipherDataHex));
|
||||
|
||||
return new String(outputBytes, StandardCharsets.UTF_8);
|
||||
} catch (Exception e) {
|
||||
throw new SmException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String iv = SM4.generateKey();
|
||||
System.out.println(iv);
|
||||
System.out.println("加密:---------");
|
||||
String v = SM4.encrypt(iv, """
|
||||
晚日照空矶,采莲承晚晖。
|
||||
风起湖难渡,莲多采未稀。
|
||||
棹动芙蓉落,船移白鹭飞。
|
||||
荷丝傍绕腕,菱角远牵衣。
|
||||
""", iv);
|
||||
System.out.println(v);
|
||||
String digest = SM3.digest(v);
|
||||
System.out.println(digest);
|
||||
System.out.println("解密:---------");
|
||||
System.out.println(SM4.decrypt(iv, v, iv));
|
||||
System.out.println("解密:---------");
|
||||
System.out.println(SM4.decrypt("864669EB9E57E15C923E1003CBEA8872", "6a05d74bda1f2a41c0b47605b06ef638", "fedcba98765432100123456789abcdef"));
|
||||
}
|
||||
|
||||
}
|
18
utils/pom.xml
Normal file
18
utils/pom.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?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">
|
||||
<parent>
|
||||
<artifactId>zyjblogs-parent</artifactId>
|
||||
<groupId>cn.zyjblogs</groupId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>zyjblogs-utils</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>sm-crypto-utils</module>
|
||||
</modules>
|
||||
</project>
|
@ -1 +0,0 @@
|
||||
Subproject commit 0df595b797730cc69469ab7f2063e4c876db22f4
|
Loading…
Reference in New Issue
Block a user