RE: EVP_Decrypt function- AES cbc 128 bit mode- Input length?
From: owner-openssl-us...@openssl.org On Behalf Of tera tellence Sent: Wednesday, 20 April, 2011 09:15 I am trying in vain to find out why the AES decrypt won't work here. I have found where exactly is the problem and now looking for some wise-crack to help me solve it. Small preliminary point not related to the actual question: 'wise-crack' in English means a joke, usually a hurtful one. And worse, in US English at least 'wise-guy' has become slang for a member of organized crime, or mafia. You want some wise person or just somebody. snip much of code to leave relevant parts cipher_type = EVP_aes_128_cbc(); EVP_EncryptInit_ex(en, cipher_type, NULL, passkey, passiv); EVP_DecryptInit_ex(de, cipher_type, NULL, passkey, passiv); olen = len = strlen(input)+1; int c_len = len + AES_BLOCK_SIZE - 1; int f_len = 0; ciphertext = (unsigned char *)malloc(c_len); if(!EVP_EncryptInit_ex(en, NULL, NULL, NULL, NULL)){ printf(ERROR in EVP_EncryptInit_ex \n); return NULL; } A general comment: whenever you get an error return from EVP, and most other OpenSSL routines, you should look at the error stack, like you did for DecryptFinal with ERR_print_errors_fp(stderr). Also, NULL isn't safe as a return value of main(). NULL is just 0 in some cases but (void*)0 in others (the C standard allows either) and the latter is illegal. And here it's semantically incorrect also; exit 0 normally means 'success' and this is not a success case. On some systems (including Unix and Windows) you can return a small integer (up to 99 at least) to indicate the level and/or type of problem. On all C systems you can return at least EXIT_SUCCESS or EXIT_FAILURE from stdlib.h. if(!EVP_EncryptUpdate(en, ciphertext, c_len, plain, len)){ printf(ERROR in EVP_EncryptUpdate \n); return NULL; } printf(len value after update \%d\\n, len); // printf(size of ciphertext after update \%d\\n, sizeof(ciphertext)); printf(strlen value of ciphertext after update \%d\\n, strlen(ciphertext)); if(!EVP_EncryptFinal_ex(en, ciphertext+c_len, f_len)){ printf(ERROR in EVP_EncryptFinal_ex \n); return NULL; } printf(len value after final \%d\\n, len); C is call by value, so len can never be changed by those calls. You might want to look instead at c_len and f_len which can be, and in fact are set except possibly for errors. printf(strlen value of ciphertext after final \%d\\n, strlen(ciphertext)); EVP_CIPHER_CTX_cleanup(en); len = c_len + f_len; printf(len value after aes_encrypt \%d\\n, len); //HERE IS THE PROBLEM: IF I USE len= strlen(ciphertext) I GET ERROR //len = strlen(ciphertext); encrypted data (ciphertext) is binary. It can and usually does include the null byte that terminates a C string, so strlen() computes the WRONG length. Using the wrong length is an error. You need to use the length(s) returned by the EVP_Encrypt routines, which in this simple case is exactly c_len + f_len. Specifically, the/each EncryptUpdate call may produce *some* of the ciphertext and store the length in the output argument. EncryptFinal will produce the *rest* (normally one block) and store that length in the output argument. That's why you provide ciphertext+c_len as the buffer to EncryptFinal, so it puts its ciphertext after any from EncryptUpdate. snip more What I dont understand: What should I feed as the len parameter for the openSSL EVP Decrypt routines? The correct length of the ciphertext, in your case c_len+f_len. what is this magic len = c_len+ f_len? See above. How should I get this in case I am given just the cipher with the key and the iv? This should be always possible right? I know strlen is a bad parametr especially for binary as the ciphertext input to EVP Decrypt is binary: so how should I get this? I don't know what your question is. To decrypt (for CBC) you need the key which is 16 octets for AES-128, the IV which is 16 octets for AES-anything, and the ciphertext whose length depends on the data that was encrypted and therefore generally you must keep track of (but will always be a multiple of 16 octets). If you simply encrypt and then decrypt in one process, it's easy to keep track of. But this is basically useless. Normally you want to encrypt data to be sent to another system, program, or person; or stored for later retrieval. In these cases, you must send or store it in some fashion that
EVP_Decrypt function- AES cbc 128 bit mode- Input length?
Hi All, I am trying in vain to find out why the AES decrypt won't work here. I have found where exactly is the problem and now looking for some wise-crack to help me solve it. Here is the code that I tested with(from various posts here): #include string.h #include stdio.h #include stdlib.h #include openssl/evp.h int AES_BLOCK_SIZE = 128; int main(int argc, char **argv) { EVP_CIPHER_CTX en; EVP_CIPHER_CTX de; EVP_CIPHER_CTX_init(en); EVP_CIPHER_CTX_init(de); const EVP_CIPHER *cipher_type; unsigned char *passkey, *passiv, *plaintxt; char *plain; char *plaintext; unsigned char *ciphertext; int olen, len; int i =0; unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0 }; unsigned char key[]= { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c , 0 }; unsigned char *input = hi this is patrick immling\n'Doctor'.\n'Doctor' who ?\nPrecisely! 123910!§$$§% !%%$$(/=))?=(#ü++Ü**,.here we go sometimes it i s difficult but 187! 1$5 78@2 14.TӒ��틪�ձ1z.$�?�U���y; printf(AES ALGORITHM FOR 128 bit CBC MODE\n); cipher_type = EVP_aes_128_cbc(); AES_BLOCK_SIZE = 128; passkey = key; passiv = iv; plain = input; printf(Initializing AES ALGORITHM FOR CBC MODE..\n); EVP_EncryptInit_ex(en, cipher_type, NULL, passkey, passiv); EVP_DecryptInit_ex(de, cipher_type, NULL, passkey, passiv); olen = len = strlen(input)+1; printf(len value before aes_encrypt \%d\\n, len); int c_len = len + AES_BLOCK_SIZE - 1; int f_len = 0; ciphertext = (unsigned char *)malloc(c_len); if(!EVP_EncryptInit_ex(en, NULL, NULL, NULL, NULL)){ printf(ERROR in EVP_EncryptInit_ex \n); return NULL; } if(!EVP_EncryptUpdate(en, ciphertext, c_len, plain, len)){ printf(ERROR in EVP_EncryptUpdate \n); return NULL; } printf(len value after update \%d\\n, len); // printf(size of ciphertext after update \%d\\n, sizeof(ciphertext)); printf(strlen value of ciphertext after update \%d\\n, strlen(ciphertext)); if(!EVP_EncryptFinal_ex(en, ciphertext+c_len, f_len)){ printf(ERROR in EVP_EncryptFinal_ex \n); return NULL; } printf(len value after final \%d\\n, len); printf(strlen value of ciphertext after final \%d\\n, strlen(ciphertext)); EVP_CIPHER_CTX_cleanup(en); len = c_len + f_len; printf(len value after aes_encrypt \%d\\n, len); //HERE IS THE PROBLEM: IF I USE len= strlen(ciphertext) I GET ERROR //len = strlen(ciphertext); printf(strlen value of ciphertext after aes_encrypt \%d\\n, len); int p_len = len; f_len = 0; plaintext = (unsigned char *)malloc(p_len); // memset(plaintext,0,sizeof(plaintext)); if(!EVP_DecryptInit_ex(de, NULL, NULL, NULL, NULL)){ printf(ERROR in EVP_DecryptInit_ex \n); return NULL; } EVP_CIPHER_CTX_set_padding(de, 0); if(!EVP_DecryptUpdate(de, plaintext, p_len, ciphertext, len)){ printf(ERROR in EVP_DecryptUpdate\n); return NULL; } printf(len value after decrypt update \%d\\n, len); if(!EVP_DecryptFinal_ex(de, plaintext+p_len, f_len)){ printf(ERROR in EVP_DecryptFinal_ex\n); ERR_print_errors_fp(stderr); return NULL; } EVP_CIPHER_CTX_cleanup(de); len = p_len + f_len; printf(Decrypted value = %s\n, plaintext); printf(len value after aes_decrypt \%d\\n, len); if (strncmp(plaintext, input, olen)) printf(FAIL: enc/dec failed for \%s\\n, input); else printf(OK: enc/dec ok for \%s\\n, plaintext); // \%s\\n printf(\n); free(ciphertext); free(plaintext); return 0; } What I dont understand: What should I feed as the len parameter for the openSSL EVP Decrypt routines? what is this magic len = c_len+ f_len? How should I get this in case I am given just the cipher with the key and the iv? This should be always possible right? I know strlen is a bad parametr especially for binary as the ciphertext input to EVP Decrypt is binary: so how should I get this? I can already see that if I use len= strlen(ciphertext) gives me a wrong answer and sizeof parameter is also not