From a9755631e39d382bfc0ebe4df12880a17db1cf93 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Mon, 9 Nov 2020 10:08:57 +1100 Subject: [PATCH] Re-implement Signal protocol encryption --- SessionMessagingKit/Configuration.swift | 2 + .../MessageSender+Encryption.swift | 58 ++++--------------- .../Sending & Receiving/MessageSender.swift | 2 +- SessionMessagingKit/Storage.swift | 3 +- SessionProtocolKit/Meta/SessionProtocolKit.h | 1 + .../Signal/LokiSessionCipher.swift | 2 +- .../Signal/SessionRestorationProtocol.swift | 6 +- Signal.xcodeproj/project.pbxproj | 2 +- 8 files changed, 22 insertions(+), 54 deletions(-) diff --git a/SessionMessagingKit/Configuration.swift b/SessionMessagingKit/Configuration.swift index bc60556ac..d1f251a4d 100644 --- a/SessionMessagingKit/Configuration.swift +++ b/SessionMessagingKit/Configuration.swift @@ -1,6 +1,8 @@ +import SessionProtocolKit public struct Configuration { public let storage: SessionMessagingKitStorageProtocol + public let sessionRestorationImplementation: SessionRestorationProtocol public let pnServerURL: String public let pnServerPublicKey: String diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift b/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift index cd7ab4b0e..1a9fbbf6d 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift @@ -3,55 +3,19 @@ import SessionUtilities internal extension MessageSender { - static func encryptWithSignalProtocol(_ plaintext: Data, for publicKey: String, using transaction: Any) throws -> Data { - + static func encryptWithSignalProtocol(_ plaintext: Data, associatedWith message: Message, for publicKey: String, using transaction: Any) throws -> Data { + let storage = Configuration.shared.storage + let cipher = try SMKSecretSessionCipher(sessionResetImplementation: Configuration.shared.sessionRestorationImplementation, + sessionStore: storage, preKeyStore: storage, signedPreKeyStore: storage, identityStore: storage) + let useFallbackEncryption: Bool = { + if (message is SessionRequest) { return true } + return !Configuration.shared.storage.containsSession(publicKey, deviceId: 1, protocolContext: transaction) + }() + let certificate = Configuration.shared.storage.getSenderCertificate(for: publicKey) + return try cipher.throwswrapped_encryptMessage(recipientPublicKey: publicKey, deviceID: 1, paddedPlaintext: (plaintext as NSData).paddedMessageBody(), + senderCertificate: certificate, protocolContext: transaction, useFallbackSessionCipher: useFallbackEncryption) } -// NSError *error; -// LKSessionResetImplementation *sessionResetImplementation = [LKSessionResetImplementation new]; -// -// SMKSecretSessionCipher *_Nullable secretCipher = -// [[SMKSecretSessionCipher alloc] initWithSessionResetImplementation:sessionResetImplementation -// sessionStore:self.primaryStorage -// preKeyStore:self.primaryStorage -// signedPreKeyStore:self.primaryStorage -// identityStore:self.identityManager -// error:&error]; -// if (error || !secretCipher) { -// OWSRaiseException(@"SecretSessionCipherFailure", @"Can't create secret session cipher."); -// } -// -// // Loki: The way this works is: -// // • Alice sends a session request (i.e. a pre key bundle) to Bob using fallback encryption. -// // • She may send any number of subsequent messages also encrypted using fallback encryption. -// // • When Bob receives the session request, he sets up his Signal cipher session locally and sends back a null message, -// // now encrypted using Signal encryption. -// // • Alice receives this, sets up her Signal cipher session locally, and sends any subsequent messages -// // using Signal encryption. -// -// BOOL shouldUseFallbackEncryption = [LKSessionManagementProtocol shouldUseFallbackEncryptionForMessage:message recipientID:recipientID transaction:transaction]; -// -// if (shouldUseFallbackEncryption) { -// [LKLogger print:@"[Loki] Using fallback encryption"]; -// } else { -// [LKLogger print:@"[Loki] Using Signal Encryption"]; -// } -// -// serializedMessage = [secretCipher throwswrapped_encryptMessageWithRecipientPublicKey:recipientID -// deviceID:@(OWSDevicePrimaryDeviceId).intValue -// paddedPlaintext:plainText.paddedMessageBody -// senderCertificate:messageSend.senderCertificate -// protocolContext:transaction -// useFallbackSessionCipher:shouldUseFallbackEncryption -// error:&error]; -// -// SCKRaiseIfExceptionWrapperError(error); -// if (serializedMessage == nil || error != nil) { -// OWSFailDebug(@"Error while UD encrypting message: %@.", error); -// return nil; -// } -// messageType = TSUnidentifiedSenderMessageType; - static func encryptWithSharedSenderKeys(_ plaintext: Data, for groupPublicKey: String, using transaction: Any) throws -> Data { // 1. ) Encrypt the data with the user's sender key guard let userPublicKey = Configuration.shared.storage.getUserPublicKey() else { diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 81cfa340c..1fac964b7 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -49,7 +49,7 @@ internal enum MessageSender { let ciphertext: Data do { switch destination { - case .contact(let publicKey): ciphertext = try encryptWithSignalProtocol(plaintext, for: publicKey, using: transaction) + case .contact(let publicKey): ciphertext = try encryptWithSignalProtocol(plaintext, associatedWith: message, for: publicKey, using: transaction) case .closedGroup(let groupPublicKey): ciphertext = try encryptWithSharedSenderKeys(plaintext, for: groupPublicKey, using: transaction) case .openGroup(_, _): preconditionFailure() } diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 151c2226a..087fdd1e3 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -1,6 +1,6 @@ import SessionProtocolKit -public protocol SessionMessagingKitStorageProtocol { +public protocol SessionMessagingKitStorageProtocol : SessionStore, PreKeyStore, SignedPreKeyStore, IdentityKeyStore { func with(_ work: (Any) -> Void) func withAsync(_ work: (Any) -> Void, completion: () -> Void) @@ -12,4 +12,5 @@ public protocol SessionMessagingKitStorageProtocol { func persist(_ job: Job, using transaction: Any) func markJobAsSucceeded(_ job: Job, using transaction: Any) func markJobAsFailed(_ job: Job, using transaction: Any) + func getSenderCertificate(for publicKey: String) -> SMKSenderCertificate } diff --git a/SessionProtocolKit/Meta/SessionProtocolKit.h b/SessionProtocolKit/Meta/SessionProtocolKit.h index ff44b9ac7..82c84e815 100644 --- a/SessionProtocolKit/Meta/SessionProtocolKit.h +++ b/SessionProtocolKit/Meta/SessionProtocolKit.h @@ -7,6 +7,7 @@ FOUNDATION_EXPORT const unsigned char SessionProtocolKitVersionString[]; #import #import #import +#import #import #import #import diff --git a/SessionProtocolKit/Signal/LokiSessionCipher.swift b/SessionProtocolKit/Signal/LokiSessionCipher.swift index a3bc7d2c0..03b4ac18c 100644 --- a/SessionProtocolKit/Signal/LokiSessionCipher.swift +++ b/SessionProtocolKit/Signal/LokiSessionCipher.swift @@ -38,7 +38,7 @@ public final class LokiSessionCipher : SessionCipher { // Note that while decrypting our state may change internally let currentState = getCurrentState(protocolContext: protocolContext) if (currentState == nil && whisperMessage.cipherMessageType == .prekey) { - try sessionResetImplementation?.validatePreKeyWhisperMessage(for: recipientID, whisperMessage: whisperMessage, using: protocolContext!) + try sessionResetImplementation?.validatePreKeyWhisperMessage(for: recipientID, preKeyWhisperMessage: whisperMessage as! PreKeyWhisperMessage, using: protocolContext!) } let plainText = try super.decrypt(whisperMessage, protocolContext: protocolContext) handleSessionReset(for: whisperMessage, previousState: currentState, protocolContext: protocolContext!) diff --git a/SessionProtocolKit/Signal/SessionRestorationProtocol.swift b/SessionProtocolKit/Signal/SessionRestorationProtocol.swift index 9e2f93d47..f5518af94 100644 --- a/SessionProtocolKit/Signal/SessionRestorationProtocol.swift +++ b/SessionProtocolKit/Signal/SessionRestorationProtocol.swift @@ -2,7 +2,7 @@ @objc(LKSessionRestorationProtocol) public protocol SessionRestorationProtocol { - func validatePreKeyWhisperMessage(for recipientPublicKey: String, whisperMessage: CipherMessage, using transaction: Any) throws - func getSessionRestorationStatus(for recipientPublicKey: String) -> SessionRestorationStatus - func handleNewSessionAdopted(for recipientPublicKey: String, using transaction: Any) + func validatePreKeyWhisperMessage(for publicKey: String, preKeyWhisperMessage: PreKeyWhisperMessage, using transaction: Any) throws + func getSessionRestorationStatus(for publicKey: String) -> SessionRestorationStatus + func handleNewSessionAdopted(for publicKey: String, using transaction: Any) } diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index f5a98ff93..6b8854330 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -646,7 +646,7 @@ C3A71D5725589FF30043A11F /* SMKCertificateValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4B25589FF20043A11F /* SMKCertificateValidator.swift */; }; C3A71D5825589FF30043A11F /* SMKSecretSessionCipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4C25589FF30043A11F /* SMKSecretSessionCipher.swift */; }; C3A71D5925589FF30043A11F /* SMKUnidentifiedSenderMessageContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4D25589FF30043A11F /* SMKUnidentifiedSenderMessageContent.swift */; }; - C3A71D5A25589FF30043A11F /* NSData+messagePadding.h in Headers */ = {isa = PBXBuildFile; fileRef = C3A71D4E25589FF30043A11F /* NSData+messagePadding.h */; }; + C3A71D5A25589FF30043A11F /* NSData+messagePadding.h in Headers */ = {isa = PBXBuildFile; fileRef = C3A71D4E25589FF30043A11F /* NSData+messagePadding.h */; settings = {ATTRIBUTES = (Public, ); }; }; C3A71D5B25589FF30043A11F /* SMKUnidentifiedSenderMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D4F25589FF30043A11F /* SMKUnidentifiedSenderMessage.swift */; }; C3A71D672558A0170043A11F /* FallbackSessionCipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D642558A0170043A11F /* FallbackSessionCipher.swift */; }; C3A71D682558A0170043A11F /* LokiSessionCipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D652558A0170043A11F /* LokiSessionCipher.swift */; };