OpenSSL MD5 gives a different hash every time - c

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.

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

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.

Related

Openssl brute force AES_128 decryption error in C

I'm trying to write a C program to brute force AES decryption using openssl. However, when I tried to decrypt the message by passing a key attackKey, I got and error printed from the decrypt() function. The error is as follows
There was an error calling the decrypted final object...: Success
The code is given below, I tried reading the book on Openssl for more information but as it is quite outdated it was not helpful. I also googled and barely found any resources on my issue and yes I am well aware of the fact that brute forcing aes_128 is a pipe dream. I am just testing some things with this library to see if the key is only a few combinations ahead, so can I iterate on the attackKey and try to get the decrypted text.
#include <string.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <stdbool.h>
#include <openssl/err.h>
#define BUFFER_SIZE 64
// void addPadding(unsigned char *buff, );
int encrypt(const unsigned char *plaintext, const int plaintext_len, const unsigned char *key, unsigned char *ciphertext);
int decrypt(const unsigned char *ciphertext, const int ciphertext_len, const unsigned char *key, unsigned char *decryptedtext);
void iterateKey(unsigned char *key, const int length);
bool compareKeys(const unsigned char *key1, const unsigned char *key2, const int length);
void *bruteForceAttack(void *arg);
int main(int argc, char *argv[])
{
OpenSSL_add_all_algorithms(); // load all cipher algorithms
ERR_load_crypto_strings(); // load human readable errors
/* A 256 bit key */
unsigned char key[] = "abcdefghijklmnqp"; // 6 + 1 bytes
unsigned char plaintext[] = "Hello, my name is shaheryar ;)."; // 32 + 1 bytes
/* Buffer to store the ciphertext. The size may be different due to padding. */
unsigned char ciphertext[BUFFER_SIZE];
int ciphertext_len = 0;
/* Encryption. */
ciphertext_len = encrypt(plaintext, strlen((char *)plaintext), key, ciphertext);
printf("Length of text:%d, Ciphertext is:\n", ciphertext_len);
BIO_dump_fp(stdout, (const char *)ciphertext, ciphertext_len);
//----------------MAIN DECRYPTION LOGIC
/* Buffer for the decrypted text for verifying decryption. */
unsigned char decryptedtext[BUFFER_SIZE];
int decryptedtext_len = 0;
unsigned char attackKey[] = "abcdefghijklmnop";
const int attackKey_len = 17;
for (int i = 0; i < 10e2; i++)
{
// printf("Key : %s\n", attackKey);
decryptedtext_len = 0;
decryptedtext_len = decrypt(ciphertext, ciphertext_len, attackKey, decryptedtext);
decryptedtext[decryptedtext_len] = '\0';
if (strcmp((const char *)attackKey, (const char *)key) == 0)
{
printf("\nLength of text: %d, Decryptedtext is: %s\n", decryptedtext_len, decryptedtext);
}
iterateKey(attackKey, attackKey_len);
}
//------------END OF DECRYPTION PHASE
if (strncmp((const char *)plaintext, (const char *)decryptedtext, decryptedtext_len))
{
printf("FAIL: enc/dec failed for \"%s\"\n", decryptedtext);
}
else
{
printf("OK: enc/dec ok for \"%s\"\n", plaintext);
}
return 0;
}
int encrypt(const unsigned char *plaintext, const int plaintext_len, const unsigned char *key, unsigned char *ciphertext)
{
/* The following object is used to keep track of the key and internal states*/
EVP_CIPHER_CTX *ctx = NULL;
int len = 0, ciphertext_len = 0;
/* Create and initialize the context and returns a pointer for success and null for failure*/
if (!(ctx = EVP_CIPHER_CTX_new()))
{
printf("There was an error creating the encryption object...");
}
/* Initialize the encryption operation. */
if (!EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, NULL))
{
printf("There was an error loading the encryption object...");
}
if (plaintext)
{
if (!EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
{
printf("There was an error creating the update the encryption object...");
}
ciphertext_len = len;
}
if (!EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
{
printf("There was an error encrypting the final object...");
}
ciphertext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int decrypt(const unsigned char *ciphertext, const int ciphertext_len, const unsigned char *key, unsigned char *decryptedtext)
{
/* The following object is used to keep track of the key and internal states*/
EVP_CIPHER_CTX *ctx = NULL;
int len = 0, decryptedtext_len = 0;
/* Create and initialize the context and returns a pointer for success and null for failure*/
if (!(ctx = EVP_CIPHER_CTX_new()))
{
printf("There was an error creating the decryption object...");
}
/* Initialize the encryption operation. */
if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, NULL))
{
printf("There was an error initializing the cipher object...");
}
if (ciphertext)
{
if (!EVP_DecryptUpdate(ctx, decryptedtext, &len, ciphertext, ciphertext_len))
{
printf("There was an error decrypting the cipher text...");
}
decryptedtext_len = len;
}
if (!EVP_DecryptFinal_ex(ctx, decryptedtext + len, &len))
{
printf("There was an error calling the decrypted final object...");
}
decryptedtext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return decryptedtext_len;
}
bool compareKeys(const unsigned char *key1, const unsigned char *key2, const int length)
{
for (int i = 0; i < length; i++)
{
if (key1[i] != key2[i])
{
return false;
}
}
return true;
}
void iterateKey(unsigned char *key, const int length)
{
for (int i = 0; i < (length - 1); i++)
{
if (key[length - 2 - i] == 'z')
{
key[length - 2 - i] = 'a';
}
else
{
key[length - 2 - i]++;
return;
}
}
}
void *bruteForceAttack(void *arg)
{
return NULL;
}
Below are the resources I used for implementing the code:
https://www.cs.ucy.ac.cy/courses/EPL326/labs/lab3/aesimplentation.pdf
https://www.oreilly.com/library/view/network-security-with/059600270X/

hmac sha256 output length

I'm trying to implement the AWS V4 signature in C, but am failing to calculate the hash in the string to sign. The test example here has:
key = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'
dateStamp = '20120215'
regionName = 'us-east-1'
serviceName = 'iam'
producing
kSecret = '41575334774a616c725855746e46454d492f4b374d44454e472b62507852666943594558414d504c454b4559'
kDate = '969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d'
kRegion = '69daa0209cd9c5ff5c8ced464a696fd4252e981430b10e3d3fd8e2f197d7a70c'
kService = 'f72cfd46f26bc4643f06a11eabb6c0ba18780c19a8da0c31ace671265e3c87fa'
kSigning = 'f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d'
But, for some reason my implementation drops the last few characters of the final element, and I get:
kSecret : 41575334774a616c725855746e46454d492f4b374d44454e472b62507852666943594558414d504c454b4559
kDate : 969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d
kRegion : 69daa0209cd9c5ff5c8ced464a696fd4252e981430b10e3d3fd8e2f197d7a70c
kService : f72cfd46f26bc4643f06a11eabb6c0ba18780c19a8da0c31ace671265e3c87fa
kSigning : f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a0
I'm just using an example for the HMAC_SHA256 calculation from https://stackoverflow.com/a/29862424/993874, I can't see what I'm missing. For other calculations (i.e. ones performing requests for my own AWS data etc) I also see that some of the hmac outputs are not 32 characters in length.
Can anyone help address this (and also confirm whether I need to convert all the char arrays to hex strings for AWS requests)?
Example code:
#include <stdio.h>
#include <string.h>
#include <openssl/hmac.h>
void printHex(const char* preface, const char* toPrint) {
printf("%s\t: ", preface);
for(size_t i = 0; i < strlen(toPrint); i++) {
printf("%02x", toPrint[i] & 0xff);
}
printf("\n");
}
void hmac_sha256(const unsigned char* key,
const unsigned char* text,
unsigned char* result) {
unsigned int resultLen;
HMAC(EVP_sha256(), key, strlen(key), text, strlen(text), result, &resultLen);
}
void amazonV4Sign(const unsigned char* accessSecret,
const unsigned char* amzDate,
const unsigned char* region,
const unsigned char* service) {
unsigned char kDate[BUFSIZ];
unsigned char kRegion[BUFSIZ];
unsigned char kService[BUFSIZ];
unsigned char kSigning[BUFSIZ];
unsigned char kSecret[BUFSIZ];
sprintf(kSecret, "AWS4%s", accessSecret);
unsigned char request[BUFSIZ];
sprintf(request, "aws4_request");
hmac_sha256(kSecret, amzDate, kDate);
hmac_sha256(kDate, region, kRegion);
hmac_sha256(kRegion, service, kService);
hmac_sha256(kService, request, kSigning);
printHex("kSecret", kSecret);
printHex("kDate", kDate);
printHex("kRegion", kRegion);
printHex("kService", kService);
printHex("kSigning", kSigning);
}
int main(int argc, char* argv[]) {
unsigned char* key = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY";
unsigned char* dateStamp = "20120215";
unsigned char* regionName = "us-east-1";
unsigned char* serviceName = "iam";
amazonV4Sign(key, dateStamp, regionName, serviceName);
return 0;
}
You cannot use strlen to print the HMAC output because byte array may contain 0 byte.
Hence you can use the md_len returned by HMAC as below to print the byte array.
HMAC returns the length of md and syntax is.
unsigned char *HMAC(const EVP_MD *evp_md, const void *key,
int key_len, const unsigned char *d, int n,
unsigned char *md, unsigned int *md_len);
Hence use md_len to print the array.
void printHex(const char* preface, const char* toPrint, int len) {
printf("%s\t: ", preface);
for(size_t i = 0; i < len; i++) {
printf("%02x", toPrint[i] & 0xff);
}
printf("\n");
}
int hmac_sha256(const unsigned char* key,
const unsigned char* text,
unsigned char* result) {
unsigned int resultLen;
HMAC(EVP_sha256(), key, strlen(key), text, strlen(text), result, &resultLen);
printf("%d\n", resultLen);
return resultLen;
}
void amazonV4Sign(const unsigned char* accessSecret,
const unsigned char* amzDate,
const unsigned char* region,
const unsigned char* service) {
unsigned char kDate[EVP_MAX_MD_SIZE] = {0};
unsigned char kRegion[EVP_MAX_MD_SIZE] = {0};
unsigned char kService[EVP_MAX_MD_SIZE] = {0};
unsigned char kSigning[EVP_MAX_MD_SIZE] = {0};
unsigned char kSecret[BUFSIZ];
sprintf(kSecret, "AWS4%s", accessSecret);
printf("%s\n", kSecret);
unsigned char request[BUFSIZ];
sprintf(request, "aws4_request");
int len = hmac_sha256(kSecret, amzDate, kDate);
printHex("kSecret", kSecret,strlen(kSecret));
printHex("kDate", kDate,len);
len = hmac_sha256(kDate, region, kRegion);
printHex("kRegion", kRegion,len);
len = hmac_sha256(kRegion, service, kService);
printHex("kService", kService,len);
len = hmac_sha256(kService, request, kSigning);
printHex("kSigning", kSigning,len);
}
Output:
kSecret : 41575334774a616c725855746e46454d492f4b374d44454e472b62507852666943594558414d504c454b4559
kDate : 969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d
kRegion : 69daa0209cd9c5ff5c8ced464a696fd4252e981430b10e3d3fd8e2f197d7a70c
kService : f72cfd46f26bc4643f06a11eabb6c0ba18780c19a8da0c31ace671265e3c87fa
kSigning : f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d
Your loop in PrintHex is up to strlen(toPrint). It's a byte array, not a string, so you cannot use strlen( ). The loop needs to go up to 32.

Malloc error when comparing arrays of bytes

I can't figure out where my code is going wrong. I know there is allocation error in my function getit() but I can't figure out why! Any help is appreciated.
What my program does is hash a message into one array. Then, I have a random word generator that makes a string and hashes them. My program will then compare the hashes and keep making words until the hash matches the origional.
#include <stdio.h>
#include <openssl/evp.h>
#include <string.h>
void randString(int length, char* s);
void getit(unsigned char rando[], unsigned char hash[]);
char* mess1 = "Test Message";
unsigned char match[3];
int boolean = 0;
unsigned char orHash[3];
unsigned char raHash[3];
int counter = 0;
int main(int argc, char *argv[])
{
srand(time(NULL));
EVP_MD_CTX *mdctx;
const EVP_MD *md;
unsigned char md_value[EVP_MAX_MD_SIZE];
int md_len, i;
OpenSSL_add_all_digests();
md = EVP_get_digestbyname("SHA256");
mdctx = EVP_MD_CTX_create();
EVP_DigestInit_ex(mdctx, md, NULL);
EVP_DigestUpdate(mdctx, mess1, strlen(mess1));
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
EVP_MD_CTX_destroy(mdctx);
strcpy(match,md_value);
strcpy(orHash,match);
printf("Digest is: ");
for (i = 0; i < 3; i++)
printf("%02x", match[i]);
printf("\n");
while(boolean < 3){
char* qt = malloc(strlen(mess1) * sizeof(char));
randString(strlen(mess1),qt);
mdctx = EVP_MD_CTX_create();
EVP_DigestInit_ex(mdctx, md, NULL);
EVP_DigestUpdate(mdctx, qt, strlen(mess1));
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
EVP_MD_CTX_destroy(mdctx);
strcpy(raHash,md_value);
getit(raHash, orHash);
}
exit(0);
}
void randString(int length, char* s) {
const char alpha[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int i = 0; i < length; i++){
s[i] = alpha[rand()%(int)(sizeof(alpha) -1)];
}
s[length] = '\0';
}
void getit(unsigned char rando[], unsigned char hash[]){
counter += 1;
for (int i = 0; i < 3; i++)
printf("%02x", rando[i]);
for(int i = 0; i < 3; i++){
if (rando[i] != hash[i]){
printf("%d: The hashes don't match\n", counter);
boolean = 0;
break;
}
boolean += 1;
if(boolean == 3){
printf("Match Found!");
}
}
}
The Error I get is as follows:
hash: malloc.c:2392: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
The code breaks at trial 505 everytime (finished comparing trial 504) trying the see if the two arrays match so that might help.
There is no need to dynamic allocation in any of this. The whole point of this exercise it to brute-force generating random, equal-length alpha-numeric strings, digesting them, and stopping when you fine one that matches the first three octets.
No string conversions are required
One like-sized message buffer (matching the size of your test message) can be used.
You can reuse the digest context. No need to keep allocating and destroying it.
getit is ultimately pointless except to tally up a counter.
The result is something like this:
Code
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
void randString(size_t length, char* s);
int main()
{
unsigned char md_value[EVP_MAX_MD_SIZE];
unsigned char md_test[EVP_MAX_MD_SIZE];
unsigned int md_len, i;
char msg[] = "Test Message";
srand((unsigned)time(NULL));
OpenSSL_add_all_digests();
const EVP_MD *md = EVP_get_digestbyname("SHA256");
EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
EVP_DigestInit_ex(mdctx, md, NULL);
EVP_DigestUpdate(mdctx, msg, sizeof msg-1);
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
printf("Digest is: ");
for (i = 0; i < md_len; i++)
printf("%02x", md_value[i]);
printf("\n");
int counter = 0;
while (1)
{
++counter;
char rand_msg[sizeof msg];
randString(sizeof msg - 1, rand_msg);
EVP_DigestInit_ex(mdctx, md, NULL);
EVP_DigestUpdate(mdctx, rand_msg, sizeof rand_msg - 1);
EVP_DigestFinal_ex(mdctx, md_test, &md_len);
if (memcmp(md_test, md_value, 3) == 0)
{
printf("Match found: %s\nAttempts: %d\n", rand_msg, counter);
printf("Digest is: ");
for (i = 0; i < md_len; i++)
printf("%02x", md_test[i]);
printf("\n");
break;
}
}
return 0;
}
Sample Output (varies, obviously)
Digest is: b67d1b3ab0d839eb8bc1156b8717bb441c897fcab323374e2ae530a40632feba
Match found: nPbeGgsZcNoo
Attempts: 9570596
Digest is: b67d1bcdab5d05a8712a8cd4c99b5bf683fdcefcf43fc453f852f4ff14b28a39
Friends I figured it out.
I never used free(qt) so eventually, it ran out of memory to allocate after looping!

Printing wrong type for hash value on C

I'm heaving a problem on printing a hash generated with OpenSSL, code (using OpenSSL):
char *computeHash(char *msg){
static char hs[20];
SHA1(msg, strlen(msg), hs);
return hs;
}
int main(){
char *text;
char *hash;
int i;
text = "test";
hash = computeHash(text);
for(i=0;i<20;i++){
printf("%02x",hash[i]);
}
return 0;
}
As returning I'm getting:
$ ./a.out ffffffa94affffff8fffffffe5ffffffccffffffb1ffffff9bffffffa61c4c0873ffffffd3ffffff91ffffffe9ffffff87ffffff982fffffffbbffffffd3
Is that any way to print it right?
Thanks,
The %02x format string is for an integer. But you are printing a character. Also, hash is a char * pointer, you probably want an unsigned char *. How about:
unsigned char *hash_ptr = (unsigned char *) hash;
for(i=0;i<20;i++){
printf("%02x", (int) hash_ptr[i]);
}

openssl not verifying signature correctly

Following the OpenSSL docs, I /think/ that what I'm doing is correct.. but apparently it's not. Compiling the file (with gcc -g -Wall -Wextra -lssl sign.c) yields no errors or warnings. EVP_VerifyFinal() always returns 0 (Meaning the check failed). What is causing that?
static const EVP_MD * type;
unsigned char * sha(char * input)
{
EVP_MD_CTX c;
unsigned char *md;
unsigned int md_len;
md = malloc(EVP_MAX_MD_SIZE);
EVP_MD_CTX_init(&c);
EVP_DigestInit_ex(&c, type, NULL);
EVP_DigestUpdate(&c, input, strlen(input));
EVP_DigestFinal_ex(&c, md, &md_len);
EVP_MD_CTX_cleanup(&c);
return md;
}
unsigned char * sign(EVP_PKEY * key, unsigned char * data)
{
EVP_MD_CTX c;
unsigned char *sig;
unsigned int len;
EVP_MD_CTX_init(&c);
sig = malloc(EVP_PKEY_size(key));
EVP_SignInit(&c, type);
EVP_SignUpdate(&c, data, strlen((char *)data));
EVP_SignFinal(&c, sig, &len, key);
EVP_MD_CTX_cleanup(&c);
return sig;
}
int verify(EVP_PKEY * key, unsigned char * data, unsigned char * original)
{
EVP_MD_CTX c;
int ret;
EVP_MD_CTX_init(&c);
EVP_VerifyInit(&c, type);
EVP_VerifyUpdate(&c, data, (unsigned int)sizeof(data));
ret = EVP_VerifyFinal(&c, original, (unsigned int)strlen((char *)original), key);
return ret;
}
int main(void)
{
EVP_PKEY *sk, *pk;
FILE *sfd, *pfd;
unsigned char *hash, *sig;
unsigned int i;
sfd = fopen("secret.pem", "r");
pfd = fopen("public.pem", "r");
sk = PEM_read_PrivateKey(sfd, NULL, NULL, NULL);
pk = PEM_read_PUBKEY(pfd, NULL, NULL, NULL);
fclose(sfd);
fclose(pfd);
OpenSSL_add_all_digests();
type = EVP_get_digestbyname("SHA1");
hash = sha("moo");
for(i = 0; i < sizeof(hash); i++)
printf("%02x", hash[i]);
printf("\n");
sig = sign(sk, hash);
switch( verify(pk, sig, hash) )
{
case 0:
printf("Check failed.\n");
break;
case 1:
printf("Check succeeded!\n");
break;
default:
printf("Oh look, an error: %d", ERR_get_error());
break;
}
return 0;
}
You are not passing the correct size:
EVP_VerifyUpdate(&c, data, (unsigned int)sizeof(data));
Since data is defined as unsigned char *, sizeof(data) is probably 4 or 8 (number of bytes required to hold a pointer).
Try passing the actual number of bytes that you've allocated, i.e. EVP_PKEY_size(key). You will have to pass that to your verify() function.
It's possible that something else is also wrong, but this one caught my eye.
I know this is an old question, but one bug could confuse users.
In the verify function original and data should be swapped, original past to EVP_VerifyUpdate and data to EVP_VerifyFinal. String length should not be used as a byte array can contain 0x00 as a valid value which will be recognized as "\0".

Resources