Using the OpenSSL C API , I want to decrypt a file using a password, in order to do that I need to manually derive the key and iv from the given password using EVP_BytesToKey()
, but the function gives me the wrong key and iv.
I encrypt the file using the command line tool like so :
openssl enc -nosalt -p -in sample.txt -out sample.txt.enc -e -aes256 -k PASSWORD
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
key=0BE64AE89DDD24E225434DE95D501711339BAEEE18F009BA9B4369AF27D30D60
iv =44A783DFFE1463B81E65064750797FA4
Here is my code (most of it is from examples I've seen of stack overflow) :
#include <string>
#include <fstream>
#include <openssl/ssl.h>
#include <iostream>
#include <vector>
#include <locale>
#include <windows.h>
int main(){
// Initializing OpenSLL
const EVP_CIPHER *cipher;
const EVP_MD *dgst = NULL;
unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
// Setting password
const char *password = "PASSWORD";
const unsigned char *salt = NULL;
int i;
OpenSSL_add_all_algorithms();
// Getting key and iv
cipher = EVP_get_cipherbyname("aes-256-cbc");
if(!cipher) { fprintf(stderr, "no such cipher\n"); return 1; }
dgst=EVP_get_digestbyname("md5");
if(!dgst) { fprintf(stderr, "no such digest\n"); return 1; }
if(!EVP_BytesToKey(cipher, dgst, salt,
(unsigned char *) password,
strlen(password), 1, key, iv))
{
fprintf(stderr, "EVP_BytesToKey failed\n");
return 1;
}
// Output key and iv to the screen
printf("Key: "); for(i=0; i< 32; ++i) { printf("%02x", key[i]); } printf("\n");
printf("IV: "); for(i=0; i< 16; ++i) { printf("%02x", iv[i]); } printf("\n");
}
When debugging, the program outputs the key and iv to the screen , they contains random bytes?!?
Somehow when printing the key and iv to the screen with "%02x" it shows valid hex values.
Here is what my program outputs :
Key: 319f4d26e3c536b5dd871bb2c52e3178dcbc5de3a413ea043012cf3506b6956e
IV: c23b1986151650adf58ba93c7a10f73f
The Output is different from the original key and iv. I've seen other people do this and it worked for them.
Thank you
Solution:
(read to the end for an improvement)Since openSSL 1.1, specifying no digest outputs the SHA256 digest instead of the MD5. If you run this command (note the -md switch):
openssl enc -nosalt -p -in sample.txt -out sample.txt.enc -e -aes256 -k PASSWORD -md md5
You get the following output:
Which is the same as your C program.
Conversely, if you switch your C source to sha256 digest:
You obtain the same output as from the command line.
Improvement
As you might have noticed, the
openssl
gives you a warning*** WARNING : deprecated key derivation used.
Looking into the openssl documentation we have an explanation for such warning:We can then obtain the key directly with this algorithm both with
openssl
executable using the switchiter 1
which uses-pbkdf2 Use password-based key derivation function 2
automatically:Getting
And modifying our C program to get the key with the same more secure algorithm:
Which outputs: