Python SHA1 整数

7

我在C代码中做了两个SHA1,一个是针对字符串的,另一个是针对整数的,结果不同。

SHA_init(&ctx);
SHA_update(&ctx, "1234", 4);
sha = SHA_final(&ctx);

unsigned n = 1234;
SHA_init(&ctx);
SHA_update(&ctx, &n, sizeof(n));
sha = SHA_final(&ctx);

string  result:  7110eda4d09e62aa5e4a390b0a572acd2c220
integer result:  c7f07b846cc46631c2079cdd7179afdd783d643

在Python中,获取字符串的SHA1非常容易。
sha1 = hashlib.sha1()
sha1.update('1234')
sha1.hexdigest()

'7110eda4d09e062aa5e4a390b0a572ac0d2c0220'

我们可以看到字符串的结果与C代码相同。但是如何在Python中获得整数SHA1?因为Python SHA1不支持整数。
我尝试了以下代码,但无法获得与C代码相同的结果。
aint = unpack('>4B', pack('>I', 1234))   
sha1 = hashlib.sha1()
sha1.update(bytearray(aint))
sha1.hexdigest()

'ac9928e78cf6ea117451ecd6654fea2adae73e21'

如何在Python中进行整数SHA1?


当然,sha1.update(str(1234))sha1.update('1234') 是相同的。 - Weicuan Yan
1
你已经验证了C中的1234布局是否与struct.pack生成的匹配吗? - chepner
@chepner,是的,我尝试了大端和小端,它们是不同的,但两者都不是相同的C代码结果。 - Weicuan Yan
1
size(n) 返回的是4吗? - chepner
@chepner 是的,大小为4。 - Weicuan Yan
显示剩余2条评论
3个回答

7
digest = sha1.hexdigest()
digest_int = int(digest,16)

2
虽然这段代码可能回答了问题,但提供有关它如何以及/或为什么解决问题的附加上下文将改善答案的长期价值。 - Donald Duck

2

我在C语言中无法重现您的结果,您使用的SHA库是什么?OpenSSL推荐使用SHA1_*函数,但表示SHA_*是为了兼容性而包含的。这两者对我来说给出了不同的结果,因此如果您要与Python的SHA1进行比较,则应该使用SHA1_*

#include <openssl/sha.h>
#include <stdio.h>

int main(void) {
    unsigned n = 1234;
    unsigned char md[50];
    SHA_CTX c;

    for (int i=0; i<sizeof(n); i++) {
        printf("%02x ", ((unsigned char*)&n)[i]);
    }
    printf("\n");

    SHA1_Init(&c);
    SHA1_Update(&c, &n, 4);
    SHA1_Final(md, &c);

    for (int i=0; i<20; i++) {
        printf("%02x", md[i]);
    }
    printf("\n");
    return 0;
}

提供:

 d2 04 00 00
 7b08e025e311c3dfcf5179b67c0fdc08e73de261

这表明您在Python实现中错误地打包了字节顺序。应该是这样的:
>>> import hashlib
>>> hashlib.sha1(b'\xd2\x04\x00\x00').hexdigest()
'7b08e025e311c3dfcf5179b67c0fdc08e73de261'
>>> hashlib.sha1(bytearray(unpack('>4B', pack('I', 1234)))).hexdigest()
'7b08e025e311c3dfcf5179b67c0fdc08e73de261'

请注意,在上面的shasum前面没有>符号。

作为参考,如果我使用SHA_*函数,我会得到

int main(void) {
    unsigned n = 1234;
    unsigned char md[50];
    SHA_CTX c;

    SHA_Init(&c);
    SHA_Update(&c, &n, 4);
    SHA_Final(md, &c);

    for (int i=0; i<20; i++) {
        printf("%02x", md[i]);
    }
    printf("\n");
    return 0;
}

3e491ac1d065d6d666e5e216e0cddf60fcb5be86

这似乎与Python中的SHA(“SHA-0”)值相符:

>>> hashlib.new('sha', b'\xd2\x04\x00\x00').hexdigest()
'3e491ac1d065d6d666e5e216e0cddf60fcb5be86'

谢谢您的回答。我使用了来自安卓代码的SHA。https://github.com/android/platform_system_core/blob/master/libmincrypt/sha.c 。但是奇怪的是字符串SHA匹配成功了。 - Weicuan Yan
hashlib.sha1(bytearray(unpack('>4B', pack('I', 1234)))).hexdigest() 是在Python中进行整数的正确函数吗?谢谢。 - Weicuan Yan

1
可能是您的代码将内容转换为十六进制进行打印。注意到您的两个哈希值都不是40个字符长吗?尝试使用下面的我的to_hex()方法。
    python ==>  '7110eda4d09e062aa5e4a390b0a572ac0d2c0220'
string  result:  7110eda4d09e62aa5e4a390b0a572acd2c220
integer result:  c7f07b846cc46631c2079cdd7179afdd783d643

我也无法重现您的C结果。这是一个OSX版本:

#include <stdio.h>
#include <CommonCrypto/CommonDigest.h>

char *to_hex(unsigned char *buffer, size_t len) {
  static char out[100];
  char *p = out;
  while (len--)
    p += sprintf(p, "%02x", *buffer++);
  *p = 0;
  return out;
}

int main() {
  unsigned char buffer[21] = { 0 };
  printf("SHA1(\"1234\") =   %s\n", to_hex(CC_SHA1("1234", 4, buffer), 20));

  unsigned n = 1234;
  printf("1234 LE =        %s\n", to_hex(&n, 4));  
  printf("SHA1(1234 LE) =  %s\n", to_hex(CC_SHA1(&n, 4, buffer), 20));

  n = htonl(n);
  printf("1234 BE =        %s\n", to_hex(&n, 4));
  printf("SHA1(1234 BE) =  %s\n", to_hex(CC_SHA1(&n, 4, buffer), 20));

  return 0;
}

这里是Android版本

#include <stdio.h>
#include "mincrypt/sha.h"

char *to_hex(unsigned char *buffer, size_t len) {
  static char out[100];
  char *p = out;
  while (len--)
    p += sprintf(p, "%02x", *buffer++);
  *p = 0;
  return out;
}

int main() {
  unsigned char buffer[21] = { 0 };
  printf("SHA1(\"1234\") =   %s\n", to_hex(SHA1_hash("1234", 4, buffer), 20));

  unsigned n = 1234;
  printf("1234 LE =        %s\n", to_hex(&n, 4));  
  printf("SHA1(1234 LE) =  %s\n", to_hex(SHA1_hash(&n, 4, buffer), 20));

  n = htonl(n);
  printf("1234 BE =        %s\n", to_hex(&n, 4));
  printf("SHA1(1234 BE) =  %s\n", to_hex(SHA1_hash(&n, 4, buffer), 20));

  return 0;
}

那个文件位于 system/core/libmincrypt 目录下,并使用 cc -I../include -o sha_test sha_test.c sha.c 编译。 两个程序产生相同的结果。
SHA1("1234") =   7110eda4d09e062aa5e4a390b0a572ac0d2c0220
1234 LE =        d2040000
SHA1(1234 LE) =  7b08e025e311c3dfcf5179b67c0fdc08e73de261
1234 BE =        000004d2
SHA1(1234 BE) =  ac9928e78cf6ea117451ecd6654fea2adae73e21

1
抱歉,我的测试代码有一些问题,n已经改变了。修复这个错误后,SHA与C代码对齐。感谢大家。 - Weicuan Yan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接