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); // 對簽名摘要進行簽名得到簽名數(shù)據(jù)s
    if(s == NULL) {
        ret = -3;
        EC_KEY_free(p_dsa);
        return ret;
    }

    data[0] = BN_bn2hex(s->r); //二進制轉(zhuǎn)十六進制
    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]); //十六進制轉(zhuǎn)二進制
        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.編譯環(huán)境

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: 1M'1M¥.R?}?尣zS??Ω 
E948080F0496BEAF2303A184BF9F67491AB95920BD3951DBABA36813768273DF
568224ECBA9A83161E1494DAB02884B123A376DE57A9A7BA4F018A5BB9E38404

root@ubuntu:/home/workspace/test/demo_sign# ./ecdsa eccpri256.pem E948080F0496BEAF2303A184BF9F67491AB95920BD3951DBABA36813768273DF 568224ECBA9A83161E1494DAB02884B123A376DE57A9A7BA4F018A5BB9E38404
verify digest: 1M'1M¥.R?}?尣zS??Ω3*fO@
ECDSA_verify ok
verify is ok!
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子净赴,更是在濱河造成了極大的恐慌,老刑警劉巖罩润,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玖翅,死亡現(xiàn)場離奇詭異,居然都是意外死亡割以,警方通過查閱死者的電腦和手機金度,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來严沥,“玉大人猜极,你說我怎么就攤上這事∠” “怎么了跟伏?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長翩瓜。 經(jīng)常有香客問我受扳,道長,這世上最難降的妖魔是什么兔跌? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任勘高,我火速辦了婚禮,結果婚禮上坟桅,老公的妹妹穿的比我還像新娘相满。我一直安慰自己,他們只是感情好桦卒,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布立美。 她就那樣靜靜地躺著,像睡著了一般方灾。 火紅的嫁衣襯著肌膚如雪建蹄。 梳的紋絲不亂的頭發(fā)上碌更,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機與錄音洞慎,去河邊找鬼痛单。 笑死,一個胖子當著我的面吹牛劲腿,可吹牛的內(nèi)容都是我干的旭绒。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼焦人,長吁一口氣:“原來是場噩夢啊……” “哼挥吵!你這毒婦竟也來了?” 一聲冷哼從身側響起花椭,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤忽匈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后矿辽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丹允,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年袋倔,在試婚紗的時候發(fā)現(xiàn)自己被綠了雕蔽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡宾娜,死狀恐怖批狐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碳默,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布缘眶,位于F島的核電站嘱根,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏巷懈。R本人自食惡果不足惜该抒,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望顶燕。 院中可真熱鬧凑保,春花似錦、人聲如沸涌攻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恳谎。三九已至芝此,卻和暖如春憋肖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背婚苹。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工岸更, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人膊升。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓怎炊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親廓译。 傳聞我的和親對象是個殘疾皇子评肆,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容