} // ns
namespace {
+ unsigned char* unsignedData(QByteArray& array)
+ {
+ return (unsigned char*)array.data();
+ }
+
QByteArray BIO2ByteArray(BIO *b) {
size_t pending = BIO_ctrl_pending(b);
- char *tmp = (char *)calloc(pending+1, sizeof(char));
- BIO_read(b, tmp, OCC::Utility::convertSizeToInt(pending));
-
- QByteArray res(tmp, OCC::Utility::convertSizeToInt(pending));
- free(tmp);
-
+ QByteArray res(pending, '\0');
+ BIO_read(b, unsignedData(res), pending);
return res;
}
BIO_free_all(bioErrors);
return errors;
}
+
+ //
+ // Simple class for safe handling of ciper context
+ // allocation and deallocation
+ //
+ class CipherCtx {
+ public:
+ CipherCtx()
+ : m_ctx(EVP_CIPHER_CTX_new())
+ {
+ }
+
+ ~CipherCtx()
+ {
+ EVP_CIPHER_CTX_free(m_ctx);
+ }
+
+ operator EVP_CIPHER_CTX*()
+ {
+ return m_ctx;
+ }
+
+ private:
+ CipherCtx(const CipherCtx&) = delete;
+ CipherCtx& operator=(const CipherCtx&) = delete;
+
+ EVP_CIPHER_CTX* m_ctx;
+ };
}
namespace EncryptionHelper {
+
+
+
+
QByteArray generateRandomFilename()
{
return QUuid::createUuid().toRfc4122().toHex();
QByteArray generateRandom(int size)
{
- auto *tmp = (unsigned char *)malloc(sizeof(unsigned char) * size);
+ QByteArray result(size, '\0');
- int ret = RAND_bytes(tmp, size);
+ int ret = RAND_bytes(unsignedData(result), size);
if (ret != 1) {
qCInfo(lcCse()) << "Random byte generation failed!";
// Error out?
}
- QByteArray result((const char *)tmp, size);
- free(tmp);
-
return result;
}
QByteArray iv = generateRandom(12);
- EVP_CIPHER_CTX *ctx;
+ CipherCtx ctx;
/* Create and initialise the context */
- if(!(ctx = EVP_CIPHER_CTX_new())) {
+ if(!ctx) {
qCInfo(lcCse()) << "Error creating cipher";
handleErrors();
}
QByteArray privateKeyB64 = privateKey.toBase64();
// Make sure we have enough room in the cipher text
- auto *ctext = (unsigned char *)malloc(sizeof(unsigned char) * (privateKeyB64.size() + 32));
+ QByteArray ctext(privateKeyB64.size() + 32, '\0');
// Do the actual encryption
int len = 0;
- if(!EVP_EncryptUpdate(ctx, ctext, &len, (unsigned char *)privateKeyB64.constData(), privateKeyB64.size())) {
+ if(!EVP_EncryptUpdate(ctx, unsignedData(ctext), &len, (unsigned char *)privateKeyB64.constData(), privateKeyB64.size())) {
qCInfo(lcCse()) << "Error encrypting";
handleErrors();
}
/* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
- if(1 != EVP_EncryptFinal_ex(ctx, ctext + len, &len)) {
+ if(1 != EVP_EncryptFinal_ex(ctx, unsignedData(ctext) + len, &len)) {
qCInfo(lcCse()) << "Error finalizing encryption";
handleErrors();
}
clen += len;
/* Get the tag */
- auto *tag = (unsigned char *)calloc(sizeof(unsigned char), 16);
- if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) {
+ QByteArray tag(16, '\0');
+ if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, unsignedData(tag))) {
qCInfo(lcCse()) << "Error getting the tag";
handleErrors();
}
- QByteArray cipherTXT((char *)ctext, clen);
- cipherTXT.append((char *)tag, 16);
+ QByteArray cipherTXT;
+ cipherTXT.reserve(clen + 16);
+ cipherTXT.append(ctext, clen);
+ cipherTXT.append(tag);
QByteArray result = cipherTXT.toBase64();
result += "fA==";
cipherTXT.chop(16);
// Init
- EVP_CIPHER_CTX *ctx;
+ CipherCtx ctx;
/* Create and initialise the context */
- if(!(ctx = EVP_CIPHER_CTX_new())) {
+ if(!ctx) {
qCInfo(lcCse()) << "Error creating cipher";
return QByteArray();
}
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr)) {
qCInfo(lcCse()) << "Error initialising context with aes 256";
- EVP_CIPHER_CTX_free(ctx);
return QByteArray();
}
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size(), nullptr)) {
qCInfo(lcCse()) << "Error setting IV size";
- EVP_CIPHER_CTX_free(ctx);
return QByteArray();
}
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, nullptr, nullptr, (unsigned char *)key.constData(), (unsigned char *)iv.constData())) {
qCInfo(lcCse()) << "Error initialising key and iv";
- EVP_CIPHER_CTX_free(ctx);
return QByteArray();
}
- auto *ptext = (unsigned char *)calloc(cipherTXT.size() + 16, sizeof(unsigned char));
+ QByteArray ptext(cipherTXT.size() + 16, '\0');
int plen;
/* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
- if(!EVP_DecryptUpdate(ctx, ptext, &plen, (unsigned char *)cipherTXT.constData(), cipherTXT.size())) {
+ if(!EVP_DecryptUpdate(ctx, unsignedData(ptext), &plen, (unsigned char *)cipherTXT.constData(), cipherTXT.size())) {
qCInfo(lcCse()) << "Could not decrypt";
- EVP_CIPHER_CTX_free(ctx);
- free(ptext);
return QByteArray();
}
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag.size(), (unsigned char *)tag.constData())) {
qCInfo(lcCse()) << "Could not set tag";
- EVP_CIPHER_CTX_free(ctx);
- free(ptext);
return QByteArray();
}
* anything else is a failure - the plaintext is not trustworthy.
*/
int len = plen;
- if (EVP_DecryptFinal_ex(ctx, ptext + plen, &len) == 0) {
+ if (EVP_DecryptFinal_ex(ctx, unsignedData(ptext) + plen, &len) == 0) {
qCInfo(lcCse()) << "Tag did not match!";
- EVP_CIPHER_CTX_free(ctx);
- free(ptext);
return QByteArray();
}
- QByteArray result((char *)ptext, plen);
-
- free(ptext);
- EVP_CIPHER_CTX_free(ctx);
-
+ QByteArray result(ptext, plen);
return QByteArray::fromBase64(result);
}
cipherTXT.chop(16);
// Init
- EVP_CIPHER_CTX *ctx;
+ CipherCtx ctx;
/* Create and initialise the context */
- if(!(ctx = EVP_CIPHER_CTX_new())) {
+ if(!ctx) {
qCInfo(lcCse()) << "Error creating cipher";
return QByteArray();
}
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) {
qCInfo(lcCse()) << "Error initialising context with aes 128";
- EVP_CIPHER_CTX_free(ctx);
return QByteArray();
}
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size(), nullptr)) {
qCInfo(lcCse()) << "Error setting IV size";
- EVP_CIPHER_CTX_free(ctx);
return QByteArray();
}
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, nullptr, nullptr, (unsigned char *)key.constData(), (unsigned char *)iv.constData())) {
qCInfo(lcCse()) << "Error initialising key and iv";
- EVP_CIPHER_CTX_free(ctx);
return QByteArray();
}
- auto *ptext = (unsigned char *)calloc(cipherTXT.size() + 16, sizeof(unsigned char));
+ QByteArray ptext(cipherTXT.size() + 16, '\0');
int plen;
/* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
- if(!EVP_DecryptUpdate(ctx, ptext, &plen, (unsigned char *)cipherTXT.constData(), cipherTXT.size())) {
+ if(!EVP_DecryptUpdate(ctx, unsignedData(ptext), &plen, (unsigned char *)cipherTXT.constData(), cipherTXT.size())) {
qCInfo(lcCse()) << "Could not decrypt";
- EVP_CIPHER_CTX_free(ctx);
- free(ptext);
return QByteArray();
}
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag.size(), (unsigned char *)tag.constData())) {
qCInfo(lcCse()) << "Could not set tag";
- EVP_CIPHER_CTX_free(ctx);
- free(ptext);
return QByteArray();
}
* anything else is a failure - the plaintext is not trustworthy.
*/
int len = plen;
- if (EVP_DecryptFinal_ex(ctx, ptext + plen, &len) == 0) {
+ if (EVP_DecryptFinal_ex(ctx, unsignedData(ptext) + plen, &len) == 0) {
qCInfo(lcCse()) << "Tag did not match!";
- EVP_CIPHER_CTX_free(ctx);
- free(ptext);
return QByteArray();
}
- QByteArray result((char *)ptext, plen);
-
- free(ptext);
- EVP_CIPHER_CTX_free(ctx);
-
+ QByteArray result(ptext, plen);
return result;
}
QByteArray encryptStringSymmetric(const QByteArray& key, const QByteArray& data) {
QByteArray iv = generateRandom(16);
- EVP_CIPHER_CTX *ctx;
+ CipherCtx ctx;
/* Create and initialise the context */
- if(!(ctx = EVP_CIPHER_CTX_new())) {
+ if(!ctx) {
qCInfo(lcCse()) << "Error creating cipher";
handleErrors();
return {};
QByteArray dataB64 = data.toBase64();
// Make sure we have enough room in the cipher text
- auto *ctext = (unsigned char *)malloc(sizeof(unsigned char) * (dataB64.size() + 16));
+ QByteArray ctext(dataB64.size() + 16, '\0');
// Do the actual encryption
int len = 0;
- if(!EVP_EncryptUpdate(ctx, ctext, &len, (unsigned char *)dataB64.constData(), dataB64.size())) {
+ if(!EVP_EncryptUpdate(ctx, unsignedData(ctext), &len, (unsigned char *)dataB64.constData(), dataB64.size())) {
qCInfo(lcCse()) << "Error encrypting";
handleErrors();
return {};
/* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
- if(1 != EVP_EncryptFinal_ex(ctx, ctext + len, &len)) {
+ if(1 != EVP_EncryptFinal_ex(ctx, unsignedData(ctext) + len, &len)) {
qCInfo(lcCse()) << "Error finalizing encryption";
handleErrors();
return {};
clen += len;
/* Get the tag */
- auto *tag = (unsigned char *)calloc(sizeof(unsigned char), 16);
- if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) {
+ QByteArray tag(16, '\0');
+ if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, unsignedData(tag))) {
qCInfo(lcCse()) << "Error getting the tag";
handleErrors();
return {};
}
- QByteArray cipherTXT((char *)ctext, clen);
- cipherTXT.append((char *)tag, 16);
+ QByteArray cipherTXT;
+ cipherTXT.reserve(clen + 16);
+ cipherTXT.append(ctext, clen);
+ cipherTXT.append(tag);
QByteArray result = cipherTXT.toBase64();
result += "fA==";
}
// Init
- EVP_CIPHER_CTX *ctx;
+ CipherCtx ctx;
/* Create and initialise the context */
- if(!(ctx = EVP_CIPHER_CTX_new())) {
+ if(!ctx) {
qCInfo(lcCse()) << "Could not create context";
return false;
}
return false;
}
- auto *out = (unsigned char *)malloc(sizeof(unsigned char) * (1024 + 16 -1));
+ QByteArray out(1024 + 16 - 1, '\0');
int len = 0;
int total_len = 0;
}
qCDebug(lcCse) << "Encrypting " << data;
- if(!EVP_EncryptUpdate(ctx, out, &len, (unsigned char *)data.constData(), data.size())) {
+ if(!EVP_EncryptUpdate(ctx, unsignedData(out), &len, (unsigned char *)data.constData(), data.size())) {
qCInfo(lcCse()) << "Could not encrypt";
return false;
}
- output->write((char *)out, len);
+ output->write(out, len);
total_len += len;
}
- if(1 != EVP_EncryptFinal_ex(ctx, out, &len)) {
+ if(1 != EVP_EncryptFinal_ex(ctx, unsignedData(out), &len)) {
qCInfo(lcCse()) << "Could finalize encryption";
return false;
}
- output->write((char *)out, len);
+ output->write(out, len);
total_len += len;
/* Get the tag */
- auto *tag = (unsigned char *)malloc(sizeof(unsigned char) * 16);
- if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) {
+ QByteArray tag(16, '\0');
+ if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, unsignedData(tag))) {
qCInfo(lcCse()) << "Could not get tag";
return false;
}
- returnTag = QByteArray((const char*) tag, 16);
- output->write((char *)tag, 16);
-
- free(out);
- free(tag);
- EVP_CIPHER_CTX_free(ctx);
+ returnTag = tag;
+ output->write(tag, 16);
input->close();
output->close();
output->open(QIODevice::WriteOnly);
// Init
- EVP_CIPHER_CTX *ctx;
+ CipherCtx ctx;
/* Create and initialise the context */
- if(!(ctx = EVP_CIPHER_CTX_new())) {
+ if(!ctx) {
qCInfo(lcCse()) << "Could not create context";
return false;
}
qint64 size = input->size() - 16;
- auto *out = (unsigned char *)malloc(sizeof(unsigned char) * (1024 + 16 -1));
+ QByteArray out(1024 + 16 - 1, '\0');
int len = 0;
while(input->pos() < size) {
return false;
}
- if(!EVP_DecryptUpdate(ctx, out, &len, (unsigned char *)data.constData(), data.size())) {
+ if(!EVP_DecryptUpdate(ctx, unsignedData(out), &len, (unsigned char *)data.constData(), data.size())) {
qCInfo(lcCse()) << "Could not decrypt";
return false;
}
- output->write((char *)out, len);
+ output->write(out, len);
}
QByteArray tag = input->read(16);
return false;
}
- if(1 != EVP_DecryptFinal_ex(ctx, out, &len)) {
+ if(1 != EVP_DecryptFinal_ex(ctx, unsignedData(out), &len)) {
qCInfo(lcCse()) << "Could finalize decryption";
return false;
}
- output->write((char *)out, len);
-
- free(out);
- EVP_CIPHER_CTX_free(ctx);
+ output->write(out, len);
input->close();
output->close();