基于OpenSSL 0.9.8a API验证4096位RSA签名的技术问询
验证4096位RSA SHA512签名(OpenSSL 0.9.8a实现)
首先得给你提个关键的点:你的代码里最后一步用了EVP_DigestFinal_ex,这是个错误——在签名验证流程中,最后应该调用EVP_DigestVerifyFinal来完成验证,而不是生成摘要的EVP_DigestFinal_ex。这是很容易踩的坑,先帮你纠正过来,再给你完整的可运行实现。
完整代码实现
下面是补全并修正后的代码,包含完整的错误处理和内存管理,适配OpenSSL 0.9.8a的API:
#include <openssl/evp.h> #include <openssl/rsa.h> #include <openssl/err.h> #include <stdio.h> #include <stdbool.h> // 加载RSA公钥(从PEM格式文件) EVP_PKEY* load_rsa_public_key(const char* pub_key_path) { FILE* fp = fopen(pub_key_path, "rb"); if (!fp) { perror("Failed to open public key file"); return NULL; } EVP_PKEY* pubKey = PEM_read_PUBKEY(fp, NULL, NULL, NULL); fclose(fp); if (!pubKey) { fprintf(stderr, "Failed to load public key: "); ERR_print_errors_fp(stderr); } return pubKey; } // 验证4096位RSA SHA512签名 bool verify_rsa_sha512_signature(EVP_PKEY* pubKey, const unsigned char* msg, size_t msg_len, const unsigned char* signature, size_t sig_len) { // 创建EVP消息摘要上下文 EVP_MD_CTX* ctx = EVP_MD_CTX_create(); if (!ctx) { fprintf(stderr, "Failed to create EVP_MD_CTX: "); ERR_print_errors_fp(stderr); return false; } // 获取SHA512摘要算法 const EVP_MD* md = EVP_get_digestbyname("SHA512"); if (!md) { fprintf(stderr, "Failed to get SHA512 digest: "); ERR_print_errors_fp(stderr); EVP_MD_CTX_destroy(ctx); return false; } // 初始化签名验证上下文 if (EVP_DigestVerifyInit(ctx, NULL, md, NULL, pubKey) <= 0) { fprintf(stderr, "Failed to init digest verify: "); ERR_print_errors_fp(stderr); EVP_MD_CTX_destroy(ctx); return false; } // 传入待验证的消息内容 if (EVP_DigestUpdate(ctx, msg, msg_len) <= 0) { fprintf(stderr, "Failed to update digest: "); ERR_print_errors_fp(stderr); EVP_MD_CTX_destroy(ctx); return false; } // 完成签名验证 int verify_result = EVP_DigestVerifyFinal(ctx, signature, sig_len); // 释放上下文资源 EVP_MD_CTX_destroy(ctx); // 解析验证结果 if (verify_result == 1) { printf("Signature verified successfully!\n"); return true; } else if (verify_result == 0) { fprintf(stderr, "Signature verification failed: signature does not match\n"); } else { fprintf(stderr, "Error during signature verification: "); ERR_print_errors_fp(stderr); } return false; } // 示例调用 int main() { // 初始化OpenSSL错误库 ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); EVP_PKEY* pubKey = load_rsa_public_key("public_key.pem"); if (!pubKey) { return 1; } // 假设这里是你的消息和签名数据 unsigned char msg[] = "Your message to verify"; size_t msg_len = sizeof(msg) - 1; unsigned char signature[512]; // 4096位RSA签名长度是512字节 size_t sig_len = 512; // 实际场景中需要从文件或网络读取签名数据 // ... bool result = verify_rsa_sha512_signature(pubKey, msg, msg_len, signature, sig_len); // 释放公钥资源 EVP_PKEY_free(pubKey); // 清理OpenSSL资源 EVP_cleanup(); ERR_free_strings(); return result ? 0 : 1; }
关键注意事项(针对OpenSSL 0.9.8a)
- 签名格式默认值:OpenSSL 0.9.8a的
EVP_DigestVerifyInit默认使用PKCS#1 v1.5填充方案。如果你的签名是用PSS填充生成的,需要手动设置填充模式——但要注意,0.9.8a的EVP接口对PSS的支持有限,可能需要直接使用RSA底层函数(比如RSA_verify)来处理PSS签名。 - 4096位RSA支持:0.9.8a默认支持4096位RSA密钥,但如果是嵌入式环境编译,需要确保编译时开启了大整数支持(通常默认是开启的)。
- 错误调试:一定要用上
ERR_print_errors_fp打印错误信息,OpenSSL的函数返回值只会告诉你失败,但具体原因都存在错误队列里,这个函数能帮你快速定位问题。 - 资源管理:所有创建的OpenSSL对象(
EVP_MD_CTX、EVP_PKEY)都要记得用对应的销毁函数释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者MBA_BAT88
相关产品推荐
相关产品推荐

