Reputation: 1164
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.
Upvotes: 2
Views: 2689
Reputation: 595305
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;
}
Upvotes: 3
Reputation: 102205
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.
Upvotes: 2