aboutsummaryrefslogtreecommitdiff
path: root/src/client/OmemoCryptoProvider.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/OmemoCryptoProvider.cpp')
-rw-r--r--src/client/OmemoCryptoProvider.cpp239
1 files changed, 239 insertions, 0 deletions
diff --git a/src/client/OmemoCryptoProvider.cpp b/src/client/OmemoCryptoProvider.cpp
new file mode 100644
index 00000000..e39124d4
--- /dev/null
+++ b/src/client/OmemoCryptoProvider.cpp
@@ -0,0 +1,239 @@
+// SPDX-FileCopyrightText: 2021 Linus Jahn <lnj@kaidan.im>
+// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de>
+//
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include "OmemoCryptoProvider.h"
+
+#include "QXmppOmemoManager_p.h"
+#include "QXmppUtils_p.h"
+
+#include <QStringBuilder>
+#include <QtCrypto>
+
+using namespace QXmpp::Private;
+
+inline QXmppOmemoManagerPrivate *managerPrivate(void *ptr)
+{
+ return reinterpret_cast<QXmppOmemoManagerPrivate *>(ptr);
+}
+
+static int random_func(uint8_t *data, size_t len, void *)
+{
+ generateRandomBytes(data, len);
+ return 0;
+}
+
+int hmac_sha256_init_func(void **hmac_context, const uint8_t *key, size_t key_len, void *user_data)
+{
+ auto *d = managerPrivate(user_data);
+
+ if (!QCA::MessageAuthenticationCode::supportedTypes().contains(PAYLOAD_MESSAGE_AUTHENTICATION_CODE_TYPE)) {
+ d->warning("Message authentication code type '" % QString(PAYLOAD_MESSAGE_AUTHENTICATION_CODE_TYPE) % "' is not supported by this system");
+ return -1;
+ }
+
+ QCA::SymmetricKey authenticationKey(QByteArray(reinterpret_cast<const char *>(key), key_len));
+ *hmac_context = new QCA::MessageAuthenticationCode(PAYLOAD_MESSAGE_AUTHENTICATION_CODE_TYPE, authenticationKey);
+ return 0;
+}
+
+int hmac_sha256_update_func(void *hmac_context, const uint8_t *data, size_t data_len, void *)
+{
+ auto *messageAuthenticationCodeGenerator = reinterpret_cast<QCA::MessageAuthenticationCode *>(hmac_context);
+ messageAuthenticationCodeGenerator->update(QCA::MemoryRegion(QByteArray(reinterpret_cast<const char *>(data), data_len)));
+ return 0;
+}
+
+int hmac_sha256_final_func(void *hmac_context, signal_buffer **output, void *user_data)
+{
+ auto *d = managerPrivate(user_data);
+ auto *messageAuthenticationCodeGenerator = reinterpret_cast<QCA::MessageAuthenticationCode *>(hmac_context);
+
+ auto messageAuthenticationCode = messageAuthenticationCodeGenerator->final();
+ if (!(*output = signal_buffer_create(reinterpret_cast<const uint8_t *>(messageAuthenticationCode.constData()), messageAuthenticationCode.size()))) {
+ d->warning("Message authentication code could not be loaded");
+ return -1;
+ }
+
+ return 0;
+}
+
+void hmac_sha256_cleanup_func(void *hmac_context, void *)
+{
+ auto *messageAuthenticationCodeGenerator = reinterpret_cast<QCA::MessageAuthenticationCode *>(hmac_context);
+ delete messageAuthenticationCodeGenerator;
+}
+
+int sha512_digest_init_func(void **digest_context, void *)
+{
+ *digest_context = new QCryptographicHash(QCryptographicHash::Sha512);
+ return 0;
+}
+
+int sha512_digest_update_func(void *digest_context, const uint8_t *data, size_t data_len, void *)
+{
+ auto *hashGenerator = reinterpret_cast<QCryptographicHash *>(digest_context);
+ hashGenerator->addData(reinterpret_cast<const char *>(data), data_len);
+ return 0;
+}
+
+int sha512_digest_final_func(void *digest_context, signal_buffer **output, void *user_data)
+{
+ auto *d = managerPrivate(user_data);
+ auto *hashGenerator = reinterpret_cast<QCryptographicHash *>(digest_context);
+
+ auto hash = hashGenerator->result();
+ if (!(*output = signal_buffer_create(reinterpret_cast<const uint8_t *>(hash.constData()), hash.size()))) {
+ d->warning("Hash could not be loaded");
+ return -1;
+ }
+
+ return 0;
+}
+
+void sha512_digest_cleanup_func(void *digest_context, void *)
+{
+ auto *hashGenerator = reinterpret_cast<QCryptographicHash *>(digest_context);
+ delete hashGenerator;
+}
+
+int encrypt_func(signal_buffer **output,
+ int cipher,
+ const uint8_t *key, size_t key_len,
+ const uint8_t *iv, size_t iv_len,
+ const uint8_t *plaintext, size_t plaintext_len,
+ void *user_data)
+{
+ auto *d = managerPrivate(user_data);
+
+ QString cipherName;
+
+ switch (key_len) {
+ case 128 / 8:
+ cipherName = QStringLiteral("aes128");
+ break;
+ case 192 / 8:
+ cipherName = QStringLiteral("aes192");
+ break;
+ case 256 / 8:
+ cipherName = QStringLiteral("aes256");
+ break;
+ default:
+ return -1;
+ }
+
+ QCA::Cipher::Mode mode;
+ QCA::Cipher::Padding padding;
+
+ switch (cipher) {
+ case SG_CIPHER_AES_CTR_NOPADDING:
+ mode = QCA::Cipher::CTR;
+ padding = QCA::Cipher::NoPadding;
+ break;
+ case SG_CIPHER_AES_CBC_PKCS5:
+ mode = QCA::Cipher::CBC;
+ padding = QCA::Cipher::PKCS7;
+ break;
+ default:
+ return -2;
+ }
+
+ const auto encryptionKey = QCA::SymmetricKey(QByteArray(reinterpret_cast<const char *>(key), key_len));
+ const auto initializationVector = QCA::InitializationVector(QByteArray(reinterpret_cast<const char *>(iv), iv_len));
+ QCA::Cipher encryptionCipher(cipherName, mode, padding, QCA::Encode, encryptionKey, initializationVector);
+
+ auto encryptedData = encryptionCipher.process(QCA::MemoryRegion(QByteArray(reinterpret_cast<const char *>(plaintext), plaintext_len)));
+
+ if (encryptedData.isEmpty()) {
+ return -3;
+ }
+
+ if (!(*output = signal_buffer_create(reinterpret_cast<const uint8_t *>(encryptedData.constData()), encryptedData.size()))) {
+ d->warning("Encrypted data could not be loaded");
+ return -4;
+ }
+
+ return 0;
+}
+
+int decrypt_func(signal_buffer **output,
+ int cipher,
+ const uint8_t *key, size_t key_len,
+ const uint8_t *iv, size_t iv_len,
+ const uint8_t *ciphertext, size_t ciphertext_len,
+ void *user_data)
+{
+ auto *d = managerPrivate(user_data);
+
+ QString cipherName;
+
+ switch (key_len) {
+ case 128 / 8:
+ cipherName = QStringLiteral("aes128");
+ break;
+ case 192 / 8:
+ cipherName = QStringLiteral("aes192");
+ break;
+ case 256 / 8:
+ cipherName = QStringLiteral("aes256");
+ break;
+ default:
+ return -1;
+ }
+
+ QCA::Cipher::Mode mode;
+ QCA::Cipher::Padding padding;
+
+ switch (cipher) {
+ case SG_CIPHER_AES_CTR_NOPADDING:
+ mode = QCA::Cipher::CTR;
+ padding = QCA::Cipher::NoPadding;
+ break;
+ case SG_CIPHER_AES_CBC_PKCS5:
+ mode = QCA::Cipher::CBC;
+ padding = QCA::Cipher::PKCS7;
+ break;
+ default:
+ return -2;
+ }
+
+ const auto encryptionKey = QCA::SymmetricKey(QByteArray(reinterpret_cast<const char *>(key), key_len));
+ const auto initializationVector = QCA::InitializationVector(QByteArray(reinterpret_cast<const char *>(iv), iv_len));
+ QCA::Cipher decryptionCipher(cipherName, mode, padding, QCA::Decode, encryptionKey, initializationVector);
+
+ auto decryptedData = decryptionCipher.process(QCA::MemoryRegion(QByteArray(reinterpret_cast<const char *>(ciphertext), ciphertext_len)));
+
+ if (decryptedData.isEmpty()) {
+ return -3;
+ }
+
+ if (!(*output = signal_buffer_create(reinterpret_cast<const uint8_t *>(decryptedData.constData()), decryptedData.size()))) {
+ d->warning("Decrypted data could not be loaded");
+ return -4;
+ }
+
+ return 0;
+}
+
+namespace QXmpp::Omemo::Private {
+
+signal_crypto_provider createOmemoCryptoProvider(QXmppOmemoManagerPrivate *d)
+{
+ return {
+ random_func,
+ hmac_sha256_init_func,
+ hmac_sha256_update_func,
+ hmac_sha256_final_func,
+ hmac_sha256_cleanup_func,
+ sha512_digest_init_func,
+ sha512_digest_update_func,
+ sha512_digest_final_func,
+ sha512_digest_cleanup_func,
+ encrypt_func,
+ decrypt_func,
+ d,
+ };
+}
+
+} // namespace QXmpp::Omemo::Private