简体   繁体   中英

OpenSSL MD5 gives a different hash every time

I'm trying to create a certain modular code using OpenSSL's EVP API for MD5 by passing the EVP_MD object within functions as shown below.

#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>

EVP_MD* md5_digest_init() {
  OpenSSL_add_all_digests();
  EVP_MD *md = EVP_get_digestbyname("MD5");
  if(!md) {
     printf("Unable to init MD5 digest\n");
     exit(1);
   }
  return md;
}

unsigned char *md5_digest_process(EVP_MD* md, unsigned char *input_text) {
    EVP_MD_CTX mdctx;
    unsigned char hash[EVP_MAX_MD_SIZE];
    int hash_len;
    EVP_MD_CTX_init(&mdctx);
    EVP_DigestInit_ex(&mdctx, md, NULL);
    EVP_DigestUpdate(&mdctx, input_text, strlen(input_text)+1);
    EVP_DigestFinal_ex(&mdctx, hash, &hash_len);
    EVP_MD_CTX_cleanup(&mdctx);
    return hash;
}

int main() {
  EVP_MD *md;
  md = md5_digest_init();
  unsigned char* res;
  res = md5_digest_process(md, "foobar");
  printf("%02x", res);
  return 0;
}

The problem is that on executing the code every time, I obtain a different hash value for the same text.

Such as

585c64a0
554454a0
5f75a4a0, etc

MD5 is deterministic and such an issue should not exist. Any reason why such as error exists? Also, the passing of the EVP_MD object within functions is important to me.

EDIT:

Replacing the final printf with the following code

for(int i = 0; i < 16; ++i)
    printf("%02x", res[i]);

I get the following output.

b4000000000000000100000000000000

However, this stays the same for all executions. But I'm guessing that this hash isn't right.

I think you are close. I would probably change md5_digest_process to:

/* md_digest is declared as unsigned char md_digest[EVP_MAX_MD_SIZE] */
unsigned int md5_digest_process(EVP_MD* md, unsigned char *input_text, unsigned int input_len, unsigned char* md_digest)
{
    int hash_len;
    EVP_MD_CTX mdctx;

    EVP_MD_CTX_init(&mdctx);
    EVP_DigestInit_ex(&mdctx, md, NULL);
    EVP_DigestUpdate(&mdctx, input_text, input_len);
    EVP_DigestFinal_ex(&mdctx, md_digest, &hash_len);
    EVP_MD_CTX_cleanup(&mdctx);
    return hash_len;
}

Then, print md_digest with:

int main()
{
  EVP_MD *md;
  unsigned char hash[EVP_MAX_MD_SIZE];
  unsigned int hash_len;

  md = md5_digest_init();
  hash_len = md5_digest_process(md, "foobar", 6, hash);

  for(unsigned int i=0; i<hash_len; i++)
      printf("%02x", hash[i]);
  printf("\n");

  return 0;
}

You should also add some error checking.

As stated in comments, md5_digest_process() is returning a pointer to a local variable that goes out of scope when the function exits, leaving the pointer dangling as it is left pointing to invalid memory.

But that doesn't matter to your issue, because you are printing the memory address that the pointer is pointing at, not the data that it is pointing at. So your printed output is displaying whatever random memory address the local hash variable existed at when the function was called. That is why you are seeing inconsistent values in your output. As stated in comments, you need to dereference the pointer in order to print the data that is being pointed at.

If you want to return a pointer to memory that outlives the function, you have to allocate the memory dynamically:

unsigned char* md5_digest_process(EVP_MD* md, unsigned char *input_text, int *hash_len) {
    unsigned char *hash = (unsigned char *) malloc(EVP_MAX_MD_SIZE);
    if (!hash) return NULL;
    EVP_MD_CTX mdctx;
    EVP_MD_CTX_init(&mdctx);
    EVP_DigestInit_ex(&mdctx, md, NULL);
    EVP_DigestUpdate(&mdctx, input_text, strlen(input_text)+1);
    EVP_DigestFinal_ex(&mdctx, hash, hash_len);
    EVP_MD_CTX_cleanup(&mdctx);
    return hash;
}

int main() {
  EVP_MD *md = md5_digest_init();
  int hash_len = 0;
  unsigned char* res = md5_digest_process(md, "foobar", &hash_len);
  if (res) {
    for(int i = 0; i < hash_len; ++i) {
      printf("%02x", res[i]);
    }
    free(res)
  }
  return 0;
}

Otherwise, the caller will have to allocate the memory and pass it into the function to fill in:

int md5_digest_process(EVP_MD* md, unsigned char *input_text, unsigned char* hash) {
    EVP_MD_CTX mdctx;
    int hash_len = 0;
    EVP_MD_CTX_init(&mdctx);
    EVP_DigestInit_ex(&mdctx, md, NULL);
    EVP_DigestUpdate(&mdctx, input_text, strlen(input_text)+1);
    EVP_DigestFinal_ex(&mdctx, hash, &hash_len);
    EVP_MD_CTX_cleanup(&mdctx);
    return hash_len;
}

int main() {
  EVP_MD *md = md5_digest_init();
  unsigned char hash[EVP_MAX_MD_SIZE];
  int hash_len = md5_digest_process(md, "foobar", hash);
  for(int i = 0; i < hash_len; ++i) {
    printf("%02x", res[i]);
  }
  return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM