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;
}
}