Hy guys, another problem about openssl:
I have this command:
openssl enc -aes-192-cbc -pbkdf2 -e -in <infile> -out <outfile> -pass pass:password
Now i have only the ciphertext of this command and i know the password and then i know also the salt that is the first 8 bytes of the ciphertext after the string "Salted__". I know also that openssl as default parameter take 1000 iteration count and sha256 as a digest. My problem is: how i can go back to the derived key and derived iv from c language?
My code is this but it not return the right values:
void decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *plaintext, const char *password, unsigned char* salt){
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
//unsigned char* key = "EF04020D6979FC09CC1859A2BFB832FFFCF57C64BA61F682"; right value
//unsigned char* iv = "722EDDC813763C9AAB96A0A6885CE1DB"; right value
unsigned char key[24], iv[16];
int i;
PKCS5_PBKDF2_HMAC(password, strlen(password), (unsigned char*)salt, strlen(salt), 1000, EVP_sha256(), 16, key);
EVP_BytesToKey(EVP_aes_192_cbc(), EVP_sha256(), (unsigned char*)salt, (unsigned char*)password, strlen(password), 1000, key+16, iv);
printf("Key: "); for(i=0; i < 24; ++i){ printf("%02x", key[i]); } printf("\n");
printf("IV: "); for(i=0; i < 16; ++i){ printf("%02x", iv[i]); } printf("\n\n");
//Create and initialise the context
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
//Initialise the decryption operation. IMPORTANT - ensure you use a key
//and IV size appropriate for your cipher
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_192_cbc(), NULL, key, iv))
handleErrors();
//Provide the message to be decrypted, and obtain the plaintext output.
//EVP_DecryptUpdate can be called multiple times if necessary.
if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleErrors();
plaintext_len = len;
//Finalise the decryption. Further plaintext bytes may be written at
//this stage.
if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
handleErrors();
plaintext_len += len;
//Clean up
EVP_CIPHER_CTX_free(ctx);
}
The right values are commented and i take it from the terminal.... but my c code don't return that values.
I think this depends by the fact that i don't translate well the -pbkdf2 derivation key...Help me please
I solved this problem seeing in the source code of openssl on GitHub:
https://github.com/openssl/openssl/blob/master/apps/enc.c
Related
I have two functions: 1. encryption (string text, string key) and 2. decryption (string text, string key). these functions encrypt/decrypt text under key . I use openssl library and functions:EVP_EncryptUpdate and EVP_DecryptUpdate the input arguments of these two functions are (EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl). my functions are below and the output is :
"Hello world\x5\x5\x5\x5\x5"
which should be "Hello world"
i suppose there is something wrong with castings.
std::string encrypt(std::string text, std::string k){
const unsigned char *plaintext=(const unsigned char*) text.c_str();
const unsigned char *key=(const unsigned char*) k.c_str();
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len=strlen((const char *)plaintext);
int ciphertext_len=plaintext_len+256;
unsigned char * ciphertext=new unsigned char[ciphertext_len];
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
/*
* Initialise the encryption operation.
*/
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, NULL))
handleErrors();
/*
* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
/*
* Finalise the encryption. Further ciphertext bytes may be written at
* this stage.
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
handleErrors();
ciphertext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
std::string cipherteststring=(char const* )ciphertext ;
delete []ciphertext;
return cipherteststring;
}
std::string decrypt(std::string text, std::string k)
{
const unsigned char *ciphertext=(const unsigned char*)text.c_str();
const unsigned char *key=(const unsigned char*) k.c_str();
int ciphertext_len=strlen((const char *)ciphertext);
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len=ciphertext_len;
unsigned char *decryptedtext=new unsigned char[plaintext_len];
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
/*
* Initialise the decryption operation.
*/
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, NULL))
handleErrors();
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary.
*/
if(1 != EVP_DecryptUpdate(ctx, decryptedtext, &len, ciphertext, ciphertext_len))
handleErrors();
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
//std::string plaintextstring( reinterpret_cast< char const* >(decryptedtext) ) ;
std::string plaintextstring=(char const*)decryptedtext;
decryptedtext[plaintext_len] = '\0';
delete []decryptedtext;
return plaintextstring;
}
int main (){
std::string key ="01234567890123456789012345678901";
std::string plaintext ="Hello world";
std::string encrypted;
std::string decrypted;
std::string decryptedhexstr;
encrypted=encrypt (plaintext,key);
decrypted = decrypt(encrypted, key);
cout<<decrypted;
return 0;
}``
I have a encrypted string in base64 as ASCII string (std::string) and a key as ASCII string. The iv will just be empty. The key will be variable length and will use padding (and I still don't know how to do this yet). I would like to use OpenSSL AES 128 CBC to decrypt that to the original text. I'm using the source code from the wiki. However the result I got are just random character when I cout or print with %s. Here is the source code:
int main(void)
{
unsigned char* key = (unsigned char*)"okamura";
unsigned char* iv = (unsigned char*)"";
unsigned char* base64 = (unsigned char*)"BPaHjjva7bBjrDQrJyekPA==";
/*
* Buffer for ciphertext. Ensure the buffer is long enough for the
* ciphertext which may be longer than the plaintext, depending on the
* algorithm and mode.
*/
unsigned char ciphertext[128];
/* Buffer for the decrypted text */
unsigned char decryptedtext[128];
int decryptedtext_len, ciphertext_len;
/* Decrypt the ciphertext */
decryptedtext_len = decrypt(base64, sizeof(base64), key, iv,
decryptedtext);
/* Add a NULL terminator. We are expecting printable text */
decryptedtext[decryptedtext_len] = '\0';
/* Show the decrypted text */
printf("Decrypted text is:\n");
printf("%s", decryptedtext);
return 0;
}
Decrypt function
int decrypt(unsigned char* ciphertext, int ciphertext_len, unsigned char* key,
unsigned char* iv, unsigned char* plaintext)
{
EVP_CIPHER_CTX* ctx;
int len;
int plaintext_len;
/* Create and initialise the context */
if (!(ctx = EVP_CIPHER_CTX_new()))
{
}
//handleErrors();
/*
* Initialise the decryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits
*/
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
{
}
//handleErrors();
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary.
*/
if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
{
}
//handleErrors();
plaintext_len = len;
/*
* Finalise the decryption. Further plaintext bytes may be written at
* this stage.
*/
if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
{
}
//handleErrors();
plaintext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return plaintext_len;
}
Encrypt function
int encrypt(unsigned char* plaintext, int plaintext_len, unsigned char* key,
unsigned char* iv, unsigned char* ciphertext)
{
EVP_CIPHER_CTX* ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if (!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
/*
* Initialise the encryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits
*/
if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
handleErrors();
/*
* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
/*
* Finalise the encryption. Further ciphertext bytes may be written at
* this stage.
*/
if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
handleErrors();
ciphertext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
I tried the following C implementation of Openssl EVP function for AES-128-CBC encryption but the results I am getting are incorrect compared to the command line OpenSSL result.
I referenced the code on the site below.
https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption
C code implementation of AES-128-CBC:
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
void handleErrors(void)
{
ERR_print_errors_fp(stderr);
abort();
}
int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
unsigned char *iv, unsigned char *ciphertext)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
handleErrors();
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
handleErrors();
ciphertext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
unsigned char *iv, unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
handleErrors();
if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleErrors();
plaintext_len = len;
if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
handleErrors();
plaintext_len += len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return plaintext_len;
}
int main (void)
{
/* A 128 bit key */
unsigned char *key = (unsigned char *)"0123456789012345";
/* A 128 bit IV */
unsigned char *iv = (unsigned char *)"0123456789012345";
/* Message to be encrypted */
unsigned char *plaintext =
(unsigned char *)"The quick brown fox jumps over the lazy dog";
/*
* Buffer for ciphertext. Ensure the buffer is long enough for the
* ciphertext which may be longer than the plaintext, depending on the
* algorithm and mode.
*/
unsigned char ciphertext[128];
/* Buffer for the decrypted text */
unsigned char decryptedtext[128];
int decryptedtext_len, ciphertext_len;
/* Encrypt the plaintext */
ciphertext_len = encrypt (plaintext, strlen ((char *)plaintext), key, iv,
ciphertext);
/* Do something useful with the ciphertext here */
printf("Ciphertext is:\n");
BIO_dump_fp (stdout, (const char *)ciphertext, ciphertext_len);
/* Decrypt the ciphertext */
decryptedtext_len = decrypt(ciphertext, ciphertext_len, key, iv,
decryptedtext);
/* Add a NULL terminator. We are expecting printable text */
decryptedtext[decryptedtext_len] = '\0';
/* Show the decrypted text */
printf("Decrypted text is:\n");
printf("%s\n", decryptedtext);
return 0;
}
Output:
Ciphertext is:
0000 - 30 89 e6 bc 22 4b d9 5b-85 cf 56 f4 b9 67 11 8a 0..."K.[..V..g..
0010 - aa 47 05 43 0f 25 b6 b4-d9 53 18 8a d1 5d d7 8f .G.C.%...S...]..
0020 - 38 67 57 7e 7d 58 e1 8c-9c b3 40 64 7c 8b 4f d8 8gW~}X....#d|.O.
Decrypted text is:
The quick brown fox jumps over the lazy dog
OpenSSL command line:
printf "The quick brown fox jumps over the lazy dog" | openssl enc -e -aes-128-cbc -K 0123456789012345 -iv 0123456789012345 | xxd
OpenSSL Output:
00000000: 86ec 68f6 1d8f 440b 70e8 e7d2 69dc 5319 ..h...D.p...i.S.
00000010: c023 893a 3451 5a17 5e51 0b69 5e70 b073 .#.:4QZ.^Q.i^p.s
00000020: 7fbe 6f6f e61f dfb0 d32e 36a9 6651 021e ..oo......6.fQ...
Why are the output results different?
How to fix code?
The key and IV passed on the command line should be formatted as a hex string representing the bytes of the key and IV, not as ASCII text.
So instead of:
-K 0123456789012345 -iv 0123456789012345
You want:
-K 30313233343536373839303132333435 -iv 30313233343536373839303132333435
I have used the following code to encrypt and decrypt an XML file:
int bytes_read, bytes_written;
unsigned char indata[AES_BLOCK_SIZE];
unsigned char outdata[AES_BLOCK_SIZE];
unsigned char ckey[] = "thiskeyisverybad";
unsigned char ivec[] = "dontusethisinput";
AES_KEY key;
AES_set_encrypt_key(ckey, 128, &key);
int num = 0;
FILE * ifp = fopen("Test.XML","rb");
FILE * ofp = fopen("Enc.XML", "wb");
while (1) {
bytes_read = fread(indata, 1, AES_BLOCK_SIZE, ifp);
AES_cfb128_encrypt(indata, outdata, bytes_read, &key, ivec,&num,AES_ENCRYPT);
bytes_written = fwrite(outdata, 1, bytes_read, ofp);
if (bytes_read < AES_BLOCK_SIZE)
break;
}
num = 0;
FILE * ifpe = fopen("Enc.XML", "wb");
FILE * ofpe = fopen("TestDec.XML", "rb");
while (1) {
bytes_read = fread(indata, 1, AES_BLOCK_SIZE, ifpe);
AES_cfb128_encrypt(indata, outdata, bytes_read, &key, ivec, &num, AES_DECRYPT);
bytes_written = fwrite(outdata, 1, bytes_read, ofpe);
if (bytes_read < AES_BLOCK_SIZE)
break;
}
I have referred to the link Encrypting and decrypting a small file using openssl. I am getting an encrypted file in Enc.XML. When I try the decrypt code, a file is getting created by blank records. Wanted to know what is missed in decrypt code.
The "ivec" buffer in modified with each call to AES_cfb128_encrypt. If your code is not two programs but one problem, like what you have above, then you need to reset the "ivec" buffer back to the original value before attempting the decryption.
Something like:
char ivec[16];
…
memcpy(ivec, "dontusethisinput", 16);
… encrypt code
memcpy(ivec, "dontusethisinput", 16);
… decrypt code
I have a problem in using higher level envelope decryption fron openssl/evp.h
EVP_OpenFinal and EVP_OpenInit fail randomly when I try to run the same program multiple times with the same values. I am working on it for last 5 days but no luck. I am writing my complete code here. Please help me out. It would be very nice if someone can try to reproduce the errors, and let me know where I am wrong.
Error message:
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
4944:error:0606506D:lib(6):func(101):reason(109):.\crypto\evp\evp_enc.c:460:
And here is the code
#include <iostream>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <stdio.h>
void handleErrors(void);
int envelope_seal(EVP_PKEY **pub_key, unsigned char *plaintext, int plaintext_len,
unsigned char **encrypted_key, int *encrypted_key_len, unsigned char *iv,
unsigned char *ciphertext);
int envelope_open(EVP_PKEY *priv_key, unsigned char *ciphertext, int ciphertext_len,
unsigned char *encrypted_key, int encrypted_key_len, unsigned char *iv,
unsigned char *plaintext);
using namespace std;
int main()
{
RSA *rsa_pubkey= RSA_new();
RSA *rsa_prikey= RSA_new();
EVP_PKEY *evp_pubkey = EVP_PKEY_new();
EVP_PKEY *evp_prikey = EVP_PKEY_new();
FILE *rsa_prikey_file = NULL;
FILE *rsa_pubkey_file = NULL;
rsa_pubkey_file = fopen("pubkey.pem", "r");
if (!rsa_pubkey_file)
{
fprintf(stderr, "Error loading PEM RSA Public Key File.\n");
exit(2);
}
PEM_read_RSA_PUBKEY(rsa_pubkey_file, &rsa_pubkey,NULL, NULL);
EVP_PKEY_assign_RSA(evp_pubkey,rsa_pubkey);
rsa_prikey_file = fopen("key.pem", "r");
if (!rsa_prikey_file)
{
fprintf(stderr, "Error loading PEM RSA private Key File.\n");
exit(2);
}
PEM_read_RSAPrivateKey(rsa_prikey_file, &rsa_prikey,NULL, NULL);
EVP_PKEY_assign_RSA(evp_prikey,rsa_prikey);
unsigned char *plaintext = (unsigned char*) "The quick brown fox jumps over thes lazy dog";
unsigned char ciphertext[256] = {};
unsigned char plaintextt[256] = {};
int ciphertextlength;
unsigned char *encKey = (unsigned char*)malloc(RSA_size(rsa_pubkey));
unsigned char iv[16] = {};
envelope_seal(&evp_pubkey, plaintext,strlen((const char*)plaintext),&encKey, &ciphertextlength,iv,ciphertext);
envelope_open(evp_prikey, ciphertext, strlen((const char*)ciphertext), encKey, strlen((const char*)encKey),iv,plaintextt);
std::cout <<"Result: "<<plaintextt<<std::endl;
EVP_PKEY_free(evp_pubkey);
EVP_PKEY_free(evp_prikey);
free(ciphertext);
free(encKey);
}
int envelope_seal(EVP_PKEY **pub_key, unsigned char *plaintext, int plaintext_len,
unsigned char **encrypted_key, int *encrypted_key_len, unsigned char *iv,
unsigned char *ciphertext)
{
EVP_CIPHER_CTX *ctx;
int ciphertext_len;
int len;
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
if(1 != EVP_SealInit(ctx, EVP_aes_128_cbc(),
encrypted_key,
encrypted_key_len,
iv,
pub_key, 1))
{
handleErrors();
}
if(1 != EVP_SealUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
{
handleErrors();
}
ciphertext_len = len;
if(1 != EVP_SealFinal(ctx, ciphertext + len, &len))
{
handleErrors();
}
ciphertext_len += len;
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int envelope_open(EVP_PKEY *priv_key, unsigned char *ciphertext, int ciphertext_len,
unsigned char *encrypted_key, int encrypted_key_len, unsigned char *iv,
unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
if(!(ctx = EVP_CIPHER_CTX_new()))
{
handleErrors();
}
if(1 != EVP_OpenInit(ctx, EVP_aes_128_cbc(), encrypted_key,
encrypted_key_len, iv, priv_key))
{
handleErrors();
}
if(1 != EVP_OpenUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
{
handleErrors();
}
plaintext_len = len;
if(1 != EVP_OpenFinal(ctx, plaintext + len, &len))
{
handleErrors();
}
plaintext_len += len;
EVP_CIPHER_CTX_free(ctx);
plaintext[plaintext_len] = '\0';
return plaintext_len;
}
void handleErrors(void)
{
perror("Error: ");
ERR_print_errors_fp(stderr);
abort();
}
envelope_seal() gives back the length of the encrypted string, I have to put this length in envelope_open()
int **length** = envelope_seal(&evp_pubkey, plaintext,strlen((const char*)plaintext),&encKey, &ciphertextlength,iv,ciphertext);
envelope_open(evp_prikey, ciphertext, **length**, encKey, strlen((const char*)encKey),iv,plaintextt);
The random crashing is caused by your length calculations before envelope_seal and envelope_open. The lengths should look like:
unsigned char *plaintext = (unsigned char*) "The quick brown fox jumps over thes lazy dog";
int ciphertextlength;
unsigned int enclen = EVP_PKEY_size(evp_prikey);
unsigned char *encKey = (unsigned char*)malloc(enclen);
unsigned char *ciphertext = (unsigned char*)malloc(enclen);
unsigned char plaintextt[enclen] = {};
unsigned char iv[16] = {};
unsigned int length = envelope_seal(&evp_pubkey, plaintext,strlen((const char*)plaintext),&encKey, &ciphertextlength,iv,ciphertext);
envelope_open(evp_prikey, ciphertext, length, encKey, enclen,iv,plaintextt);
As your answer states envelope_seal returns the size. You cannot get the size of a char* as your crashing always occured when the size of your plaintext was less than 48.