Hi Support, I have implemented a demo project at enables encrypting a plaintext based on 2 input param values.
Version: 1.01f Cipher Mode: EVP_aes_256_cbc Salt[]={1,2,3,4,5,6,7,8} Digest = md5 (functions encapsulated in DLL) *Encrypt(Param1, Param2, PlainText)* >> Param1 +HardCoded+Param2 = *Password* >> Password Send to *EVP_BytesToKey* (Salt+Iteration 10) = Generate Key + IV >> Encrypting PlainText >> Base64Encode to Save in DB *Decrypt(Param1,Param2,Cipher(ASCII))* >> Param1 +HardCoded+Param2= *Password* >>Password Send to *EVP_BytesToKey* (Salt+Iteration 10) = Generate Key + IV >> Base64Decode >> Decrypt Cipher >> Output PlainText i.e: Encrypt('2', '?this123!', '123456789012') >> QKFf3xNKTgCGghkMziTQQ== Decrypt('2', '?this123!', 'QKFf3xNKTgCGghkMziTQQ==') >> 123456789012 Sometimes *Encrypt *resulting an invalid encrypted value or empty result. it happens randomly on a certain values. As example, e.g: assumption: instead of 2, we'll pass 3 (guessing 3 is a error prone param value as described) Encrypt('3', '?this123!', '123456789012') >> QKiTQ== (this is invalid) Decrypt('3', '?this123!', 'QKiTQ==') >> '' I have checked the IV length and its 16. But I changes iteration count, cipher mode to *EVP_aes_256_ecb (*where IV not considered*)* will gives a correct output. That even can't guarantee as solution might result an invalid output on an another value. Could anybody provide me some solution? Many Thanks, Buddhika PS: I attached a code sample
const static char* b64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const static unsigned char unb64[]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, //50 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, //60 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, //70 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //80 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //90 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, //100 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, //110 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, //120 49, 50, 51, 0, 0, 0, 0, 0, 0, 0, //130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //250 0, 0, 0, 0, 0, 0, }; /*----------------------------------------------------------------------------*/ /* do convert binary to plaintext and vice versa using base 64 encode/decode */ /*----------------------------------------------------------------------------*/ char* convert_to_base64(const void* binaryData, int len, int *flen ) { const unsigned char* bin = (const unsigned char*) binaryData ; char* res ; int rc = 0; // result counter int byteNo; // I need this after the loop int modulusLen = len % 3 ; int pad = ((modulusLen&1)<<1) + ((modulusLen&2)>>1) ; // 2 gives 1 and 1 gives 2, but 0 gives 0. *flen = 4*(len + pad)/3 ; res = (char*) malloc( *flen + 1 ) ; // and one for the null if( !res ){ return 0; } // encoding... for( byteNo = 0 ; byteNo <= len-3 ; byteNo+=3 ){ unsigned char BYTE0=bin[byteNo]; unsigned char BYTE1=bin[byteNo+1]; unsigned char BYTE2=bin[byteNo+2]; res[rc++] = b64[BYTE0 >> 2]; res[rc++] = b64[((0x3&BYTE0)<<4) + (BYTE1 >> 4)]; res[rc++] = b64[((0x0f&BYTE1)<<2) + (BYTE2>>6) ]; res[rc++] = b64[0x3f&BYTE2]; } // pad level 2 if( pad==2 ){ res[rc++] = b64[bin[byteNo] >> 2]; res[rc++] = b64[(0x3&bin[byteNo])<<4]; res[rc++] = '='; res[rc++] = '='; } // pad level 1 else if( pad==1 ){ res[rc++] = b64[bin[byteNo] >> 2] ; res[rc++] = b64[((0x3&bin[byteNo])<<4) + (bin[byteNo+1] >> 4)]; res[rc++] = b64[(0x0f&bin[byteNo+1])<<2]; res[rc++] = '='; } res[rc]=0; // null terminate return res; } /*----------------------------------------------------------------------------*/ unsigned char* convert_from_base64(const char *encodedStr, int len, int *flen ) { const unsigned char *safePtr = (const unsigned char*)encodedStr; unsigned char *bin; int cb=0,pad=0; int charNo; // catch empty/invalid encoded string, return NULL as result. if( len < 2 ) { *flen=0; return 0 ; } if( safePtr[len-1]=='=') ++pad; if( safePtr[len-2]=='=') ++pad; *flen = 3*len/4 - pad; bin = (unsigned char*)malloc( *flen ) ; // not enough memory to continue. exisiting... if(!bin){ return 0; } // decoding... for( charNo=0; charNo <= len - 4 - pad ; charNo+=4 ){ int A=unb64[safePtr[charNo ]]; int B=unb64[safePtr[charNo+1]]; int C=unb64[safePtr[charNo+2]]; int D=unb64[safePtr[charNo+3]]; bin[cb++] = (A<<2) | (B>>4); bin[cb++] = (B<<4) | (C>>2); bin[cb++] = (C<<6) | (D); } // calling pad level 1 if( pad==1 ){ int A=unb64[safePtr[charNo ]]; int B=unb64[safePtr[charNo+1]]; int C=unb64[safePtr[charNo+2]]; bin[cb++] = (A<<2) | (B>>4) ; bin[cb++] = (B<<4) | (C>>2) ; } // calling pad level 2 else if( pad==2 ) { int A=unb64[safePtr[charNo ]]; int B=unb64[safePtr[charNo+1]]; bin[cb++] = (A<<2) | (B>>4) ; } return bin ; } /*----------------------------------------------------------------------------*/ /* set character pattern + encryption/decryption using OpenSSL EVP AES 256 */ /*----------------------------------------------------------------------------*/ void set_pattern(unsigned char* rz,unsigned char* seq) { // uses 3rd variable to generate final char pattern strcat(rz,"Concat"); strcat(rz,seq); } /*----------------------------------------------------------------------------*/ short int do_encrypt(const char *data, unsigned char *out, int *outlen, unsigned char *key, unsigned char *iv) { int buflen, tmplen; // init cipher context EVP_CIPHER_CTX ctx; EVP_CIPHER_CTX_init(&ctx); EVP_EncryptInit_ex(&ctx, MY_CIPHER_MODE, NULL, key, iv); // encrypt data if(!EVP_EncryptUpdate(&ctx, out, &buflen, (unsigned char*)data, strlen(data))) { return 0; } if(!EVP_EncryptFinal_ex(&ctx, out + buflen, &tmplen)) { return 0; } buflen += tmplen; *outlen = buflen; // clean EVP_CIPHER_CTX_cleanup(&ctx); return 1; } /*----------------------------------------------------------------------------*/ short int do_decrypt(const unsigned char *cipher, unsigned char *out, unsigned char *key, unsigned char *iv) { int buflen, tmplen, outlen; // init cipher context EVP_CIPHER_CTX ctx; EVP_CIPHER_CTX_init(&ctx); EVP_DecryptInit_ex(&ctx, MY_CIPHER_MODE, NULL, key, iv); // decrypt data if(!EVP_DecryptUpdate(&ctx, out, &buflen, cipher, strlen(cipher))) { return 0; } if(!EVP_DecryptFinal_ex(&ctx, out + buflen, &tmplen)) { return 0; } outlen = buflen + tmplen; out[outlen] =(char) 0; // clean EVP_CIPHER_CTX_cleanup(&ctx); return 1; } /*----------------------------------------------------------------------------*/ /* PNA_DLL_EXPORT external entry points: EncodeData/DecodeData/ReEncodeData */ /*----------------------------------------------------------------------------*/ DLL_EXPORT unsigned char* Encrypt(unsigned char *seq_1, unsigned char *seq_2 , unsigned char *data) { if (data==NULL){ return NULL; }else { const EVP_MD *dgst; unsigned char salt[]= {1,2,3,4,5,6,7,8}; unsigned int outlen,x; unsigned char *sz_result=(unsigned char*)MALLOC(LOC_STRING_SIZE); // have used this with firebird ib_utils lib unsigned char key[EVP_MAX_KEY_LENGTH],iv[EVP_MAX_IV_LENGTH]; unsigned char cipher[LOC_STRING_SIZE],sz_code[LOC_STRING_SIZE] ; memset(key , 0, sizeof(key )); memset(iv , 0, sizeof(iv )); memset(cipher , 0, sizeof(cipher )); memset(sz_code, 0, sizeof(sz_code)); // load all algos + set digest to md5 OpenSSL_add_all_algorithms(); dgst=EVP_get_digestbyname("md5"); // set pattern strcpy(sz_code,seq_1); set_pattern(sz_code,seq_2); // generate key and iv if (!EVP_BytesToKey(MY_CIPHER_MODE,dgst,salt,sz_code,strlen(sz_code),10,key,iv)){ sprintf(sz_result,"%s","KEY GENERATE ERROR!!!"); }else { // if key success, then to encrypt the data if (!do_encrypt((char*)data, cipher, &outlen, key, iv)){ sprintf(sz_result,"%s","ENCRYPTION ERROR!!!"); }else { sprintf(sz_result,"%s",(convert_to_base64(cipher,strlen(cipher),&x))); //sprintf(sz_result,"%d",strlen(iv)); } } return sz_result; } } /*----------------------------------------------------------------------------*/ DLL_EXPORT unsigned char* Decrypt(unsigned char *seq_1, unsigned char *seq_2, unsigned char *cipher) { if (cipher==NULL){ return NULL; }else { const EVP_MD *dgst; unsigned int x; unsigned char salt[]= {1,2,3,4,5,6,7,8}; unsigned char *sz_result=(unsigned char*)MALLOC(LOC_STRING_SIZE); unsigned char key[EVP_MAX_KEY_LENGTH],iv[EVP_MAX_IV_LENGTH]; unsigned char plainText[LOC_STRING_SIZE],sz_code[LOC_STRING_SIZE] ; memset(key , 0, sizeof(key )); memset(iv , 0, sizeof(iv )); memset(plainText , 0, sizeof(plainText)); memset(sz_code , 0, sizeof(sz_code )); // loading all algorithems and set digest to md5 OpenSSL_add_all_algorithms(); dgst =EVP_get_digestbyname("md5"); // set pattern strcpy(sz_code,seq_1); set_pattern(sz_code,seq_2); //generate key + iv >> KEY should identical to original encrypted key if (!EVP_BytesToKey(MY_CIPHER_MODE,dgst,salt,sz_code,strlen(sz_code),10,key,iv)){ sprintf(sz_result,"%s","KEY GENERATE ERROR!!!"); }else { // if key success, then to decrypt do_decrypt((convert_from_base64((char*)cipher,strlen(cipher),&x)), plainText, key, iv); sprintf(sz_result,"%s",plainText); } return sz_result; } }