【问题标题】:Compare part of sha1 digest with hex string in C将部分 sha1 摘要与 C 中的十六进制字符串进行比较
【发布时间】:2010-12-07 21:18:18
【问题描述】:

我有一个字符串,我可以像这样计算一个 sha1 摘要:

SHA1(sn, snLength, sha1Bin);

如果我是正确的,这会产生一个 20 字节的字符(带有二进制数据)。我想将此字符的最后 3 个字节与另一个字符进行比较。此字符包含字符串“6451E6”。 64、51 和 E6 是十六进制值。如何转换“6451E6”以便我可以通过以下方式进行比较:

if(memcmp(&sha1Bin[(20 - 3)], theVarWithHexValues, 3) == 0)

{

}

我有这个功能:

/*
 * convert hexadecimal ssid string to binary
 * return 0 on error or binary length of string
 *
 */
u32 str2ssid(u8 ssid[],u8 *str) {
    u8 *p,*q = ssid;
    u32 len = strlen(str);

    if( (len % 2) || (len > MAX_SSID_OCTETS) )
      return(0);

    for(p = str;(*p = toupper(*p)) && (strchr(hexTable,*p)) != 0;) {

      if(--len % 2) {
        *q = ((u8*)strchr(hexTable,*p++) - hexTable);
        *q <<= 4;
      } else {
        *q++ |= ((u8*)strchr(hexTable,*p++) - hexTable);
      }
    }
    return( (len) ? 0 : (p - str) / 2);
}

这也是一样的,但我是 C 新手,不理解它:-(

【问题讨论】:

    标签: c hex sha1


    【解决方案1】:

    另一种方式更容易——将二进制数据转换为十六进制字符串进行比较:

    char suffix[7];
    sprintf(suffix, "%02x%02x%02x", sha1Bin[17], sha1Bin[18], sha1Bin[19]);
    return stricmp(suffix, theVarWithHexValues) == 0;
    

    即使您更喜欢转换为二进制,sscanf(...%2x...) 也比手动解析十六进制数字要好。

    【讨论】:

    • 也许这是真的,但速度非常重要(19000000 次迭代),我不想触及 sha1Bin 部分。另一边的 theVarWithHexValues 是 const。还有其他建议吗?
    • 我怀疑内存带宽会占主导地位,所以这个版本可能会让你大吃一惊。或者它可能不会,只是不要假设任何事情。另外,我不知道“触摸 sha1Bin 部分”是什么意思。我的代码不会以任何方式修改 sha1Bin。
    【解决方案2】:

    修复 AShelly 的代码:

    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    
    int hashequal(const unsigned char *sha1Bin, const char *hexstr) {
        unsigned long hexvar = strtoul(hexstr, NULL, 16);
        unsigned char theVarWithHexValues[] = { hexvar >> 16, hexvar >> 8, hexvar };
        return memcmp(sha1Bin + 17, theVarWithHexValues, 3) == 0;
    }
    
    int main() {
        unsigned char sha1Bin[20];
        sha1Bin[17] = 0x64;
        sha1Bin[18] = 0x51;
        sha1Bin[19] = 0xE6;
        printf("%d\n", hashequal(sha1Bin, "6451E6"));
        printf("%d\n", hashequal(sha1Bin, "6451E7"));
    }
    

    【讨论】:

    • 这就像一个魅力!你能解释一下这里发生了什么吗: unsigned char theVarWithHexValues[] = { hexvar >> 16, hexvar >> 8, hexvar };
    • @tersmitten:{} 引入了一个数组初始值设定项 - 列表中的每个逗号分隔项都成为数组中的一个 unsigned char 值。当 unsigned int 转换为 unsigned char 时,它只是取模 256(假设为 8 位 char),因此转换为 unsigned char 的 hexvar 是 hexvar 的最低有效 8 位,即最后两个十六进制数字. hexvar &gt;&gt; 8 的最低 8 位是 hexvar 的第 9-16 位,hexvar &gt;&gt; 16 也是如此。如果一个字节中有超过 8 位,则此代码不起作用,但这种情况很少见(基本上是一些 DSP 和一些大型机)。
    • ... 如果需要,可以通过将 hexvar &gt;&gt; 16 更改为 (hexvar &gt;&gt; 16) &amp; 0xff 来修复它,其他两个也一样,假设该系统上的 sha1 哈希显示为 20 个字节,每个包含 8 位哈希值,字节中的任何附加位都设置为 0。
    • 非常感谢您的解释!
    【解决方案3】:

    如果theVarWithHexValues 确实是某种常量,那么最简单的方法就是直接将其转换为二进制形式。而不是:

    const char *theVarWithHexValues = "6451E6";
    

    使用:

    const char *theVarWithHexValues = "\x64\x51\xE6";
    

    ...那你可以直接memcmp()。

    【讨论】:

      【解决方案4】:
      char* hexstr = "6451E6";
      unsigned long hexvar = strtoul(hexstr, NULL, 16);
      hexvar = htonl(hexvar)<<8;  //convert to big-endian and get rid of zero byte.
      
      memcmp(&sha1Bin[(20 - 3)], (char*)hexvar, 3)
      

      【讨论】:

      • 这在大端架构上是错误的,因为第一个字节将是值为零的高字节,而在小端架构上是错误的,因为字节将被反转。
      猜你喜欢
      • 2013-05-24
      • 1970-01-01
      • 1970-01-01
      • 2011-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-11
      • 1970-01-01
      相关资源
      最近更新 更多