使用 nist 向量值作为输入的 openssl hmac 代码验证系统

Validation system for openssl hmac code using nist vector values as input

我写了一个 c 代码,它接受键的输入值,消息调用 openssl hmac 函数并生成 mac 代码的结果。 输入值是从 NIST 测试向量中收集的

#define KEY_SIZE 11         // in bytes
#define MSG_SIZE 129          // in bytes
#include <stdio.h>
#include <string.h>
#include <openssl/hmac.h>

void str2hex(char *, char*, int);

int main() {
   char *key, *msg;
   unsigned char keyy[KEY_SIZE], msgt[MSG_SIZE], temp[4];
   unsigned char* result;
   unsigned int i, len = 20,Tlen = 10;

   key = "";//values specified below
   msg ="";//values specified below
   /*CONVERT STRING TO HEX DIGITS - KEY*/
   str2hex(key, keyy, KEY_SIZE);
  //CONVERT STRING TO HEX DIGITS - MSG*//
   str2hex(msg, msgt, MSG_SIZE);


   result = (unsigned char*)malloc(sizeof(char) * len);

   HMAC_CTX ctx;
   HMAC_CTX_init(&ctx);


   HMAC_Init_ex(&ctx, keyy, strlen(keyy), EVP_sha1(), NULL);
   HMAC_Update(&ctx, (unsigned char*)&msgt, strlen(msgt));
   HMAC_Final(&ctx, result, &len);
   HMAC_CTX_cleanup(&ctx);

   printf("HMAC digest: ");

   for (i = 0; i < Tlen; i++)
    printf("%02x", result[i]);

   printf("\n");

   free(result);

   return 0;
}
//=====================  string to hex conversion 
================================//

void str2hex(char *str, char *hex, int len) {
  int tt, ss;
  unsigned char temp[4];
  for (tt = 0, ss = 0; tt < len, ss < 2 * len; tt++, ss += 2) {
    temp[0] = '0';
    temp[1] = 'x';
    temp[2] = str[ss];
    temp[3] = str[ss + 1];

    hex[tt] = (int) strtol(temp, NULL, 0);
  }
}

//---------------------------------------------------------------------------------//

给出的第一个输入:

Key = 82f3b69a1bff4de15c33
Msg = fcd6d98bef45ed6850806e96f255fa0c8114b72873abe8f43c10bea7c1df706f10458e6d4e1c9201f057b8492fa10fe4b541d0fc9d41ef839acff1bc76e3fdfebf2235b5bd0347a9a6303e83152f9f8db941b1b94a8a1ce5c273b55dc94d99a171377969234134e7dad1ab4c8e46d18df4dc016764cf95a11ac4b491a2646be1

生成的输出:

 HMAC digest: 1ba0e66cf72efc349207

Nist_Mac = 1ba0e66cf72efc349207

匹配成功

但是对于第二个输入

Key = 4766e6fe5dffc98a5c50
Msg = d68b828a153f5198c005ee36c0af2ff92e84907517f01d9b7c7993469df5c21078fa356a8c9715ece2414be94e10e547f32cbb8d0582523ed3bb0066046e51722094aa44533d2c876e82db402fbb00a6c2f2cc3487973dfc1674463e81e42a39d9402941f39b5e126bafe864ea1648c0a5be0a912697a87e4f8eabf79cbf130e

生成的输出:

 HMAC digest: ca96f112a79882074b63

Nist_Mac = 007e4504041a12f9e345

它 failing.If 任何人都可以检查我的代码并请告诉我我做错了什么这将非常有帮助。

在消息中的字节位置 58,您有一个 0x00 字节(空)。由于您正在执行 strlen(msgt),因此结果为 58 而不是 128。文档摘录(强调我的):

The C library function size_t strlen(const char *str) computes the length of the string str up to, but not including the terminating null character.

只使用适当的消息长度,不要对不包含可打印字节的字符数组使用字符串操作。

这里有两个问题。

首先是您在可能包含空字节的字符数组上使用 strlen。由于此函数计算字节数直到找到空字节,如果您的数组包含空字节(如第二个示例的情况),您将无法获得预期结果。

不使用字节数组上的strlen来确定长度,而是使用数据的实际长度。由于您要将包含十六进制数字的字符串转换为字节,因此字节数组的长度是输入字符串长度的一半。

HMAC_Init_ex(&ctx, keyy, strlen(key)/2, EVP_sha1(), NULL);
HMAC_Update(&ctx, msgt, strlen(msg)/2);

另请注意,您应该将 msgt 传递给 HMAC_Update,而不是 &msgt,因为后者是指向数组的指针。

第二个问题在您的 str2hex 函数中。当您构造 temp 时,您没有足够的 space 用于终止空字节。这会导致 strtol 读取到数组末尾之后,它需要一个以 null 结尾的字符串。这会调用 undefined behavior

在这种特殊情况下,您 "lucky" 它起作用了,因为内存中 temp 之后的字节恰好包含空字节或非数字。但是,您不能依赖这种行为。通过使 temp 长一个字节并将该字节显式设置为 0 来解决此问题。同时,您还应该修复函数参数中的有符号/无符号不匹配并更改 [=18= 的类型] 到 unsigned char 数组。

void str2hex(char *, unsigned char*, int);

...

void str2hex(char *str, unsigned char *hex, int len) {
  int tt, ss;
  char temp[5];
  for (tt = 0, ss = 0; tt < len, ss < 2 * len; tt++, ss += 2) {
    temp[0] = '0';
    temp[1] = 'x';
    temp[2] = str[ss];
    temp[3] = str[ss + 1];
    temp[4] = 0;

    hex[tt] = strtol(temp, NULL, 0);
  }
}