美文网首页加解密算法 签名音视频数据结构与算法
C语言openssl库的ECDSA-with-sha256签名和

C语言openssl库的ECDSA-with-sha256签名和

作者: 加班猿 | 来源:发表于2021-12-28 08:35 被阅读0次

    1.直接上源码:

    #include <stdio.h>
    #include <string.h>
    #include <openssl/ecdsa.h>
    #include <openssl/pem.h>
    #include <openssl/err.h>
    
    // base64 编码
    char *base64_encode(const char *buffer, int length) {
        BIO *bmem = NULL;
        BIO *b64 = NULL;
        BUF_MEM *bptr;
        char *buff = NULL;
        
        b64 = BIO_new(BIO_f_base64());
        BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
        bmem = BIO_new(BIO_s_mem());
        b64 = BIO_push(b64, bmem);
        BIO_write(b64, buffer, length);
        BIO_flush(b64);
        BIO_get_mem_ptr(b64, &bptr);
        BIO_set_close(b64, BIO_NOCLOSE);
    
        buff = (char *)malloc(bptr->length + 1);
        memcpy(buff, bptr->data, bptr->length);
        buff[bptr->length] = 0;
        BIO_free_all(b64);
    
        return buff;
    }
    
    // base64 解码
    char *base64_decode(char *input, int length) {
        BIO *b64 = NULL;
        BIO *bmem = NULL;
        char *buffer = NULL;
        buffer = (char *)malloc(length);
        memset(buffer, 0, length);
        b64 = BIO_new(BIO_f_base64());
        BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
        bmem = BIO_new_mem_buf(input, length);
        bmem = BIO_push(b64, bmem);
        BIO_read(bmem, buffer, length);
        BIO_free_all(bmem);
    
        return buffer;
    }
    
    //公钥验证签名
    int my_verify(const char *input, int input_len, ECDSA_SIG *signret, const char *pub_key_fn)
    {
        EC_KEY *p_dsa = NULL;
        FILE *file = NULL;
        int ret = 0;
        unsigned char digest[EVP_MAX_MD_SIZE];
        unsigned int digest_len = 0;
        EVP_MD_CTX md_ctx;
        if((file = fopen(pub_key_fn, "rb")) == NULL) {
            ret = -1;
            return ret;
        }
    
        if((p_dsa = PEM_read_EC_PUBKEY(file, NULL,NULL,NULL )) == NULL) { // 获取公钥的ec key
            ret = -2;
            fclose(file);
            return ret;
        }
    
        fclose(file);
        EVP_MD_CTX_init(&md_ctx);
        if (!EVP_DigestInit(&md_ctx, EVP_sha256())) {
            printf("EVP_digest fail \n");
            return -1;
        }
        if (!EVP_DigestUpdate(&md_ctx, (const void *)input, input_len)) {
            printf("EVP_DigestUpdate fail \n");
            return -1;
        }
        if (!EVP_DigestFinal(&md_ctx, digest, &digest_len)) { // 待签名消息用sha256生成256比特的签名摘要
            printf("EVP_DigestFinal fail \n");        
            return -1;
        }
    
        printf("verify digest: %s\n", digest);
    
        ret = ECDSA_do_verify(digest, digest_len, signret, p_dsa); // 对签名摘要进行验签得到结果
    
        if (ret == -1) {
            ret = -3;
            printf("ECDSA_verify err!\n");
            EC_KEY_free(p_dsa);
            return ret;
        } else if (ret == 0) {
            ret = -3;
            printf("ECDSA_verify err incorrect signature!\n");
            EC_KEY_free(p_dsa);
            return ret;
        } else {
           printf("ECDSA_verify ok\n");
        }
        printf("verify is ok!\n");
    
        EC_KEY_free(p_dsa);
    
        return 0;
    }
    
    
    //私钥签名
    int my_sign(const char *input, int input_len, const char *pri_key_fn)
    {
        EC_KEY *p_dsa = NULL;
        ECDSA_SIG *s;
        FILE *file = NULL;
        unsigned char *data[2];
        int nid;
        int signlen = 0;
        int i = 0;
        int ret = 0;
        unsigned char digest[EVP_MAX_MD_SIZE];
        unsigned int digest_len = 0;
        EVP_MD_CTX md_ctx;
    
        memset(data, 0x00, sizeof(data));
        nid = 0;
        file = fopen(pri_key_fn, "rb");
        if(!file)
        {
            ret = -1;
            return ret;
        }
    
        if((p_dsa = PEM_read_ECPrivateKey(file, NULL, NULL, NULL)) == NULL) { // 获取私钥的ec key
            ret = -2;
            fclose(file);
            return ret;
        }
    
        fclose(file);
        EVP_MD_CTX_init(&md_ctx);
        if (!EVP_DigestInit(&md_ctx, EVP_sha256())) {
            printf("EVP_digest fail \n");
            return -1;
        }
        if (!EVP_DigestUpdate(&md_ctx, (const void *)input, input_len)) {
            printf("EVP_DigestUpdate fail \n");
            return -1;
        }
        if (!EVP_DigestFinal(&md_ctx, digest, &digest_len)) { // 待签名消息用sha256生成256比特的签名摘要
            printf("EVP_DigestFinal fail \n");
            return -1;
        }
    
        printf("sign digest: %s\n", digest);
        s = ECDSA_do_sign(digest, digest_len, p_dsa); // 对签名摘要进行签名得到签名数据s
        if(s == NULL) {
            ret = -3;
            EC_KEY_free(p_dsa);
            return ret;
        }
    
        data[0] = BN_bn2hex(s->r); //二进制转十六进制
        data[1] = BN_bn2hex(s->s);
    
        EC_KEY_free(p_dsa);
        ECDSA_SIG_free(s);
    
        printf("%s\n", data[0]);
        printf("%s\n", data[1]);
    
        free(data[0]);
        free(data[1]);
    
        return 0;
    }
    
    int main(int argc, char**argv)
    {
        char src[512+1];
        char dst_str[2][512+1];
        int src_len;
        int ret;
        FILE *f;
    
        memset(src, 0x00, sizeof(src));
        memset(dst_str, 0x00, sizeof(dst_str));
    
        if(argv[1][0] == 's') {
            strcpy(src, "hello world"); // 待签名消息
            src_len = strlen(src) ;
            ret = my_sign(src, src_len, argv[2]);
            if(ret) {
                    fprintf(stderr, "Error\n");
            }
        }
        else {
            ECDSA_SIG *s = (ECDSA_SIG *)malloc(sizeof(ECDSA_SIG));
    
            strcpy(src, "hello world"); // 需要验证的签名消息
            strncpy(dst_str[0], argv[2], 512);
            strncpy(dst_str[1], argv[3], 512);
            src_len = strlen(src);
    
            s->r = BN_new();
            s->s = BN_new();
    
            BN_hex2bn(&(s->r), dst_str[0]); //十六进制转二进制
            BN_hex2bn(&(s->s), dst_str[1]);
    
            ret = my_verify(src, src_len, s, argv[1]);
            if(ret) {
                    fprintf(stderr, "Error\n");
            }
    
            BN_free(s->r);
            BN_free(s->s);
    
            free(s);
        }
    
        return 0;
    }
    

    2.编译环境

    openssl版本为1.0.2g,openssl version查看openssl的版本,其他版本自行验证
    base的编解码代码也有,这里demo暂不使用

    3.编译

    gcc ecdsa.c -o ecdsa -lssl -lcrypto
    

    4.生成私钥和公钥

    openssl ecparam -genkey -name prime256v1 -out eccpri256.key
    openssl ec -in eccpri256.key -pubout -out eccpri256.pem
    

    5.运行结果

    root@ubuntu:/home/workspace/test/demo_sign# ./ecdsa s eccpri256.key
    sign digest: ¹M'¹M¥.Rؚ}«尣zS󭣯Ω 
    E948080F0496BEAF2303A184BF9F67491AB95920BD3951DBABA36813768273DF
    568224ECBA9A83161E1494DAB02884B123A376DE57A9A7BA4F018A5BB9E38404
    
    root@ubuntu:/home/workspace/test/demo_sign# ./ecdsa eccpri256.pem E948080F0496BEAF2303A184BF9F67491AB95920BD3951DBABA36813768273DF 568224ECBA9A83161E1494DAB02884B123A376DE57A9A7BA4F018A5BB9E38404
    verify digest: ¹M'¹M¥.Rؚ}«尣zS󭣯Ω3*fO@
    ECDSA_verify ok
    verify is ok!
    

    相关文章

      网友评论

        本文标题:C语言openssl库的ECDSA-with-sha256签名和

        本文链接:https://www.haomeiwen.com/subject/rmchfrtx.html