In message <[EMAIL PROTECTED]> on Mon, 21 Mar 2005 21:06:05 -0300, Rafael 
Cividanes <[EMAIL PROTECTED]> said:

rafacividanes>       I'm doing a little program to encrypt and decrypt
rafacividanes> a string using the EVP API. I couldn't understand if I
rafacividanes> have to use EVP_DecryptFinal_ex( ) or just
rafacividanes> EVP_DecryptUpdate( ) in the decryption operation. The
rafacividanes> second function return the entire recovered plaintext,
rafacividanes> then I can't understand why EVP_DecryptFinal_ex( )
rafacividanes> exist.  Just for checking error?

EVP_DecryptFinal_ex() clears the padding that's tucked at the end of
the ciphertext, and through the padding, it will also check that the
decryption was correctly done.  This ALSO applies to messages that are
an exact multiple of 8 bytes (or whatever the cipher block size is) in
length.

rafacividanes> 
rafacividanes>       Here is my code:
rafacividanes> 
rafacividanes>     int main(int argc, char *argv[])
rafacividanes>     {
rafacividanes>         EVP_CIPHER_CTX ctx;
rafacividanes>         char key[EVP_MAX_KEY_LENGTH];
rafacividanes>         char iv[EVP_MAX_IV_LENGTH];
rafacividanes>         char intext[] = "The problem will be solved until12345"; 
//32    
rafacividanes>                    
rafacividanes>         unsigned char outbuf[1024];
rafacividanes>         unsigned char recover_msg[1024];
rafacividanes>         unsigned char final[1024];
rafacividanes>         int size_recover_msg, size_final;
rafacividanes>         int outlen, tmplen;
rafacividanes>         int i;
rafacividanes> 
rafacividanes>         printf("\n START!!! \n");
rafacividanes>         RAND_screen();
rafacividanes>         RAND_bytes(key, EVP_MAX_KEY_LENGTH);
rafacividanes>         RAND_bytes (iv, EVP_MAX_IV_LENGTH);
rafacividanes> 
rafacividanes>         //initialization
rafacividanes>         for (i=0; i<1024; i++){
rafacividanes>             outbuf[i]='\0';
rafacividanes>             recover_msg[i]='\0';
rafacividanes>             final[i]='\0';
rafacividanes>         }
rafacividanes> 
rafacividanes>         //encryption
rafacividanes>         EVP_CIPHER_CTX_init(&ctx);
rafacividanes>         EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc( ), NULL, key, 
iv);
rafacividanes> 
rafacividanes>         printf("\n EVP_CIPHER_CTX_key_length(&ctx): %d ", 
rafacividanes> EVP_CIPHER_CTX_key_length(&ctx));
rafacividanes>         printf("\n Size of plaintext: %d \n", strlen(intext));
rafacividanes> 
rafacividanes>         if(!EVP_EncryptUpdate(&ctx, outbuf, &outlen, intext, 
rafacividanes> strlen(intext)))                            
rafacividanes>                 printf("\n ERROR! \n");
rafacividanes>                
rafacividanes>         // Buffer passed to EVP_EncryptFinal() must be after 
data just
rafacividanes>         // encrypted to avoid overwriting it.
rafacividanes>         
rafacividanes>         if(!EVP_EncryptFinal_ex(&ctx, outbuf + outlen, 
rafacividanes> &tmplen))                               
rafacividanes>                 printf("\n ERROR!! \n");
rafacividanes>                                
rafacividanes>         outlen += tmplen;
rafacividanes> 
rafacividanes>         //print the ciphertext
rafacividanes>         printf("\n ciphertext: \n");
rafacividanes>         for (i=0;i<outlen;i++) printf("%02x",outbuf[i]);
rafacividanes>         printf("\n");
rafacividanes> 
rafacividanes>         EVP_CIPHER_CTX_cleanup(&ctx);
rafacividanes> 
rafacividanes>         //Decryption
rafacividanes>         if (!EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc( ), NULL, 
key, iv))
rafacividanes>             printf("\n ERROR!! \n");
rafacividanes> 
rafacividanes>         if (!EVP_DecryptUpdate(&ctx, recover_msg, 
&size_recover_msg, 
rafacividanes> outbuf, outlen))
rafacividanes>             printf("\n ERROR!! \n");
rafacividanes> 
rafacividanes>         if (!EVP_DecryptFinal_ex(&ctx, final, &size_final))
rafacividanes>             printf("\n ERROR!! \n");
rafacividanes> 
rafacividanes>         //print the recovered plaintext as a string
rafacividanes>         printf("\n recovered_plaintext1: \n %s \n", recover_msg);
rafacividanes> 
rafacividanes>         //print the recovered plaintext as an array
rafacividanes>         printf("\n recovered_plaintext2: \n ");
rafacividanes>         for (i=0;i<=size_recover_msg;i++) 
printf("%c",recover_msg[i]);
rafacividanes> 
rafacividanes>         //print the resultt of finalization phase
rafacividanes>         printf("\n\n final: %s \n", final);
rafacividanes>         printf("\n size_final = %d \n", size_final);
rafacividanes> 
rafacividanes>         EVP_CIPHER_CTX_cleanup(&ctx);
rafacividanes> 
rafacividanes>     }//end main
rafacividanes> 
rafacividanes>      Another thing I coundn't understand is why
rafacividanes> "recovered_plaintext1" sometimes ataches trash when
rafacividanes> printed in the screen, and sometimes doesn't.

That "trash" is there because you didn't allow EVP_Decrypt_Final_ex()
to do it's job properly, by directing it's output to final.  You might
also notice that the output "recovered_plaintext2" is missing a bit.
The last few bytes ended up in final instead, *added* *by*
*EVP_DecryptFinal_ex()*!  Your decryption should look like this:

  //Decryption
  if (!EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc( ), NULL, key, iv))
    printf("\n ERROR!! \n");

  if (!EVP_DecryptUpdate(&ctx, recover_msg, &size_recover_msg,
                         outbuf, outlen))
    printf("\n ERROR!! \n");

  if (!EVP_DecryptFinal_ex(&ctx, recover_msg + size_recover_msg, &size_final))
    printf("\n ERROR!! \n");

  //print the recovered plaintext as a string
  printf("\n recovered_plaintext1: \n %s \n", recover_msg);

  //print the recovered plaintext as an array
  printf("\n recovered_plaintext2: \n ");
  for (i=0;i<=size_recover_msg + size_final;i++) printf("%c",recover_msg[i]);

  //print the resultt of finalization phase
  printf("\n\n final: %s \n", recover_msg + size_recover_msg);
  printf("\n size_final = %d \n", size_final);


And oh, you will still potentially get trash by
"recovered_plaintext1".  The reason is that you didn't include the
ending NUL byte in the text to encrypt, so there's no guarantee you'll
get a NUL byte in the proper place in the recovered plaintext either.
You should either trust the total returned size of the recovered
plaintext, or make sure the NUL byte becomes part of the encrypted
text.  The latter can be done by using sizeof(intext) instead of
strlen(intext).

Cheers,
Richard

-----
Please consider sponsoring my work on free software.
See http://www.free.lp.se/sponsoring.html for details.

-- 
Richard Levitte                         [EMAIL PROTECTED]
                                        http://richard.levitte.org/

"When I became a man I put away childish things, including
 the fear of childishness and the desire to be very grown up."
                                                -- C.S. Lewis
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@openssl.org
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to