From 67367d0004abe54445c9c6ca354c787fc0af8a79 Mon Sep 17 00:00:00 2001
From: CH Chethan Reddy <40890937+Chethan2k1@users.noreply.github.com>
Date: Sat, 20 Jun 2020 17:50:43 +0530
Subject: [PATCH] Shared secret with decimal and emoji works!

---
 resources/qml/TimelineView.qml                |  13 +-
 .../DeviceVerification.qml                    |  26 +--
 src/DeviceVerificationFlow.cpp                | 167 ++++++++++++++----
 src/DeviceVerificationFlow.h                  |  10 ++
 src/timeline/TimelineViewManager.cpp          |  64 ++++---
 src/timeline/TimelineViewManager.h            |   5 +-
 6 files changed, 202 insertions(+), 83 deletions(-)

diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml
index 5170a41a2..99d146851 100644
--- a/resources/qml/TimelineView.qml
+++ b/resources/qml/TimelineView.qml
@@ -103,18 +103,15 @@ Page {
 			id: deviceVerificationDialog
 			DeviceVerification {}
 		}
-		Component{
-        	id: deviceVerificationFlow
-        	DeviceVerificationFlow {}
-    	}
 		Connections {
 			target: timelineManager
 			onNewDeviceVerificationRequest: {
-				var newFlow = deviceVerificationFlow.createObject(timelineRoot,
-                {userId : userId,sender: false,deviceId : deviceId,tranId:transactionId});
-                deviceVerificationList.add(newFlow.tranId);
+				flow.userId = userId;
+				flow.sender = false;
+				flow.deviceId = deviceId;
+				flow.tranId = transactionId;
 				var dialog = deviceVerificationDialog.createObject(timelineRoot, 
-                    {flow: newFlow,sender: false});
+                    {flow: flow,sender: false});
 				dialog.show();
 			}
 		}
diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml
index ad0edeb7f..316fbe400 100644
--- a/resources/qml/device-verification/DeviceVerification.qml
+++ b/resources/qml/device-verification/DeviceVerification.qml
@@ -78,7 +78,7 @@ ApplicationWindow {
 						onClicked: { 
 							dialog.close(); 
 							flow.cancelVerification();
-							deviceVerificationList.remove(flow.tranId);
+							// deviceVerificationList.remove(flow.tranId);
 							delete flow; 
 						}
 					}
@@ -135,7 +135,7 @@ ApplicationWindow {
 						onClicked: { 
 							dialog.close(); 
 							flow.cancelVerification();
-							deviceVerificationList.remove(flow.tranId);
+							// deviceVerificationList.remove(flow.tranId);
 							delete flow; 
 						}
 					}
@@ -179,7 +179,7 @@ ApplicationWindow {
 						onClicked: { 
 							dialog.close(); 
 							flow.cancelVerification();
-							deviceVerificationList.remove(flow.tranId);
+							// deviceVerificationList.remove(flow.tranId);
 							delete flow; 
 						}
 					}
@@ -211,15 +211,15 @@ ApplicationWindow {
 					Layout.alignment: Qt.AlignHCenter
 					Label {
 						font.pixelSize: Qt.application.font.pixelSize * 2
-						text: "1234"
+						text: flow.sasList[0]
 					}
 					Label {
 						font.pixelSize: Qt.application.font.pixelSize * 2
-						text: "1234"
+						text: flow.sasList[1]
 					}
 					Label {
 						font.pixelSize: Qt.application.font.pixelSize * 2
-						text: "1234"
+						text: flow.sasList[2]
 					}
 				}
 
@@ -230,7 +230,7 @@ ApplicationWindow {
 						onClicked: { 
 							dialog.close(); 
 							flow.cancelVerification();
-							deviceVerificationList.remove(flow.tranId);
+							// deviceVerificationList.remove(flow.tranId);
 							delete flow; 
 						}
 					}
@@ -345,7 +345,7 @@ ApplicationWindow {
 							ColumnLayout {
 								id: col
 								anchors.bottom: parent.bottom
-								property var emoji: emojis.mapping[Math.floor(Math.random()*64)]
+								property var emoji: emojis.mapping[flow.sasList[index]]
 								Label {
 									//height: font.pixelSize * 2
 									Layout.alignment: Qt.AlignHCenter
@@ -369,7 +369,7 @@ ApplicationWindow {
 						onClicked: { 
 							dialog.close(); 
 							flow.cancelVerification();
-							deviceVerificationList.remove(flow.tranId);
+							// deviceVerificationList.remove(flow.tranId);
 							delete flow; 
 						}
 					}
@@ -413,7 +413,7 @@ ApplicationWindow {
 						onClicked: { 
 							dialog.close(); 
 							flow.cancelVerification(); 
-							deviceVerificationList.remove(flow.tranId);
+							// deviceVerificationList.remove(flow.tranId);
 							delete flow;
 						}
 					}
@@ -451,7 +451,7 @@ ApplicationWindow {
 						text: "Close"
 						onClicked: {
 							dialog.close()
-							deviceVerificationList.remove(flow.tranId);
+							// deviceVerificationList.remove(flow.tranId);
 							delete flow;
 						}
 					}
@@ -486,7 +486,7 @@ ApplicationWindow {
 						text: "Close"
 						onClicked: {
 							dialog.close()
-							deviceVerificationList.remove(flow.tranId);
+							// deviceVerificationList.remove(flow.tranId);
 							delete flow;
 						}
 					}
@@ -521,7 +521,7 @@ ApplicationWindow {
 						text: "Close"
 						onClicked: {
 							dialog.close()
-							deviceVerificationList.remove(flow.tranId);
+							// deviceVerificationList.remove(flow.tranId);
 							delete flow;
 						}
 					}
diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp
index efb9882bc..607cc2796 100644
--- a/src/DeviceVerificationFlow.cpp
+++ b/src/DeviceVerificationFlow.cpp
@@ -15,32 +15,80 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *)
 {
         timeout = new QTimer(this);
         timeout->setSingleShot(true);
-        if (this->sender == true)
-                this->transaction_id = http::client()->generate_txn_id();
+        this->sas = olm::client()->sas_init();
         connect(timeout, &QTimer::timeout, this, [this]() {
                 emit timedout();
                 this->deleteLater();
         });
+
         connect(ChatPage::instance(),
-                &ChatPage::recievedDeviceVerificationAccept,
-                this,
-                [this](const mtx::events::collections::DeviceEvents &message) {
-                        auto msg =
-                          std::get<mtx::events::DeviceEvent<msgs::KeyVerificationAccept>>(message);
-                        if (msg.content.transaction_id == this->transaction_id) {
-                                std::cout << "Recieved Event Accept" << std::endl;
-                        }
-                });
-        connect(ChatPage::instance(),
-                &ChatPage::recievedDeviceVerificationRequest,
+                &ChatPage::recievedDeviceVerificationStart,
                 this,
                 [this](const mtx::events::collections::DeviceEvents &message) {
                         auto msg =
-                          std::get<mtx::events::DeviceEvent<msgs::KeyVerificationRequest>>(message);
+                          std::get<mtx::events::DeviceEvent<msgs::KeyVerificationStart>>(message);
                         if (msg.content.transaction_id == this->transaction_id) {
-                                std::cout << "Recieved Event Request" << std::endl;
+                                if (std::find(msg.content.key_agreement_protocols.begin(),
+                                              msg.content.key_agreement_protocols.end(),
+                                              "curve25519-hkdf-sha256") !=
+                                      msg.content.key_agreement_protocols.end() &&
+                                    std::find(msg.content.hashes.begin(),
+                                              msg.content.hashes.end(),
+                                              "sha256") != msg.content.hashes.end() &&
+                                    (std::find(msg.content.message_authentication_codes.begin(),
+                                               msg.content.message_authentication_codes.end(),
+                                               "hmac-sha256") !=
+                                       msg.content.message_authentication_codes.end() ||
+                                     std::find(msg.content.message_authentication_codes.begin(),
+                                               msg.content.message_authentication_codes.end(),
+                                               "hkdf-hmac-sha256") !=
+                                       msg.content.message_authentication_codes.end()) &&
+                                    (std::find(msg.content.short_authentication_string.begin(),
+                                               msg.content.short_authentication_string.end(),
+                                               mtx::events::msg::SASMethods::Decimal) !=
+                                       msg.content.short_authentication_string.end() ||
+                                     std::find(msg.content.short_authentication_string.begin(),
+                                               msg.content.short_authentication_string.end(),
+                                               mtx::events::msg::SASMethods::Emoji) !=
+                                       msg.content.short_authentication_string.end())) {
+                                        this->sendVerificationKey(); // Not sure about this maybe
+                                                                     // those optional methods
+                                        this->canonical_json = nlohmann::json(msg);
+                                } else {
+                                        this->cancelVerification();
+                                }
                         }
                 });
+        connect(
+          ChatPage::instance(),
+          &ChatPage::recievedDeviceVerificationAccept,
+          this,
+          [this](const mtx::events::collections::DeviceEvents &message) {
+                  auto msg =
+                    std::get<mtx::events::DeviceEvent<msgs::KeyVerificationAccept>>(message);
+                  if (msg.content.transaction_id == this->transaction_id) {
+                          if ((msg.content.method ==
+                               mtx::events::msg::VerificationMethods::SASv1) &&
+                              (msg.content.key_agreement_protocol == "curve25519-hkdf-sha256") &&
+                              (msg.content.hash == "sha256") &&
+                              ((msg.content.message_authentication_code == "hkdf-hmac-sha256") ||
+                               (msg.content.message_authentication_code == "hmac-sha256"))) {
+                                  this->commitment = msg.content.commitment;
+                                  if (std::find(msg.content.short_authentication_string.begin(),
+                                                msg.content.short_authentication_string.end(),
+                                                mtx::events::msg::SASMethods::Emoji) !=
+                                      msg.content.short_authentication_string.end()) {
+                                          this->method = DeviceVerificationFlow::Method::Emoji;
+                                  } else {
+                                          this->method = DeviceVerificationFlow::Method::Decimal;
+                                  }
+                                  this->mac_method = msg.content.message_authentication_code;
+                                  this->sendVerificationKey();
+                          } else {
+                                  this->cancelVerification();
+                          }
+                  }
+          });
         connect(ChatPage::instance(),
                 &ChatPage::recievedDeviceVerificationCancel,
                 this,
@@ -48,19 +96,55 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *)
                         auto msg =
                           std::get<mtx::events::DeviceEvent<msgs::KeyVerificationCancel>>(message);
                         if (msg.content.transaction_id == this->transaction_id) {
-                                std::cout << "Recieved Event Cancel" << std::endl;
-                        }
-                });
-        connect(ChatPage::instance(),
-                &ChatPage::recievedDeviceVerificationKey,
-                this,
-                [this](const mtx::events::collections::DeviceEvents &message) {
-                        auto msg =
-                          std::get<mtx::events::DeviceEvent<msgs::KeyVerificationKey>>(message);
-                        if (msg.content.transaction_id == this->transaction_id) {
-                                std::cout << "Recieved Event Key" << std::endl;
+                                emit verificationCanceled();
                         }
                 });
+        connect(
+          ChatPage::instance(),
+          &ChatPage::recievedDeviceVerificationKey,
+          this,
+          [this](const mtx::events::collections::DeviceEvents &message) {
+                  auto msg = std::get<mtx::events::DeviceEvent<msgs::KeyVerificationKey>>(message);
+                  if (msg.content.transaction_id == this->transaction_id) {
+                          this->sas->set_their_key(msg.content.key);
+                          std::string info;
+                          if (this->sender == true) {
+                                  info = "MATRIX_KEY_VERIFICATION_SAS|" +
+                                         http::client()->user_id().to_string() + "|" +
+                                         http::client()->device_id() + "|" +
+                                         this->sas->public_key() + "|" +
+                                         this->toClient.to_string() + "|" +
+                                         this->deviceId.toStdString() + "|" + msg.content.key +
+                                         "|" + this->transaction_id;
+                          } else {
+                                  info = "MATRIX_KEY_VERIFICATION_SAS|" +
+                                         this->toClient.to_string() + "|" +
+                                         this->deviceId.toStdString() + "|" + msg.content.key +
+                                         "|" + http::client()->user_id().to_string() + "|" +
+                                         http::client()->device_id() + "|" +
+                                         this->sas->public_key() + "|" + this->transaction_id;
+                          }
+
+                          if (this->method == DeviceVerificationFlow::Method::Emoji) {
+                                  this->sasList = this->sas->generate_bytes_emoji(info);
+                          } else if (this->method == DeviceVerificationFlow::Method::Decimal) {
+                                  this->sasList = this->sas->generate_bytes_decimal(info);
+                          }
+                          if (this->sender == false) {
+                                  emit this->verificationRequestAccepted(this->method);
+                                  this->sendVerificationKey();
+                          } else {
+                                  if (this->commitment ==
+                                      mtx::crypto::bin2base64_unpadded(mtx::crypto::sha256(
+                                        msg.content.key +
+                                        this->canonical_json["content"].dump()))) {
+                                          emit this->verificationRequestAccepted(this->method);
+                                  } else {
+                                          this->cancelVerification();
+                                  }
+                          }
+                  }
+          });
         connect(ChatPage::instance(),
                 &ChatPage::recievedDeviceVerificationMac,
                 this,
@@ -104,6 +188,12 @@ DeviceVerificationFlow::getSender()
         return this->sender;
 }
 
+std::vector<int>
+DeviceVerificationFlow::getSasList()
+{
+        return this->sasList;
+}
+
 void
 DeviceVerificationFlow::setTransactionId(QString transaction_id_)
 {
@@ -133,6 +223,8 @@ void
 DeviceVerificationFlow::setSender(bool sender_)
 {
         this->sender = sender_;
+        if (this->sender == true)
+                this->transaction_id = http::client()->generate_txn_id();
 }
 
 //! accepts a verification
@@ -147,23 +239,26 @@ DeviceVerificationFlow::acceptVerificationRequest()
         req.key_agreement_protocol      = "curve25519-hkdf-sha256";
         req.hash                        = "sha256";
         req.message_authentication_code = "hkdf-hmac-sha256";
-        req.short_authentication_string = {mtx::events::msg::SASMethods::Decimal,
-                                           mtx::events::msg::SASMethods::Emoji};
-        req.commitment                  = "";
-
-        emit this->verificationRequestAccepted(this->method);
+        if (this->method == DeviceVerificationFlow::Method::Emoji)
+                req.short_authentication_string = {mtx::events::msg::SASMethods::Emoji};
+        else if (this->method == DeviceVerificationFlow::Method::Decimal)
+                req.short_authentication_string = {mtx::events::msg::SASMethods::Decimal};
+        req.commitment = mtx::crypto::bin2base64_unpadded(
+          mtx::crypto::sha256(this->sas->public_key() + this->canonical_json.dump()));
 
         body[this->toClient][this->deviceId.toStdString()] = req;
 
+        std::cout << "Accepting the Verification" << std::endl;
+        std::cout << json(body) << std::endl;
+
         http::client()
           ->send_to_device<mtx::events::msg::KeyVerificationAccept,
                            mtx::events::EventType::KeyVerificationAccept>(
-            this->transaction_id, body, [this](mtx::http::RequestErr err) {
+            this->transaction_id, body, [](mtx::http::RequestErr err) {
                     if (err)
                             nhlog::net()->warn("failed to accept verification request: {} {}",
                                                err->matrix_error.error,
                                                static_cast<int>(err->status_code));
-                    emit this->verificationRequestAccepted(rand() % 2 ? Emoji : Decimal);
             });
 }
 //! starts the verification flow
@@ -183,6 +278,7 @@ DeviceVerificationFlow::startVerificationRequest()
                                            mtx::events::msg::SASMethods::Emoji};
 
         body[this->toClient][this->deviceId.toStdString()] = req;
+        this->canonical_json                               = nlohmann::json(req);
 
         http::client()
           ->send_to_device<mtx::events::msg::KeyVerificationStart,
@@ -192,7 +288,6 @@ DeviceVerificationFlow::startVerificationRequest()
                             nhlog::net()->warn("failed to start verification request: {} {}",
                                                err->matrix_error.error,
                                                static_cast<int>(err->status_code));
-                    std::cout << nlohmann::json(body).dump(2) << std::endl;
             });
 }
 //! sends a verification request
@@ -236,6 +331,8 @@ DeviceVerificationFlow::cancelVerification()
 
         body[this->toClient][deviceId.toStdString()] = req;
 
+        emit this->verificationCanceled();
+
         http::client()
           ->send_to_device<mtx::events::msg::KeyVerificationCancel,
                            mtx::events::EventType::KeyVerificationCancel>(
@@ -254,7 +351,7 @@ DeviceVerificationFlow::sendVerificationKey()
         mtx::requests::ToDeviceMessages<mtx::events::msg::KeyVerificationKey> body;
         mtx::events::msg::KeyVerificationKey req;
 
-        req.key            = "";
+        req.key            = this->sas->public_key();
         req.transaction_id = this->transaction_id;
 
         body[this->toClient][deviceId.toStdString()] = req;
diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h
index b651394ba..bddf8edd1 100644
--- a/src/DeviceVerificationFlow.h
+++ b/src/DeviceVerificationFlow.h
@@ -7,6 +7,8 @@
 
 class QTimer;
 
+using sas_ptr = std::unique_ptr<mtx::crypto::SAS>;
+
 class DeviceVerificationFlow : public QObject
 {
         Q_OBJECT
@@ -16,6 +18,7 @@ class DeviceVerificationFlow : public QObject
         Q_PROPERTY(QString userId READ getUserId WRITE setUserId)
         Q_PROPERTY(QString deviceId READ getDeviceId WRITE setDeviceId)
         Q_PROPERTY(Method method READ getMethod WRITE setMethod)
+        Q_PROPERTY(std::vector<int> sasList READ getSasList)
 
 public:
         enum Method
@@ -30,6 +33,7 @@ public:
         QString getUserId();
         QString getDeviceId();
         Method getMethod();
+        std::vector<int> getSasList();
         void setTransactionId(QString transaction_id_);
         bool getSender();
         void setUserId(QString userID);
@@ -37,6 +41,8 @@ public:
         void setMethod(Method method_);
         void setSender(bool sender_);
 
+        nlohmann::json canonical_json;
+
 public slots:
         //! sends a verification request
         void sendVerificationRequest();
@@ -66,6 +72,10 @@ private:
         bool sender;
 
         QTimer *timeout = nullptr;
+        sas_ptr sas;
+        std::string mac_method;
         std::string transaction_id;
+        std::string commitment;
         mtx::identifiers::User toClient;
+        std::vector<int> sasList;
 };
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 22fe4d6db..aaefaed46 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -170,32 +170,44 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettin
                 &ChatPage::decryptSidebarChanged,
                 this,
                 &TimelineViewManager::updateEncryptedDescriptions);
-        connect(dynamic_cast<ChatPage *>(parent),
-                &ChatPage::recievedDeviceVerificationRequest,
-                this,
-                [this](const mtx::events::collections::DeviceEvents &message) {
-                        auto msg =
-                          std::get<mtx::events::DeviceEvent<msgs::KeyVerificationRequest>>(message);
-                        QString tranID   = QString::fromStdString(msg.content.transaction_id);
-                        QString deviceId = QString::fromStdString(msg.content.from_device);
-                        QString userId   = QString::fromStdString(msg.sender);
-                        if (!(this->dvList->exist(tranID))) {
-                                emit newDeviceVerificationRequest(tranID, userId, deviceId);
-                        }
-                });
-        connect(dynamic_cast<ChatPage *>(parent),
-                &ChatPage::recievedDeviceVerificationStart,
-                this,
-                [this](const mtx::events::collections::DeviceEvents &message) {
-                        auto msg =
-                          std::get<mtx::events::DeviceEvent<msgs::KeyVerificationStart>>(message);
-                        QString tranID   = QString::fromStdString(msg.content.transaction_id);
-                        QString deviceId = QString::fromStdString(msg.content.from_device);
-                        QString userId   = QString::fromStdString(msg.sender);
-                        if (!(this->dvList->exist(tranID))) {
-                                emit newDeviceVerificationRequest(tranID, userId, deviceId);
-                        }
-                });
+        connect(
+          dynamic_cast<ChatPage *>(parent),
+          &ChatPage::recievedDeviceVerificationRequest,
+          this,
+          [this](const mtx::events::collections::DeviceEvents &message) {
+                  auto msg =
+                    std::get<mtx::events::DeviceEvent<msgs::KeyVerificationRequest>>(message);
+                  auto flow = new DeviceVerificationFlow(this);
+                  if (!(this->dvList->exist(QString::fromStdString(msg.content.transaction_id)))) {
+                          if (std::find(msg.content.methods.begin(),
+                                        msg.content.methods.end(),
+                                        mtx::events::msg::VerificationMethods::SASv1) !=
+                              msg.content.methods.end()) {
+                                  emit newDeviceVerificationRequest(
+                                    std::move(flow),
+                                    QString::fromStdString(msg.content.transaction_id),
+                                    QString::fromStdString(msg.sender),
+                                    QString::fromStdString(msg.content.from_device));
+                          }
+                  }
+          });
+        connect(
+          dynamic_cast<ChatPage *>(parent),
+          &ChatPage::recievedDeviceVerificationStart,
+          this,
+          [this](const mtx::events::collections::DeviceEvents &message) {
+                  auto msg =
+                    std::get<mtx::events::DeviceEvent<msgs::KeyVerificationStart>>(message);
+                  auto flow            = new DeviceVerificationFlow(this);
+                  flow->canonical_json = nlohmann::json(msg.content);
+                  if (!(this->dvList->exist(QString::fromStdString(msg.content.transaction_id)))) {
+                          emit newDeviceVerificationRequest(
+                            std::move(flow),
+                            QString::fromStdString(msg.content.transaction_id),
+                            QString::fromStdString(msg.sender),
+                            QString::fromStdString(msg.content.from_device));
+                  }
+          });
 }
 
 void
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 709127157..946461f97 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -67,7 +67,10 @@ signals:
         void initialSyncChanged(bool isInitialSync);
         void replyingEventChanged(QString replyingEvent);
         void replyClosed();
-        void newDeviceVerificationRequest(QString transactionId, QString userId, QString deviceId);
+        void newDeviceVerificationRequest(DeviceVerificationFlow *flow,
+                                          QString transactionId,
+                                          QString userId,
+                                          QString deviceId);
 
 public slots:
         void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
-- 
GitLab