c - Getting wrong plain text after decrypting (AES) and decoding (Base64) -
i have written small test program takes string of plain text, encrypts using aes, , encodes base 64. portion seems fine, when try decode , decrypt data, wrong information.
my code below. i'm quite new c, presume making rookie mistake wrongly using pointer or reference somewhere. have tried find problem myself in evp_decryptfinal_ex function, can't seem find bug(s). note! please ignore use of iv , key, test code.
code:
#define _gnu_source #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <openssl/evp.h> #include <openssl/bio.h> #include <openssl/pem.h> // base 64 encoding char* base64encode(const unsigned char *message, const size_t length) { bio *bio; bio *b64; file* stream; int encodedsize = 4*ceil((double)length/3); char *buffer = (char*)malloc(encodedsize+1); stream = fmemopen(buffer, encodedsize+1, "w"); b64 = bio_new(bio_f_base64()); bio = bio_new_fp(stream, bio_noclose); bio = bio_push(b64, bio); bio_set_flags(bio, bio_flags_base64_no_nl); bio_write(bio, message, length); (void)bio_flush(bio); bio_free_all(bio); fclose(stream); return buffer; } // base 64 decoding int calcdecodelength(const char *b64input) { int len = strlen(b64input); int padding = 0; // check trailing '=''s padding if (b64input[len-1] == '=' && b64input[len-2] == '=') { padding = 2; } else if (b64input[len-1] == '=') { padding = 1; } return (int)len*0.75 - padding; } int base64decode(const char *b64message, unsigned char **buffer) { bio *bio; bio *b64; int decodelen = calcdecodelength(b64message); *buffer = (unsigned char*)malloc(decodelen+1); file* stream = fmemopen((char*)b64message, strlen(b64message), "r"); b64 = bio_new(bio_f_base64()); bio = bio_new_fp(stream, bio_noclose); bio = bio_push(b64, bio); bio_set_flags(bio, bio_flags_base64_no_nl); size_t length = bio_read(bio, *buffer, strlen(b64message)); (*buffer)[length] = '\0'; bio_free_all(bio); fclose(stream); return decodelen; } // aes encryption int encryptaes(const char *plaintext, char *ciphertext, const char *key) { unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; int plaintextlength = 0; int ciphertextlength = 0; int blocklength = 0; static const int max_padding_length = 16; evp_cipher_ctx encryptctx; evp_cipher_ctx_init(&encryptctx); plaintextlength = strlen(plaintext); ciphertext = (unsigned char *) malloc(plaintextlength + max_padding_length); // initialise encryption aes256 (cbc mode) using key , iv evp_encryptinit_ex(&encryptctx, evp_aes_256_cbc(), null, key, iv); // encrypt plaintext ciphertext, update ciphertextlength length of generated ciphertext if (!evp_encryptupdate(&encryptctx, ciphertext, &blocklength, (unsigned char *) plaintext, plaintextlength) ) { printf("error in evp_encryptupdate \n"); return 1; } ciphertextlength += blocklength; // encrypt "final" data remaining in partial block if (!evp_encryptfinal_ex(&encryptctx, ciphertext + ciphertextlength, &blocklength)) { printf("error in evp_encryptfinal_ex \n"); return 1; } ciphertextlength += blocklength; evp_cipher_ctx_cleanup(&encryptctx); return ciphertextlength; } // aes decryption int decryptaes(const char *ciphertext, char *decipheredplaintext, int ciphertextlength, const char *key) { unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; int plaintextlength = 0; int blocklength = 0; decipheredplaintext = (unsigned char *) malloc(ciphertextlength + 1); evp_cipher_ctx decryptctx; evp_cipher_ctx_init(&decryptctx); // initialise decryption aes256 (cbc mode) using key , iv evp_decryptinit_ex(&decryptctx, evp_aes_256_cbc(), null, key, iv); // decrypt ciphertext plaintext, update plaintextlength if (!evp_decryptupdate(&decryptctx, decipheredplaintext, &blocklength, ciphertext, ciphertextlength)) { printf("error in evp_decryptupdate\n"); return 1; } plaintextlength += blocklength; // decrypt "final" data remaining in partial block if (!evp_decryptfinal_ex(&decryptctx, decipheredplaintext + plaintextlength, &blocklength)) { printf("error in evp_decryptfinal_ex\n"); return 1; } plaintextlength += blocklength; evp_cipher_ctx_cleanup(&decryptctx); return plaintextlength; } int main(int argc, char **argv) { unsigned char key[] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }; const char *plaintext = "cipher cipher cipher cipher cipher text! 187? 1$5 78@2 14 .tӒ��틪�ձ1z.$�?�u���<y"; printf("original plain text\t[%s]\n", plaintext); ////////////// // encryption ////////////// // encrypt plain text using aes unsigned char ciphertext[180]; int ciphertextlength = encryptaes(plaintext, ciphertext, key); printf("cipher length\t\t[%d]\n", ciphertextlength); // base64 encode buffer char* encodedciphertext = base64encode(ciphertext, ciphertextlength); printf("base64 is\t\t[%s]\n", encodedciphertext); ////////////// // decryption ////////////// // decode base64 string unsigned char* decodedciphertext; int decodedciphertextlength = base64decode(encodedciphertext, &decodedciphertext); printf("decoded cipher length\t[%d]\n", decodedciphertextlength); // decrypt cipher text unsigned char decryptedplaintext[180]; int decryptedplaintextlength = decryptaes(decodedciphertext, decryptedplaintext, decodedciphertextlength, key); printf("decrypted plain text\t[%s]\n", decryptedplaintext); // compare before , after if (strcmp(plaintext, (char *) decryptedplaintext) == 0) { printf("decrypted data matches input data.\n"); } else { printf("decrypted data not match input data.\n"); } return 0; } command:
gcc aestest2.c -lcrypto -std=c99 -lm output:
original plain text [cipher cipher cipher cipher cipher text! 187? 1$5 78@2 14 .tӒ��틪�ձ1z.$�?�u���<y] cipher length [112] base64 [aqaaaaaaaacieylbpgaaaoh04wx/fwaadgaaaaaaaaajaaaaaaaaap504wx/fwaaaaaaaaaaaadgfilbpgaaabb14wx/fwaalwwp2z4aaaaodemf/38aaaaaaaabaaaa2lgg2z4aaabxb0aaaaaaaa==] decoded cipher length [112] error in evp_decryptfinal_ex decrypted plain text [�t��] decrypted data not match input data. any seasoned c developer appreciated. many thanks.
you declare buffers in main(), , pass references them down en/decrypt functions.
in en/decrypt functions overwrite buffer's address received main() result returned malloc(). data calculated written freshly allocated memory. reference latter lost when returning 2 en/decrypt functions, leaving memory leak.
due buffers in main() hadn't been touched @ all.
you easyly prove setting them 0 before calling en/decrypt functions , printing them out after having returned en/decrypt functions.
Comments
Post a Comment