国密sm2签名验签

186 篇文章 1 订阅
9 篇文章 0 订阅

生成私钥:

#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/conf.h>
#include <openssl/x509v3.h>

#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/asn1.h>
#include <openssl/x509.h>
#include <openssl/objects.h>
#include <openssl/buffer.h>

#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
#endif
int make_server_private_key()
{
    OpenSSL_add_all_ciphers();
    OpenSSL_add_all_digests();
    ERR_load_crypto_strings();

    SSL_CTX *ctx = SSL_CTX_new (SSLv23_server_method ());
    SSL_CTX_set_options (ctx,
                         SSL_OP_SINGLE_DH_USE |
                         SSL_OP_SINGLE_ECDH_USE |
                         SSL_OP_NO_SSLv2);

    EVP_PKEY *evk = EVP_PKEY_new();

    EC_KEY *ec_server = EC_KEY_new_by_curve_name (NID_sm2p256v1);
    if (! ec_server)
        printf("ecdh error!EC_KEY_new_by_curve_name\n");

    EC_KEY_generate_key(ec_server);
    BIO *bio_out = BIO_new_file("server_private.key", "w");

    PEM_write_bio_ECPrivateKey(bio_out, ec_server, NULL, NULL, 0, NULL, NULL);
    BIO_free(bio_out);

    EC_KEY_free(ec_server);
    EVP_PKEY_free(evk);

    return 0;
}

生成证书

int make_cert(char* name_C, char* name_S, char* name_L, char* name_O, char * name_OU, char* name_CN, 
           char* PrivateKeyFileName, char* CertFileName )
{
    X509 *x;
    EVP_PKEY *pk;
    X509_NAME *name = NULL;
    BIO  * key  =  NULL;

    key  =  BIO_new(BIO_s_file()); 
    BIO_read_filename(key,PrivateKeyFileName);
    EC_KEY *ecdh = PEM_read_bio_ECPrivateKey(key, NULL, NULL, NULL);
    EVP_PKEY *evk = EVP_PKEY_new();
    EVP_PKEY_set1_EC_KEY(evk, ecdh);

    X509 *x509 = NULL;

    if (evk == NULL)
    {
        abort();
        return(0);
    }
    else
        pk = evk;

    if ((x = X509_new()) == NULL)
        return(0);

    X509_set_version(x, 2);
    int serial = 12345;
    ASN1_INTEGER_set(X509_get_serialNumber(x), serial);
    X509_gmtime_adj(X509_get_notBefore(x), 0);
    int days = 36500;
    X509_gmtime_adj(X509_get_notAfter(x), (long)60 * 60 * 24 * days);
    X509_set_pubkey(x, pk);

    name = X509_get_subject_name(x);

    X509_NAME_add_entry_by_txt(name, "C",
                               MBSTRING_ASC, name_C, -1, -1, 0);

    X509_NAME_add_entry_by_txt(name, "S",
                               MBSTRING_ASC, name_S, -1, -1, 0);

    X509_NAME_add_entry_by_txt(name, "L",
                               MBSTRING_ASC, name_L, -1, -1, 0);

    X509_NAME_add_entry_by_txt(name, "O",
                               MBSTRING_ASC, name_O, -1, -1, 0);

    X509_NAME_add_entry_by_txt(name, "OU",
                               MBSTRING_ASC, name_OU, -1, -1, 0);

    X509_NAME_add_entry_by_txt(name, "CN",
                               MBSTRING_ASC, name_CN, -1, -1, 0);


    X509_NAME *issuer_name=NULL;

    if (!issuer_name)
        X509_set_issuer_name(x, name);
    else
        X509_set_issuer_name(x, issuer_name);

    int n=X509_sign(x, evk, EVP_sm3());

    x509 = x;
    evk = pk;

    BIO *bio_x = BIO_new_file(CertFileName, "w");
    PEM_write_bio_X509(bio_x, x509);

    printf("n=%d\n",n);

    BIO_free(bio_x);
    EVP_PKEY_free(evk);
    EC_KEY_free(ecdh);
    X509_free(x509);

    return(1);
}

以下代码有可能不符合国标

签名

int signature(char *msg)
{
    int ret = 0;
    unsigned int slen=256;
    unsigned char sig[256];
    

    BIO  * key  =  NULL;

    key  =  BIO_new(BIO_s_file()); 
    BIO_read_filename(key,"server_private.key");
    EC_KEY *ecdh = PEM_read_bio_ECPrivateKey(key, NULL, NULL, NULL);
    printf("sig len:%d\n", ECDSA_size(ecdh));
    if (!SM2_sign(0,msg, strlen(msg), sig,&slen,ecdh))
    {
       return 0;
    }
    
    FILE *fp = fopen("server_16.sig", "wb");
    for(int i=0; i < slen; i++)
    {
        fwrite(((unsigned char*)(sig+i)), 1, 1, fp);
    }    
    fclose(fp);

    printf("slen:%d\n", slen);
    for(int i=0; i < slen; i++)
    {
    	printf("%02x ", *((unsigned char*)(sig+i)));
    }
    printf("\n");

    /* 成功 */
    ret = 1;

    /* 清理 */


    return ret;
}

验签

int verify_sig(void *sig, char *msg, size_t slen)
{
    int nRet;
    ECDSA_SIG *s;
    const unsigned char *p = sig;
    unsigned char *der = NULL;
    int derlen = -1;
    int ret = -1;
    
    FILE *fp = fopen("server_cert.pem", "r");
    X509 *cert = PEM_read_X509(fp, NULL, NULL, NULL);
    //FILE *fp = fopen("server_cert.der", "r");
    //X509 *cert = d2i_X509_fp(fp, NULL);
     
    EVP_PKEY *evk = X509_get_pubkey(cert);
    EC_KEY *ec_key=EVP_PKEY_get0_EC_KEY(evk);

    printf("\nslen:%ld\n", slen);
    for(int i=0; i < slen; i++)
    {
    	printf("%02x ", *((unsigned char*)(sig+i)));
    }
    printf("\n");

    nRet = SM2_verify(0,msg, strlen(msg), sig, slen,ec_key);
    return nRet == 1 ? 1 : 0;
}

ChatGPT

国密GM/T 0003.5-2012 标准中的 SM2 是一种公钥加密算法,类似于其他加密标准,如 RSA 或 ECC。SM2 同样包含了签名、验签、加密和解密等功能。下面将提供一个 SM2 签名和验签的示例代码,这是基于 OpenSSL 的 GmSSL 分支实现的,但请注意务必检查 OpenSSL/GmSSL 的许可证和出于安全考虑,始终使用最新版本的库和补丁。
以下是使用 GmSSL 实现 SM2 签名和验签的基本示例:

#include <string.h>
#include <openssl/sm2.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/bn.h>
#include <openssl/objects.h>

int main() {
    int ret = 0;
    // 初始化
    OpenSSL_add_all_algorithms();

    // 创建 SM2 密钥对
    EC_KEY *sm2_key = EC_KEY_new_by_curve_name(NID_sm2);
    if (!sm2_key || !EC_KEY_generate_key(sm2_key)) {
        // 处理密钥生成失败
    }

    // 要签名的消息和其长度
    unsigned char message[] = "The quick brown fox jumps over the lazy dog";
    size_t message_len = strlen(message);

    // 签名操作
    ECDSA_SIG *signature = NULL;
    if (!SM2_do_sign(sm2_key, EVP_sm3(), message, message_len, &signature)) {
        // 处理签名失败
    }

    // 验签操作
    int verify = SM2_do_verify(sm2_key, EVP_sm3(), signature, message, message_len);
    if (verify != 1) {
        // 验证失败处理
    }

    // 释放资源
    ECDSA_SIG_free(signature);
    EC_KEY_free(sm2_key);

    // 结束,清理 OpenSSL
    EVP_cleanup();
    return ret;
}

在使用上面的代码之前,请确认你有安装 GmSSL 或 OpenSSL 并且已包含 SM2 支持。如果需要编译前述代码,可以用类似下面的 gcc 命令:

gcc sm2_example.c -o sm2_example -lssl -lcrypto

请根据你的系统和安装路径调整库的链接选项。这个代码仅作为一个示例,不包含错误处理。在生产代码中,需要对所有返回值做出充分的检查。此外,密钥的管理和保护也是关键考虑点。在实际应用中,你需要确保采取安全的密钥管理措施,避免密钥泄露风险。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
您好,您的问题似乎有些不明确。您是想了解如何在 Java 或 Go 中使用国密 SM2 算法进行签名验签,或是想了解如何进行 P7 格式的签名验签吗?以下是两个问题的回答: 1. 如何在 Java 或 Go 中使用国密 SM2 算法进行签名验签? 在 Java 中使用国密 SM2 算法进行签名验签,您可以使用 BouncyCastle 库。具体实现可以参考下面的代码: Java: ```java // 加载 BouncyCastle Provider Security.addProvider(new BouncyCastleProvider()); // 生成密钥对 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC"); ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("sm2p256v1"); keyPairGenerator.initialize(ecGenParameterSpec, new SecureRandom()); KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 获取私钥和公钥 PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); // 签名 Signature signature = Signature.getInstance("SM3withSM2", "BC"); signature.initSign(privateKey); signature.update(data); byte[] signatureBytes = signature.sign(); // 验签 signature.initVerify(publicKey); signature.update(data); boolean verifyResult = signature.verify(signatureBytes); ``` Go: ```go // 生成密钥对 privateKey, err := sm2.GenerateKey() if err != nil { log.Fatal(err) } publicKey := &privateKey.PublicKey // 签名 hash := sm3.SumSM3(data) signature, err := privateKey.Sign(rand.Reader, hash[:], nil) if err != nil { log.Fatal(err) } // 验签 verifyResult := publicKey.Verify(hash[:], signature) ``` 2. 如何进行 P7 格式的签名验签? 在 Java 中进行 P7 格式的签名验签,您可以使用 BouncyCastle 库。具体实现可以参考下面的代码: Java: ```java // 加载 BouncyCastle Provider Security.addProvider(new BouncyCastleProvider()); // 读取证书和私钥 KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(new FileInputStream("keystore.p12"), "password".toCharArray()); PrivateKey privateKey = (PrivateKey) keyStore.getKey("alias", "password".toCharArray()); Certificate[] certChain = keyStore.getCertificateChain("alias"); X509Certificate cert = (X509Certificate) certChain[0]; // 加载证书链 JcaCertStore jcaCertStore = new JcaCertStore(Arrays.asList(certChain)); // 签名 ContentSigner signer = new JcaContentSignerBuilder("SM3withSM2").setProvider("BC").build(privateKey); CMSTypedData cmsData = new CMSProcessableByteArray(data); CMSSignedDataGenerator generator = new CMSSignedDataGenerator(); generator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).build(signer, cert)); generator.addCertificates(jcaCertStore); CMSSignedData signedData = generator.generate(cmsData, true); byte[] signedBytes = signedData.getEncoded(); // 验签 CMSSignedData cms = new CMSSignedData(signedBytes); SignerInformationStore signers = cms.getSignerInfos(); Collection<SignerInformation> c = signers.getSigners(); Iterator<SignerInformation> it = c.iterator(); if (it.hasNext()) { SignerInformation signer = it.next(); X509CertificateHolder certHolder = (X509CertificateHolder) cms.getCertificates().getMatches(signer.getSID()).iterator().next(); if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certHolder))) { return true; } } return false; ``` Go: ```go // 读取证书和私钥 pemData, err := ioutil.ReadFile("keystore.pem") if err != nil { log.Fatal(err) } blocks := pem.Decode(pemData) key, err := x509.ParsePKCS8PrivateKey(blocks.Bytes) if err != nil { log.Fatal(err) } certData, err := ioutil.ReadFile("cert.pem") if err != nil { log.Fatal(err) } cert, err := x509.ParseCertificate(certData) if err != nil { log.Fatal(err) } // 加载证书链 certs := []*x509.Certificate{cert} intermediateData, err := ioutil.ReadFile("intermediate.pem") if err == nil { for { blocks := pem.Decode(intermediateData) if blocks == nil { break } intermediateCert, err := x509.ParseCertificate(blocks.Bytes) if err != nil { log.Fatal(err) } certs = append(certs, intermediateCert) } } // 签名 hash := sm3.SumSM3(data) signedData, err := cms.NewSignedData(hash[:], key, cert, certs...) if err != nil { log.Fatal(err) } signedBytes, err := signedData.ToDER() if err != nil { log.Fatal(err) } // 验签 cms, err := cms.ParseCMS(signedBytes) if err != nil { log.Fatal(err) } signerInfos := cms.GetSignerInfos() for _, signerInfo := range signerInfos { err = signerInfo.Verify(cert) if err == nil { return true } } return false ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

109702008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值