Skip to content

Instantly share code, notes, and snippets.

@vaibhavpandeyvpz
Last active May 31, 2023 05:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save vaibhavpandeyvpz/3b3d2254242a9c3a90d9428de274c524 to your computer and use it in GitHub Desktop.
Save vaibhavpandeyvpz/3b3d2254242a9c3a90d9428de274c524 to your computer and use it in GitHub Desktop.
AES-256-CBC encryption in Qt with OpenSLL
#include <QCryptographicHash>
#include <QRandomGenerator>
#include <QStringList>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include "SecurityUtil.h"
static char *bytes2chara(const QByteArray &bytes) {
auto size = bytes.size() + 1;
auto data = new char[size];
strcpy_s(data, size, bytes.data());
return data;
}
static int decrypt_aes_256(unsigned char *input, unsigned char *key, unsigned char *iv, unsigned char *output) {
int session, total;
auto ctx = EVP_CIPHER_CTX_new();
EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key, iv);
EVP_DecryptUpdate(ctx, output, &session, input, strlen((char *) input));
total = session;
EVP_DecryptFinal_ex(ctx, output + session, &session);
total += session;
EVP_CIPHER_CTX_free(ctx);
return total;
}
static int encrypt_aes_256(unsigned char *input, unsigned char *key, unsigned char *iv, unsigned char *output) {
int session, total;
auto ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key, iv);
EVP_EncryptUpdate(ctx, output, &session, input, strlen((char *) input));
total = session;
EVP_EncryptFinal_ex(ctx, output + session, &session);
total += session;
EVP_CIPHER_CTX_free(ctx);
return total;
}
static QByteArray decrypt(const QString &password, const QString &input) {
auto md5 = QCryptographicHash::hash(password.toLocal8Bit(), QCryptographicHash::Md5).toHex();
auto key = bytes2chara(md5);
auto parts = input.split('.');
auto iv = bytes2chara(QByteArray::fromBase64(parts[0].toLocal8Bit(), QByteArray::OmitTrailingEquals));
auto encrypted = bytes2chara(QByteArray::fromBase64(parts[1].toLocal8Bit(), QByteArray::OmitTrailingEquals));
auto output = new unsigned char[parts[1].size() * 2];
auto n = decrypt_aes_256((unsigned char *) encrypted, (unsigned char *) key, (unsigned char *) iv, output);
return QByteArray::fromRawData((char *) output, n);
}
static QString encrypt(const QString &password, const QByteArray &input) {
auto md5 = QCryptographicHash::hash(password.toLocal8Bit(), QCryptographicHash::Md5).toHex();
auto key = bytes2chara(md5);
auto iv = bytes2chara(random(16 /* AES IV Length */).toLocal8Bit());
auto plain = bytes2chara(input);
auto output = new unsigned char[input.size() * 2];
auto n = encrypt_aes_256((unsigned char *) plain, (unsigned char *) key, (unsigned char *) iv, output);
return QString()
.append(QByteArray::fromRawData(iv, strlen(iv)).toBase64(QByteArray::OmitTrailingEquals))
.append('.')
.append(QByteArray::fromRawData((char *) output, n).toBase64(QByteArray::OmitTrailingEquals));
}
static QString random(int length) {
static const QString charset("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
QString result;
for (auto i = 0; i < length; ++i) {
auto j = QRandomGenerator::global()->bounded(0, charset.length() - 1);
result.append(charset.at(j));
}
return result;
}
@drewpts
Copy link

drewpts commented Jan 24, 2022

Hi, thanks for the snippet.

It is worth mentioning to the others who might get here: the QByteArray::fromRawData returns non-owning QByteArray instance so that data under the hood should persist. And do not forget to manage with manual allocation at 55 string.

@YuHongShanghai
Copy link

Tanks for your code.

But there is a bug here:
If the ciphertext contains '\0', in line 19, the real length of ciphertext can't be obtained by strlen(), resulting in the inability to restore the plaintext.
A suggested way to fix that is getting the real length by the byte array outside function decrypt_aes_256(), then pass the length to the function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment