diff options
author | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-02-16 08:40:56 +0100 |
---|---|---|
committer | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-02-16 17:58:17 +0100 |
commit | b5e1fc7d8fcf9336db0dfb351403aa06dcb226a0 (patch) | |
tree | c5af5984d51a1db1d6ff59bb2360eb4cec4f0b29 | |
parent | 0a43c023b94e12b3130572f2dd0d6ac8bb4ed110 (diff) | |
download | libquotient-b5e1fc7d8fcf9336db0dfb351403aa06dcb226a0.tar.gz libquotient-b5e1fc7d8fcf9336db0dfb351403aa06dcb226a0.zip |
More cleanup, especially in EncryptedFile
For EncryptedFile:
- JSON converter bodies moved away to .cpp;
- instead of C-style casts, reinterpret_cast is used to convert from
(const) char* to (const) unsigned char*;
- the size for the target plain text takes into account the case where
the cipher block size can be larger than 1 (after reading
https://www.openssl.org/docs/man1.1.1/man3/EVP_DecryptUpdate.html).
- file decryption is wrapped in #ifdef Quotient_E2EE_ENABLED, to avoid
OpenSSL linking errors when compiling without E2EE.
-rw-r--r-- | lib/connection.cpp | 21 | ||||
-rw-r--r-- | lib/events/encryptedfile.cpp | 89 | ||||
-rw-r--r-- | lib/events/encryptedfile.h | 40 | ||||
-rw-r--r-- | lib/jobs/downloadfilejob.cpp | 6 |
4 files changed, 99 insertions, 57 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp index 87fc8e2c..1ef2495d 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -2007,8 +2007,10 @@ void Connection::Private::loadOutdatedUserDevices() << device.algorithms; continue; } - if(!verifyIdentitySignature(device, device.deviceId, device.userId)) { - qCWarning(E2EE) << "Failed to verify devicekeys signature. Skipping this device"; + if (!verifyIdentitySignature(device, device.deviceId, + device.userId)) { + qCWarning(E2EE) << "Failed to verify devicekeys signature. " + "Skipping this device"; continue; } deviceKeys[user][device.deviceId] = device; @@ -2022,9 +2024,11 @@ void Connection::Private::loadOutdatedUserDevices() void Connection::Private::saveDevicesList() { q->database()->transaction(); - auto query = q->database()->prepareQuery(QStringLiteral("DELETE FROM tracked_users")); + auto query = q->database()->prepareQuery( + QStringLiteral("DELETE FROM tracked_users")); q->database()->execute(query); - query.prepare(QStringLiteral("INSERT INTO tracked_users(matrixId) VALUES(:matrixId);")); + query.prepare(QStringLiteral( + "INSERT INTO tracked_users(matrixId) VALUES(:matrixId);")); for (const auto& user : trackedUsers) { query.bindValue(":matrixId", user); q->database()->execute(query); @@ -2032,13 +2036,18 @@ void Connection::Private::saveDevicesList() query.prepare(QStringLiteral("DELETE FROM outdated_users")); q->database()->execute(query); - query.prepare(QStringLiteral("INSERT INTO outdated_users(matrixId) VALUES(:matrixId);")); + query.prepare(QStringLiteral( + "INSERT INTO outdated_users(matrixId) VALUES(:matrixId);")); for (const auto& user : outdatedUsers) { query.bindValue(":matrixId", user); q->database()->execute(query); } - query.prepare(QStringLiteral("INSERT INTO tracked_devices(matrixId, deviceId, curveKeyId, curveKey, edKeyId, edKey) VALUES(:matrixId, :deviceId, :curveKeyId, :curveKey, :edKeyId, :edKey);")); + query.prepare(QStringLiteral( + "INSERT INTO tracked_devices" + "(matrixId, deviceId, curveKeyId, curveKey, edKeyId, edKey) " + "VALUES(:matrixId, :deviceId, :curveKeyId, :curveKey, :edKeyId, :edKey);" + )); for (const auto& user : deviceKeys.keys()) { for (const auto& device : deviceKeys[user]) { auto keys = device.keys.keys(); diff --git a/lib/events/encryptedfile.cpp b/lib/events/encryptedfile.cpp index dbb72af8..d4a517bd 100644 --- a/lib/events/encryptedfile.cpp +++ b/lib/events/encryptedfile.cpp @@ -5,27 +5,88 @@ #include "encryptedfile.h" #include "logging.h" +#ifdef Quotient_E2EE_ENABLED #include <openssl/evp.h> #include <QtCore/QCryptographicHash> +#endif using namespace Quotient; -QByteArray EncryptedFile::decryptFile(const QByteArray &ciphertext) const +QByteArray EncryptedFile::decryptFile(const QByteArray& ciphertext) const { - QString _key = key.k; - auto keyBytes = QByteArray::fromBase64(_key.replace(QLatin1Char('_'), QLatin1Char('/')).replace(QLatin1Char('-'), QLatin1Char('+')).toLatin1()); +#ifdef Quotient_E2EE_ENABLED + auto _key = key.k; + const auto keyBytes = QByteArray::fromBase64( + _key.replace(u'_', u'/').replace(u'-', u'+').toLatin1()); const auto sha256 = QByteArray::fromBase64(hashes["sha256"].toLatin1()); - if(sha256 != QCryptographicHash::hash(ciphertext, QCryptographicHash::Sha256)) { + if (sha256 + != QCryptographicHash::hash(ciphertext, QCryptographicHash::Sha256)) { qCWarning(E2EE) << "Hash verification failed for file"; - return QByteArray(); + return {}; } - QByteArray plaintext(ciphertext.size(), 0); - EVP_CIPHER_CTX *ctx; - int length; - ctx = EVP_CIPHER_CTX_new(); - EVP_DecryptInit_ex(ctx, EVP_aes_256_ctr(), NULL, (const unsigned char *)keyBytes.data(), (const unsigned char *)QByteArray::fromBase64(iv.toLatin1()).data()); - EVP_DecryptUpdate(ctx, (unsigned char *)plaintext.data(), &length, (const unsigned char *)ciphertext.data(), ciphertext.size()); - EVP_DecryptFinal_ex(ctx, (unsigned char *)plaintext.data() + length, &length); - EVP_CIPHER_CTX_free(ctx); - return plaintext; + { + int length; + auto* ctx = EVP_CIPHER_CTX_new(); + QByteArray plaintext(ciphertext.size() + EVP_CIPHER_CTX_block_size(ctx) + - 1, + '\0'); + EVP_DecryptInit_ex(ctx, EVP_aes_256_ctr(), nullptr, + reinterpret_cast<const unsigned char*>( + keyBytes.data()), + reinterpret_cast<const unsigned char*>( + QByteArray::fromBase64(iv.toLatin1()).data())); + EVP_DecryptUpdate( + ctx, reinterpret_cast<unsigned char*>(plaintext.data()), &length, + reinterpret_cast<const unsigned char*>(ciphertext.data()), + ciphertext.size()); + EVP_DecryptFinal_ex(ctx, + reinterpret_cast<unsigned char*>(plaintext.data()) + + length, + &length); + EVP_CIPHER_CTX_free(ctx); + return plaintext; + } +#else + qWarning(MAIN) << "This build of libQuotient doesn't support E2EE, " + "cannot decrypt the file"; + return ciphertext; +#endif +} + +void JsonObjectConverter<EncryptedFile>::dumpTo(QJsonObject& jo, + const EncryptedFile& pod) +{ + addParam<>(jo, QStringLiteral("url"), pod.url); + addParam<>(jo, QStringLiteral("key"), pod.key); + addParam<>(jo, QStringLiteral("iv"), pod.iv); + addParam<>(jo, QStringLiteral("hashes"), pod.hashes); + addParam<>(jo, QStringLiteral("v"), pod.v); +} + +void JsonObjectConverter<EncryptedFile>::fillFrom(const QJsonObject& jo, + EncryptedFile& pod) +{ + fromJson(jo.value("url"_ls), pod.url); + fromJson(jo.value("key"_ls), pod.key); + fromJson(jo.value("iv"_ls), pod.iv); + fromJson(jo.value("hashes"_ls), pod.hashes); + fromJson(jo.value("v"_ls), pod.v); +} + +void JsonObjectConverter<JWK>::dumpTo(QJsonObject &jo, const JWK &pod) +{ + addParam<>(jo, QStringLiteral("kty"), pod.kty); + addParam<>(jo, QStringLiteral("key_ops"), pod.keyOps); + addParam<>(jo, QStringLiteral("alg"), pod.alg); + addParam<>(jo, QStringLiteral("k"), pod.k); + addParam<>(jo, QStringLiteral("ext"), pod.ext); +} + +void JsonObjectConverter<JWK>::fillFrom(const QJsonObject &jo, JWK &pod) +{ + fromJson(jo.value("kty"_ls), pod.kty); + fromJson(jo.value("key_ops"_ls), pod.keyOps); + fromJson(jo.value("alg"_ls), pod.alg); + fromJson(jo.value("k"_ls), pod.k); + fromJson(jo.value("ext"_ls), pod.ext); } diff --git a/lib/events/encryptedfile.h b/lib/events/encryptedfile.h index 43bafc49..0558563f 100644 --- a/lib/events/encryptedfile.h +++ b/lib/events/encryptedfile.h @@ -49,42 +49,14 @@ public: }; template <> -struct JsonObjectConverter<EncryptedFile> { - static void dumpTo(QJsonObject& jo, const EncryptedFile& pod) - { - addParam<>(jo, QStringLiteral("url"), pod.url); - addParam<>(jo, QStringLiteral("key"), pod.key); - addParam<>(jo, QStringLiteral("iv"), pod.iv); - addParam<>(jo, QStringLiteral("hashes"), pod.hashes); - addParam<>(jo, QStringLiteral("v"), pod.v); - } - static void fillFrom(const QJsonObject& jo, EncryptedFile& pod) - { - fromJson(jo.value("url"_ls), pod.url); - fromJson(jo.value("key"_ls), pod.key); - fromJson(jo.value("iv"_ls), pod.iv); - fromJson(jo.value("hashes"_ls), pod.hashes); - fromJson(jo.value("v"_ls), pod.v); - } +struct QUOTIENT_API JsonObjectConverter<EncryptedFile> { + static void dumpTo(QJsonObject& jo, const EncryptedFile& pod); + static void fillFrom(const QJsonObject& jo, EncryptedFile& pod); }; template <> -struct JsonObjectConverter<JWK> { - static void dumpTo(QJsonObject& jo, const JWK& pod) - { - addParam<>(jo, QStringLiteral("kty"), pod.kty); - addParam<>(jo, QStringLiteral("key_ops"), pod.keyOps); - addParam<>(jo, QStringLiteral("alg"), pod.alg); - addParam<>(jo, QStringLiteral("k"), pod.k); - addParam<>(jo, QStringLiteral("ext"), pod.ext); - } - static void fillFrom(const QJsonObject& jo, JWK& pod) - { - fromJson(jo.value("kty"_ls), pod.kty); - fromJson(jo.value("key_ops"_ls), pod.keyOps); - fromJson(jo.value("alg"_ls), pod.alg); - fromJson(jo.value("k"_ls), pod.k); - fromJson(jo.value("ext"_ls), pod.ext); - } +struct QUOTIENT_API JsonObjectConverter<JWK> { + static void dumpTo(QJsonObject& jo, const JWK& pod); + static void fillFrom(const QJsonObject& jo, JWK& pod); }; } // namespace Quotient diff --git a/lib/jobs/downloadfilejob.cpp b/lib/jobs/downloadfilejob.cpp index 634e5fb9..d00fc5f4 100644 --- a/lib/jobs/downloadfilejob.cpp +++ b/lib/jobs/downloadfilejob.cpp @@ -127,7 +127,7 @@ BaseJob::Status DownloadFileJob::prepareResult() QByteArray encrypted = d->tempFile->readAll(); EncryptedFile file = *d->encryptedFile; - auto decrypted = file.decryptFile(encrypted); + const auto decrypted = file.decryptFile(encrypted); d->targetFile->write(decrypted); d->tempFile->remove(); } else { @@ -149,10 +149,10 @@ BaseJob::Status DownloadFileJob::prepareResult() #ifdef Quotient_E2EE_ENABLED if (d->encryptedFile.has_value()) { d->tempFile->seek(0); - auto encrypted = d->tempFile->readAll(); + const auto encrypted = d->tempFile->readAll(); EncryptedFile file = *d->encryptedFile; - auto decrypted = file.decryptFile(encrypted); + const auto decrypted = file.decryptFile(encrypted); d->tempFile->write(decrypted); } else { #endif |