Home > Net >  OpenSSL EVP AES Encryption and Base64 Encoding producing unusable results
OpenSSL EVP AES Encryption and Base64 Encoding producing unusable results

Time:09-22

So I'm trying to reproduce an encryption and encoding operation in C, that I've managed to make work in C#, JScript, Python and Java. Now, it's mostly just for obfuscating data - not actual encryption - so it's basically for aesthetic purposes only.

First thing's first, the data string that's being encrypted looks like this:

"[3671,3401,736,1081,0,32558], [3692,3401,748,1105,0,32558], [3704,3401,774,1162,0,32558], [3722,3401,774,1162,0,32558], [3733,3401,769,1172,0,32558]"

Biggest first issue for C is that this can vary in length. Each [x,y,z,a,b,c] represents some data point, and the actual string that will be encrypted can have anywhere from one data point, to 100. So I'm sure my memory management might be broken somewhere as well. Second issue is, I don't seem to be getting the correct expected result after encoding. After encrypting, the byte result of the C cipher is the same as the python cipher. But when I encode to base64 in C, it does not get the expected result at all.

#include <X11/Xlib.h>
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>
#include <errno.h>
#include <linux/input.h>
#include <fcntl.h>
#include <string.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
#include <openssl/params.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>

void PBKDF2_HMAC_SHA_1(const char* pass, int passlen, const unsigned char* salt, int saltlen, int32_t iterations, uint32_t outputBytes, char* hexResult, uint8_t* binResult)
{
    unsigned int i;
    unsigned char digest[outputBytes];
    PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iterations, EVP_sha1(), outputBytes, digest);
    for (i = 0; i < sizeof(digest); i  )
    {
        sprintf(hexResult   (i * 2), "x", 255 & digest[i]);
        binResult[i] = digest[i];
    }
}

int main(void){

char intext[] = "[3671,3401,736,1081,0,32558], [3692,3401,748,1105,0,32558], [3704,3401,774,1162,0,32558], [3722,3401,774,1162,0,32558], [3733,3401,769,1172,0,32558]";
int outlen, final_length;
EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();
size_t i;
char sid[] = "u9SXNMeTkvyBr3n81SJ7Lj216w04gJ99";
char pk[] = "jeIHjod1cZeM1U04cy8z7488AeY1Sl25";
uint32_t outputBytes = 48;
uint32_t iterations = 128;
unsigned char byteresult[2*outputBytes 1]; 
char hexresult[2*outputBytes 1];
memset(byteresult,0,sizeof(byteresult));
uint8_t binResult[outputBytes 1]; 
memset(binResult,0,sizeof(binResult));
char *finResult = NULL;
char key[65];
memset(key,0,sizeof(key));
char * keystart = hexresult  32;
char iv[33];
memset(iv,0,sizeof(iv));

PBKDF2_HMAC_SHA_1(sid,strlen(sid),pk,strlen(pk),iterations,outputBytes,hexresult,binResult);

memcpy(key, keystart,64);
memcpy(iv, hexresult,32);

EVP_CipherInit_ex(ctx, EVP_aes_256_cbc(), NULL,(unsigned char *)key, (unsigned char *)iv, 1);

unsigned char *outbuf;
int outbuflen = sizeof(intext)   EVP_MAX_BLOCK_LENGTH - (sizeof(intext) % 16);

outbuf = (unsigned char *)malloc(outbuflen);

EVP_CipherUpdate(ctx, outbuf, &outbuflen,(unsigned char *)intext, strlen(intext));
EVP_CipherFinal_ex(ctx, outbuf   outbuflen, &final_length);

outlen  = final_length;
EVP_CIPHER_CTX_free(ctx);

char bytesout[strlen(outbuf)   outbuflen];
int buflen = 0;

for (i=0;i< outbuflen   final_length;i  )
{
    buflen  = 1;
    sprintf(bytesout   (i * 2),"x", outbuf[i]);
}
printf("bytesout: %s\n", bytesout);


char outtext[sizeof(bytesout)];
memset(outtext,0, sizeof(outtext)); 

int outtext_len = sizeof(outtext);

EVP_ENCODE_CTX *ectx = EVP_ENCODE_CTX_new();
EVP_EncodeInit(ectx);
EVP_EncodeBlock(outtext, bytesout, sizeof(bytesout));
EVP_EncodeFinal(ectx, (unsigned char*)outtext, &outtext_len);
EVP_ENCODE_CTX_free(ectx);

printf("b64Encoded String %s \n", outtext);}

Makefile:

gcc simplecipher.c -o simplecipher -lX11 -lncurses -lssl -lcrypto 

Result:

bytesout: eafafcde5c00eb6e649d61a09f9b52d13dd8c783d73afcbc03dfb5cea0cd3ab627528ec1b2997105871d570c0b972349943800aacd063093d97f7f39554775aa4256bd26599dde66bb76b925d9f021f6b657d1a91eb08e1900b6ad91f7f65b97e1a7e17b8d959a65d6893af458e26761536b3ffdf470f89f1aac24ca02782fb8a691c25b368549387890dc73143bb213e0ce616264e5b30add3b480c24f5edc6

b64Encoded String ZWFmYWZjZGU1YzAwZWI2ZTY0OWQ2MWEwOWY5YjUyZDEzZGQ4Yzc4M2Q3M2FmY2JjMDNkZmI1Y2VhMGNkM2FiNjI3NTI4ZWMxYjI5OTcxMDU4NzFkNTcwYzBiOTcyMzQ5OTQzODAwYWFjZDA2MzA5M2Q5N2Y3ZjM5NTU0Nzc1YWE0MjU2YmQyNjU5OWRkZTY2YmI3NmI=

When I do a similar script in python:

import base64
from Cryptodome.Cipher import AES
from Cryptodome.Random import get_random_bytes
from Cryptodome.Protocol.KDF import PBKDF2 
from Crypto.Util.Padding import pad
import binascii


symmetric_key = "u9SXNMeTkvyBr3n81SJ7Lj216w04gJ99"
salt = "jeIHjod1cZeM1U04cy8z7488AeY1Sl25"

pbbytes = PBKDF2(symmetric_key.encode("utf-8"), salt.encode("utf-8"), 48, 128)
iv = pbbytes[0:16]
key = pbbytes[16:48]

half_iv=iv[0:8]
half_key=key[0:16]

cipher = AES.new(key, AES.MODE_CBC, iv)
cipher = AES.new(binascii.hexlify(bytes(half_key)), AES.MODE_CBC, binascii.hexlify(bytes(half_iv)))

print("test encoding:")
intext = b"[3671,3401,736,1081,0,32558], [3692,3401,748,1105,0,32558], [3704,3401,774,1162,0,32558], [3722,3401,774,1162,0,32558], [3733,3401,769,1172,0,32558]"

print("intext pre padding: ", intext)


paddedtext = pad(intext,16)

print("intext post padding: ", paddedtext)


en_bytes = cipher.encrypt(paddedtext)
print("encrypted bytes: ", binascii.hexlify(bytearray(en_bytes)))


en_data = base64.b64encode(en_bytes)

en_bytes_string = ''.join(map(chr, en_bytes))
print("encoded bytes: ", en_data)

Result:

encrypted bytes:  b'eafafcde5c00eb6e649d61a09f9b52d13dd8c783d73afcbc03dfb5cea0cd3ab627528ec1b2997105871d570c0b972349943800aacd063093d97f7f39554775aa4256bd26599dde66bb76b925d9f021f6b657d1a91eb08e1900b6ad91f7f65b97e1a7e17b8d959a65d6893af458e26761536b3ffdf470f89f1aac24ca02782fb8a691c25b368549387890dc73143bb213e0ce616264e5b30add3b480c24f5edc6'

encoded bytes:  b'6vr83lwA625knWGgn5tS0T3Yx4PXOvy8A9 1zqDNOrYnUo7BsplxBYcdVwwLlyNJlDgAqs0GMJPZf385VUd1qkJWvSZZnd5mu3a5JdnwIfa2V9GpHrCOGQC2rZH39luX4afhe42VmmXWiTr0WOJnYVNrP/30cPifGqwkygJ4L7imkcJbNoVJOHiQ3HMUO7IT4M5hYmTlswrdO0gMJPXtxg=='

So as you can see, the encoded portion comes out completely differently in the C application. In Jscript, C#, and Java it comes out exactly as in the python script. The encrypted portion, however, is the same between the two. Just encoding seems to break it. Now this could be 100% because I've absolutely butchered something when passing the bytes/char arrays around. I just can't seem to find out where in the chain I've broken down here. Any suggestions?

CodePudding user response:

The C code base64s the wrong buffer. namely bytesout, which is already an ASCII text:

for (i=0;i< outbuflen   final_length;i  )
{
    buflen  = 1;
    sprintf(bytesout   (i * 2),"x", outbuf[i]);
}

You need to encode outbuf instead.

PS: the code cries for a serious cleanup.

CodePudding user response:

Alright,

Just wanted to say thanks to everyone who commented, and answered but I did figure it out this morning, basically using

EVP_EncodeBlock(outtext, outbuf, buflen);

Is what solved it. Before I'd pass in either sizeof(outtext) or sizeof(outbuf) and that would only encode what looked like a part of the first data point (likely up to the first ',' or something). But this fixes it. I can now encrypt a string of datapoints regardless of their starting size, and decrypt it in python. I had buflen in there just to debug the amount of bytes that were being written to the bytesout char array, but it seemed to do the trick.

Cheers, everyone!

  • Related