在将项目从 OpenSSL 1.1 升级到 OpenSSL 3.0 的过程中,开发者可能会遇到许多 API 的变化和弃用,导致开发者在实现某些功能时,找不到正确的实现方式。比如:如何实现RSA的公钥解密。
在一些场景中,我们需要验证公私钥是否匹配。一般情况下,可以使用私钥签名,公钥验签的方式来实现。但是在一些特殊情况下,比如调用TEE的接口来获取签名值,但是没有相应的验签接口来实现公私钥匹配的验证,自己实现的验签接口验证签名值失败,在这种情况下,可以使用公钥解密的方式来验证公私钥是否匹配。
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;
}
注:
- 以下实现方式本质上并不是使用公钥去解密,而是通过特殊算法来恢复签名数据。
- 其中返回值的相关定义、日志输出、内存释放需要自行实现
具体实现的代码如下:
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相关函数的内存释放示例
#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
本站由北京市万商天勤律师事务所王兴未律师提供法律服务