aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Rusakov <Kitsune-Ral@users.sf.net>2022-02-16 08:40:56 +0100
committerAlexey Rusakov <Kitsune-Ral@users.sf.net>2022-02-16 17:58:17 +0100
commitb5e1fc7d8fcf9336db0dfb351403aa06dcb226a0 (patch)
treec5af5984d51a1db1d6ff59bb2360eb4cec4f0b29
parent0a43c023b94e12b3130572f2dd0d6ac8bb4ed110 (diff)
downloadlibquotient-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.cpp21
-rw-r--r--lib/events/encryptedfile.cpp89
-rw-r--r--lib/events/encryptedfile.h40
-rw-r--r--lib/jobs/downloadfilejob.cpp6
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