[network/ruqola] src/core: Prepare to extract session key

Laurent Montel <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 3d6093840b42771fce72c47ece32e555a7ed6809 by Laurent Montel.
Committed on 05/08/2026 at 12:24.
Pushed by mlaurent into branch 'master'.

Prepare to extract session key

M  +0    -27   src/core/encryption/encryptionutils.cpp
M  +58   -9    src/core/roomencryptionkey.cpp
M  +12   -1    src/core/roomencryptionkey.h

https://invent.kde.org/network/ruqola/-/commit/3d6093840b42771fce72c47ece32e555a7ed6809

diff --git a/src/core/encryption/encryptionutils.cpp b/src/core/encryption/encryptionutils.cpp
index ee9b87a354..c9595b3c57 100644
--- a/src/core/encryption/encryptionutils.cpp
+++ b/src/core/encryption/encryptionutils.cpp
@@ -268,33 +268,6 @@ QByteArray EncryptionUtils::getMasterKey(const QString &password, const QString
     }
 
     return masterKey;
-
-#if 0
-    async getMasterKey(password: string): Promise<void | CryptoKey> {
-            if (password == null) {
-                    alert('You should provide a password');
-            }
-
-            // First, create a PBKDF2 "key" containing the password
-            let baseKey;
-            try {
-                    baseKey = await importRawKey(toArrayBuffer(password));
-            } catch (error) {
-                    this.setState(E2EEState.ERROR);
-                    return this.error('Error creating a key based on user password: ', error);
-            }
-
-            // Derive a key from the password
-            try {
-                    return await deriveKey(toArrayBuffer(Meteor.userId()), baseKey);
-            } catch (error) {
-                    this.setState(E2EEState.ERROR);
-                    return this.error('Error deriving baseKey: ', error);
-            }
-    }
-    // TODO
-    return {};
-#endif
 }
 
 /**
diff --git a/src/core/roomencryptionkey.cpp b/src/core/roomencryptionkey.cpp
index 3488e05122..85241162c2 100644
--- a/src/core/roomencryptionkey.cpp
+++ b/src/core/roomencryptionkey.cpp
@@ -6,6 +6,9 @@
 
 #include "roomencryptionkey.h"
 #include "ruqola_room_memory_debug.h"
+#if USE_E2E_SUPPORT
+#include "encryption/encryptionutils.h"
+#endif
 
 RoomEncryptionKey::RoomEncryptionKey()
 {
@@ -24,8 +27,10 @@ QString RoomEncryptionKey::e2EKey() const
 
 void RoomEncryptionKey::setE2EKey(const QString &newE2EKey)
 {
-    mE2EKey = newE2EKey;
-    parseSessionKey();
+    if (mE2EKey != newE2EKey) {
+        mE2EKey = newE2EKey;
+        parseSessionKey();
+    }
 }
 
 void RoomEncryptionKey::parseSessionKey()
@@ -45,12 +50,17 @@ void RoomEncryptionKey::parseSessionKey()
 
     mE2eKeyId = mE2EKey.left(36); // ← UUID
 
-    // Extraire encryptedKey
-    const QString encryptedKeyBase64 = mE2EKey.mid(36); // ← base64
+    // Extraire encryptedKey (base64)
+    mEncryptedKeyBase64 = mE2EKey.mid(36);
 
-    // Décoder le base64
-    const QByteArray encryptedKey = QByteArray::fromBase64(encryptedKeyBase64.toLatin1());
+    if (mEncryptedKeyBase64.isEmpty()) {
+        qCWarning(RUQOLA_ROOM_MEMORY_LOG) << "E2EKey encryptedKey part is empty";
+        mSessionKey.clear();
+        return;
+    }
 
+    // Validate base64 can be decoded
+    const QByteArray encryptedKey = QByteArray::fromBase64(mEncryptedKeyBase64.toLatin1());
     if (encryptedKey.isEmpty()) {
         qCWarning(RUQOLA_ROOM_MEMORY_LOG) << "Failed to decode E2EKey from base64";
         mSessionKey.clear();
@@ -64,9 +74,7 @@ void RoomEncryptionKey::parseSessionKey()
     }
 
     qDebug() << "E2EKey parsed - keyId:" << mE2eKeyId << "encryptedKey size:" << encryptedKey.size();
-
-    // TODO: Decrypt with user's RSA private key
-    // mSessionKey = EncryptionUtils::decryptSessionKey(encryptedKey, privateKey);
+    // Waiting for RSA private key to decrypt session key
 }
 
 QString RoomEncryptionKey::e2eKeyId() const
@@ -78,6 +86,47 @@ void RoomEncryptionKey::setE2eKeyId(const QString &newE2eKeyId)
 {
     mE2eKeyId = newE2eKeyId;
 }
+#if USE_E2E_SUPPORT
+void RoomEncryptionKey::decryptWithPrivateKey(RSA *privateKey)
+{
+    if (!privateKey) {
+        qCWarning(RUQOLA_ROOM_MEMORY_LOG) << "Private key is null, cannot decrypt session key";
+        mSessionKey.clear();
+        return;
+    }
+
+    if (mEncryptedKeyBase64.isEmpty()) {
+        qCWarning(RUQOLA_ROOM_MEMORY_LOG) << "No encrypted key available for decryption";
+        mSessionKey.clear();
+        return;
+    }
+
+    // Decode base64 to binary
+    const QByteArray encryptedKey = QByteArray::fromBase64(mEncryptedKeyBase64.toLatin1());
+
+    if (encryptedKey.size() != 256) {
+        qCWarning(RUQOLA_ROOM_MEMORY_LOG) << "Invalid encryptedKey size for decryption:" << encryptedKey.size();
+        mSessionKey.clear();
+        return;
+    }
+
+    // Decrypt using RSA private key
+    mSessionKey = EncryptionUtils::decryptSessionKey(encryptedKey, privateKey);
+
+    if (mSessionKey.isEmpty()) {
+        qCWarning(RUQOLA_ROOM_MEMORY_LOG) << "Failed to decrypt session key with private key";
+        return;
+    }
+
+    if (mSessionKey.size() != 32) {
+        qCWarning(RUQOLA_ROOM_MEMORY_LOG) << "Invalid decrypted session key size:" << mSessionKey.size() << "(expected 32)";
+        mSessionKey.clear();
+        return;
+    }
+
+    qDebug() << "Session key successfully decrypted for keyId:" << mE2eKeyId;
+}
+#endif
 
 bool RoomEncryptionKey::operator==(const RoomEncryptionKey &other) const
 {
diff --git a/src/core/roomencryptionkey.h b/src/core/roomencryptionkey.h
index a6df609984..2d4b538370 100644
--- a/src/core/roomencryptionkey.h
+++ b/src/core/roomencryptionkey.h
@@ -4,9 +4,14 @@
    SPDX-License-Identifier: LGPL-2.0-or-later
 */
 #pragma once
+#include "config-ruqola.h"
 #include "libruqolacore_export.h"
 #include <QSharedData>
-
+#if USE_E2E_SUPPORT
+extern "C" {
+#include <openssl/rsa.h>
+}
+#endif
 class LIBRUQOLACORE_EXPORT RoomEncryptionKey : public QSharedData
 {
 public:
@@ -22,10 +27,16 @@ public:
 
     [[nodiscard]] QByteArray sessionKey() const;
 
+#if USE_E2E_SUPPORT
+    // Decrypt the session key using the provided RSA private key
+    // This is called after E2EKey is received from DDP
+    void decryptWithPrivateKey(RSA *privateKey);
+#endif
 private:
     LIBRUQOLACORE_NO_EXPORT void parseSessionKey();
     // Encryption Key
     QString mE2EKey;
     QString mE2eKeyId;
+    QString mEncryptedKeyBase64; // Base64-encoded RSA-encrypted session key
     QByteArray mSessionKey;
 };
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.