diff --git a/src/main/java/minsecurity/certificate/cert/CertUtils.java b/src/main/java/minsecurity/certificate/cert/CertUtils.java index 36175f4..3859630 100644 --- a/src/main/java/minsecurity/certificate/cert/CertUtils.java +++ b/src/main/java/minsecurity/certificate/cert/CertUtils.java @@ -3,12 +3,19 @@ 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 minsecurity.crypto.*; 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.Base64; /* * @Author: hongyu guo @@ -21,6 +28,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,6 +57,14 @@ 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(); @@ -64,6 +86,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 +103,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 +141,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 +160,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 +187,134 @@ 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[] 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); + } + + /** + * 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[] 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); + 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); + } } diff --git a/src/main/java/minsecurity/certificate/cert/Certificate.java b/src/main/java/minsecurity/certificate/cert/Certificate.java index 7984fe2..2d19775 100644 --- a/src/main/java/minsecurity/certificate/cert/Certificate.java +++ b/src/main/java/minsecurity/certificate/cert/Certificate.java @@ -15,6 +15,7 @@ import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import java.lang.reflect.Array; import java.security.*; +import java.util.Arrays; import java.util.Base64; import static minsecurity.certificate.cert.CertUtils.*; @@ -22,7 +23,7 @@ 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 +175,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 + + '}'; } } diff --git a/src/main/java/minsecurity/certificate/cert/InnerCertificate.java b/src/main/java/minsecurity/certificate/cert/InnerCertificate.java index 056cd20..d36caa4 100644 --- a/src/main/java/minsecurity/certificate/cert/InnerCertificate.java +++ b/src/main/java/minsecurity/certificate/cert/InnerCertificate.java @@ -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;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 diff --git a/src/main/java/minsecurity/certificate/cert/TbsCertificate.java b/src/main/java/minsecurity/certificate/cert/TbsCertificate.java index cdbdfda..f024096 100644 --- a/src/main/java/minsecurity/certificate/cert/TbsCertificate.java +++ b/src/main/java/minsecurity/certificate/cert/TbsCertificate.java @@ -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;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 diff --git a/src/main/java/minsecurity/crypto/HashAlgo.java b/src/main/java/minsecurity/crypto/HashAlgo.java index 3f52396..949cb87 100644 --- a/src/main/java/minsecurity/crypto/HashAlgo.java +++ b/src/main/java/minsecurity/crypto/HashAlgo.java @@ -19,7 +19,7 @@ import java.nio.charset.StandardCharsets; * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 */ public class HashAlgo { - // TODO: 单元测试 + // TODO: 单元测试 基本上只需要对sm3做单元测试 /////////////// ///// SM3 ///// /////////////// diff --git a/src/main/java/minsecurity/crypto/PublicKeyUtils.java b/src/main/java/minsecurity/crypto/PublicKeyUtils.java index f2d4221..bf5baa3 100644 --- a/src/main/java/minsecurity/crypto/PublicKeyUtils.java +++ b/src/main/java/minsecurity/crypto/PublicKeyUtils.java @@ -11,6 +11,14 @@ import minsecurity.crypto.sm2.Sm2PublicKey; * @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 */ public class PublicKeyUtils { + /** + * 返回的数据类型为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; diff --git a/src/main/java/minsecurity/crypto/sm2/Sm2Base.java b/src/main/java/minsecurity/crypto/sm2/Sm2Base.java index 9304228..bf86b64 100644 --- a/src/main/java/minsecurity/crypto/sm2/Sm2Base.java +++ b/src/main/java/minsecurity/crypto/sm2/Sm2Base.java @@ -39,6 +39,10 @@ public class Sm2Base { } 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 +60,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 +78,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 +109,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 +125,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 +153,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(), diff --git a/src/main/java/minsecurity/crypto/sm2/Sm2PrivateKey.java b/src/main/java/minsecurity/crypto/sm2/Sm2PrivateKey.java index 71d8ccd..9367ed5 100644 --- a/src/main/java/minsecurity/crypto/sm2/Sm2PrivateKey.java +++ b/src/main/java/minsecurity/crypto/sm2/Sm2PrivateKey.java @@ -23,7 +23,20 @@ import java.security.SecureRandom; public class Sm2PrivateKey implements PrivateKeyInterface { 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); diff --git a/src/main/java/minsecurity/crypto/sm2/Sm2PublicKey.java b/src/main/java/minsecurity/crypto/sm2/Sm2PublicKey.java index 9251ff2..5b9e76a 100644 --- a/src/main/java/minsecurity/crypto/sm2/Sm2PublicKey.java +++ b/src/main/java/minsecurity/crypto/sm2/Sm2PublicKey.java @@ -15,7 +15,7 @@ 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;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 @@ -27,11 +27,22 @@ public class Sm2PublicKey implements PublicKeyInterface { 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[] bytes){ + setBytes(bytes); + } + @Override @@ -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); @@ -108,7 +125,10 @@ public class Sm2PublicKey implements PublicKeyInterface { } return result; } + + + + private ECPublicKeyParameters publicKey; ////////////////////////////////////////////// private end ////////////////////////////////////////////// - ECPublicKeyParameters publicKey; } diff --git a/src/test/java/minsecurity/certificate/cert/TestCert.java b/src/test/java/minsecurity/certificate/cert/TestCert.java index 73bee78..eb3f780 100644 --- a/src/test/java/minsecurity/certificate/cert/TestCert.java +++ b/src/test/java/minsecurity/certificate/cert/TestCert.java @@ -4,20 +4,13 @@ import minsecurity.Common; import minsecurity.crypto.sm2.Sm2Base; import minsecurity.crypto.sm2.Sm2PrivateKey; import minsecurity.crypto.sm2.Sm2PublicKey; -import minsecurity.crypto.sm2.TestSm2; 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: @@ -45,11 +38,33 @@ 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 @@ -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)); } } diff --git a/src/test/java/minsecurity/certificate/x509/TestX509.java b/src/test/java/minsecurity/certificate/x509/TestX509.java index 7d42326..920cdce 100644 --- a/src/test/java/minsecurity/certificate/x509/TestX509.java +++ b/src/test/java/minsecurity/certificate/x509/TestX509.java @@ -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()); } diff --git a/src/test/java/minsecurity/crypto/sm2/TestSm2.java b/src/test/java/minsecurity/crypto/TestSm2.java similarity index 79% rename from src/test/java/minsecurity/crypto/sm2/TestSm2.java rename to src/test/java/minsecurity/crypto/TestSm2.java index 41cb631..57e616c 100644 --- a/src/test/java/minsecurity/crypto/sm2/TestSm2.java +++ b/src/test/java/minsecurity/crypto/TestSm2.java @@ -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 @@ -86,6 +91,7 @@ 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); @@ -94,4 +100,36 @@ public class TestSm2 { 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[] res = new List[days + 15]; + for(int i = 0; i < days + 15; i++){ + res[i] = new ArrayList(); + } + + 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); + } }