Everright Chen
Everright Chen

Reputation: 43

sha512 hashed result in C is different with other languages (php, python)

This is my first time to write code with C. I have a problem with sha512. The result is not same with other languages (php, python).

My target is use sha512 to encrypt the string loop more times. But first and second time is same with python or php, but start from third, it was different.

Result image: enter image description here

Run on Linux.

Here is my code:

C

$ gcc test.c -lcrypto -o test

$ ./test

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

char *hash_sha512(char *data) {
  SHA512_CTX ctx;
  char *md = malloc(sizeof(char)*(SHA512_DIGEST_LENGTH+1));
  SHA512_Init(&ctx);
  SHA512_Update(&ctx, data, strlen(data));
  SHA512_Final(md, &ctx);
  md[SHA512_DIGEST_LENGTH] = '\0';

  return md;
}

int main(void) {

  char *str = hash_sha512("123456");
  FILE *fp;
  int count = 10;

  fp = fopen("/tmp/c.txt", "w+");
  do {
    fputs(str, fp);
    fputs("\n", fp);
    str = hash_sha512(str);
  } while (--count);

  fclose(fp);

  return 0;
}

PHP

<?php
$password='123456';
$hash = hash('sha512', $password, TRUE);
$i = 10;
do {
  file_put_contents('/tmp/php.txt',$hash . "\n", FILE_APPEND);
  $hash = hash('sha512', $hash, TRUE);
} while (--$i);

Python

#! /usr/bin/env python

import hashlib
password='123456'
count = 10
f = open('/tmp/python.txt','a')
pass_hash = hashlib.sha512(password).digest()
for _ in range(count):
    f.write(pass_hash)
    pass_hash = hashlib.sha512(pass_hash).digest()
f.close()

Upvotes: 2

Views: 1069

Answers (2)

Everright Chen
Everright Chen

Reputation: 43

Thanks for @WhozCraig.

Here is my final code.

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

int main(void) {
  char pwd[] = "123456";
  unsigned char digest[2][SHA512_DIGEST_LENGTH] = {{0}};
  SHA512((unsigned char*)pwd, strlen(pwd), digest[0]);

  unsigned int count = 1;
  for (; count<10; ++count) {
    SHA512(digest[(count-1)%2], SHA512_DIGEST_LENGTH, digest[count%2]);
  }

  unsigned char result[SHA512_DIGEST_LENGTH * 2 + 1];
  unsigned int i = 0;
  for(; i < SHA512_DIGEST_LENGTH; i++) {
    sprintf(&result[i*2], "%02x", digest[(count-1)%2][i]);
  }
  printf("The result is %s.\n", result);

  return 0;
}

Upvotes: 2

WhozCraig
WhozCraig

Reputation: 66194

You're not comparing apples to apples, and in the process also not computing your digest correctly for your C code. The byte stream emitted from a sha512 digest is not a C-string, and putting a zero-char on the end doesn't magically make it one. For example, the first digest looks like this (in hex):

ba 32 53 87 6a ed 6b c2 2d 4a 6f f5 3d 84 06 c6 
ad 86 41 95 ed 14 4a b5 c8 76 21 b6 c2 33 b5 48 
ba ea e6 95 6d f3 46 ec 8c 17 f5 ea 10 f3 5e e3 
cb c5 14 79 7e d7 dd d3 14 54 64 e2 a0 ba b4 13 

The second digest is:

73 14 8c 26 3f fc 49 86 34 cc 1e be bd 67 51 69 
97 01 11 69 a3 7e 28 11 ed 51 d5 2c 82 d4 d5 72 
af 32 c2 31 13 9f 1d 0f d7 af e2 9e 44 1d 44 ae 
fa 29 c1 85 5e c6 52 07 63 92 72 11 0d 19 56 74 

and the third, this:

a5 b2 65 20 84 63 58 8b 56 c1 08 4c 37 03 c4 a1 
a9 0c 71 05 89 cb 09 fc 22 07 85 8f 64 3b b1 72 
8b 3e f3 f3 06 2c 84 72 f8 3a c6 1f f9 47 87 b8 
b8 00 3d 73 0b 29 a3 7b 88 a9 e3 14 ee 19 06 f7 

Do you see it? Look at the last set of octets. Last row, second byte.

b8 00 3d 73 0b 29 a3 7b 88 a9 e3 14 ee 19 06 f7 
   ^^

Since your digest source length is erroneously based on a C string length, that is where it is cut off. The remaining bytes are ignored and your digest chain is forever-more wrong.

Apart from that, your code leaks memory like a sieve leaks rainwater. Probably not a big deal for 640 bytes and 10 iterations, but move this to a million iterations and it starts adding up. Put it in a mission-critical piece of software and it is entirely unacceptable. Consider this:

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

void hash_sha512(unsigned char const *src, size_t len, unsigned char *dst)
{
    SHA512_CTX ctx;
    SHA512_Init(&ctx);
    SHA512_Update(&ctx, src, len);
    SHA512_Final(dst, &ctx);
}

int main(void)
{
    char pwd[] = "123456"
    unsigned char digest[2][SHA512_DIGEST_LENGTH] = {{0}};
    hash_sha512((unsigned char*)pwd, strlen(pwd), digest[0]);

    unsigned int count=1;
    for (; count<10; ++count)
    {
        hash_sha512(digest[(count-1)%2], SHA512_DIGEST_LENGTH, digest[count%2]);
    }

    return 0;
}

This fixes the problem described earlier, and the final digest will be in digest[(count-1)%2].I leave it to you to integrate your file IO. Below is the first 10 iterations using an initial password of "123456" for your reference. I suggest you use hexdump to make sure things are going according to plan.

Ten Iterations

ba 32 53 87 6a ed 6b c2 2d 4a 6f f5 3d 84 06 c6 
ad 86 41 95 ed 14 4a b5 c8 76 21 b6 c2 33 b5 48 
ba ea e6 95 6d f3 46 ec 8c 17 f5 ea 10 f3 5e e3 
cb c5 14 79 7e d7 dd d3 14 54 64 e2 a0 ba b4 13 

73 14 8c 26 3f fc 49 86 34 cc 1e be bd 67 51 69 
97 01 11 69 a3 7e 28 11 ed 51 d5 2c 82 d4 d5 72 
af 32 c2 31 13 9f 1d 0f d7 af e2 9e 44 1d 44 ae 
fa 29 c1 85 5e c6 52 07 63 92 72 11 0d 19 56 74 

a5 b2 65 20 84 63 58 8b 56 c1 08 4c 37 03 c4 a1 
a9 0c 71 05 89 cb 09 fc 22 07 85 8f 64 3b b1 72 
8b 3e f3 f3 06 2c 84 72 f8 3a c6 1f f9 47 87 b8 
b8 00 3d 73 0b 29 a3 7b 88 a9 e3 14 ee 19 06 f7 

75 15 b6 cb ef 3e 0b 4a 35 e3 58 b9 8b bb a3 2d 
a0 bd 1e c8 9d 32 23 7c 09 ae c0 a7 f7 4e 70 35 
c8 34 dd 2a ac 8d e4 e9 d1 e8 b5 7a 80 d8 80 db 
07 7c 28 18 e8 30 40 aa 06 85 a5 2a 63 41 c6 b7 

4d 25 d3 24 5e 22 b1 e4 e4 3f 1e a4 4e a3 eb e4 
89 ab e3 c2 63 56 01 17 ea 1f 85 58 d4 da d2 63 
6d 9c 2f 74 39 b6 87 85 2c 1c 27 f8 a8 9d 2a cf 
ee 64 1c d9 28 5d 88 e5 c7 8b 9f 6e 1e c8 dd 99 

17 e2 7f 2f fd a7 c3 b7 41 73 b9 2d e7 61 6e 77 
72 79 41 16 14 90 01 db 6f 66 3b e6 12 94 22 06 
a9 91 14 55 ab 7f 3a 34 eb 12 b3 a9 78 69 6a 23 
8e 82 13 46 1e ed b4 33 e8 74 f8 15 15 a3 19 57 

c1 60 9e c9 c4 82 4f 1c 71 a7 e2 7c 6e fc d9 5b 
63 4f 27 25 ec fe d2 58 d6 77 61 8f 93 a1 a4 1e 
f0 b7 8a 24 36 91 40 9b 5f dd c3 b5 b9 e1 c6 97 
24 66 89 b0 79 c2 84 05 8e 4f 43 4b 5a bb 53 e6 

7b f9 4c 45 be 2f 29 68 80 36 79 b7 1a 79 36 a3 
7e 8b 9f 6e a0 80 3a 9e 5c bc 27 39 bd 2e 6e 9f 
5a b2 8c b9 7f 43 9f b2 c4 72 41 99 f7 65 71 26 
b7 b8 06 24 a8 34 ea 69 e4 05 ab 55 a7 a8 32 c2 

1a 28 09 ee c5 a4 e5 86 98 0f 52 a1 fd ff a6 14 
0f 3f 8b 14 85 34 bd a6 bd 45 54 2e 4c 2b da 62 
d0 7c 98 38 5c 98 cd 76 df 18 ca 36 16 f2 be 8e 
6c ed 76 e8 28 39 e6 38 d7 41 a4 9e 31 6d f0 ab 

ce 0c 0f 2e 89 e5 1d c3 58 88 a3 1f a6 7c 18 74 
1a 20 d3 84 43 9c 3a e8 4b d9 f1 fe 2e a1 67 0b 
62 62 2d dc 02 eb 82 cd 90 b2 0f 8f e2 fe f5 43 
7a ad 0c b1 62 d7 e9 45 3f be 14 53 2e b6 d0 68 

Upvotes: 1

Related Questions