Last active
May 31, 2023 05:28
-
-
Save vaibhavpandeyvpz/3b3d2254242a9c3a90d9428de274c524 to your computer and use it in GitHub Desktop.
AES-256-CBC encryption in Qt with OpenSLL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
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
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.