您好,欢迎来到星星旅游。
搜索
您的当前位置:首页基于openssl3.0,如何实现RSA公钥解密

基于openssl3.0,如何实现RSA公钥解密

来源:星星旅游


前言

在将项目从 OpenSSL 1.1 升级到 OpenSSL 3.0 的过程中,开发者可能会遇到许多 API 的变化和弃用,导致开发者在实现某些功能时,找不到正确的实现方式。比如:如何实现RSA的公钥解密。

一、问题分析

在一些场景中,我们需要验证公私钥是否匹配。一般情况下,可以使用私钥签名,公钥验签的方式来实现。但是在一些特殊情况下,比如调用TEE的接口来获取签名值,但是没有相应的验签接口来实现公私钥匹配的验证,自己实现的验签接口验证签名值失败,在这种情况下,可以使用公钥解密的方式来验证公私钥是否匹配。

二、在openssl1.1下可以使用如下方式来实现公钥解密

int public_decrypt(const X509* cert, const unsigned char* signBuf, size_t signBufLen, const int signMode)
{
    EVP_PKEY *pkey = NULL;
    pkey = X509_get_pubkey(cert);
    if (NULL == pkey) {
        printf("X509_get_pubkey error, %ld, %s", ERR_get_error(), ERR_error_string(ERR_get_error(), NULL));
        return -1;
    }
   
    RSA *rsa = NULL;
    rsa = EVP_PKEY_get1_RSA(pkey);
    if (NULL == rsa) {
        printf("EVP_PKEY_get1_RSA error, %ld, %s", ERR_get_error(), ERR_error_string(ERR_get_error(), NULL));
       	WY_OPENSSL_FREE(EVP_PKEY, pkey);
        return -1;
    }
    
    unsigned char* out = NULL;
    int outLen = 0;
    out = (unsigned char*)calloc(1, signBufLen + 1);
    if (out != NULL) {
        printf("calloc error");
        WY_OPENSSL_FREE(EVP_PKEY, pkey);
       	WY_OPENSSL_FREE(RSA, rsa);
        return -1;
    }

    outLen= RSA_public_decrypt(signBufLen, (unsigned char *)signBuf, out, rsa , signMode);
    if (outLen <= 0) {
        printf("RSA_public_decrypt error, %ld, %s", ERR_get_error(), ERR_error_string(ERR_get_error(), NULL));
       	WY_OPENSSL_FREE(EVP_PKEY, pkey);
        WY_OPENSSL_FREE(RSA, rsa);
        WY_FREE(out);
       	return -1;
    }
    
    WY_OPENSSL_FREE(EVP_PKEY, pkey);
    WY_OPENSSL_FREE(RSA, rsa);
    WY_FREE(out);
    return 0;
}

三、在openssl3.0中可以使用如下方式来实现公钥解密

注:

  1. 以下实现方式本质上并不是使用公钥去解密,而是通过特殊算法来恢复签名数据。
  2. 其中返回值的相关定义、日志输出、内存释放需要自行实现
    具体实现的代码如下:
int public_decrypt(const EVP_PKEY* evpPublicKey, const unsigned char *sign, size_t signLen, const int signMode)
{
    EVP_PKEY_CTX *evpCtx = NULL;
    evpCtx = EVP_PKEY_CTX_new((EVP_PKEY*)evpPublicKey, NULL);
    if (NULL == evpCtx) {
        LOG_E("EVP_PKEY_CTX_new error, %ld, %s", ERR_get_error(), ERR_error_string(ERR_get_error(), NULL));
        return ERROR_EVP_PKEY_CTX_NEW;
    }

    unsigned char *out = NULL;
    size_t outLen = 0;
    if ((EVP_PKEY_verify_recover_init(evpCtx) <= 0)
        || (EVP_PKEY_CTX_set_rsa_padding(evpCtx, signMode) <= 0)
        || (EVP_PKEY_verify_recover(evpCtx, NULL, &outLen, sign, signLen) <= 0)) {
        LOG_E("EVP_PKEY_verify_recover error, %ld, %s", ERR_get_error(), ERR_error_string(ERR_get_error(), NULL));
        WY_OPENSSL_FREE(EVP_PKEY_CTX, evpCtx);
        return ERROR_RSA_VERIFY;
    }

    out = OPENSSL_malloc(outLen);
    if(NULL == out) {
        LOG_E("OPENSSL_malloc error, %ld, %s", ERR_get_error(), ERR_error_string(ERR_get_error(), NULL));
        WY_OPENSSL_FREE(EVP_PKEY_CTX, evpCtx);
        return ERROR_RSA_VERIFY;
    }

    if (EVP_PKEY_verify_recover(evpCtx, out, &outLen, sign, signLen) <= 0) {
        LOG_E("OPENSSL_malloc error, %ld, %s", ERR_get_error(), ERR_error_string(ERR_get_error(), NULL));
        WY_FREE(out);
        WY_OPENSSL_FREE(EVP_PKEY_CTX, evpCtx);
        return ERROR_RSA_VERIFY;
    }
    LOG_E("EVP_PKEY_verify_recover success");
    WY_FREE(out);
    WY_OPENSSL_FREE(EVP_PKEY_CTX, evpCtx);
    return ERROR_SUCCESS;
}

四、openssl相关函数的内存释放示例

// openssl相关函数的内存释放示例
#define WY_OPENSSL_FREE(name, ptr) openssl_##name##_free(ptr)
void openssl_EVP_PKEY_free(EVP_PKEY *ptr)
{
	if (NULL != ptr) {
        EVP_PKEY_free(ptr);
        ptr = NULL;
    }
}

五、参考资料

总结

本文主要介绍了如何基于openssl3.0,实现RSA签名值使用公钥解密用于验证签名值。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- stra.cn 版权所有 赣ICP备2024042791号-4

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务