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

简介: C语言openssl库的ECDSA-with-sha256签名和验签,直接上源码。

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!
目录
相关文章
|
1月前
|
存储 算法 程序员
C语言:库函数
C语言的库函数是预定义的函数,用于执行常见的编程任务,如输入输出、字符串处理、数学运算等。使用库函数可以简化编程工作,提高开发效率。C标准库提供了丰富的函数,满足各种需求。
ly~
|
2月前
|
数据可视化 BI API
除了 OpenGL,还有哪些常用的图形库可以在 C 语言中使用?
除了OpenGL,C语言中还有多个常用的图形库:SDL,适合初学者,用于2D游戏和多媒体应用;Allegro,高性能,支持2D/3D图形,广泛应用于游戏开发;Cairo,矢量图形库,支持高质量图形输出,适用于数据可视化;SFML,提供简单接口,用于2D/3D游戏及多媒体应用;GTK+,开源窗口工具包,用于创建图形用户界面。这些库各有特色,适用于不同的开发需求。
ly~
617 4
|
2月前
|
存储 安全 编译器
深入C语言库:字符与字符串函数模拟实现
深入C语言库:字符与字符串函数模拟实现
|
7月前
|
C语言 存储
C语言—部分库函数的模拟实现
C语言—部分库函数的模拟实现
|
4月前
|
C语言
C语言中的math库概述
C语言中的math库概述
133 1
|
4月前
|
存储 Serverless C语言
C语言中的标准库函数
C语言中的标准库函数
71 0
|
4月前
|
API 开发工具 C语言
C语言与图形界面:利用GTK+、Qt等库创建GUI应用。
C语言与图形界面:利用GTK+、Qt等库创建GUI应用。
248 0
|
6月前
|
存储 移动开发 C语言
技术心得记录:嵌入式开发中常用到的C语言库函数
技术心得记录:嵌入式开发中常用到的C语言库函数
68 1
|
6月前
|
C语言
C语言的标准库:string.h, math.h, stdlib.h
C语言的标准库:string.h, math.h, stdlib.h
|
6月前
|
C语言
【海贼王编程冒险 - C语言海上篇】库函数怎样模拟实现?
【海贼王编程冒险 - C语言海上篇】库函数怎样模拟实现?
39 1