【问题标题】:Converting MD5 result into an integer in C将 MD5 结果转换为 C 中的整数
【发布时间】:2012-06-24 18:18:39
【问题描述】:

我的目标是使用 MD5 结果的结果来索引哈希表。我想对其执行模运算以在表中找到适当的插槽。我尝试将其转换为无符号长长类型。当我打印结果时,对于相同的 MD5 哈希,我每次都会得到一个不同的数字。 MD5 哈希最初是一个无符号字符 *。谁能告诉我我做错了什么?

这是我的功能:

int get_fp_slot(unsigned char * fingerprint, int size)
{
return (unsigned long long)fingerprint % size;
}

【问题讨论】:

  • 你正在尝试投射一个指针,这并没有多大意义。
  • 什么是“指纹”?指向哈希值的字符串表示形式的指针?我建议您构建哈希值的字符串表示的整数表示,然后重试。在上面的代码中,您使用的是指针,而不是哈希的实际值。不完全是你想要达到的目标。另外,请注意冲突的可能性,因为您尝试在此处压缩密钥。
  • 您应该考虑使用除 md5 之外的散列算法来降低冲突的可能性。
  • @C0deH4cker - 但是 MD5 一种散列算法!
  • 我说除了 md5。意思是输出较小,因此您不需要压缩它。

标签: c casting md5


【解决方案1】:

MD5 哈希是一个 128 位的数字。因此,为了获得最佳性能,您可能应该保留所有 128 位。

鉴于您的函数将 128 位哈希作为字符串,您需要将该字符串解析为一系列 4 个整数。你的字符串可能看起来像这样:

79054025255fb1a26e4bc422aef54eb4

这是一个 32 字节的十六进制字符串。如果是这样,您可以像这样提取二进制版本:

int v1, v2, v3, v4;
sscanf( &fingerprint[0], "%x", &v1 );
sscanf( &fingerprint[8], "%x", &v2 );
sscanf( &fingerprint[16], "%x", &v3 );
sscanf( &fingerprint[24], "%x", &v4 );

你现在做什么取决于你希望你的哈希有多好。如果你真的需要使用 32 位数字,那么只需将所有这些数字异或:

int hash = v1 ^ v2 ^ v3 ^v4;

【讨论】:

  • 所以对于 v1,sscanf 会从指纹中获取尽可能多的 int 对吗?但那不是只有前 4 个字节吗?为什么MD5本身是16字节,却打印出32字节的十六进制值?
  • sscanf 将解析尽可能多的字节,在本例中为 8 个。如果您觉得更安全,您可以一次将 8 个字节复制到临时缓冲区中(例如,防止 sscanf 损坏).每个字符仅编码 4 位 1/2 字节。 char 本身是 8 位,但在这种情况下,它只编码 4 位。
【解决方案2】:

您正在投射指针,即散列的 地址。当然该地址与哈希值无关。

如何解决它取决于您想要什么。例如,您可以使用哈希的最后 16 个字节并将其解析为 unsigned long long

// sanity and error checking omitted for brevity
int get_fp_slot(unsigned char *fingerprint, int size)
{
    size_t len = strlen(fingerprint);
    size_t offset = len < 16 ? 0 : len-16;
    unsigned long long hash_tail = strtoull(fingerprint + offset,NULL,16);
    return hash_tail % size;
}

或增量取模

// uses a helper hex_val that converts a hexadecimal digit to the integer it signifies
int get_fp_slot(unsigned char *fingerprint, int size)
{
    unsigned long long hash_mod = 0;
    while(*fingerprint) {
        hash_mod = (16*hash_mod + hex_val(*fingerprint)) % size;
        ++fingerprint;
    }
    return hash_mod;
}

【讨论】:

  • 第二种方案,while循环什么时候结束?
  • 在 0 终止符处,我只是忘记了增量 :(
【解决方案3】:

在您的代码中,您正在转换指针本身,而不是形成 MD5 值的字节!

一个 MD5 是 128 位,即 16 个字节。假设您的 long long 类型是 64 位(8 字节),您可以将其表示为两个 long long 值,然后对它们进行异或运算以获得哈希。或者,如果您愿意,您可以简单地选择其中一个...哈希质量可能相似。

你没有说出来,但我假设你的指纹是一个指针,指向一个具有 MD5 值的 16 字节数组。那么:

unsigned long long a = *(unsigned long long*)fingerprint;
unsigned long long b = *(unsigned long long*)(fingerprint + 8);
return a ^ b;

请注意,ab 的值将取决于您机器的字节序。只要您不将散列发送到不同的架构,这无关紧要。

【讨论】:

  • 哇——这可能是错误的。字符缓冲区可能是散列的文本表示 - 而不是实际的散列。您的哈希函数最终会变得稀疏。例如。如果你这样做,有很多位总是为零。
  • 那么实际的哈希是一个数字吗?此外,就此操作的结果而言,尽管可能是错误的,但我从任何单个哈希中获得的数字都是一致的。不过,我会相信你的话。
  • @RafaelBaptista - 我不知道你为什么认为文本表示更有可能。例如,在man MD5_Final 的快速检查表明它返回 16 个字节,这是哈希的二进制表示。当然,OP 并没有说他正在使用哪个库,所以我们只是猜测......
  • 你说得对,我们不知道。但原型 char* 建议使用文本。
  • 我在 linux 内核中使用 cypto Api。它要求一个无符号字符缓冲区来放置结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-12
  • 2011-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-24
相关资源
最近更新 更多