PDA

View Full Version : QT and OpenSSL EVP.h



TCB13
31st August 2011, 01:16
Hi,

I've been looking around for C++ or better QT examples of AES encryption using OpenSSL EVP but I've been messing around with some code with no luck.

I think this is a lot to ask, but can someone provide me an example of AES encryption using the EVP in QT?

I've tried to implement the code here (http://www.slideshare.net/guanzhi/crypto-with-openssl) without any luck :(

Currently my code is:


void qkCrypto::AES_CBC(const unsigned char *string, const unsigned char *key, const unsigned char *iv)
{

int outlen;
unsigned char *out;

EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
const EVP_CIPHER *cipher = EVP_aes_128_cbc();

EVP_EncryptInit(&ctx,cipher,key,iv);
EVP_EncryptUpdate(&ctx,out,&outlen,string,strlen(string));

EVP_EncryptFinal(&ctx,out,&outlen);

EVP_CIPHER_CTX_cleanup(&ctx);

qDebug() << out;


}

But when I try to compile I get this:


[...]/qkcrypto.cpp: In member function 'void qkCrypto::AES_CBC(const unsigned char*, const unsigned char*, const unsigned char*)':
[...]/qkcrypto.cpp:39: error: invalid conversion from 'const unsigned char*' to 'const char*'
[...]/qkcrypto.cpp:39: error: initializing argument 1 of 'size_t strlen(const char*)'

How should I solve this... and BTW, how can I get rid of things like "const unsigned char" and make this a little bit more QT friendly using QByteArray instead?

Thank you all ;)

wysota
31st August 2011, 08:18
"man EVP_EncryptInit" will give you an example of using EVP. If you're on Windows then you can probably find the manual on OpenSSL webpage too.

TCB13
31st August 2011, 13:56
"man EVP_EncryptInit" will give you an example of using EVP. If you're on Windows then you can probably find the manual on OpenSSL webpage too.

Hi, the website I was reading seems to take a bit from the man.
Anyway, my errors are not related to the usage itself but conversions and casts, can you help me solve the compiler error above?

Thanks.

wysota
31st August 2011, 14:03
Just force the cast by explicit casting to the proper type.

TCB13
31st August 2011, 15:46
Just force the cast by explicit casting to the proper type.

Hi, it seems to work with:
EVP_EncryptUpdate(&ctx,out,&outlen,string,strlen((const char*)string));

Anyway, how can I convert this guys here
(const unsigned char *string, const unsigned char *key, const unsigned char *iv) to QByteArrays?

Added after 13 minutes:

I could use something like:


QByteArray somedata;
somedata.constData();

In order to convert them but I'll get an error anyway because the they should be unsigned. --> SOLVED!

[...] (Old code not really needed, removed, check the new one bellow)

Well, now I can compile it after changing some things:



void qkCrypto::AES_CBC(QByteArray string, QByteArray key, QByteArray iv)
{
int outlen;
QByteArray out;

EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
const EVP_CIPHER *cipher = EVP_aes_128_cbc();
EVP_EncryptInit(&ctx,cipher, (const unsigned char*)key.constData() , (const unsigned char*)iv.constData() );
EVP_EncryptUpdate(&ctx, (unsigned char*)out.data() ,&outlen, (const unsigned char*)string.constData() ,strlen( string.constData() ));
EVP_EncryptFinal(&ctx, (unsigned char*)out.data() ,&outlen);
EVP_CIPHER_CTX_cleanup(&ctx);

qDebug() << "OUT: "<< out;
}


But the QByteArray out returns nothing. :S

If I replace the QByteArray by a normal unsigned char qDebug outputs "0x7fff5fbff950" and then the program crashes.

Thanks

wysota
31st August 2011, 17:50
If you use QByteArray::data() then you need to ensure there is enough space reserved for the byte array. it seems you are trying to pass an empty byte array to a function that intends to write to the array. This won't work.

TCB13
31st August 2011, 18:45
If you use QByteArray::data() then you need to ensure there is enough space reserved for the byte array. it seems you are trying to pass an empty byte array to a function that intends to write to the array. This won't work.

How should I proceed here:
EVP_EncryptFinal(&ctx, (unsigned char*)out.data() ,&outlen); then?

The second parameter is an output.

wysota
31st August 2011, 22:24
Probably something like:

out.resize(1024);
outlen = 1024;
EVP_EncryptFinal(&ctx, (unsigned char*)out.data(), &outlen);

TCB13
1st September 2011, 00:20
Probably something like:

out.resize(1024);
outlen = 1024;
EVP_EncryptFinal(&ctx, (unsigned char*)out.data(), &outlen);

Hi,
Giving a value to "outlen" is not needed but now with the resize I get an output like this:
"¢ ViÎ ð–«u (`T

Thanks.

TCB13
2nd September 2011, 01:21
I think I wasn't really clear in my last post, the output value is not what it should be, If I try to decode with the key and IV it's wrong. I'll be diving in OpenSSL documentation to make this work and post some code later.

Thank you all specially wysota.
(Who ends up saving my code multiple times :P)

TCB13
2nd September 2011, 23:34
Hi everyone,
I've new code now almost perfect.


QByteArray qkCrypto::encrypt_AES_CBC(QByteArray string, QByteArray key, QByteArray ivv)
{

char mykey[EVP_MAX_KEY_LENGTH] = { 0 };
strcpy(mykey,key.constData());

char iv[EVP_MAX_IV_LENGTH] = { 0 };
strcpy(iv,ivv.constData());

char ciphertext[1024];

const EVP_CIPHER *cipher = EVP_aes_256_cbc();
int in_len;
int out_len=0;

in_len = (string.length());

qDebug() << "Before encrypt: " << string << "\r\n";

EVP_EncryptInit(&ctx, cipher, (const unsigned char*)mykey, (const unsigned char*)iv);
EVP_EncryptUpdate(&ctx, ( unsigned char*)ciphertext, &out_len, (const unsigned char*)string.data(), in_len);
EVP_EncryptFinal(&ctx, ( unsigned char*)&ciphertext[out_len], &out_len);
EVP_CIPHER_CTX_cleanup(&ctx);
qDebug() << "Encrypted: " << ciphertext << "\r\n";

return ciphertext;

}

By some reason the output is only right some times... other times the output is wrong and I can't decrypt it later with OpenSSL.
What's wrong about this? Some help will be great. :S

Thanks.

wysota
3rd September 2011, 08:17
I can give you the right code if you want, it seems I made a complete OpenSSL EVP implementation some time ago :)

TCB13
3rd September 2011, 13:19
I can give you the right code if you want, it seems I made a complete OpenSSL EVP implementation some time ago :)

Hi,
My implementation seems to be right but somehow sometimes some extras chars are added to the end of the encrypted string.
I would really like to understand what's happening there... but If you have a working implementation I would love to see it maybe compare mine and yours. :)

Thanks.

wysota
3rd September 2011, 14:42
My implementation looks like this (at least part of it does):

QByteArray qEncrypt(const QString &algorithm, const QByteArray &inba, const QByteArray &key, const QByteArray &iv) {
OpenSSL_add_all_ciphers();
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
const EVP_CIPHER *cipher = EVP_get_cipherbyname(qPrintable(algorithm));
if (!cipher) {
EVP_cleanup();
return QByteArray();
}
EVP_EncryptInit_ex(&ctx, cipher, NULL, (const unsigned char*)key.constData(), (const unsigned char*)iv.constData());
int outlen, inlen, tmplen;
inlen = inba.count();
QByteArray outbuf(inlen+EVP_MAX_BLOCK_LENGTH, 0);
// outbuf = inlen+cipher_block-1

if (!EVP_EncryptUpdate(&ctx, (unsigned char*)outbuf.data(), &outlen, (const unsigned char*)inba.constData(), inlen)) {
return QByteArray();
}
if (!EVP_EncryptFinal_ex(&ctx, ((unsigned char*)outbuf.data())+outlen, &tmplen)) {
return QByteArray();
}
outlen += tmplen;
EVP_CIPHER_CTX_cleanup(&ctx);
EVP_cleanup();
outbuf.resize(outlen);
return outbuf;
}

I also have a class that does the encryption that can be called like so:

QwwCipher ciph("aes-128-cbc");
ciph.setKey("0123456789ABCDEF");
ciph.setIv("12345678");
QByteArray inba("text to be encrypted");
QByteArray outba;
ciph.setInput(&inba);
ciph.setOutput(&outba);
ciph.encryptAll();
qDebug() << outba.toBase64().constData();

or so (asynchronous encryption):

QCoreApplication app(argc, argv);
...
QwwCipher ciph("des-ofb");
ciph.setKey("01234567");
ciph.setIv("12345678");
QByteArray inba("text to be encrypted");
ciph.setInput(&inba);
QFile file("cipher.bin");
ciph.setOutput(&file);
ciph.encrypt();
QObject::connect(&ciph, SIGNAL(done()), &app, SLOT(quit()));
return app.exec();

Your implementation is incorrectly assuming that the ciphertext is readable. You can't just dump it to stderr, first \0 byte will terminate the printout and a lack of \0 at the end will append garbage to printout. Also you are returning a pointer to a local stack based variable.

TCB13
3rd September 2011, 22:05
Your code works fine ;)

I'm still having some problems related to base64 in my program because I'm posting the encrypted data over http and sometimes the decrypted string on the PHP side is wrong. -> Any tips?
I'm still working on it ;)

Thanks for all.

wysota
4th September 2011, 15:17
Base64 is not encryption, it is merely encoding. Try retracing your steps on both sides and see where the difference pops up.

TCB13
4th September 2011, 20:04
Base64 is not encryption, it is merely encoding. Try retracing your steps on both sides and see where the difference pops up.

Yes.. I was looking into AES-CBC because of that. I'm doing now:

"Some text" --> toAES_CBC() --> toBase64() ----- http post ------ > base64_decode() --> aes->decrypt()

But sometimes after the base64 is decoded by the PHP the message different. But I'll look seriously into it very soon. ;)

Yesterday I changed the encoding to hex and I saw that some "0" were missing if I encode the string again to hex after decoding in the PHP side. So maybe PHP is not dealing so well with the AES encrypted ( possible not readable ) chars.
But I'll check it soon I'm working on my TCP client code now... ;)

Thanks.