C++版本ECDSA-with-SHA256签名验证

简介: 由于项目需要验证签名,这里不做签名,只验签,所以直接上代码。

由于项目需要验证签名,这里不做签名,只验签


直接上代码:


使用方法:


openssl版本:1.0.2g 其他的自行验证


编译:g++ x509.cpp -o x509 -lssl -lcrypto


执行:./x509


#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <cstring>
#include <iostream>
// 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 get_str_len(const char *in) {
    int num = 0;
    if(in == NULL) {
        return 0;
    }
    while (!((*(in + num) == NULL) && (*(in + num + 1) == NULL) \
    && (*(in + num + 2) == NULL) && (*(in + num + 3) == NULL) \
    && (*(in + num + 4) == NULL)&& (*(in + num + 5) == NULL) \
    && (*(in + num + 6) == NULL)&& (*(in + num + 7) == NULL))) {
        num++;
    }
    return num;
}
static const char hex_table[16] = {
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
// 字节转十六进制字符串
std::string BytesToHexStr(const char* aInStr, int len)
{
    std::string hex_str;
    for (int i = 0; i < len; ++i) {
        hex_str.append(&hex_table[(aInStr[i] & 0xF0) >> 4], 1);
        hex_str.append(&hex_table[aInStr[i] & 0xF], 1);
    }
    std::cout << hex_str << std::endl;
    return hex_str;
}
// 字符串截取
char* substring(char* ch,int pos,int length)  
{  
    // 定义字符指针 指向传递进来的ch地址
    char *pch = ch;
    // 通过calloc来分配一个length长度的字符数组,返回的是字符指针。
    char *subch = (char*)calloc(sizeof(char),length+1);
    int i;
    // 只有在C99下for循环中才可以声明变量,这里写在外面,提高兼容性。
    pch = pch + pos;
    // 是pch指针指向pos位置。
    for(i = 0; i < length; i++) {
        subch[i] = *(pch++); // 循环遍历赋值数组。
    }  
    subch[length]='\0'; // 加上字符串结束符。
    return subch;       // 返回分配的字符数组地址。
} 
int ECDSA_WithSHA256_do_verify(const char *strx509, char *message, unsigned int messageLen, char *signBuf, unsigned int signLen) {
    EC_KEY * ec_key;
    EVP_MD_CTX md_ctx;
    int ret = -1;
    char *Sigbuff = NULL, *Signature = NULL, *r = NULL, *s = NULL;
    char dst_str[2][512+1];
    unsigned char digest[EVP_MAX_MD_SIZE];
    unsigned int digestLen = 0;
    BIO *bio_mem = BIO_new(BIO_s_mem());
    BIO_puts(bio_mem, strx509);
    X509 * x509 = PEM_read_bio_X509(bio_mem, NULL, NULL, NULL);
    EVP_PKEY *pkey = X509_get_pubkey(x509); // 获取证书的公钥
    if (pkey->type == EVP_PKEY_EC) {
        ec_key = EVP_PKEY_get1_EC_KEY(pkey);
        if (!ec_key) {
            printf("get EVP_PKEY_get1_EC_KEY fail \n");
        }
    }
    EVP_PKEY_free(pkey);
    Sigbuff = base64_decode(message,messageLen);  // base64解码后的验证数据
    Signature = base64_decode(signBuf,signLen);     // base64解码后的签名数据
    printf("Sigbuff: %s\n", Sigbuff);
    printf("Signature: %s\n Signature len: %d\n EVP_MAX_MD_SIZE: %d\n", Signature,get_str_len(Signature), EVP_MAX_MD_SIZE);
    r = substring(Signature,0,get_str_len(Signature)/2);
    s = substring(Signature,get_str_len(Signature)/2,get_str_len(Signature));
    std::string rSignatureInHex = BytesToHexStr(r,get_str_len(Signature)/2);
    std::string sSignatureInHex = BytesToHexStr(s,get_str_len(Signature)/2);
    free(r);
    free(s);
    EVP_MD_CTX_init(&md_ctx);
    if (!EVP_DigestInit(&md_ctx, EVP_sha256())) {
        printf("EVP_digest fail \n");
    }
    if (!EVP_DigestUpdate(&md_ctx, (const void *)Sigbuff, get_str_len(Sigbuff))) {
        printf("EVP_DigestUpdate fail \n");
    }
    if (!EVP_DigestFinal(&md_ctx, digest, &digestLen)) {
        printf("EVP_DigestFinal fail \n");
    }
    free(Sigbuff);
    free(Signature);
    ECDSA_SIG *sig = (ECDSA_SIG *)malloc(sizeof(ECDSA_SIG));
    strncpy(dst_str[0], rSignatureInHex.c_str(), 512);
    strncpy(dst_str[1], sSignatureInHex.c_str(), 512);
    printf("dst_str[0]: %s\n", &dst_str[0]);
    printf("dst_str[1]: %s\n", &dst_str[1]);
    sig->r = BN_new();
    sig->s = BN_new();
    BN_hex2bn(&(sig->r), dst_str[0]); //十六进制转二进制
    BN_hex2bn(&(sig->s), dst_str[1]);
    /*do verify*/
    ret = ECDSA_do_verify((const unsigned char*)digest, digestLen, sig, ec_key);
    if (ret == -1) {
       printf("ECDSA_verify failed\n");
    } else if (ret == 0) {
       printf("ECDSA_verify incorrect signature\n");
    } else {
       printf("ECDSA_verify ok\n");
    }
    BN_free(sig->r);
    BN_free(sig->s);
    free(sig);
    if (ec_key) {
        EC_KEY_free(ec_key);
        ec_key = NULL;
    }
    BIO_free(bio_mem);
    X509_free(x509);
    return ret;
}
int main(int argc, char **argv)
{
    OpenSSL_add_all_algorithms();
    // 需要验证的数据的base64编码
    char message[] = "hGpTaWduYXR1cmUxTaIESDSaQrDC0HKOASZAWQECpAQaZF2BgAYaYUOemQFiSVQ5AQOhAaRhdoGqYmRuAWJtYW1PUkctMTAwMDAxNjk5YnZwajExMTkzMDUwMDViZHRqMjAyMS0wNS0wNWJjb2JJVGJjaXgmMDFJVDVBMUM2NEYyREYwODQ3RjI5Rjc0MTA2MjA1OEFGQUUwIzFibXBsRVUvMS8yMS8xNTI5Ymlzdk1pbmlzdGVybyBkZWxsYSBTYWx1dGVic2QBYnRnaTg0MDUzOTAwNmNuYW2kY2ZudGdQQU5ESU5JYmZuZ1BBTkRJTkljZ250ZkFORFJFQWJnbmZBTkRSRUFjdmVyZTEuMC4wY2RvYmoxOTUyLTA5LTI4";
    // 摘要签名数据的base64编码
    char signBuf[] = "a0KNpWa23iFQue19IioU/jrUPd/Utoo9A4prMG9LvS3FCsNEHHAwoAUpO4/KIfLB6R1MiIakaIJo4lIBawvUOA==";
    // 证书
    std::string str = "MIIEDzCCAfegAwIBAgIURldu5rsfrDeZtDBxrJ+SujMr2IswDQYJKoZIhvcNAQELBQAwSTELMAkGA1UEBhMCSVQxHzAdBgNVBAoMFk1pbmlzdGVybyBkZWxsYSBTYWx1dGUxGTAXBgNVBAMMEEl0YWx5IERHQyBDU0NBIDEwHhcNMjEwNTEyMDgxODE3WhcNMjMwNTEyMDgxMTU5WjBIMQswCQYDVQQGEwJJVDEfMB0GA1UECgwWTWluaXN0ZXJvIGRlbGxhIFNhbHV0ZTEYMBYGA1UEAwwPSXRhbHkgREdDIERTQyAxMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnL9+WnIp9fvbcocZSGUFlSw9ffW/jbMONzcvm1X4c+pXOPEs7C4/83+PxS8Swea2hgm/tKt4PI0z8wgnIehoj6OBujCBtzAfBgNVHSMEGDAWgBS+VOVpXmeSQImXYEEAB/pLRVCw/zBlBgNVHR8EXjBcMFqgWKBWhlRsZGFwOi8vY2Fkcy5kZ2MuZ292Lml0L0NOPUl0YWx5JTIwREdDJTIwQ1NDQSUyMHhcMSxPPU1pbmlzdGVybyUyMGRlbGxhJTIwU2FsdXRlLEM9SVQwHQYDVR0OBBYEFC4bAbCvpArrgZ0E+RrqS8V7TNNIMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAjxTeF7yhKz/3PKZ9+WfgZPaIzZvnO/nmuUartgVd3xuTPNtd5tuYRNS/1B78HNNk7fXiq5hH2q8xHF9yxYxExov2qFrfUMD5HOZzYKHZcjcWFNHvH6jx7qDCtb5PrOgSK5QUQzycR7MgWIFinoWwsWIrA1AJOwfUoi7v1aoWNMK1eHZmR3Y9LQ84qeE2yDk3jqEGjlJVCbgBp7O8emzy2KhWv3JyRZgTmFz7p6eRXDzUYHtJaufveIhkNM/U8p3S7egQegliIFMmufvEyZemD2BMvb97H9PQpuzeMwB8zcFbuZmNl42AFMQ2PhQe27pU0wFsDEqLe0ETb5eR3T9L6zdSrWldw6UuXoYV0/5fvjA55qCjAaLJ0qi16Ca/jt6iKuws/KKh9yr+FqZMnZUH2D2j2i8LBA67Ie0JoZPSojr8cwSTxQBdJFI722uczCj/Rt69Y4sLdV3hNQ2A9hHrXesyQslr0ez3UHHzDRFMVlOXWCayj3LIgvtfTjKrT1J+/3Vu9fvs1+CCJELuC9gtVLxMsdRc/A6/bvW4mAsyY78ROX27Bi8CxPN5IZbtiyjpmdfr2bufDcwhwzdwsdQQDoSiIF1LZqCn7sHBmUhzoPcBJdXFET58EKow0BWcerZzpvsVHcMTE2uuAUr/JUh1SBpoJCiMIRSl+XPoEA2qqYU=";
    str.insert(0,"-----BEGIN CERTIFICATE-----" "\n");
    str.append( "\n" "-----END CERTIFICATE-----" "\n");
    int ret = ECDSA_WithSHA256_do_verify(str.c_str(), message, sizeof(message), signBuf, sizeof(signBuf));
    printf("ECDSA_WithSHA256 ret = %d\n", ret);
}
/*
使用方法:
openssl版本:1.0.2g 其他的自行验证
编译:g++ x509.cpp -o x509 -lssl -lcrypto
执行:./x509
*/
openssl   
目录
相关文章
|
6月前
|
C++
二叉树进阶面试题(精华总结)【C++版本】
二叉树进阶面试题(精华总结)【C++版本】
|
6月前
|
C++
【PTA】L1-016 验证身份(C++)
【PTA】L1-016 验证身份(C++)
83 0
【PTA】L1-016 验证身份(C++)
|
6月前
|
算法 API 计算机视觉
[opencv学习笔记] jiazhigang 30讲源码C++版本(含Makefile)
[opencv学习笔记] jiazhigang 30讲源码C++版本(含Makefile)
72 0
|
6月前
|
C++
验证回文串(C++)
验证回文串(C++)
27 0
|
29天前
|
Linux 编译器 测试技术
【C++】CentOS环境搭建-快速升级G++版本
通过上述任一方法,您都可以在CentOS环境中高效地升级G++至所需的最新版本,进而利用C++的新特性,提升开发效率和代码质量。
147 64
|
30天前
|
Linux 编译器 测试技术
【C++】CentOS环境搭建-快速升级G++版本
通过上述任一方法,您都可以在CentOS环境中高效地升级G++至所需的最新版本,进而利用C++的新特性,提升开发效率和代码质量。
171 63
|
6月前
|
C++ 索引
c++:string相关的oj题(415. 字符串相加、125. 验证回文串、541. 反转字符串 II、557. 反转字符串中的单词 III)
c++:string相关的oj题(415. 字符串相加、125. 验证回文串、541. 反转字符串 II、557. 反转字符串中的单词 III)
66 0
|
3月前
|
缓存 C++ Windows
Inno setup 脚本判断 Microsoft Visual C++ Redistributable 不同版本区别
Inno setup 脚本判断 Microsoft Visual C++ Redistributable 不同版本区别
|
5月前
|
Linux vr&ar C语言
Linux怎样更新Centos下Gcc版本支持C17?Centos7快速安装gcc8.3.1 可支持C++17(附gcc相关链接整理)
Linux怎样更新Centos下Gcc版本支持C17?Centos7快速安装gcc8.3.1 可支持C++17(附gcc相关链接整理)
291 2
|
Linux vr&ar C语言
Linux怎样更新Centos下Gcc版本支持C++17?
Centos7快速安装gcc8.3.1 可支持C++17(附gcc相关链接整理) centos7直接yum安装的那个gcc版本为4.8.5,对于大多数的需求来说都是低了。系统安装镜像里的那个版本也是4.8.5。 在g++ 7 以上的版本中添加了对c++17 的支持,所以为了工作需要现在需要升级到高版本。
1167 1