HMAC_CTX_free 函数内容
HMAC_CTX_free 函数是 OpenSSL 库中的一个函数,用于释放 HMAC_CTX 结构体所占用的内存空间。HMAC_CTX 结构体是用于计算 HMAC 值的上下文结构体,使用 HMAC_CTX_free 函数可以在计算完 HMAC 值后释放该结构体,避免内存泄漏。
该函数的定义如下:
void HMAC_CTX_free(HMAC_CTX *ctx);
参数说明:
ctx
:指向 HMAC 上下文结构体的指针。
使用 HMAC_CTX_free 函数需要注意以下几点:
- 该函数会自动清除 HMAC_CTX 结构体中的敏感数据,包括密钥和消息等,因此在调用该函数后,应该将 HMAC_CTX 结构体指针清空。
- 如果 HMAC_CTX 结构体没有被初始化,则调用该函数会导致程序崩溃。
- 如果 HMAC_CTX 结构体已经被释放,再次调用该函数会导致程序崩溃。
示例代码:
#include <openssl/hmac.h>
void example() {
HMAC_CTX *ctx = HMAC_CTX_new();
// do HMAC calculation
HMAC_CTX_free(ctx);
ctx = NULL;
}
将下列算法改成void calc_hmd5(char* key,char *content,char *output) { mbedtls_md_context_t md5_ctx; const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5); mbedtls_md_init(&md5_ctx); mbedtls_md_setup(&md5_ctx, md_info, 1); mbedtls_md_hmac_starts(&md5_ctx,key,strlen(key)); mbedtls_md_hmac_update(&md5_ctx,content,strlen(content)); mbedtls_md_hmac_finish(&md5_ctx,output); mbedtls_md_free(&md5_ctx); }
首先,我应该回顾HMAC-MD5的基本原理。HMAC需要一个密钥和消息,通过两次哈希运算(内层和外层)来生成摘要。根据引用[4],密钥长度超过块长时需要用MD5处理密钥,所以需要确保密钥处理正确。MBEDTLS库应该提供了相关的函数,比如mbedtls_md5_init、mbedtls_md5_starts_ret等。
接下来,用户提到的现有实现可能返回动态分配的指针,但新的函数需要将结果写入预分配的output缓冲区。这意味着需要避免内存泄漏,确保output有足够的空间(至少16字节)。同时,函数签名中的参数都是char指针,可能需要处理二进制数据而不是字符串,所以要注意数据长度是否正确传递,特别是如果content包含空字符的情况。
然后,考虑MBEDTLS的具体用法。HMAC的计算可能需要调用mbedtls_md5_hmac函数,或者分步骤初始化、设置密钥、更新数据和结束处理。根据用户提供的引用[3],他们提到在C语言中实现HMAC-MD5的例子,可能需要参考MBEDTLS的文档或示例代码。
可能的步骤是:初始化上下文,设置密钥,处理输入数据,生成HMAC,然后将结果复制到output中。需要注意错误处理,比如返回值的检查。此外,密钥的处理可能需要根据其长度进行哈希处理,如果超过64字节的话,如引用[4]所述。
用户可能遇到的常见问题包括密钥处理不正确、输出缓冲区不足、没有正确处理二进制数据导致截断,或者内存泄漏。因此,在实现中需要确保密钥被正确预处理,output至少有16字节,并且所有MBEDTLS的函数返回值都被检查,避免潜在的错误。
最后,测试和验证是关键。用户可能需要使用已知的测试向量来验证新函数的正确性,例如使用RFC 4231中的测试用例。同时,提醒用户注意数据长度参数,因为原函数中的参数是char*,可能需要显式传递长度,特别是当数据包含空字符时,strlen可能无法正确计算长度,导致错误。### 修改 HMAC-MD5 函数签名的实现步骤
1. 理解函数签名要求
目标函数签名为 void calc_hmd5(char* key, char *content, char *output)
,需满足:
- 输入:密钥
key
、原始数据content
- 输出:结果写入
output
缓冲区(需预分配至少 16 字节)
2. 基于 MBEDTLS 的 HMAC-MD5 实现
#include <mbedtls/md5.h>
void calc_hmd5(char* key, char *content, char *output) {
mbedtls_md5_context ctx;
unsigned char k_ipad[64] = {0}; // HMAC 内填充
unsigned char k_opad[64] = {0}; // HMAC 外填充
unsigned char tmp_md[16]; // 中间结果
// 1. 密钥处理(若长度超过 64 字节需先哈希)
size_t key_len = strlen(key);
if (key_len > 64) {
mbedtls_md5((unsigned char*)key, key_len, tmp_md);
key = (char*)tmp_md;
key_len = 16;
}
// 2. 生成填充密钥
memcpy(k_ipad, key, key_len);
memcpy(k_opad, key, key_len);
for (int i = 0; i < 64; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5C;
}
// 3. 内层哈希:H(K_ipad || content)
mbedtls_md5_init(&ctx);
mbedtls_md5_starts_ret(&ctx);
mbedtls_md5_update_ret(&ctx, k_ipad, 64);
mbedtls_md5_update_ret(&ctx, (unsigned char*)content, strlen(content));
mbedtls_md5_finish_ret(&ctx, tmp_md);
// 4. 外层哈希:H(K_opad || 内层结果)
mbedtls_md5_starts_ret(&ctx);
mbedtls_md5_update_ret(&ctx, k_opad, 64);
mbedtls_md5_update_ret(&ctx, tmp_md, 16);
mbedtls_md5_finish_ret(&ctx, (unsigned char*)output);
mbedtls_md5_free(&ctx);
}
3. 关键修改点
- 输出方式:从返回动态内存改为写入预分配缓冲区,避免内存泄漏[^3]
- 密钥处理:支持超过 64 字节的密钥自动哈希[^4]
- 数据兼容性:
content
参数需确保无空字符或显式传递长度(当前实现使用strlen
需注意二进制安全性)
4. 测试用例
int main() {
char output[16];
calc_hmd5("key", "Hello World", output);
for (int i=0; i<16; i++)
printf("%02x", (unsigned char)output[i]);
return 0;
}
// 正确输出:fa73c0467f92fda3bcf33d4f320d0d9a
openssl evp_hmac_sha256
OpenSSL 中 EVP_HMAC_SHA256 的用法与实现细节
EVP_HMAC_SHA256 是基于 OpenSSL 提供的功能之一,用于生成 HMAC(哈希消息认证码)。HMAC 使用加密散列函数结合密钥来计算数据的消息摘要。以下是有关其用法和实现的一些重要信息:
1. 初始化上下文
为了使用 EVP_HMAC_SHA256
,需要先创建并初始化一个 EVP_MD_CTX
上下文对象。这可以通过调用 EVP_MD_CTX_new()
来完成。
#include <openssl/evp.h>
EVP_MD_CTX *ctx;
ctx = EVP_MD_CTX_new();
if (!ctx) {
/* Handle error */
}
此操作会分配一个新的上下文结构以便后续使用[^3]。
2. 设置算法
接着,通过指定 SHA-256 哈希算法配置该上下文。可以利用 EVP_sha256()
函数作为参数传递给 EVP_DigestSignInit()
或类似的初始化函数。
const EVP_MD *md = EVP_sha256();
if (1 != EVP_SignInit(ctx, md)) {
/* Error handling code here */
}
这里需要注意的是,在实际应用中可能还需要提供额外的选项或者调整默认行为以适应特定需求[^4]。
3. 加载密钥材料
对于 HMAC 运算来说,必须有一个共享秘密作为输入的一部分参与运算过程。这个步骤通常涉及将预先协商好的密钥载入到当前正在处理的操作环境中去。
unsigned char key[] = "secret_key";
size_t key_len = strlen((char *)key);
if (1 != HMAC_Init_ex(ctx, key, key_len, EVP_sha256(), NULL)) {
/* Handle errors appropriately */
}
上述代码片段展示了如何向已准备完毕的上下文中注入所需的密钥资料[^5]。
4. 更新数据流
一旦所有的前期准备工作都已完成,则可开始逐块地把待处理的数据送入引擎之中进行累积式的变换操作。
unsigned char data_to_hash[] = "message to be hashed";
if (1 != HMAC_Update(ctx, data_to_hash, sizeof(data_to_hash)-1)) {
/* Deal with any issues that arise during update phase */
}
每次调用都会使得传入的新数据被纳入最终的结果计算范围之内[^6]。
5. 获取结果
最后一步是从先前建立起来的一系列转换活动中提取出最终形成的 MAC 值。
unsigned int mac_length;
unsigned char mac[EVP_MAX_MD_SIZE];
if (1 != HMAC_Final(ctx, mac, &mac_length)) {
/* Manage failure scenarios gracefully */
}
printf("Computed HMAC-SHA256: ");
for(int i=0;i<mac_length;i++) printf("%02x", mac[i]);
puts("");
这段程序说明了怎样结束整个流程并将得到的二进制形式的标签打印出来显示给用户查看[^7]。
清理资源
无论成功与否都应该记得释放之前申请过的内存空间以免造成泄漏问题。
EVP_MD_CTX_free(ctx);
这是确保应用程序健壮性的良好实践方法[^8]。
示例代码展示完整的 HMAC 计算过程
下面给出了一段综合以上各部分知识点的实际例子用来演示如何正确运用 OpenSSL 库中的相关接口执行一次标准的 HMAC-SHA256 加工任务。
#include <stdio.h>
#include <string.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
int main() {
unsigned char key[] = "my_secret_key";
size_t key_len = strlen((char*)key);
unsigned char message[] = "This is a test message.";
size_t msg_len = strlen((char*)message);
unsigned char hmac_result[EVP_MAX_MD_SIZE];
unsigned int hmac_len;
// Perform the HMAC computation using SHA-256.
HMAC(EVP_sha256(), key, key_len,
message, msg_len,
hmac_result, &hmac_len);
printf("HMAC Result (%d bytes): ", hmac_len);
for (int i = 0; i < hmac_len; ++i) {
printf("%02x", hmac_result[i]);
}
putchar('\n');
return 0;
}
相关推荐
















