手动HMACSHA1计算与openssl结果不同

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手动HMACSHA1计算与openssl结果不同相关的知识,希望对你有一定的参考价值。

我试图通过Hand实现HMAC SHA1,以检查您的服务提供商或我们是否为Support-Ticket计算了错误的HMAC(SOAP调用,因此是xml内容)。

问题是,我坚持使用NIST规范进行HMAC,并在使用openssl HMAC功能时获得不同的结果。

以下代码打印:

B92674DCBA96F2DA93F7043071B931F5F2583FBD
4303E965D88D288C9AC594CE6C5E6AFF27D40B2D

虽然openssl的结果与我们的应用程序相同 - 所以我假设,基于openssl是如此常用,我的结果是错误的 - 但我的错误在哪里?

这是我所指的规范:http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.198-1.pdf

这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <string.h>

#define byte unsigned char
#define IPAD 0x36
#define OPAD 0x5c
#define DIGESTSIZE 20



int main () {
    byte *derivedKey =  (byte[DIGESTSIZE]) {0x42,0xA9,0x78,0x90,0xFC,0xE5,0x16,0x8E,0x58,0x12,0x2F,0xF1,0xBA,0x32,0x5F,0x09,0x88,0x94,0x02,0x91};
    byte *content =     "<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:soap="http://www.w3.org/2003/05/soap-envelope"><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="soap"></ec:InclusiveNamespaces></ds:CanonicalizationMethod><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"></ds:SignatureMethod><ds:Reference URI="#TS-B183A13FEB0189143115136776276601"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="wsse soap"></ec:InclusiveNamespaces></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod><ds:DigestValue>rXJdGuDqoRrUJxuGiA1eyAozifk=</ds:DigestValue></ds:Reference></ds:SignedInfo>";
    byte *oPadKey =     malloc(DIGESTSIZE);
    byte *iPadKey =     malloc(DIGESTSIZE);


    int i;
    for(i=0;i<DIGESTSIZE;i++){
        iPadKey[i]=derivedKey[i]^IPAD;
        oPadKey[i]=derivedKey[i]^OPAD;
    }

    byte *rOpInput=     malloc(strlen(content)+DIGESTSIZE);

    //concat iPad and content
    memcpy(rOpInput, iPadKey, DIGESTSIZE);
    memcpy(rOpInput+DIGESTSIZE,content,strlen(content));

    //SHA1 (iPad||content) gives the rightmost 20 bytes of the final SHA1 Input
    byte *rOp=malloc(DIGESTSIZE); // H(iPad||content)
    SHA1(rOpInput,strlen(content)+DIGESTSIZE,rOp);
    free(rOpInput);

    byte *finalInput = malloc(2*DIGESTSIZE); //oPad||H(iPad||content)

    //concat oPad and H(ipad||content)
    memcpy(finalInput, oPadKey,DIGESTSIZE);
    memcpy(finalInput+DIGESTSIZE,rOp,DIGESTSIZE);

    free(rOp);
    free(oPadKey);
    free(iPadKey);
    //SHA1(oPad||H(iPad||content))

    byte *hmac = malloc(DIGESTSIZE);
    SHA1(finalInput,40,hmac);
    free(finalInput);

    //print calculated HMAC as HEX
    for(i=0;i<DIGESTSIZE;i++){
        printf("%02X", (hmac[i] & 0xFF ));
    }
    printf("
");


    //verify with openssl HMAC
    byte *result = HMAC(EVP_sha1(), derivedKey, DIGESTSIZE, content, strlen(content), NULL, NULL);
    for(i=0;i<DIGESTSIZE;i++){
        printf("%02X", (result[i] & 0xFF ));
    }
    printf("
");
    return 0;
}
答案

这个bug很简单。 ipadopad的长度需要为(input) block size,而不是摘要输出的长度。即对于SHA-1,它们必须是512位(64字节),而不是20位。

#define INPUT_BLOCK_SIZE 64
byte derivedKey[64] =  {0x42,0xA9,0x78,0x90,0xFC,0xE5,0x16,0x8E,0x58,0x12,
                        0x2F,0xF1,0xBA,0x32,0x5F,0x09,0x88,0x94,0x02,0x91};
// null-padded on the right

然后将DIGESTSIZE改为INPUT_BLOCK_SIZE,无论ipadopad的长度都需要。

结果:

4303E965D88D288C9AC594CE6C5E6AFF27D40B2D

来自Wikipedia

K'是另一个密钥,源自原始密钥K(通过向右填充K,使用额外的零填充到散列函数的输入块大小,或者如果它比该块大小更长,则通过散列K)

(强调我的)。


附:最好使用SHA1_Init / Update / Final,因为这样就会跳过很多复制。您还可以通过首先计算ipad并在使用之后分别为opadipad分配内存,然后通过0x6a进行xorring以获得opad。

以上是关于手动HMACSHA1计算与openssl结果不同的主要内容,如果未能解决你的问题,请参考以下文章

与手动计算相比,R 中的 glht 函数给出不同的结果

csharp 哈希与HMACSHA1

csharp 哈希与HMACSHA1

评估指标的手动计算与 Sklearn 函数不匹配

unable to access ‘https://github.com/***.git‘: OpenSSL SSL_read: Connection was reset, errno 10054(代

不同平台的加密结果不同,使用 OpenSSL