7

I did two SHA1 in C code, one is for a string, and another is for a integer, and get different result.

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

In python, it's very easy to get the string SHA1

sha1 = hashlib.sha1()
sha1.update('1234')
sha1.hexdigest()

'7110eda4d09e062aa5e4a390b0a572ac0d2c0220'

We can see the string result is same as C code. But how to get the integer SHA1 in python? because the python sha1 doesn't support integer.

I tried following code, but it can't get the same result as C code.

aint = unpack('>4B', pack('>I', 1234))   
sha1 = hashlib.sha1()
sha1.update(bytearray(aint))
sha1.hexdigest()

'ac9928e78cf6ea117451ecd6654fea2adae73e21'

How to do the integer SHA1 in python?

Weicuan Yan
  • 71
  • 1
  • 5

3 Answers3

7
digest = sha1.hexdigest()
digest_int = int(digest,16)
Donald Duck
  • 8,409
  • 22
  • 75
  • 99
lobato
  • 83
  • 1
  • 4
  • 2
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – Donald Duck Mar 18 '17 at 08:54
2

I can't reproduce your results in C, what SHA library are you using? OpenSSL recommends the SHA1_* functions but says that SHA_* are included for compatibility. These two give different results for me, so if you're comparing to Pythons SHA1, you should be using 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;
}

Gives:

 d2 04 00 00
 7b08e025e311c3dfcf5179b67c0fdc08e73de261

Which suggests that you're packing bytes in the wrong order in your python implementation. It should be:

>>> import hashlib
>>> hashlib.sha1(b'\xd2\x04\x00\x00').hexdigest()
'7b08e025e311c3dfcf5179b67c0fdc08e73de261'
>>> hashlib.sha1(bytearray(unpack('>4B', pack('I', 1234)))).hexdigest()
'7b08e025e311c3dfcf5179b67c0fdc08e73de261'

(Note no > in front of the I) which matches the shasum above.

For reference, if I use the SHA_* functions I get

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

Which seems to agree with the SHA ("SHA-0") value in Python:

>>> hashlib.new('sha', b'\xd2\x04\x00\x00').hexdigest()
'3e491ac1d065d6d666e5e216e0cddf60fcb5be86'
Peter Gibson
  • 19,086
  • 7
  • 60
  • 64
  • Thank you for your answer. I used the SHA from android code. https://github.com/android/platform_system_core/blob/master/libmincrypt/sha.c . But it's strange that the string SHA is matched. – Weicuan Yan Jul 02 '15 at 04:36
  • And `hashlib.sha1(bytearray(unpack('>4B', pack('I', 1234)))).hexdigest()` is the right function to do integrer in python? Thanks. – Weicuan Yan Jul 02 '15 at 04:44
1

It may be your code that converts to hex for printing. Notice how neither of your hashes is 40 characters long? Try using my to_hex() method below.

    python ==>  '7110eda4d09e062aa5e4a390b0a572ac0d2c0220'
string  result:  7110eda4d09e62aa5e4a390b0a572acd2c220
integer result:  c7f07b846cc46631c2079cdd7179afdd783d643

I also couldn't reproduce your C results. Here's an OSX version:

#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;
}

and here's the Android version

#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;
}

that file is in system/core/libmincrypt and compiled with cc -I../include -o sha_test sha_test.c sha.c

both programs yield the same results

SHA1("1234") =   7110eda4d09e062aa5e4a390b0a572ac0d2c0220
1234 LE =        d2040000
SHA1(1234 LE) =  7b08e025e311c3dfcf5179b67c0fdc08e73de261
1234 BE =        000004d2
SHA1(1234 BE) =  ac9928e78cf6ea117451ecd6654fea2adae73e21
Harvey
  • 5,703
  • 1
  • 32
  • 41
  • 1
    Sorry, my test code have some issues, the n is changed. After fix this mistake, the SHA is aligned to C code. Thank all you – Weicuan Yan Jul 02 '15 at 06:16