From 024eb001698d235b608834fac115d61c341c1199 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Tue, 27 Jul 2021 15:10:13 +1000 Subject: [PATCH] Store the ED25519 key pair upon receiving it --- .../Database/Storage+ClosedGroups.swift | 35 ++++++++++++---- .../MessageReceiver+Handling.swift | 40 ++++++++++++++++--- 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/SessionMessagingKit/Database/Storage+ClosedGroups.swift b/SessionMessagingKit/Database/Storage+ClosedGroups.swift index 05e9fc1a5..cab366f1f 100644 --- a/SessionMessagingKit/Database/Storage+ClosedGroups.swift +++ b/SessionMessagingKit/Database/Storage+ClosedGroups.swift @@ -1,14 +1,12 @@ +import Sodium extension Storage { - + + // MARK: Encryption Key Pairs private static func getClosedGroupEncryptionKeyPairCollection(for groupPublicKey: String) -> String { return "SNClosedGroupEncryptionKeyPairCollection-\(groupPublicKey)" } - - private static let closedGroupPublicKeyCollection = "SNClosedGroupPublicKeyCollection" - private static let closedGroupFormationTimestampCollection = "SNClosedGroupFormationTimestampCollection" - private static let closedGroupZombieMembersCollection = "SNClosedGroupZombieMembersCollection" - + public func getClosedGroupEncryptionKeyPairs(for groupPublicKey: String) -> [ECKeyPair] { let collection = Storage.getClosedGroupEncryptionKeyPairCollection(for: groupPublicKey) var timestampsAndKeyPairs: [(timestamp: Double, keyPair: ECKeyPair)] = [] @@ -25,10 +23,11 @@ extension Storage { return getClosedGroupEncryptionKeyPairs(for: groupPublicKey).last } - public func addClosedGroupEncryptionKeyPair(_ keyPair: ECKeyPair, for groupPublicKey: String, using transaction: Any) { + public func addClosedGroupEncryptionKeyPair(_ keyPair: ECKeyPair, for groupPublicKey: String, using transaction: Any) -> String { let collection = Storage.getClosedGroupEncryptionKeyPairCollection(for: groupPublicKey) let timestamp = String(Date().timeIntervalSince1970) (transaction as! YapDatabaseReadWriteTransaction).setObject(keyPair, forKey: timestamp, inCollection: collection) + return timestamp } public func removeAllClosedGroupEncryptionKeyPairs(for groupPublicKey: String, using transaction: Any) { @@ -36,6 +35,19 @@ extension Storage { (transaction as! YapDatabaseReadWriteTransaction).removeAllObjects(inCollection: collection) } + // MARK: Authentication Key Pairs + private static func getClosedGroupAuthenticationKeyPairCollection(for groupPublicKey: String) -> String { + return "SNClosedGroupAuthenticationKeyPairCollection-\(groupPublicKey)" + } + + public func addClosedGroupAuthenticationKeyPair(_ keyPair: Sign.KeyPair, for groupPublicKey: String, timestamp: String, using transaction: Any) { + let collection = Storage.getClosedGroupAuthenticationKeyPairCollection(for: groupPublicKey) + (transaction as! YapDatabaseReadWriteTransaction).setObject(keyPair, forKey: timestamp, inCollection: collection) + } + + // MARK: Public Keys + private static let closedGroupPublicKeyCollection = "SNClosedGroupPublicKeyCollection" + public func getUserClosedGroupPublicKeys() -> Set { var result: Set = [] Storage.read { transaction in @@ -52,6 +64,9 @@ extension Storage { (transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: groupPublicKey, inCollection: Storage.closedGroupPublicKeyCollection) } + // MARK: Formation Timestamps + private static let closedGroupFormationTimestampCollection = "SNClosedGroupFormationTimestampCollection" + public func getClosedGroupFormationTimestamp(for groupPublicKey: String) -> UInt64? { var result: UInt64? Storage.read { transaction in @@ -64,6 +79,9 @@ extension Storage { (transaction as! YapDatabaseReadWriteTransaction).setObject(timestamp, forKey: groupPublicKey, inCollection: Storage.closedGroupFormationTimestampCollection) } + // MARK: Zombie Members + private static let closedGroupZombieMembersCollection = "SNClosedGroupZombieMembersCollection" + public func getZombieMembers(for groupPublicKey: String) -> Set { var result: Set = [] Storage.read { transaction in @@ -77,7 +95,8 @@ extension Storage { public func setZombieMembers(for groupPublicKey: String, to zombies: Set, using transaction: Any) { (transaction as! YapDatabaseReadWriteTransaction).setObject(zombies, forKey: groupPublicKey, inCollection: Storage.closedGroupZombieMembersCollection) } - + + // MARK: Convenience public func isClosedGroup(_ publicKey: String) -> Bool { getUserClosedGroupPublicKeys().contains(publicKey) } diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index a5cf2c8e7..67d807351 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -1,4 +1,5 @@ import SignalCoreKit +import Sodium extension MessageReceiver { @@ -423,32 +424,61 @@ extension MessageReceiver { } // Find our wrapper and decrypt it if possible guard let wrapper = wrappers.first(where: { $0.publicKey == userPublicKey }), let encryptedX25519KeyPair = wrapper.encryptedX25519KeyPair else { return } + // Handle the X25519 key pair + let timestamp = handleEncryptedX25519KeyPair(encryptedX25519KeyPair, for: groupPublicKey, userKeyPair: userKeyPair, transaction: transaction) + // Handle the ED25519 key pair if needed + if let timestamp = timestamp, let encryptedED25519KeyPair = wrapper.encryptedED25519KeyPair { + handleEncryptedED25519KeyPair(encryptedED25519KeyPair, for: groupPublicKey, timestamp: timestamp, userKeyPair: userKeyPair, transaction: transaction) + } + } + + private static func handleEncryptedX25519KeyPair(_ encryptedX25519KeyPair: Data, for groupPublicKey: String, userKeyPair: ECKeyPair, transaction: Any) -> String? { let plaintext: Data do { plaintext = try MessageReceiver.decryptWithSessionProtocol(ciphertext: encryptedX25519KeyPair, using: userKeyPair).plaintext } catch { - return SNLog("Couldn't decrypt closed group encryption key pair.") + SNLog("Couldn't decrypt closed group encryption key pair."); return nil } // Parse it let proto: SNProtoKeyPair do { proto = try SNProtoKeyPair.parseData(plaintext) } catch { - return SNLog("Couldn't parse closed group encryption key pair.") + SNLog("Couldn't parse closed group encryption key pair."); return nil } let keyPair: ECKeyPair do { keyPair = try ECKeyPair(publicKeyData: proto.publicKey.removing05PrefixIfNeeded(), privateKeyData: proto.privateKey) } catch { - return SNLog("Couldn't parse closed group encryption key pair.") + SNLog("Couldn't parse closed group encryption key pair."); return nil } // Store it if needed let closedGroupEncryptionKeyPairs = Storage.shared.getClosedGroupEncryptionKeyPairs(for: groupPublicKey) guard !closedGroupEncryptionKeyPairs.contains(keyPair) else { - return SNLog("Ignoring duplicate closed group encryption key pair.") + SNLog("Ignoring duplicate closed group encryption key pair."); return nil } - Storage.shared.addClosedGroupEncryptionKeyPair(keyPair, for: groupPublicKey, using: transaction) SNLog("Received a new closed group encryption key pair.") + return Storage.shared.addClosedGroupEncryptionKeyPair(keyPair, for: groupPublicKey, using: transaction) + } + + private static func handleEncryptedED25519KeyPair(_ encryptedED25519KeyPair: Data, for groupPublicKey: String, timestamp: String, userKeyPair: ECKeyPair, transaction: Any) { + let plaintext: Data + do { + plaintext = try MessageReceiver.decryptWithSessionProtocol(ciphertext: encryptedED25519KeyPair, using: userKeyPair).plaintext + } catch { + return SNLog("Couldn't decrypt closed group authentication key pair.") + } + // Parse it + let proto: SNProtoKeyPair + do { + proto = try SNProtoKeyPair.parseData(plaintext) + } catch { + return SNLog("Couldn't parse closed group authentication key pair.") + } + let keyPair = Sign.KeyPair(publicKey: Bytes(proto.publicKey), secretKey: Bytes(proto.privateKey)) + // Store it + SNLog("Received a new closed group authentication key pair.") + return Storage.shared.addClosedGroupAuthenticationKeyPair(keyPair, for: groupPublicKey, timestamp: timestamp, using: transaction) } private static func handleClosedGroupNameChanged(_ message: ClosedGroupControlMessage, using transaction: Any) {