Merge branch 'master' of gitee.com:willfree/min-dev-java

This commit is contained in:
free will committed 2021-03-09 17:27:25 +08:00
commit 472f3585c6
25 files changed
+1045 -247

No files matched your search

@@ -1,7 +1,6 @@
package minsecurity.certificate.X509;
import minsecurity.Common;
import minsecurity.crypto.sm2.Sm2Base;
import minsecurity.crypto.sm2.SM2Base;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
@@ -34,7 +33,7 @@ public class X509CertMaker {
String ou, String cn,
long expireTimeInMs, String signAlgo)
throws Exception {
KeyPair rootKP = Sm2Base.generateKeyPair();
KeyPair rootKP = SM2Base.generateKeyPair();
return makeRootCA(rootKP, c, o, ou, cn, expireTimeInMs, signAlgo);
}
@@ -116,7 +115,7 @@ public class X509CertMaker {
public static void main(String[] args) {
try {
KeyPair rootKP = Sm2Base.generateKeyPair();
KeyPair rootKP = SM2Base.generateKeyPair();
X509Certificate rootCA = makeRootCA(rootKP,"CN","MIN",
"MIN-GROUP","MIN ROOT CA",
365L * 24 * 60 * 60 * 1000, "SM3withSM2");
@@ -3,12 +3,18 @@ package minsecurity.certificate.cert;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import minsecurity.Common;
import minsecurity.crypto.PublicKeyInterface;
import minsecurity.crypto.PublicKeyUtils;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import minsecurity.crypto.*;
import org.slf4j.LoggerFactory;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Base64;
/*
* @Author: hongyu guo
@@ -21,6 +27,13 @@ public class CertUtils {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(CertUtils.class);
public static final int VERSION1 = 1;
/**
* Certificate -> InnerCertificate
* @param certificate
* @return InnerCertificate
* @author hongyu guo
* @date 2021/3/7
**/
public static InnerCertificate parseCertToInnerCert(Certificate certificate){
TbsCertificate tbsCertificate = new TbsCertificate();
tbsCertificate.setVersion(certificate.getVersion());
@@ -43,12 +56,20 @@ public class CertUtils {
return innerCertificate;
}
/**
* InnerCertificate -> Certificate
* @param i
* @return minsecurity.certificate.cert.Certificate
* @author hongyu guo
* @date 2021/3/7
**/
public static Certificate parseInnerCertToCert(InnerCertificate i){
Certificate certificate = new Certificate();
certificate.setVersion(i.getTbsCertificate().getVersion());
certificate.setSerialNumber(i.getTbsCertificate().getSerialNumber());
PublicKeyInterface publicKey = PublicKeyUtils.unMarshalPublicKey(i.getTbsCertificate().getPublicKey(),i.getSignatureAlgorithm());
PublicKeyInterface publicKey = KeyUtils.unMarshalPublicKey(i.getTbsCertificate().getPublicKey(),i.getSignatureAlgorithm());
certificate.setPublicKey(publicKey);
certificate.setSignature(i.getSignatureValue());
certificate.setSignatureAlgorithm(i.getTbsCertificate().getSignatureAlgorithm());
@@ -64,6 +85,13 @@ public class CertUtils {
return certificate;
}
/**
* 检查证书是否在有效期内
* @param innerCertificate
* @return boolean
* @author hongyu guo
* @date 2021/3/7
**/
public static boolean checkDuration(InnerCertificate innerCertificate){
long curTime = System.currentTimeMillis();
// logger.debug("current time: {}", curTime);
@@ -74,26 +102,32 @@ public class CertUtils {
return true;
}
// cur = 1615018693993
// notbefore = 1615018693858
// notafter = 1615018694058
/**
* 使用publicKey验证签名
* @param cert
* @param publicKey
* @return boolean
* @author hongyu guo
* @date 2021/3/7
**/
public static boolean checkSign(InnerCertificate cert, PublicKeyInterface publicKey) throws Exception {
switch (cert.getTbsCertificate().getSignatureAlgorithm()){
case Common.SM3withSM2:
// TODO: 证书序列化方法
byte[] bytesOfCert = serialization(cert.getTbsCertificate());
logger.debug("验签序列化bytes: {}", ByteUtils.toHexString(bytesOfCert));
// byte[] digest = HashAlgo.sm3(bytesOfCert);
logger.debug("验签sign: {}", ByteUtils.toHexString(cert.getSignatureValue()));
return publicKey.verify(bytesOfCert, cert.getSignatureValue());
default:
throw new Exception("未定义的签名方法");
}
}
// TODO: 证书序列化方法
/**
* 将TbsCertificate类型实例转化为字节流
* @param tbsCertificate
* @return byte[]
* @author hongyu guo
* @date 2021/3/7
**/
public static byte[] serialization(TbsCertificate tbsCertificate){
ObjectMapper mapper = new ObjectMapper();
byte[] bytesOfCertJson;
@@ -106,6 +140,13 @@ public class CertUtils {
return new byte[0];
}
/**
* 将InnerCertificate类型实例转化为字节流
* @param innerCertificate
* @return byte[]
* @author hongyu guo
* @date 2021/3/7
**/
public static byte[] serialization(InnerCertificate innerCertificate){
ObjectMapper mapper = new ObjectMapper();
byte[] bytesOfCertJson;
@@ -118,17 +159,23 @@ public class CertUtils {
return new byte[0];
}
// TODO: 证书反序列化
/**
* 根据typeOfCert可将字节流反序列化为TbsCertificate或InnerCertificate,
* 返回Object类型, 调用者调用时需要手动强制类型转化
* @param bytesOfCert 字节流
* @param typeOfCert Common.TbsCertificate或Common.InnerCertificate
* @return java.lang.Object
* @author hongyu guo
* @date 2021/3/7
**/
public static Object deserialization(byte[] bytesOfCert, int typeOfCert){
ObjectMapper mapper = new ObjectMapper();
try {
switch (typeOfCert) {
case Common.TbsCertificate:
TbsCertificate tbsCertificate = mapper.readValue(bytesOfCert, TbsCertificate.class);
return tbsCertificate;
return mapper.readValue(bytesOfCert, TbsCertificate.class);
case Common.InnerCertificate:
InnerCertificate innerCertificate = mapper.readValue(bytesOfCert, InnerCertificate.class);
return innerCertificate;
return mapper.readValue(bytesOfCert, InnerCertificate.class);
default:
throw new CertException("未知证书类型");
}
@@ -139,4 +186,120 @@ public class CertUtils {
}
/**
* 使用priv私钥给Certificate类型实例签名
* @param certificate 未签名证书
* @param priv 私钥
* @return void
* @author hongyu guo
* @date 2021/3/7
**/
public static void signCert(Certificate certificate, PrivateKeyInterface priv) throws Exception {
byte[] bytesOfCert = serialization(CertUtils.parseCertToInnerCert(certificate).getTbsCertificate());
// logger.debug("签名序列化bytes: {}", ByteUtils.toHexString(bytesOfCert));
switch (certificate.getSignatureAlgorithm()){
case Common.SM3withSM2:
certificate.setSignature(priv.sign(bytesOfCert));
break;
default:
logger.debug("signAlgo: {}", certificate.getSignatureAlgorithm());
throw new Exception("未定义的签名方法");
}
}
/**
* 使用ca的公钥对sub进行验签, 如果时根证书验签, 调用时ca与sub指向同一个实例
* @param ca
* @param sub
* @return boolean
* @author hongyu guo
* @date 2021/3/7
**/
public static boolean verifyCert(Certificate ca, Certificate sub) throws Exception {
InnerCertificate innerCertificate = CertUtils.parseCertToInnerCert(sub);
switch (innerCertificate.getTbsCertificate().getVersion()){
case CertUtils.VERSION1:
boolean isValid = CertUtils.checkDuration(innerCertificate);
// logger.debug("有效期内:{}", isValid);
if(!isValid)
return false;
if(sub.isCA()){ // 根证书, 自验证
return checkSign(innerCertificate, sub.getPublicKey());
} else { // 使用ca验证sub
return checkSign(innerCertificate, ca.getPublicKey());
}
default:
return false;
}
}
/**
* 证书序列化为String类型, 密码为null或为空时不对证书进行加密保存
* @param certificate
* @param passwd
* @param symAlgoMode Common.SM4CBC / Common.SM4ECB
* @return java.lang.String
* @author hongyu guo
* @date 2021/3/7
**/
public static String toPem(Certificate certificate, byte[] passwd, int symAlgoMode) throws CertException, NoSuchPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException, InvalidKeyException {
if(certificate.getSignature() == null){
throw new CertException("该证书未签名");
}
byte[] bytesOfCert = serialization(CertUtils.parseCertToInnerCert(certificate));
byte[] ret;
if(passwd != null && passwd.length > 0){
// byte[] sm4Key;
byte[] sm4Key = KeyUtils.get16bytePasswd(passwd);
switch (symAlgoMode){
case Common.SM4CBC:{
// TODO: PADDING??? IV?????
ret = SM4.encrypt_CBC_Padding(sm4Key, new byte[16],bytesOfCert);
break;
}
case Common.SM4ECB:{
ret = SM4.encrypt_ECB_Padding(sm4Key, bytesOfCert);
break;
}
default:
throw new CertException("未定义的对称加密算法");
}
} else {
ret = bytesOfCert;
}
return Base64.getEncoder().encodeToString(ret);
}
/**
* String类型证书转化为Certificate对象
* @param pemString
* @param passwd
* @param symAlgoMode Common.SM4CBC / Common.SM4ECB
* @return minsecurity.certificate.cert.Certificate
* @author hongyu guo
* @date 2021/3/7
**/
public static Certificate fromPem(String pemString, byte[] passwd, int symAlgoMode) throws CertException, BadPaddingException, NoSuchPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, NoSuchProviderException, InvalidKeyException {
if(pemString == null || pemString.equals("")){
throw new CertException("pem串为空");
}
byte[] bytesOfPem = Base64.getDecoder().decode(pemString);
byte[] bytesOfCert = new byte[0];
if(passwd != null && passwd.length > 0){
byte[] sm4Key = KeyUtils.get16bytePasswd(passwd);
switch (symAlgoMode){
case Common.SM4CBC:
bytesOfCert = SM4.decrypt_CBC_Padding(sm4Key,new byte[16], bytesOfPem);
break;
case Common.SM4ECB:
bytesOfCert = SM4.decrypt_ECB_Padding(sm4Key, bytesOfPem);
break;
}
} else {
bytesOfCert = bytesOfPem;
}
InnerCertificate innerCertificate = (InnerCertificate) deserialization(bytesOfCert, Common.InnerCertificate);
return CertUtils.parseInnerCertToCert(innerCertificate);
}
}
@@ -1,28 +1,13 @@
package minsecurity.certificate.cert;
import minsecurity.Common;
import minsecurity.crypto.HashAlgo;
import minsecurity.crypto.PrivateKeyInterface;
import minsecurity.crypto.PublicKeyInterface;
import minsecurity.crypto.Sm4;
import minsecurity.crypto.sm2.Sm2PublicKey;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.slf4j.LoggerFactory;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.lang.reflect.Array;
import java.security.*;
import java.util.Base64;
import static minsecurity.certificate.cert.CertUtils.*;
/*
* @Author: hongyu guo
* @Description:
* @Description: 证书bean类
* @Version: 1.0.0
* @Date: 17:05 2021/03/05
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
@@ -174,104 +159,23 @@ public class Certificate {
this.publicKey = publicKey;
}
public void signCert(PrivateKeyInterface priv) throws Exception {
byte[] bytesOfCert = serialization(CertUtils.parseCertToInnerCert(this).getTbsCertificate());
logger.debug("签名序列化bytes: {}", ByteUtils.toHexString(bytesOfCert));
switch (this.signatureAlgorithm){
case Common.SM3withSM2:
// byte[] digest = HashAlgo.sm3(bytesOfCert);
this.signature = priv.sign(bytesOfCert);
logger.debug("签名sign: {}", ByteUtils.toHexString(this.signature));
// Sm2PublicKey sm2PublicKey = (Sm2PublicKey) this.publicKey;
// logger.debug("临时验签: {}", sm2PublicKey.verify(bytesOfCert, signature));
break;
default:
logger.debug("signAlgo: {}",this.signatureAlgorithm);
throw new Exception("未定义的签名方法");
}
}
public static boolean verifyCert(Certificate ca, Certificate sub) throws Exception {
InnerCertificate innerCertificate = CertUtils.parseCertToInnerCert(sub);
switch (innerCertificate.getTbsCertificate().getVersion()){
case CertUtils.VERSION1:
boolean isValid = CertUtils.checkDuration(innerCertificate);
logger.debug("有效期内:{}", isValid);
if(!isValid)
return false;
if(sub.isCA()){
return checkSign(innerCertificate, sub.getPublicKey());
} else {
return checkSign(innerCertificate, ca.getPublicKey());
}
default:
return false;
}
}
public String toPem(byte[] passwd, int symAlgoMode) throws CertException, NoSuchPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException, InvalidKeyException {
if(this.getSignature() == null){
throw new CertException("该证书未签名");
}
byte[] bytesOfCert = serialization(CertUtils.parseCertToInnerCert(this));
byte[] ret = new byte[0];
if(passwd != null && passwd.length > 0){
byte[] hashPasswd = HashAlgo.sm3(passwd);
if( hashPasswd.length == 32){
for(int i = 0; i < 16; i++){
hashPasswd[i] += hashPasswd[i + 16];
}
}
byte[] sm4Key = new byte[16];
System.arraycopy(hashPasswd,0,sm4Key,0,16);
switch (symAlgoMode){
case Common.SM4CBC:{
// TODO: PADDING??? IV?????
ret = Sm4.encrypt_CBC_Padding(sm4Key, new byte[16],bytesOfCert);
break;
}
case Common.SM4ECB:{
ret = Sm4.encrypt_ECB_Padding(sm4Key, bytesOfCert);
break;
}
default:
throw new CertException("未定义的对称加密算法");
}
} else {
ret = bytesOfCert;
}
return Base64.getEncoder().encodeToString(ret);
}
public static Certificate fromPem(String pemString, byte[] passwd, int symAlgoMode) throws CertException, BadPaddingException, NoSuchPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, NoSuchProviderException, InvalidKeyException {
if(pemString == null || pemString.equals("")){
throw new CertException("pem串为空");
}
byte[] bytesOfPem = Base64.getDecoder().decode(pemString);
byte[] bytesOfCert = new byte[0];
if(passwd != null && passwd.length > 0){
byte[] hashPasswd = HashAlgo.sm3(passwd);
if( hashPasswd.length == 32){
for(int i = 0; i < 16; i++){
hashPasswd[i] += hashPasswd[i + 16];
}
}
byte[] sm4Key = new byte[16];
System.arraycopy(hashPasswd,0,sm4Key,0,16);
switch (symAlgoMode){
case Common.SM4CBC:
bytesOfCert = Sm4.decrypt_CBC_Padding(sm4Key,new byte[16], bytesOfPem);
case Common.SM4ECB:
bytesOfCert = Sm4.decrypt_ECB_Padding(sm4Key, bytesOfPem);
}
} else {
bytesOfCert = bytesOfPem;
}
InnerCertificate innerCertificate = (InnerCertificate) deserialization(bytesOfCert, Common.InnerCertificate);
return CertUtils.parseInnerCertToCert(innerCertificate);
@Override
public String toString() {
return "Certificate{" +
"version=" + version +
", serialNumber=" + serialNumber +
", publicKey=" + publicKey +
", signature=" + ByteUtils.toHexString(signature) +
", signatureAlgorithm=" + signatureAlgorithm +
", publicKeyAlgorithm=" + publicKeyAlgorithm +
", issueTo='" + issueTo + '\'' +
", issuer='" + issuer + '\'' +
", notBefore=" + notBefore +
", notAfter=" + notAfter +
", keyUsage=" + keyUsage +
", isCA=" + isCA +
", timestamp=" + timestamp +
'}';
}
}
@@ -7,7 +7,7 @@ import java.util.Arrays;
/*
* @Author: hongyu guo
* @Description:
* @Description: 将签名和签名类型单独拎出来, 签名时签TbsCertificate
* @Version: 1.0.0
* @Date: 17:07 2021/03/05
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
@@ -7,7 +7,7 @@ import java.util.Arrays;
/*
* @Author: hongyu guo
* @Description:
* @Description: 内层结构, 不包含签名和签名类型
* @Version: 1.0.0
* @Date: 17:00 2021/03/05
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
@@ -19,7 +19,7 @@ import java.nio.charset.StandardCharsets;
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class HashAlgo {
// TODO: 单元测试
// TODO: 单元测试 基本上只需要对sm3做单元测试
///////////////
///// SM3 /////
///////////////
@@ -0,0 +1,62 @@
package minsecurity.crypto;
import minsecurity.Common;
import minsecurity.crypto.sm2.SM2PrivateKey;
import minsecurity.crypto.sm2.SM2PublicKey;
/*
* @Author: hongyu guo
* @Description:
* @Version: 1.0.0
* @Date: 16:02 2021/03/06
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class KeyUtils {
/**
* 返回的数据类型为PublicKeyInterface接口, 必要时调用者需要手动将类型强制转化为需要的类型
* @param bytesOfPublicKey 公钥的bytes数组
* @param algorithm 公钥类型
* @return minsecurity.crypto.PublicKeyInterface
* @author ghy
* @date 2021/3/7
**/
public static PublicKeyInterface unMarshalPublicKey(byte[] bytesOfPublicKey, int algorithm) {
if (bytesOfPublicKey == null || bytesOfPublicKey.length == 0) {
return null;
}
switch (algorithm) {
case Common.SM2:
SM2PublicKey sm2PublicKey = new SM2PublicKey();
sm2PublicKey.setBytes(bytesOfPublicKey);
return sm2PublicKey;
default:
return null;
}
}
public static PrivateKeyInterface unMarshalPrivateKey(byte[] bytesOfPrivateKey, int algorithm){
if(bytesOfPrivateKey == null || bytesOfPrivateKey.length == 0){
return null;
}
switch (algorithm) {
case Common.SM2:
SM2PrivateKey sm2PrivateKey = new SM2PrivateKey();
sm2PrivateKey.setBytes(bytesOfPrivateKey);
return sm2PrivateKey;
default:
return null;
}
}
public static byte[] get16bytePasswd(byte[] passwd) {
byte[] hashPasswd = HashAlgo.sm3(passwd);
if( hashPasswd.length == 32){
for(int i = 0; i < 16; i++){
hashPasswd[i] += hashPasswd[i + 16];
}
}
byte[] sm4Key = new byte[16];
System.arraycopy(hashPasswd,0,sm4Key,0,16);
return sm4Key;
}
}
@@ -13,6 +13,6 @@ import org.bouncycastle.crypto.InvalidCipherTextException;
public interface PrivateKeyInterface {
public byte[] getBytes();
public boolean setBytes(byte[] bytes);
public byte[] decrypt(byte[] content) throws InvalidCipherTextException;
public byte[] decrypt(byte[] cipher) throws InvalidCipherTextException;
public byte[] sign(byte[] content) throws CryptoException;
}
@@ -1,27 +0,0 @@
package minsecurity.crypto;
import minsecurity.Common;
import minsecurity.crypto.sm2.Sm2PublicKey;
/*
* @Author: hongyu guo
* @Description:
* @Version: 1.0.0
* @Date: 16:02 2021/03/06
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class PublicKeyUtils {
public static PublicKeyInterface unMarshalPublicKey(byte[] bytesOfPublicKey, int algorithm) {
if (bytesOfPublicKey == null || bytesOfPublicKey.length == 0) {
return null;
}
switch (algorithm) {
case Common.SM2:
Sm2PublicKey sm2PublicKey = new Sm2PublicKey();
sm2PublicKey.setBytes(bytesOfPublicKey);
return sm2PublicKey;
default:
return null;
}
}
}
@@ -14,7 +14,7 @@ import java.security.*;
* @Date: 16:26 2021/03/04
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class Sm4 {
public class SM4 {
static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
@@ -1,6 +1,5 @@
package minsecurity.crypto.sm2;
import minsecurity.Common;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
@@ -17,7 +16,6 @@ import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve;
import org.slf4j.LoggerFactory;
import javax.crypto.KeyGenerator;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
@@ -32,13 +30,17 @@ import static minsecurity.Common.ALGO_NAME_EC;
* @Date: 18:48 2021/03/03
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class Sm2Base {
public class SM2Base {
static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Sm2Base.class);
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(SM2Base.class);
/*
* 以下为SM2推荐曲线参数
*/
public static final SM2P256V1Curve CURVE = new SM2P256V1Curve();
public final static BigInteger SM2_ECC_P = CURVE.getQ();
public final static BigInteger SM2_ECC_A = CURVE.getA().toBigInteger();
@@ -56,6 +58,14 @@ public class Sm2Base {
private static final String PEM_STRING_PUBLIC = "PUBLIC KEY";
private static final String PEM_STRING_ECPRIVATEKEY = "EC PRIVATE KEY";
/**
* 生成BC自定义的SM2公私钥
* @param
* @return org.bouncycastle.crypto.AsymmetricCipherKeyPair
* @author hongyu guo
* @date 2021/3/7
**/
public static AsymmetricCipherKeyPair generateKeyPairParameter(){
SecureRandom random = new SecureRandom();
ECKeyGenerationParameters keyGenerationParams = new ECKeyGenerationParameters(DOMAIN_PARAMS,
@@ -66,12 +76,27 @@ public class Sm2Base {
return keyPair;
}
/**
* 生成java.security.KeyPair类型的SM2公私钥
* @param
* @return java.security.KeyPair
* @author hongyu guo
* @date 2021/3/7
**/
public static KeyPair generateKeyPair() throws NoSuchProviderException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException {
SecureRandom random = new SecureRandom();
return generateKeyPair(DOMAIN_PARAMS, random);
}
/**
* 生成java.security.KeyPair类型的SM2公私钥, 需自定义曲线参数
* @param domainParameters
* @param random
* @return
* @author hongyu guo
* @date 2021/3/7
**/
public static KeyPair generateKeyPair(ECDomainParameters domainParameters, SecureRandom random)
throws NoSuchProviderException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException {
@@ -82,7 +107,13 @@ public class Sm2Base {
return kpg.generateKeyPair();
}
/**
* BC公私钥转换为java.security.KeyPair公私钥
* @param bcKeyPair
* @return
* @author hongyu guo
* @date 2021/3/7
**/
public static KeyPair convertBcToJceKeyPair(AsymmetricCipherKeyPair bcKeyPair) throws Exception {
byte[] pkcs8Encoded = PrivateKeyInfoFactory.createPrivateKeyInfo(bcKeyPair.getPrivate()).getEncoded();
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(pkcs8Encoded);
@@ -92,13 +123,27 @@ public class Sm2Base {
return new KeyPair(keyFac.generatePublic(spkiKeySpec), keyFac.generatePrivate(pkcs8KeySpec));
}
/**
* java.security.KeyPair转换为BC类型的公私钥对
* @param keyPair
* @return
* @author hongyu guo
* @date 2021/3/7
**/
public static AsymmetricCipherKeyPair convertKeyPair2Bc(KeyPair keyPair) {
ECPrivateKeyParameters priKey = convertPrivateKeyToParameters((BCECPrivateKey) keyPair.getPrivate());
ECPublicKeyParameters pubKey = convertPublicKeyToParameters((BCECPublicKey) keyPair.getPublic());
return new AsymmetricCipherKeyPair(priKey,pubKey);
}
/**
* BCECPrivateKey类型私钥转化为ECPrivateKeyParameters类型的私钥,
* 调用者若想将java.security.PrivateKey转化为ECPrivateKeyParameters, 调用时将其强制转换为BCECPrivateKey类型
* @param ecPriKey
* @return ECPrivateKeyParameters
* @author hongyu guo
* @date 2021/3/7
**/
public static ECPrivateKeyParameters convertPrivateKeyToParameters(BCECPrivateKey ecPriKey) {
ECParameterSpec parameterSpec = ecPriKey.getParameters();
ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
@@ -106,6 +151,14 @@ public class Sm2Base {
return new ECPrivateKeyParameters(ecPriKey.getD(), domainParameters);
}
/**
* BCECPublicKey类型私钥转化为ECPublicKeyParameters类型的私钥,
* 调用者若想将java.security.PublicKey转化为ECPublicKeyParameters, 调用时将其强制转换为BCECPublicKey类型
* @param ecPubKey
* @return ECPrivateKeyParameters
* @author hongyu guo
* @date 2021/3/7
**/
public static ECPublicKeyParameters convertPublicKeyToParameters(BCECPublicKey ecPubKey) {
ECParameterSpec parameterSpec = ecPubKey.getParameters();
ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
@@ -7,8 +7,8 @@ package minsecurity.crypto.sm2;
* @Date: 19:00 2021/03/03
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class Sm2Exception extends java.lang.Exception {
public Sm2Exception(String msg){
public class SM2Exception extends java.lang.Exception {
public SM2Exception(String msg){
super(msg);
}
}
@@ -20,28 +20,41 @@ import java.security.SecureRandom;
* @Date: 19:40 2021/03/03
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class Sm2PrivateKey implements PrivateKeyInterface {
public class SM2PrivateKey implements PrivateKeyInterface {
public Sm2PrivateKey(){}
public Sm2PrivateKey(byte[] d) {
public SM2PrivateKey(){}
/*
* @param d
* @return
* @author hongyu guo
* @date 2021/3/7
**/
/*
* @param d 大数
* @return
* @author hongyu guo
* @date 2021/3/7
**/
public SM2PrivateKey(byte[] d) {
if(d.length == 32 || d.length == 33)
privateKey = new ECPrivateKeyParameters(new BigInteger(d), Sm2Base.DOMAIN_PARAMS);
privateKey = new ECPrivateKeyParameters(new BigInteger(d), SM2Base.DOMAIN_PARAMS);
else {
try {
throw new Sm2Exception("SM2私钥中,参数d长度应为32/33");
} catch (Sm2Exception e) {
throw new SM2Exception("SM2私钥中,参数d长度应为32/33");
} catch (SM2Exception e) {
e.printStackTrace();
}
}
}
public Sm2PrivateKey(byte[] d, ECDomainParameters parameters){
public SM2PrivateKey(byte[] d, ECDomainParameters parameters){
if(d.length == 32 || d.length == 33)
privateKey = new ECPrivateKeyParameters(new BigInteger(d), parameters);
else {
try {
throw new Sm2Exception("SM2私钥中,参数d长度应为32/33");
} catch (Sm2Exception e) {
throw new SM2Exception("SM2私钥中,参数d长度应为32/33");
} catch (SM2Exception e) {
e.printStackTrace();
}
}
@@ -56,7 +69,7 @@ public class Sm2PrivateKey implements PrivateKeyInterface {
public boolean setBytes(byte[] d) {
if(d.length != 32 && d.length != 33)
return false;
privateKey = new ECPrivateKeyParameters(new BigInteger(d), Sm2Base.DOMAIN_PARAMS);
privateKey = new ECPrivateKeyParameters(new BigInteger(d), SM2Base.DOMAIN_PARAMS);
return true;
}
@@ -15,21 +15,32 @@ import java.security.SecureRandom;
/*
* @Author: hongyu guo
* @Description: 国密sm2 非对称加密公钥
* @Description: 国密sm2 非对称加密公钥, 实现PublicKeyInterface中的方法
* @Version: 1.0.0
* @Date: 17:32 2021/03/03
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class Sm2PublicKey implements PublicKeyInterface {
public class SM2PublicKey implements PublicKeyInterface {
public Sm2PublicKey(){}
public SM2PublicKey(){}
public Sm2PublicKey(byte[] xBytes, byte[] yBytes, ECCurve curve, ECDomainParameters domainParameters){
public SM2PublicKey(byte[] xBytes, byte[] yBytes, ECCurve curve, ECDomainParameters domainParameters){
publicKey = createPublicKey(xBytes,yBytes,curve,domainParameters);
}
/**
* 使用SM2推荐曲线参数
* @param xBytes 曲线x参数
* @param yBytes 曲线y参数
* @return
* @author ghy
* @date 2021/3/7
**/
public SM2PublicKey(byte[] xBytes, byte[] yBytes){
this(xBytes,yBytes, SM2Base.CURVE, SM2Base.DOMAIN_PARAMS);
}
public Sm2PublicKey(byte[] xBytes, byte[] yBytes){
this(xBytes,yBytes, Sm2Base.CURVE, Sm2Base.DOMAIN_PARAMS);
public SM2PublicKey(byte[] bytes){
setBytes(bytes);
}
@@ -55,6 +66,12 @@ public class Sm2PublicKey implements PublicKeyInterface {
return true;
}
/**
* @param content
* @return byte[] 密文
* @author ghy
* @date 2021/3/7
**/
@Override
public byte[] encrypt(byte[] content) throws InvalidCipherTextException {
SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C2C3);
@@ -88,7 +105,7 @@ public class Sm2PublicKey implements PublicKeyInterface {
}
private static ECPublicKeyParameters createPublicKey(byte[] xBytes, byte[] yBytes){
return createPublicKey(xBytes,yBytes,Sm2Base.CURVE,Sm2Base.DOMAIN_PARAMS);
return createPublicKey(xBytes,yBytes, SM2Base.CURVE, SM2Base.DOMAIN_PARAMS);
}
private static int getCurveLength(ECDomainParameters domainParams) {
@@ -108,7 +125,10 @@ public class Sm2PublicKey implements PublicKeyInterface {
}
return result;
}
private ECPublicKeyParameters publicKey;
////////////////////////////////////////////// private end //////////////////////////////////////////////
ECPublicKeyParameters publicKey;
}
@@ -0,0 +1,14 @@
package minsecurity.crypto.sm2;
/*
* @Author: hongyu guo
* @Description:
* @Version: 1.0.0
* @Date: 15:19 2021/03/09
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class SM4Exception extends Exception{
SM4Exception(String msg){
super(msg);
}
}
@@ -0,0 +1,255 @@
package minsecurity.identity;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import minsecurity.Common;
import minsecurity.certificate.cert.CertException;
import minsecurity.certificate.cert.Certificate;
import minsecurity.crypto.KeyUtils;
import minsecurity.crypto.PrivateKeyInterface;
import minsecurity.crypto.PublicKeyInterface;
import minsecurity.crypto.SM4;
import minsecurity.crypto.sm2.SM2PrivateKey;
import minsecurity.crypto.sm2.SM2PublicKey;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.slf4j.LoggerFactory;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Arrays;
import java.util.Base64;
/*
* @Author: hongyu guo
* @Description:
* @Version: 1.0.0
* @Date: 20:25 2021/03/07
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class Identity {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Identity.class);
private String Name;
private KeyParam KeyParam;
private PrivateKeyInterface Prikey;
private byte[] PrikeyRawByte;
private PublicKeyInterface Pubkey;
private String Passwd;
private Certificate Cert;
public Identity(String name, KeyParam keyParam,
PrivateKeyInterface prikey, byte[] prikeyRawByte,
PublicKeyInterface pubkey, String passwd, Certificate cert) {
Name = name;
KeyParam = keyParam;
Prikey = prikey;
PrikeyRawByte = prikeyRawByte;
Pubkey = pubkey;
Passwd = passwd;
Cert = cert;
}
public Identity(){}
public byte[] sign(byte[] digest) throws CryptoException {
if(this.Prikey == null)
return null;
switch (this.KeyParam.PublicKeyAlgorithm){
case Common.SM2:
SM2PrivateKey sm2PrivateKey = (SM2PrivateKey) this.Prikey;
switch (this.KeyParam.SignatureAlgorithm){
case Common.SM3withSM2:
return sm2PrivateKey.sign(digest);
default:
return null;
}
default:
return null;
}
}
public boolean verify(byte[] msg, byte[] digest) {
if(this.Pubkey == null)
return false;
switch (this.KeyParam.PublicKeyAlgorithm){
case Common.SM2:
SM2PublicKey sm2PublicKey = (SM2PublicKey) this.Pubkey;
switch (this.KeyParam.SignatureAlgorithm){
case Common.SM3withSM2:
return sm2PublicKey.verify(msg, digest);
default:
return false;
}
default:
return false;
}
}
public byte[] decrypt(byte[] cipher) throws InvalidCipherTextException {
if(this.Prikey == null)
return null;
return this.Prikey.decrypt(cipher);
}
public byte[] encrypt(byte[] content) throws InvalidCipherTextException {
if(this.Pubkey == null)
return null;
return this.Pubkey.encrypt(content);
}
public byte[] dump(String passwd) throws NoSuchPaddingException, InvalidAlgorithmParameterException, CertException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
InnerIdentity innerIdentity = IdentityUtil.parseIdentityToInner(this);
byte[] bytesOfInnerIdentity = mapper.writeValueAsBytes(innerIdentity);
// logger.debug(ByteUtils.toHexString(bytesOfInnerIdentity));
if(passwd != null && passwd.length() != 0) {
byte[] sm4key = KeyUtils.get16bytePasswd(passwd.getBytes());
byte[] cipher = SM4.encrypt_CBC_Padding(sm4key, new byte[16], bytesOfInnerIdentity);
return Base64.getEncoder().encode(cipher);
}
return Base64.getEncoder().encode(bytesOfInnerIdentity);
}
public static Identity load(byte[] data, String passwd)
throws BadPaddingException, NoSuchPaddingException, InvalidAlgorithmParameterException,
NoSuchAlgorithmException, IllegalBlockSizeException, NoSuchProviderException,
InvalidKeyException, CertException {
byte[] bytesOfIdentity = Base64.getDecoder().decode(data);
byte[] plain;
if(passwd != null && passwd.length() != 0){
byte[] sm4Key = KeyUtils.get16bytePasswd(passwd.getBytes());
plain = SM4.decrypt_CBC_Padding(sm4Key, new byte[16], bytesOfIdentity);
} else{
plain = bytesOfIdentity;
}
ObjectMapper mapper = new ObjectMapper();
InnerIdentity innerIdentity = null;
// logger.debug(ByteUtils.toHexString(plain));
try {
innerIdentity = mapper.readValue(plain, InnerIdentity.class);
} catch (IOException e) {
e.printStackTrace();
}
return IdentityUtil.parseInnerToIdentity(innerIdentity);
}
// TODO: passwd ???
public boolean lock(String passwd, int algo) throws IdentityException {
switch (algo){
case Common.SM4ECB:
if (passwd.length() != 16){
throw new IdentityException("密码应为16位");
}
PrikeyRawByte = Prikey.getBytes();
Prikey = null;
return true;
default:
return false;
}
}
public boolean isLocked(){
return PrikeyRawByte != null && PrikeyRawByte.length > 0;
}
// TODO: passwd ???
public boolean unLock(String passwd, int algo) throws IdentityException {
switch (algo) {
case Common.SM4ECB:
if(passwd == null || passwd.length() == 0)
return false;
PrivateKeyInterface privateKey = KeyUtils.unMarshalPrivateKey(PrikeyRawByte, KeyParam.PublicKeyAlgorithm);
Prikey = privateKey;
PrikeyRawByte = null;
return true;
default:
throw new IdentityException("未知对称加密算法");
}
}
public boolean hasPrivateKey() {
return Prikey != null || (PrikeyRawByte != null && PrikeyRawByte.length > 0);
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public minsecurity.identity.KeyParam getKeyParam() {
return KeyParam;
}
public void setKeyParam(minsecurity.identity.KeyParam keyParam) {
KeyParam = keyParam;
}
public PrivateKeyInterface getPrikey() {
return Prikey;
}
public void setPrikey(PrivateKeyInterface prikey) {
Prikey = prikey;
}
public byte[] getPrikeyRawByte() {
return PrikeyRawByte;
}
public void setPrikeyRawByte(byte[] prikeyRawByte) {
PrikeyRawByte = prikeyRawByte;
}
public PublicKeyInterface getPubkey() {
return Pubkey;
}
public void setPubkey(PublicKeyInterface pubkey) {
Pubkey = pubkey;
}
public String getPasswd() {
return Passwd;
}
public void setPasswd(String passwd) {
Passwd = passwd;
}
public Certificate getCert() {
return Cert;
}
public void setCert(Certificate cert) {
Cert = cert;
}
@Override
public String toString() {
return "Identity{" +
"Name='" + Name + '\'' +
", KeyParam=" + KeyParam +
", Prikey=" + Prikey +
", PrikeyRawByte=" + (PrikeyRawByte == null ? "null":ByteUtils.toHexString(PrikeyRawByte)) +
", Pubkey=" + Pubkey +
", Passwd='" + Passwd + '\'' +
", Cert=" + Cert +
'}';
}
}
@@ -0,0 +1,14 @@
package minsecurity.identity;
/*
* @Author: hongyu guo
* @Description: Identity自定义异常
* @Version: 1.0.0
* @Date: 14:59 2021/03/09
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class IdentityException extends Exception{
public IdentityException(String msg){
super(msg);
}
}
@@ -0,0 +1,72 @@
package minsecurity.identity;
import minsecurity.Common;
import minsecurity.certificate.cert.CertException;
import minsecurity.certificate.cert.CertUtils;
import minsecurity.certificate.cert.Certificate;
import minsecurity.crypto.KeyUtils;
import minsecurity.crypto.PrivateKeyInterface;
import minsecurity.crypto.PublicKeyInterface;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
/*
* @Author: hongyu guo
* @Description:
* @Version: 1.0.0
* @Date: 10:12 2021/03/09
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class IdentityUtil {
public static InnerIdentity parseIdentityToInner(Identity identity)
throws NoSuchPaddingException, InvalidKeyException, CertException,
IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException,
NoSuchProviderException, InvalidAlgorithmParameterException {
InnerIdentity innerIdentity = new InnerIdentity();
innerIdentity.setName(identity.getName());
innerIdentity.setKeyParam(identity.getKeyParam());
if(identity.getPrikey() != null){
innerIdentity.setPrikey(identity.getPrikey().getBytes());
}
if(identity.getPubkey() != null){
innerIdentity.setPubkey(identity.getPubkey().getBytes());
}
innerIdentity.setPasswd(identity.getPasswd());
innerIdentity.setCert(CertUtils.toPem(identity.getCert(), identity.getPasswd().getBytes(), Common.SM4CBC));
return innerIdentity;
}
public static Identity parseInnerToIdentity(InnerIdentity innerIdentity)
throws BadPaddingException, InvalidKeyException, CertException,
NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException,
InvalidAlgorithmParameterException, IllegalBlockSizeException {
Identity identity = new Identity();
identity.setName(innerIdentity.getName());
identity.setKeyParam(innerIdentity.getKeyParam());
if(innerIdentity.getPubkey() == null || innerIdentity.getPubkey().length == 0){
return null;
}
if(innerIdentity.getPrikey() == null || innerIdentity.getPrikey().length == 0){
return null;
}
PublicKeyInterface pub =
KeyUtils.unMarshalPublicKey(innerIdentity.getPubkey(), innerIdentity.getKeyParam().PublicKeyAlgorithm);
identity.setPubkey(pub);
PrivateKeyInterface priv =
KeyUtils.unMarshalPrivateKey(innerIdentity.getPrikey(), innerIdentity.getKeyParam().PublicKeyAlgorithm);
identity.setPrikey(priv);
identity.setPasswd(innerIdentity.getPasswd());
Certificate certificate =
CertUtils.fromPem(innerIdentity.getCert(), innerIdentity.getPasswd().getBytes(), Common.SM4CBC);
identity.setCert(certificate);
return identity;
}
}
@@ -0,0 +1,96 @@
package minsecurity.identity;
import minsecurity.certificate.cert.Certificate;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import java.util.Arrays;
/*
* @Author: hongyu guo
* @Description:
* @Version: 1.0.0
* @Date: 09:41 2021/03/09
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class InnerIdentity {
private String Name;
private KeyParam KeyParam;
private byte[] Prikey;
private byte[] Pubkey;
private String Passwd;
private String Cert;
public InnerIdentity(String name, minsecurity.identity.KeyParam keyParam, byte[] prikey, byte[] pubkey, String passwd, String cert) {
Name = name;
KeyParam = keyParam;
Prikey = prikey;
Pubkey = pubkey;
Passwd = passwd;
Cert = cert;
}
public InnerIdentity() {
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public minsecurity.identity.KeyParam getKeyParam() {
return KeyParam;
}
public void setKeyParam(minsecurity.identity.KeyParam keyParam) {
KeyParam = keyParam;
}
public byte[] getPrikey() {
return Prikey;
}
public void setPrikey(byte[] prikey) {
Prikey = prikey;
}
public byte[] getPubkey() {
return Pubkey;
}
public void setPubkey(byte[] pubkey) {
Pubkey = pubkey;
}
public String getPasswd() {
return Passwd;
}
public void setPasswd(String passwd) {
Passwd = passwd;
}
public String getCert() {
return Cert;
}
public void setCert(String cert) {
Cert = cert;
}
@Override
public String toString() {
return "InnerIdentity{" +
"Name='" + Name + '\'' +
", KeyParam=" + KeyParam +
", Prikey=" + (Prikey == null ? "null" : ByteUtils.toHexString(Prikey)) +
", Pubkey=" + (Pubkey == null ? "null" : ByteUtils.toHexString(Pubkey)) +
", Passwd='" + Passwd + '\'' +
", Cert='" + Cert + '\'' +
'}';
}
}
@@ -0,0 +1,21 @@
package minsecurity.identity;
/*
* @Author: hongyu guo
* @Description:
* @Version: 1.0.0
* @Date: 20:31 2021/03/07
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class KeyParam {
public int PublicKeyAlgorithm;
public int SignatureAlgorithm;
public KeyParam(int publicKeyAlgorithm, int signatureAlgorithm) {
this.PublicKeyAlgorithm = publicKeyAlgorithm;
this.SignatureAlgorithm = signatureAlgorithm;
}
public KeyParam() {
}
}
@@ -1,23 +1,16 @@
package minsecurity.certificate.cert;
import minsecurity.Common;
import minsecurity.crypto.sm2.Sm2Base;
import minsecurity.crypto.sm2.Sm2PrivateKey;
import minsecurity.crypto.sm2.Sm2PublicKey;
import minsecurity.crypto.sm2.TestSm2;
import minsecurity.crypto.sm2.SM2Base;
import minsecurity.crypto.sm2.SM2PrivateKey;
import minsecurity.crypto.sm2.SM2PublicKey;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.*;
import org.slf4j.LoggerFactory;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
/*
* @Author: hongyu guo
* @Description:
@@ -29,15 +22,15 @@ public class TestCert {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestCert.class);
@Test
public void testCertSignAndVerify() throws Exception {
AsymmetricCipherKeyPair keyPair = Sm2Base.generateKeyPairParameter();
AsymmetricCipherKeyPair keyPair = SM2Base.generateKeyPairParameter();
ECPrivateKeyParameters priKey = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters pubKey = (ECPublicKeyParameters) keyPair.getPublic();
byte[] d = priKey.getD().toByteArray();
// d = Arrays.copyOf(d,32);
byte[] x = pubKey.getQ().getAffineXCoord().getEncoded();
byte[] y = pubKey.getQ().getAffineYCoord().getEncoded();
Sm2PrivateKey sm2PrivateKey = new Sm2PrivateKey(d);
Sm2PublicKey sm2PublicKey = new Sm2PublicKey(x,y);
SM2PrivateKey sm2PrivateKey = new SM2PrivateKey(d);
SM2PublicKey sm2PublicKey = new SM2PublicKey(x,y);
Certificate certificate = new Certificate(1,1,sm2PublicKey,
@@ -45,24 +38,46 @@ public class TestCert {
"issueTo","issuer",System.currentTimeMillis(),
System.currentTimeMillis() + 200, Common.CertSign,
true,System.currentTimeMillis());
certificate.signCert(sm2PrivateKey);
CertUtils.signCert(certificate, sm2PrivateKey);
// logger.debug(certificate.toString());
boolean verify = Certificate.verifyCert(certificate, certificate);
// 根证书验签
boolean verify = CertUtils.verifyCert(certificate, certificate);
assertTrue(verify);
AsymmetricCipherKeyPair keyPair2 = SM2Base.generateKeyPairParameter();
ECPrivateKeyParameters priKey2 = (ECPrivateKeyParameters) keyPair2.getPrivate();
ECPublicKeyParameters pubKey2 = (ECPublicKeyParameters) keyPair2.getPublic();
byte[] d2 = priKey2.getD().toByteArray();
// d = Arrays.copyOf(d,32);
byte[] x2 = pubKey2.getQ().getAffineXCoord().getEncoded();
byte[] y2 = pubKey2.getQ().getAffineYCoord().getEncoded();
SM2PrivateKey sm2PrivateKey2 = new SM2PrivateKey(d2);
SM2PublicKey sm2PublicKey2 = new SM2PublicKey(x2, y2);
Certificate sub = new Certificate(1,2,sm2PublicKey2,
null, Common.SM3withSM2,Common.SM2,
"sub","issuer",System.currentTimeMillis() - 1000,
System.currentTimeMillis() + 2000, Common.CertSign,
false, System.currentTimeMillis());
CertUtils.signCert(sub, sm2PrivateKey);
// 下层证书验签
boolean verify2 = CertUtils.verifyCert(certificate, sub);
assertTrue(verify2);
}
@Test
public void testCert2Pem() throws Exception {
AsymmetricCipherKeyPair keyPair = Sm2Base.generateKeyPairParameter();
AsymmetricCipherKeyPair keyPair = SM2Base.generateKeyPairParameter();
ECPrivateKeyParameters priKey = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters pubKey = (ECPublicKeyParameters) keyPair.getPublic();
byte[] d = priKey.getD().toByteArray();
// d = Arrays.copyOf(d,32);
byte[] x = pubKey.getQ().getAffineXCoord().getEncoded();
byte[] y = pubKey.getQ().getAffineYCoord().getEncoded();
Sm2PrivateKey sm2PrivateKey = new Sm2PrivateKey(d);
Sm2PublicKey sm2PublicKey = new Sm2PublicKey(x,y);
SM2PrivateKey sm2PrivateKey = new SM2PrivateKey(d);
SM2PublicKey sm2PublicKey = new SM2PublicKey(x,y);
Certificate certificate = new Certificate(1,1,sm2PublicKey,
@@ -70,17 +85,17 @@ public class TestCert {
"issueTo","issuer",System.currentTimeMillis(),
System.currentTimeMillis() + 111111, Common.CertSign,
true,System.currentTimeMillis());
certificate.signCert(sm2PrivateKey);
CertUtils.signCert(certificate, sm2PrivateKey);
String pem = certificate.toPem(null,0);
Certificate certFromPem = Certificate.fromPem(pem, null,0);
String pem = CertUtils.toPem(certificate,null,0);
Certificate certFromPem = CertUtils.fromPem(pem, null,0);
logger.debug(certFromPem.toString());
assertTrue(Certificate.verifyCert(certFromPem,certFromPem));
assertTrue(CertUtils.verifyCert(certFromPem,certFromPem));
String pem2 = certificate.toPem(new byte[]{1,2,3,4,5,6,7,8},Common.SM4ECB);
Certificate certFromPem2 = Certificate.fromPem(pem2, new byte[]{1,2,3,4,5,6,7,8},Common.SM4ECB);
String pem2 = CertUtils.toPem(certificate, new byte[]{1,2,3,4,5,6,7,8},Common.SM4ECB);
Certificate certFromPem2 = CertUtils.fromPem(pem2, new byte[]{1,2,3,4,5,6,7,8},Common.SM4ECB);
logger.debug(certFromPem.toString());
assertTrue(Certificate.verifyCert(certFromPem2,certFromPem2));
assertTrue(CertUtils.verifyCert(certFromPem2,certFromPem2));
}
}
@@ -3,7 +3,7 @@ package minsecurity.certificate.x509;
import minsecurity.Common;
import minsecurity.certificate.X509.X509CertMaker;
import minsecurity.certificate.X509.X509CertUtil;
import minsecurity.crypto.sm2.Sm2Base;
import minsecurity.crypto.sm2.SM2Base;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.bouncycastle.util.io.pem.PemObject;
@@ -32,6 +32,14 @@ import static minsecurity.certificate.X509.X509CertMaker.makeRootCA;
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class TestX509 {
// WARNING: X509不需要测试!!!!!!!
// WARNING: X509不需要测试!!!!!!!
// WARNING: X509不需要测试!!!!!!!
// WARNING: X509不需要测试!!!!!!!
// WARNING: X509不需要测试!!!!!!!
static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
@@ -42,7 +50,7 @@ public class TestX509 {
public void testRebuildKeyPair(){
try {
KeyPair rootKP = Sm2Base.generateKeyPair();
KeyPair rootKP = SM2Base.generateKeyPair();
X509Certificate rootCA = makeRootCA(rootKP,"CN","MIN",
"MIN-GROUP","MIN ROOT CA",
365L * 24 * 60 * 60 * 1000, "SM3withSM2");
@@ -69,7 +77,7 @@ public class TestX509 {
logger.debug("origin: {}", ByteUtils.toHexString(rootKP.getPublic().getEncoded()));
logger.debug("rebuild:{}", ByteUtils.toHexString(rootKeyPair.getPublic().getEncoded()));
KeyPair subKeyPair = Sm2Base.generateKeyPair();
KeyPair subKeyPair = SM2Base.generateKeyPair();
X509Certificate subCert =
X509CertMaker.makeSubCACert(rootKeyPair,
cert,
@@ -1,5 +1,8 @@
package minsecurity.crypto.sm2;
package minsecurity.crypto;
import minsecurity.crypto.sm2.SM2Base;
import minsecurity.crypto.sm2.SM2PrivateKey;
import minsecurity.crypto.sm2.SM2PublicKey;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.InvalidCipherTextException;
@@ -11,6 +14,8 @@ import static org.junit.Assert.*;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
/*
* @Author: hongyu guo
@@ -19,11 +24,11 @@ import java.nio.ByteBuffer;
* @Date: 20:15 2021/03/03
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class TestSm2 {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestSm2.class);
public class TestSM2 {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestSM2.class);
@Test
public void testSetGet() throws InvalidCipherTextException {
AsymmetricCipherKeyPair keyPair = Sm2Base.generateKeyPairParameter();
AsymmetricCipherKeyPair keyPair = SM2Base.generateKeyPairParameter();
ECPrivateKeyParameters priKey = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters pubKey = (ECPublicKeyParameters) keyPair.getPublic();
byte[] d = priKey.getD().toByteArray();
@@ -31,8 +36,8 @@ public class TestSm2 {
byte[] y = pubKey.getQ().getAffineYCoord().getEncoded();
logger.debug("d.len = {}, x.len = {}, y.len = {}",d.length, x.length, y.length);
// BigInteger bigInteger = priKey.getD();
Sm2PrivateKey sm2PrivateKey = new Sm2PrivateKey();
Sm2PublicKey sm2PublicKey = new Sm2PublicKey();
SM2PrivateKey sm2PrivateKey = new SM2PrivateKey();
SM2PublicKey sm2PublicKey = new SM2PublicKey();
sm2PrivateKey.setBytes(d);
@@ -57,7 +62,7 @@ public class TestSm2 {
@Test
public void testEncAndDec() throws InvalidCipherTextException {
AsymmetricCipherKeyPair keyPair = Sm2Base.generateKeyPairParameter();
AsymmetricCipherKeyPair keyPair = SM2Base.generateKeyPairParameter();
ECPrivateKeyParameters priKey = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters pubKey = (ECPublicKeyParameters) keyPair.getPublic();
byte[] d = priKey.getD().toByteArray();
@@ -66,8 +71,8 @@ public class TestSm2 {
byte[] y = pubKey.getQ().getAffineYCoord().getEncoded();
logger.debug("d.len = {}, x.len = {}, y.len = {}",d.length, x.length, y.length);
// BigInteger bigInteger = priKey.getD();
Sm2PrivateKey sm2PrivateKey = new Sm2PrivateKey(d);
Sm2PublicKey sm2PublicKey = new Sm2PublicKey(x,y);
SM2PrivateKey sm2PrivateKey = new SM2PrivateKey(d);
SM2PublicKey sm2PublicKey = new SM2PublicKey(x,y);
String content = "hello world";
byte[] encBytes = sm2PublicKey.encrypt(content.getBytes());
@@ -78,7 +83,7 @@ public class TestSm2 {
@Test
public void testSignAndVerify() throws CryptoException {
AsymmetricCipherKeyPair keyPair = Sm2Base.generateKeyPairParameter();
AsymmetricCipherKeyPair keyPair = SM2Base.generateKeyPairParameter();
ECPrivateKeyParameters priKey = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters pubKey = (ECPublicKeyParameters) keyPair.getPublic();
byte[] d = priKey.getD().toByteArray();
@@ -86,12 +91,45 @@ public class TestSm2 {
byte[] x = pubKey.getQ().getAffineXCoord().getEncoded();
byte[] y = pubKey.getQ().getAffineYCoord().getEncoded();
logger.debug("d.len = {}, x.len = {}, y.len = {}",d.length, x.length, y.length);
// BigInteger bigInteger = priKey.getD();
Sm2PrivateKey sm2PrivateKey = new Sm2PrivateKey(d);
Sm2PublicKey sm2PublicKey = new Sm2PublicKey(x,y);
SM2PrivateKey sm2PrivateKey = new SM2PrivateKey(d);
SM2PublicKey sm2PublicKey = new SM2PublicKey(x,y);
String content = "7b227462734365727469666963617465223a7b2276657273696f6e223a312c2273657269616c4e756d626572223a312c227075626c69634b6579223a22424a304d7047714e5958706b695879575a4d6e5838776d6b694a51326f576d37336257615932525473706b695058342f37705443666332764e7272596e766c6a644d3448647850537531753272616363506c74485245593d222c227369676e6174757265416c676f726974686d223a302c227075626c69634b6579416c676f726974686d223a302c226973737565546f223a226973737565546f222c22697373756572223a22697373756572222c226e6f744265666f7265223a313631353032303130393339352c226e6f744166746572223a313631353032303130393539352c226b65795573616765223a322c2274696d657374616d70223a313631353032303130393339352c226361223a747275657d2c227369676e6174757265416c676f726974686d223a302c227369676e617475726556616c7565223a6e756c6c7d";
byte[] digest = sm2PrivateKey.sign(ByteUtils.fromHexString(content));
boolean flag = sm2PublicKey.verify(ByteUtils.fromHexString(content), digest);
assertTrue(flag);
}
// 按照艾宾浩斯记忆曲线
// 第x天刷完题, 需要在第x+1,x+2,x+4,x+7,x+15时重新记忆
public static void testMemory(int total, int numsInOneDay){
int days = total / numsInOneDay + 1;
List<Integer>[] res = new List[days + 15];
for(int i = 0; i < days + 15; i++){
res[i] = new ArrayList<Integer>();
}
for(int i = 0; i < days; i++){
for(int j = 1; j <= numsInOneDay; j++){
if(i * numsInOneDay + j <= total) {
res[i].add((i * numsInOneDay + j) * -1);
res[i + 1].add(i * numsInOneDay + j);
res[i + 2].add(i * numsInOneDay + j);
res[i + 4].add(i * numsInOneDay + j);
res[i + 7].add(i * numsInOneDay + j);
res[i + 15].add(i * numsInOneDay + j);
}
}
}
for(int i = 0; i < days + 15; i++){
System.out.println("第" + (i + 1) + "天: " + res[i]);
}
}
public static void main(String[] args) {
testMemory(75,2);
}
}
@@ -2,7 +2,6 @@ package minsecurity.crypto;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
@@ -14,7 +13,7 @@ import java.util.Arrays;
* @Date: 16:28 2021/03/04
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class TestSm4 {
public class TestSM4 {
public static final byte[] SRC_DATA = new byte[]{1, 2, 3, 4, 5, 6, 7, 8};
public static final byte[] SRC_DATA_16B = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8};
public static final byte[] SRC_DATA_24B = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8};
@@ -25,42 +24,42 @@ public class TestSm4 {
@Test
public void testEncryptAndDecrypt() {
try {
byte[] key = Sm4.generateKey();
byte[] iv = Sm4.generateKey();
byte[] key = SM4.generateKey();
byte[] iv = SM4.generateKey();
byte[] cipherText = null;
byte[] decryptedData = null;
System.out.println("key: " + ByteUtils.toHexString(key));
System.out.println("iv: " + ByteUtils.toHexString(iv));
cipherText = Sm4.encrypt_ECB_NoPadding(key, SRC_DATA_16B);
cipherText = SM4.encrypt_ECB_NoPadding(key, SRC_DATA_16B);
System.out.println("SM4 ECB NoPadding encrypt result:\n" + Arrays.toString(cipherText));
System.out.println(ByteUtils.toHexString(cipherText));
decryptedData = Sm4.decrypt_ECB_NoPadding(key, cipherText);
decryptedData = SM4.decrypt_ECB_NoPadding(key, cipherText);
System.out.println("SM4 ECB NoPadding decrypt result:\n" + Arrays.toString(decryptedData));
if (!Arrays.equals(decryptedData, SRC_DATA_16B)) {
Assert.fail();
}
cipherText = Sm4.encrypt_ECB_Padding(key, SRC_DATA_16B);
cipherText = SM4.encrypt_ECB_Padding(key, SRC_DATA_16B);
System.out.println("SM4 ECB Padding encrypt result:\n" + Arrays.toString(cipherText));
System.out.println(ByteUtils.toHexString(cipherText));
decryptedData = Sm4.decrypt_ECB_Padding(key, cipherText);
decryptedData = SM4.decrypt_ECB_Padding(key, cipherText);
System.out.println("SM4 ECB Padding decrypt result:\n" + Arrays.toString(decryptedData));
if (!Arrays.equals(decryptedData, SRC_DATA_16B)) {
Assert.fail();
}
cipherText = Sm4.encrypt_CBC_Padding(key, iv, SRC_DATA);
cipherText = SM4.encrypt_CBC_Padding(key, iv, SRC_DATA);
System.out.println("SM4 CBC Padding encrypt result:\n" + Arrays.toString(cipherText));
decryptedData = Sm4.decrypt_CBC_Padding(key, iv, cipherText);
decryptedData = SM4.decrypt_CBC_Padding(key, iv, cipherText);
System.out.println("SM4 CBC Padding decrypt result:\n" + Arrays.toString(decryptedData));
if (!Arrays.equals(decryptedData, SRC_DATA)) {
Assert.fail();
}
cipherText = Sm4.encrypt_CBC_NoPadding(key, iv, SRC_DATA_16B);
cipherText = SM4.encrypt_CBC_NoPadding(key, iv, SRC_DATA_16B);
System.out.println("SM4 CBC NoPadding encrypt result:\n" + Arrays.toString(cipherText));
decryptedData = Sm4.decrypt_CBC_NoPadding(key, iv, cipherText);
decryptedData = SM4.decrypt_CBC_NoPadding(key, iv, cipherText);
System.out.println("SM4 CBC NoPadding decrypt result:\n" + Arrays.toString(decryptedData));
if (!Arrays.equals(decryptedData, SRC_DATA_16B)) {
Assert.fail();
@@ -0,0 +1,79 @@
package minsecurity.identity;
import minsecurity.Common;
import minsecurity.certificate.cert.CertUtils;
import minsecurity.certificate.cert.Certificate;
import minsecurity.crypto.TestSM2;
import minsecurity.crypto.sm2.SM2Base;
import minsecurity.crypto.sm2.SM2PrivateKey;
import minsecurity.crypto.sm2.SM2PublicKey;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.junit.Test;
import static org.junit.Assert.*;
import org.slf4j.LoggerFactory;
/*
* @Author: hongyu guo
* @Description:
* @Version: 1.0.0
* @Date: 15:24 2021/03/09
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class TestIdentity {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestIdentity.class);
@Test
public void testIdentity1() throws Exception {
AsymmetricCipherKeyPair keyPair = SM2Base.generateKeyPairParameter();
ECPrivateKeyParameters priKey = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters pubKey = (ECPublicKeyParameters) keyPair.getPublic();
byte[] d = priKey.getD().toByteArray();
// d = Arrays.copyOf(d,32);
byte[] x = pubKey.getQ().getAffineXCoord().getEncoded();
byte[] y = pubKey.getQ().getAffineYCoord().getEncoded();
logger.debug("d.len = {}, x.len = {}, y.len = {}",d.length, x.length, y.length);
// BigInteger bigInteger = priKey.getD();
SM2PrivateKey sm2PrivateKey = new SM2PrivateKey(d);
SM2PublicKey sm2PublicKey = new SM2PublicKey(x,y);
KeyParam keyParam = new KeyParam(Common.SM2, Common.SM3withSM2);
Identity identity = new Identity("root",keyParam,sm2PrivateKey,null,sm2PublicKey, "123456", null);
Certificate certificate = new Certificate(1, 1, sm2PublicKey, null,
Common.SM3withSM2, Common.SM2, "root", "root",
System.currentTimeMillis() - 1000, System.currentTimeMillis() + 5000,
Common.CertSign, true, System.currentTimeMillis());
CertUtils.signCert(certificate, sm2PrivateKey);
identity.setCert(certificate);
String text = "2020-03-09";
// test sign and verify
byte[] signature = identity.sign(text.getBytes());
boolean flag = identity.verify(text.getBytes(), signature);
logger.debug("identity verify: {}", flag);
assertTrue(flag);
// test enc and dec
byte[] cipher = identity.encrypt(text.getBytes());
byte[] bytesOfDec = identity.decrypt(cipher);
assertArrayEquals(bytesOfDec, text.getBytes());
// test dump and load
byte[] bytesOfDump = identity.dump(identity.getPasswd());
Identity idFromBytes = Identity.load(bytesOfDump, identity.getPasswd());
assertEquals(ByteUtils.toHexString(identity.getPrikey().getBytes()), ByteUtils.toHexString(idFromBytes.getPrikey().getBytes()));
assertEquals(ByteUtils.toHexString(identity.getPubkey().getBytes()), ByteUtils.toHexString(idFromBytes.getPubkey().getBytes()));
// test dump and load without passwd
bytesOfDump = identity.dump(null);
idFromBytes = Identity.load(bytesOfDump, null);
assertEquals(ByteUtils.toHexString(identity.getPrikey().getBytes()), ByteUtils.toHexString(idFromBytes.getPrikey().getBytes()));
assertEquals(ByteUtils.toHexString(identity.getPubkey().getBytes()), ByteUtils.toHexString(idFromBytes.getPubkey().getBytes()));
}
}