From c1ade86a8b10cdd7b4c61f5f41d4517aa25b7c5f Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Sat, 1 Oct 2016 14:42:39 -0400 Subject: [PATCH] New fingerprint format In coordination with Desktop and Android, iOS will be using all-numeric fingerprints, aka "Safety Numbers". Furthermore, the concept of verifying one identity and then the other has been removed. Instead we ask users to exchange a single number, or scan a single QR code. These credentials are built by combining the users identities. // FREEBIE --- .../TSKitiOSTestApp.xcodeproj/project.pbxproj | 15 + protobuf/Makefile | 26 +- protobuf/OWSFingerprintProtos.proto | 18 + src/Contacts/Threads/TSContactThread.m | 8 +- .../TSInvalidIdentityKeyErrorMessage.h | 9 +- .../TSInvalidIdentityKeyErrorMessage.m | 16 +- ...SInvalidIdentityKeyReceivingErrorMessage.h | 5 +- ...SInvalidIdentityKeyReceivingErrorMessage.m | 28 +- .../TSInvalidIdentityKeySendingErrorMessage.h | 9 +- .../TSInvalidIdentityKeySendingErrorMessage.m | 22 +- src/Messages/TSMessagesManager.h | 2 + src/Messages/TSMessagesManager.m | 19 +- src/Security/OWSFingerprint.h | 41 ++ src/Security/OWSFingerprint.m | 299 +++++++++ src/Security/OWSFingerprintProtos.pb.h | 199 ++++++ src/Security/OWSFingerprintProtos.pb.m | 632 ++++++++++++++++++ src/Security/TSFingerprintGenerator.h | 15 - src/Security/TSFingerprintGenerator.m | 37 - src/Storage/TSStorageManager+keyingMaterial.h | 1 + src/Storage/TSStorageManager+keyingMaterial.m | 10 +- src/Util/OWSError.h | 5 +- tests/Messages/TSMessagesManagerTest.m | 35 + tests/Security/OWSFingerprintTest.m | 74 ++ 23 files changed, 1421 insertions(+), 104 deletions(-) create mode 100644 protobuf/OWSFingerprintProtos.proto create mode 100644 src/Security/OWSFingerprint.h create mode 100644 src/Security/OWSFingerprint.m create mode 100644 src/Security/OWSFingerprintProtos.pb.h create mode 100644 src/Security/OWSFingerprintProtos.pb.m delete mode 100644 src/Security/TSFingerprintGenerator.h delete mode 100644 src/Security/TSFingerprintGenerator.m create mode 100644 tests/Security/OWSFingerprintTest.m diff --git a/Example/TSKitiOSTestApp/TSKitiOSTestApp.xcodeproj/project.pbxproj b/Example/TSKitiOSTestApp/TSKitiOSTestApp.xcodeproj/project.pbxproj index 0447848e9..4f55a046c 100644 --- a/Example/TSKitiOSTestApp/TSKitiOSTestApp.xcodeproj/project.pbxproj +++ b/Example/TSKitiOSTestApp/TSKitiOSTestApp.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 45C6A09A1D2F029B007D8AC0 /* TSMessageTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C6A0991D2F029B007D8AC0 /* TSMessageTest.m */; }; 45D7243F1D67899F00E0CA54 /* OWSDeviceProvisionerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45D7243E1D67899F00E0CA54 /* OWSDeviceProvisionerTest.m */; }; 51520592F83F2440F2DE4D67 /* libPods-TSKitiOSTestApp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B8362AB8E280E0F64352F08A /* libPods-TSKitiOSTestApp.a */; }; + 6323E1F7730289398452E5C5 /* OWSFingerprintTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6323E02A33682A8838FE3F27 /* OWSFingerprintTest.m */; }; 6323E339D5B8F4CB77EB3ED4 /* SignalRecipientTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6323E3E540CF763D71DACB59 /* SignalRecipientTest.m */; }; B6273DD61C13A2E500738558 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B6273DD51C13A2E500738558 /* main.m */; }; B6273DD91C13A2E500738558 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B6273DD81C13A2E500738558 /* AppDelegate.m */; }; @@ -63,6 +64,7 @@ 45A856AB1D220BFF0056CD4D /* TSAttributesTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttributesTest.m; sourceTree = ""; }; 45C6A0991D2F029B007D8AC0 /* TSMessageTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSMessageTest.m; path = ../../../tests/Messages/Interactions/TSMessageTest.m; sourceTree = ""; }; 45D7243E1D67899F00E0CA54 /* OWSDeviceProvisionerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDeviceProvisionerTest.m; path = ../../../tests/Devices/OWSDeviceProvisionerTest.m; sourceTree = ""; }; + 6323E02A33682A8838FE3F27 /* OWSFingerprintTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSFingerprintTest.m; path = ../../../tests/Security/OWSFingerprintTest.m; sourceTree = ""; }; 6323E3E540CF763D71DACB59 /* SignalRecipientTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SignalRecipientTest.m; path = ../../tests/Contacts/SignalRecipientTest.m; sourceTree = ""; }; B6273DD11C13A2E500738558 /* TSKitiOSTestApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TSKitiOSTestApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; B6273DD51C13A2E500738558 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; @@ -143,6 +145,14 @@ path = ../../../tests/Util; sourceTree = ""; }; + 454AB2261D89CC6E006325C9 /* Security */ = { + isa = PBXGroup; + children = ( + 6323E02A33682A8838FE3F27 /* OWSFingerprintTest.m */, + ); + name = Security; + sourceTree = ""; + }; 459850BF1D22C6C4006FFEDB /* Contacts */ = { isa = PBXGroup; children = ( @@ -251,6 +261,7 @@ 459850BF1D22C6C4006FFEDB /* Contacts */, 45D7243D1D67894100E0CA54 /* Devices */, 45C6A0971D2F0254007D8AC0 /* Messages */, + 454AB2261D89CC6E006325C9 /* Security */, 45458B6D1CC342B600A02153 /* Storage */, 45458B721CC342B600A02153 /* Util */, B6273DF01C13A2E500738558 /* Info.plist */, @@ -313,6 +324,7 @@ TargetAttributes = { B6273DD01C13A2E500738558 = { CreatedOnToolsVersion = 7.1.1; + DevelopmentTeam = U68MSDN6DR; }; B6273DE91C13A2E500738558 = { CreatedOnToolsVersion = 7.1.1; @@ -483,6 +495,7 @@ 45458B7C1CC342B600A02153 /* MessagePaddingTests.m in Sources */, 45A856AC1D220BFF0056CD4D /* TSAttributesTest.m in Sources */, 6323E339D5B8F4CB77EB3ED4 /* SignalRecipientTest.m in Sources */, + 6323E1F7730289398452E5C5 /* OWSFingerprintTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -603,6 +616,7 @@ baseConfigurationReference = 31DFDA8F9523F5B15EA2376B /* Pods-TSKitiOSTestApp.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = U68MSDN6DR; INFOPLIST_FILE = TSKitiOSTestApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = org.whispersystems.TSKitiOSTestApp; @@ -615,6 +629,7 @@ baseConfigurationReference = 1A50A62A8930EE2BC9B8AC11 /* Pods-TSKitiOSTestApp.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = U68MSDN6DR; INFOPLIST_FILE = TSKitiOSTestApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = org.whispersystems.TSKitiOSTestApp; diff --git a/protobuf/Makefile b/protobuf/Makefile index 0c40bfcf5..33c1f855e 100644 --- a/protobuf/Makefile +++ b/protobuf/Makefile @@ -1,23 +1,23 @@ # Assumes you've installed protobug-objc # see: https://github.com/alexeyxo/protobuf-objc -all: signal_service_proto provisioning_protos - -signal_service_proto: - protoc \ +PROTOC=protoc \ --plugin=/usr/local/bin/proto-gen-objc \ --proto_path="${HOME}/src/WhisperSystems/protobuf-objc/src/compiler/" \ --proto_path="${HOME}/src/WhisperSystems/protobuf-objc/src/compiler/google/protobuf/" \ - --proto_path='./' \ - --objc_out=../src/Messages/ \ + --proto_path='./' + +all: signal_service_proto provisioning_protos fingerprint_protos + +signal_service_proto: OWSSignalServiceProtos.proto + $(PROTOC) --objc_out=../src/Messages/ \ OWSSignalServiceProtos.proto -provisioning_protos: - protoc \ - --plugin=/usr/local/bin/proto-gen-objc \ - --proto_path="${HOME}/src/WhisperSystems/protobuf-objc/src/compiler/" \ - --proto_path="${HOME}/src/WhisperSystems/protobuf-objc/src/compiler/google/protobuf/" \ - --proto_path='./' \ - --objc_out=../src/Devices/ \ +provisioning_protos: OWSProvisioningProtos.proto + $(PROTOC) --objc_out=../src/Devices/ \ OWSProvisioningProtos.proto +fingerprint_protos: OWSFingerprintProtos.proto + $(PROTOC) --objc_out=../src/Security/ \ + OWSFingerprintProtos.proto + diff --git a/protobuf/OWSFingerprintProtos.proto b/protobuf/OWSFingerprintProtos.proto new file mode 100644 index 000000000..79479917b --- /dev/null +++ b/protobuf/OWSFingerprintProtos.proto @@ -0,0 +1,18 @@ +package textsecure; + +option java_package = "org.whispersystems.libaxolotl.fingerprint"; +option java_outer_classname = "FingerprintProtos"; + +import "objectivec-descriptor.proto"; +option (google.protobuf.objectivec_file_options).class_prefix = "OWSFingerprintProtos"; + +message FingerprintData { + optional bytes publicKey = 1; + optional bytes identifier = 2; +} + +message CombinedFingerprint { + optional uint32 version = 1; + optional FingerprintData localFingerprint = 2; + optional FingerprintData remoteFingerprint = 3; +} diff --git a/src/Contacts/Threads/TSContactThread.m b/src/Contacts/Threads/TSContactThread.m index 87d66ba63..ecbfccd67 100644 --- a/src/Contacts/Threads/TSContactThread.m +++ b/src/Contacts/Threads/TSContactThread.m @@ -76,13 +76,7 @@ NS_ASSUME_NONNULL_BEGIN - (NSString *)name { NSString *contactId = [self contactIdentifier]; - NSString *name = [[TextSecureKitEnv sharedEnv].contactsManager nameStringForPhoneIdentifier:contactId]; - - if (!name) { - name = contactId; - } - - return name; + return [[TextSecureKitEnv sharedEnv].contactsManager nameStringForPhoneIdentifier:contactId]; } #if TARGET_OS_IPHONE diff --git a/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.h b/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.h index 44a52f4c6..84588736c 100644 --- a/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.h +++ b/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.h @@ -8,9 +8,16 @@ #import "TSErrorMessage.h" +NS_ASSUME_NONNULL_BEGIN + +@class OWSFingerprint; + @interface TSInvalidIdentityKeyErrorMessage : TSErrorMessage - (void)acceptNewIdentityKey; -- (NSString *)newIdentityFingerprint; +- (NSData *)newIdentityKey; +- (NSString *)theirSignalId; @end + +NS_ASSUME_NONNULL_END diff --git a/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.m b/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.m index b53ea3c39..556e53b31 100644 --- a/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.m +++ b/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.m @@ -8,15 +8,27 @@ #import "TSInvalidIdentityKeyErrorMessage.h" +NS_ASSUME_NONNULL_BEGIN + @implementation TSInvalidIdentityKeyErrorMessage -- (void)acceptNewIdentityKey { +- (void)acceptNewIdentityKey +{ NSAssert(NO, @"Method needs to be implemented in subclasses of TSInvalidIdentityKeyErrorMessage."); } -- (NSString *)newIdentityFingerprint + +- (NSString *)newIdentityKey +{ + NSAssert(NO, @"Method needs to be implemented in subclasses of TSInvalidIdentityKeyErrorMessage."); + return nil; +} + +- (NSString *)theirSignalId { NSAssert(NO, @"Method needs to be implemented in subclasses of TSInvalidIdentityKeyErrorMessage."); return nil; } @end + +NS_ASSUME_NONNULL_END diff --git a/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.h b/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.h index b9f81c3a9..20a33f8e3 100644 --- a/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.h +++ b/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.h @@ -8,10 +8,13 @@ #import "TSInvalidIdentityKeyErrorMessage.h" +NS_ASSUME_NONNULL_BEGIN + @interface TSInvalidIdentityKeyReceivingErrorMessage : TSInvalidIdentityKeyErrorMessage + (instancetype)untrustedKeyWithEnvelope:(OWSSignalServiceProtosEnvelope *)envelope withTransaction:(YapDatabaseReadWriteTransaction *)transaction; -- (NSData *)newIdentityKey; @end + +NS_ASSUME_NONNULL_END diff --git a/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m b/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m index 0aed655d6..a2354377a 100644 --- a/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m +++ b/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m @@ -2,10 +2,10 @@ // Copyright (c) 2014 Open Whisper Systems. All rights reserved. #import "TSInvalidIdentityKeyReceivingErrorMessage.h" +#import "OWSFingerprint.h" #import "TSContactThread.h" #import "TSDatabaseView.h" #import "TSErrorMessage_privateConstructor.h" -#import "TSFingerprintGenerator.h" #import "TSMessagesManager.h" #import "TSStorageManager+IdentityKeyStore.h" #import "TSStorageManager.h" @@ -14,6 +14,14 @@ #import #import +NS_ASSUME_NONNULL_BEGIN + +@interface TSInvalidIdentityKeyReceivingErrorMessage () + +@property (nonatomic, readonly, copy) NSString *authorId; + +@end + @implementation TSInvalidIdentityKeyReceivingErrorMessage { // Not using a property declaration in order to exclude from DB serialization OWSSignalServiceProtosEnvelope *_envelope; @@ -29,20 +37,21 @@ TSInvalidIdentityKeyReceivingErrorMessage *errorMessage = [[self alloc] initForUnknownIdentityKeyWithTimestamp:envelope.timestamp inThread:contactThread - incomingEnvelopeData:envelope.data]; + incomingEnvelope:envelope]; return errorMessage; } - (instancetype)initForUnknownIdentityKeyWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread - incomingEnvelopeData:(NSData *)envelopeData + incomingEnvelope:(OWSSignalServiceProtosEnvelope *)envelope { self = [self initWithTimestamp:timestamp inThread:thread failedMessageType:TSErrorMessageWrongTrustedIdentityKey]; if (!self) { return self; } - _envelopeData = envelopeData; + _envelopeData = envelope.data; + _authorId = envelope.source; return self; } @@ -108,9 +117,16 @@ return [message.identityKey removeKeyType]; } -- (NSString *)newIdentityFingerprint +- (NSString *)theirSignalId { - return [TSFingerprintGenerator getFingerprintForDisplay:[self newIdentityKey]]; + if (self.authorId) { + return self.authorId; + } else { + // for existing messages before we were storing author id. + return self.envelope.source; + } } @end + +NS_ASSUME_NONNULL_END diff --git a/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.h b/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.h index e52965021..d7e6ec6b2 100644 --- a/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.h +++ b/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.h @@ -7,9 +7,12 @@ // #import "TSInvalidIdentityKeyErrorMessage.h" -#import "TSOutgoingMessage.h" + +NS_ASSUME_NONNULL_BEGIN @class PreKeyBundle; +@class TSOutgoingMessage; +@class TSThread; @interface TSInvalidIdentityKeySendingErrorMessage : TSInvalidIdentityKeyErrorMessage @@ -22,6 +25,8 @@ preKeyBundle:(PreKeyBundle *)preKeyBundle withTransaction:(YapDatabaseReadWriteTransaction *)transaction; -- (NSString *)recipientId; +@property (nonatomic, readonly) NSString *recipientId; @end + +NS_ASSUME_NONNULL_END diff --git a/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m b/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m index 2cba98885..3e67b5f6b 100644 --- a/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m +++ b/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m @@ -2,20 +2,21 @@ // Copyright (c) 2015 Open Whisper Systems. All rights reserved. #import "TSInvalidIdentityKeySendingErrorMessage.h" +#import "OWSFingerprint.h" #import "PreKeyBundle+jsonDict.h" #import "SignalRecipient.h" #import "TSContactThread.h" #import "TSErrorMessage_privateConstructor.h" -#import "TSFingerprintGenerator.h" #import "TSMessagesManager+sendMessages.h" #import "TSOutgoingMessage.h" #import "TSStorageManager+IdentityKeyStore.h" #import +NS_ASSUME_NONNULL_BEGIN + @interface TSInvalidIdentityKeySendingErrorMessage () @property (nonatomic, readonly) PreKeyBundle *preKeyBundle; -@property (nonatomic, readonly) NSString *recipientId; @property (nonatomic, readonly) NSString *messageId; @end @@ -55,9 +56,9 @@ - (void)acceptNewIdentityKey { - [[TSStorageManager sharedManager] saveRemoteIdentity:[self newKey] recipientId:self.recipientId]; + [[TSStorageManager sharedManager] saveRemoteIdentity:self.newIdentityKey recipientId:self.recipientId]; - __block TSOutgoingMessage *message; + __block TSOutgoingMessage *_Nullable message; __block TSThread *thread; __block SignalRecipient *recipient; @@ -89,15 +90,16 @@ } } -- (NSString *)newIdentityFingerprint +- (NSData *)newIdentityKey { - NSData *identityKey = [self newKey]; - - return [TSFingerprintGenerator getFingerprintForDisplay:identityKey]; + return [self.preKeyBundle.identityKey removeKeyType]; } -- (NSData *)newKey { - return [self.preKeyBundle.identityKey removeKeyType]; +- (NSString *)theirSignalId +{ + return self.recipientId; } @end + +NS_ASSUME_NONNULL_END diff --git a/src/Messages/TSMessagesManager.h b/src/Messages/TSMessagesManager.h index a9b6cc740..10120c10d 100644 --- a/src/Messages/TSMessagesManager.h +++ b/src/Messages/TSMessagesManager.h @@ -11,11 +11,13 @@ @class OWSSignalServiceProtosEnvelope; @class OWSSignalServiceProtosDataMessage; @class ContactsUpdater; +@protocol ContactsManagerProtocol; @interface TSMessagesManager : NSObject - (instancetype)initWithNetworkManager:(TSNetworkManager *)networkManager dbConnection:(YapDatabaseConnection *)dbConnection + contactsManager:(id)contactsManager contactsUpdater:(ContactsUpdater *)contactsUpdater NS_DESIGNATED_INITIALIZER; + (instancetype)sharedManager; diff --git a/src/Messages/TSMessagesManager.m b/src/Messages/TSMessagesManager.m index 6956b3ea6..525ca2cc8 100644 --- a/src/Messages/TSMessagesManager.m +++ b/src/Messages/TSMessagesManager.m @@ -26,6 +26,12 @@ #import #import +@interface TSMessagesManager () + +@property (nonatomic, readonly) id contactsManager; + +@end + @implementation TSMessagesManager + (instancetype)sharedManager { @@ -41,11 +47,14 @@ { return [self initWithNetworkManager:[TSNetworkManager sharedManager] dbConnection:[TSStorageManager sharedManager].newDatabaseConnection + contactsManager:[TextSecureKitEnv sharedEnv].contactsManager contactsUpdater:[ContactsUpdater sharedUpdater]]; + } - (instancetype)initWithNetworkManager:(TSNetworkManager *)networkManager dbConnection:(YapDatabaseConnection *)dbConnection + contactsManager:(id)contactsManager contactsUpdater:(ContactsUpdater *)contactsUpdater { self = [super init]; @@ -56,6 +65,7 @@ _networkManager = networkManager; _dbConnection = dbConnection; + _contactsManager = contactsManager; _contactsUpdater = contactsUpdater; return self; @@ -257,7 +267,7 @@ DDLogInfo(@"Received request `Contacts` syncMessage."); OWSSyncContactsMessage *syncContactsMessage = - [[OWSSyncContactsMessage alloc] initWithContactsManager:[TextSecureKitEnv sharedEnv].contactsManager]; + [[OWSSyncContactsMessage alloc] initWithContactsManager:self.contactsManager]; [self sendTemporaryAttachment:[syncContactsMessage buildPlainTextAttachmentData] contentType:OWSMimeTypeApplicationOctetStream @@ -378,12 +388,7 @@ messageType:TSInfoMessageTypeGroupUpdate customMessage:updateGroupInfo] saveWithTransaction:transaction]; } else if (dataMessage.group.type == OWSSignalServiceProtosGroupContextTypeQuit) { - NSString *nameString = - [[TextSecureKitEnv sharedEnv].contactsManager nameStringForPhoneIdentifier:envelope.source]; - - if (!nameString) { - nameString = envelope.source; - } + NSString *nameString = [self.contactsManager nameStringForPhoneIdentifier:envelope.source]; NSString *updateGroupInfo = [NSString stringWithFormat:NSLocalizedString(@"GROUP_MEMBER_LEFT", @""), nameString]; diff --git a/src/Security/OWSFingerprint.h b/src/Security/OWSFingerprint.h new file mode 100644 index 000000000..0a833a004 --- /dev/null +++ b/src/Security/OWSFingerprint.h @@ -0,0 +1,41 @@ +// Created by Michael Kirk on 9/14/16. +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +NS_ASSUME_NONNULL_BEGIN + +@class UIImage; + +@interface OWSFingerprint : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithMyStableId:(NSString *)myStableId + myIdentityKey:(NSData *)myIdentityKeyWithoutKeyType + theirStableId:(NSString *)theirStableId + theirIdentityKey:(NSData *)theirIdentityKeyWithoutKeyType + hashIterations:(uint32_t)hashIterations NS_DESIGNATED_INITIALIZER; + ++ (instancetype)fingerprintWithMyStableId:(NSString *)myStableId + myIdentityKey:(NSData *)myIdentityKeyWithoutKeyType + theirStableId:(NSString *)theirStableId + theirIdentityKey:(NSData *)theirIdentityKeyWithoutKeyType + hashIterations:(uint32_t)hashIterations; + ++ (instancetype)fingerprintWithMyStableId:(NSString *)myStableId + myIdentityKey:(NSData *)myIdentityKeyWithoutKeyType + theirStableId:(NSString *)theirStableId + theirIdentityKey:(NSData *)theirIdentityKeyWithoutKeyType; + +- (BOOL)matchesCombinedFingerprintData:(NSData *)combinedFingerprintData error:(NSError **)error; + +@property (nonatomic, readonly) NSData *myStableIdData; +@property (nonatomic, readonly) NSData *myIdentityKey; +@property (nonatomic, readonly) NSString *theirStableId; +@property (nonatomic, readonly) NSData *theirStableIdData; +@property (nonatomic, readonly) NSData *theirIdentityKey; +@property (nonatomic, readonly) NSString *displayableText; +@property (nonatomic, readonly) UIImage *image; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/Security/OWSFingerprint.m b/src/Security/OWSFingerprint.m new file mode 100644 index 000000000..e845081dc --- /dev/null +++ b/src/Security/OWSFingerprint.m @@ -0,0 +1,299 @@ +// Created by Michael Kirk on 9/14/16. +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +#import "OWSFingerprint.h" +#import "NSData+Base64.h" +#import "OWSError.h" +#import "OWSFingerprintProtos.pb.h" +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +static uint32_t const OWSFingerprintVersion = 0; +static uint32_t const OWSFingerprintDefaultHashIterations = 5200; + +@interface OWSFingerprint () + +@property (nonatomic, readonly) NSUInteger hashIterations; +@property (nonatomic, readonly) NSString *text; + +@end + +@implementation OWSFingerprint + +- (instancetype)initWithMyStableId:(NSString *)myStableId + myIdentityKey:(NSData *)myIdentityKeyWithoutKeyType + theirStableId:(NSString *)theirStableId + theirIdentityKey:(NSData *)theirIdentityKeyWithoutKeyType + hashIterations:(uint32_t)hashIterations +{ + self = [super init]; + if (!self) { + return self; + } + + _myStableIdData = [myStableId dataUsingEncoding:NSUTF8StringEncoding]; + _myIdentityKey = [myIdentityKeyWithoutKeyType prependKeyType]; + _theirStableId = theirStableId; + _theirStableIdData = [theirStableId dataUsingEncoding:NSUTF8StringEncoding]; + _theirIdentityKey = [theirIdentityKeyWithoutKeyType prependKeyType]; + _hashIterations = hashIterations; + _text = [self generateText]; + _image = [self generateImage]; + + return self; +} + ++ (instancetype)fingerprintWithMyStableId:(NSString *)myStableId + myIdentityKey:(NSData *)myIdentityKeyWithoutKeyType + theirStableId:(NSString *)theirStableId + theirIdentityKey:(NSData *)theirIdentityKeyWithoutKeyType + hashIterations:(uint32_t)hashIterations +{ + return [[self alloc] initWithMyStableId:myStableId + myIdentityKey:myIdentityKeyWithoutKeyType + theirStableId:theirStableId + theirIdentityKey:theirIdentityKeyWithoutKeyType + hashIterations:hashIterations]; +} + ++ (instancetype)fingerprintWithMyStableId:(NSString *)myStableId + myIdentityKey:(NSData *)myIdentityKeyWithoutKeyType + theirStableId:(NSString *)theirStableId + theirIdentityKey:(NSData *)theirIdentityKeyWithoutKeyType +{ + return [[self alloc] initWithMyStableId:myStableId + myIdentityKey:myIdentityKeyWithoutKeyType + theirStableId:theirStableId + theirIdentityKey:theirIdentityKeyWithoutKeyType + hashIterations:OWSFingerprintDefaultHashIterations]; +} + +- (BOOL)matchesCombinedFingerprintData:(NSData *)data error:(NSError **)error +{ + OWSFingerprintProtosCombinedFingerprint *combinedFingerprint; + @try { + combinedFingerprint = [OWSFingerprintProtosCombinedFingerprint parseFromData:data]; + } @catch (NSException *exception) { + if ([exception.name isEqualToString:@"InvalidProtocolBuffer"]) { + NSString *description = NSLocalizedString(@"PRIVACY_VERIFICATION_FAILURE_INVALID_QRCODE", @"alert body"); + *error = OWSErrorWithCodeDescription(OWSErrorCodePrivacyVerificationFailure, description); + return NO; + } else { + // Sync log in case we bail. + NSLog(@"%@ parsing QRCode data failed with error: %@", self.tag, exception); + @throw exception; + } + } + + if (combinedFingerprint.version < OWSFingerprintVersion) { + DDLogWarn(@"%@ Verification failed. We're running an old version.", self.tag); + NSString *description + = NSLocalizedString(@"PRIVACY_VERIFICATION_FAILED_WITH_OLD_REMOTE_VERSION", @"alert body"); + *error = OWSErrorWithCodeDescription(OWSErrorCodePrivacyVerificationFailure, description); + return NO; + } + + if (combinedFingerprint.version > OWSFingerprintVersion) { + DDLogWarn(@"%@ Verification failed. They're running an old version.", self.tag); + NSString *description = NSLocalizedString(@"PRIVACY_VERIFICATION_FAILED_WITH_OLD_LOCAL_VERSION", @"alert body"); + *error = OWSErrorWithCodeDescription(OWSErrorCodePrivacyVerificationFailure, description); + return NO; + } + + // Their local is *our* remote. + OWSFingerprintProtosFingerprintData *localFingerprint = combinedFingerprint.remoteFingerprint; + OWSFingerprintProtosFingerprintData *remoteFingerprint = combinedFingerprint.localFingerprint; + + if (![remoteFingerprint.identifier isEqual:self.theirStableIdData]) { + DDLogWarn(@"%@ Verification failed. We're expecting a different contact.", self.tag); + NSString *errorFormat = NSLocalizedString(@"PRIVACY_VERIFICATION_FAILED_WITH_MISMATCHED_REMOTE_IDENTIFIER", + @"Alert body {{expected phone number}}, {{actual phone number we found}}"); + NSString *expected = [[NSString alloc] initWithData:self.theirStableIdData encoding:NSUTF8StringEncoding]; + NSString *actual = [[NSString alloc] initWithData:remoteFingerprint.identifier encoding:NSUTF8StringEncoding]; + NSString *description = [NSString stringWithFormat:errorFormat, expected, actual]; + + *error = OWSErrorWithCodeDescription(OWSErrorCodePrivacyVerificationFailure, description); + return NO; + } + + if (![localFingerprint.identifier isEqual:self.myStableIdData]) { + DDLogWarn(@"%@ Verification failed. They presented the wrong fingerprint.", self.tag); + NSString *errorFormat = NSLocalizedString(@"PRIVACY_VERIFICATION_FAILED_WITH_MISMATCHED_LOCAL_IDENTIFIER", + @"Alert body {{expected phone number}}, {{actual phone number we found}}"); + NSString *expected = [[NSString alloc] initWithData:self.myStableIdData encoding:NSUTF8StringEncoding]; + NSString *actual = [[NSString alloc] initWithData:localFingerprint.identifier encoding:NSUTF8StringEncoding]; + NSString *description = [NSString stringWithFormat:errorFormat, expected, actual]; + + *error = OWSErrorWithCodeDescription(OWSErrorCodePrivacyVerificationFailure, description); + return NO; + } + + if (![localFingerprint.publicKey isEqual:self.myIdentityKey]) { + DDLogWarn(@"%@ Verification failed. They have the wrong key for us", self.tag); + NSString *description = NSLocalizedString(@"PRIVACY_VERIFICATION_FAILED_WITH_MISMATCHED_KEYS", @"Alert body"); + *error = OWSErrorWithCodeDescription(OWSErrorCodePrivacyVerificationFailure, description); + return NO; + } + + if (![remoteFingerprint.publicKey isEqual:self.theirIdentityKey]) { + DDLogWarn(@"%@ Verification failed. We have the wrong key for them", self.tag); + NSString *description = NSLocalizedString(@"PRIVACY_VERIFICATION_FAILED_WITH_MISMATCHED_KEYS", @"Alert body"); + *error = OWSErrorWithCodeDescription(OWSErrorCodePrivacyVerificationFailure, description); + return NO; + } + + DDLogWarn(@"%@ Verification Succeeded.", self.tag); + return YES; +} + + +- (NSString *)generateText +{ + NSString *myDisplayString = [self stringForStableId:self.myStableIdData publicKey:self.myIdentityKey]; + NSString *theirDisplayString = [self stringForStableId:self.theirStableIdData publicKey:self.theirIdentityKey]; + + if ([theirDisplayString compare:myDisplayString] == NSOrderedAscending) { + return [NSString stringWithFormat:@"%@%@", theirDisplayString, myDisplayString]; + } else { + return [NSString stringWithFormat:@"%@%@", myDisplayString, theirDisplayString]; + } +} + +- (NSString *)displayableText +{ + NSString *input = self.text; + + NSMutableArray *chunks = [NSMutableArray new]; + for (uint i = 0; i < input.length / 5; i++) { + NSString *nextChunk = [input substringWithRange:NSMakeRange(i * 5, 5)]; + [chunks addObject:nextChunk]; + } + return [chunks componentsJoinedByString:@" "]; +} + + +- (NSData *)dataFromShort:(uint32_t)aShort +{ + uint8_t bytes[] = { + ((uint8_t)(aShort & 0xFF00) >> 8), + (uint8_t)(aShort & 0x00FF) + }; + + return [NSData dataWithBytes:bytes length:2]; +} + +/** + * An identifier for a mutable public key, belonging to an immutable identifier (stableId). + * + * This method is intended to be somewhat expensive to produce in order to be brute force adverse. + * + * @param stableId + * Immutable global identifier e.g. Signal Identifier, an e164 formatted phone number encoded as UTF-8 data + * @param publicKey + * The current public key for + * @return + * All-number textual representation + */ +- (NSString *)stringForStableId:(NSData *)stableIdData publicKey:(NSData *)publicKey +{ + NSData *versionData = [self dataFromShort:OWSFingerprintVersion]; + NSMutableData *hash = [NSMutableData dataWithData:versionData]; + [hash appendData:publicKey]; + [hash appendData:stableIdData]; + + uint8_t digest[CC_SHA512_DIGEST_LENGTH]; + for (int i = 0; i < self.hashIterations; i++) { + [hash appendData:publicKey]; + CC_SHA512(hash.bytes, (unsigned int)hash.length, digest); + // TODO get rid of this loop-allocation + hash = [NSMutableData dataWithBytes:digest length:CC_SHA512_DIGEST_LENGTH]; + } + + return [NSString stringWithFormat:@"%@%@%@%@%@%@", + [self encodedChunkFromData:hash offset:0], + [self encodedChunkFromData:hash offset:5], + [self encodedChunkFromData:hash offset:10], + [self encodedChunkFromData:hash offset:15], + [self encodedChunkFromData:hash offset:20], + [self encodedChunkFromData:hash offset:25]]; +} + +- (NSString *)encodedChunkFromData:(NSData *)data offset:(uint)offset +{ + uint8_t fiveBytes[5]; + [data getBytes:fiveBytes range:NSMakeRange(offset, 5)]; + + int chunk = [self uint64From5Bytes:fiveBytes] % 100000; + return [NSString stringWithFormat:@"%05d", chunk]; +} + +- (int64_t)uint64From5Bytes:(uint8_t[])bytes +{ + int64_t result = ((bytes[0] & 0xffLL) << 32) | + ((bytes[1] & 0xffLL) << 24) | + ((bytes[2] & 0xffLL) << 16) | + ((bytes[3] & 0xffLL) << 8) | + ((bytes[4] & 0xffLL)); + + return result; +} + +- (nullable UIImage *)generateImage +{ + OWSFingerprintProtosCombinedFingerprintBuilder *combinedFingerprintBuilder = + [OWSFingerprintProtosCombinedFingerprintBuilder new]; + + [combinedFingerprintBuilder setVersion:OWSFingerprintVersion]; + + OWSFingerprintProtosFingerprintDataBuilder *remoteFingerprintDataBuilder = + [OWSFingerprintProtosFingerprintDataBuilder new]; + [remoteFingerprintDataBuilder setPublicKey:self.theirIdentityKey]; + [remoteFingerprintDataBuilder setIdentifier:self.theirStableIdData]; + [combinedFingerprintBuilder setRemoteFingerprintBuilder:remoteFingerprintDataBuilder]; + + OWSFingerprintProtosFingerprintDataBuilder *localFingerprintDataBuilder = + [OWSFingerprintProtosFingerprintDataBuilder new]; + [localFingerprintDataBuilder setPublicKey:self.myIdentityKey]; + [localFingerprintDataBuilder setIdentifier:self.myStableIdData]; + [combinedFingerprintBuilder setLocalFingerprintBuilder:localFingerprintDataBuilder]; + + // Build ByteMode QR (Latin-1 encodable data) + NSData *fingerprintData = [combinedFingerprintBuilder build].data; + DDLogDebug(@"%@ Building fingerprint with data: %@", self.tag, fingerprintData); + + CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; + [filter setDefaults]; + [filter setValue:fingerprintData forKey:@"inputMessage"]; + + CIImage *ciImage = [filter outputImage]; + if (!ciImage) { + DDLogError(@"%@ Failed to create QR image from fingerprint text: %@", self.tag, self.text); + return nil; + } + + // UIImages backed by a CIImage won't render without antialiasing, so we convert the backign image to a CGImage, + // which can be scaled crisply. + CIContext *context = [CIContext contextWithOptions:nil]; + CGImageRef cgImage = [context createCGImage:ciImage fromRect:ciImage.extent]; + UIImage *qrImage = [UIImage imageWithCGImage:cgImage]; + CGImageRelease(cgImage); + + return qrImage; +} + ++ (NSString *)tag +{ + return [NSString stringWithFormat:@"[%@]", self.class]; +} + +- (NSString *)tag +{ + return self.class.tag; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/Security/OWSFingerprintProtos.pb.h b/src/Security/OWSFingerprintProtos.pb.h new file mode 100644 index 000000000..c4c0a93b3 --- /dev/null +++ b/src/Security/OWSFingerprintProtos.pb.h @@ -0,0 +1,199 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! + +#import + +// @@protoc_insertion_point(imports) + +@class OWSFingerprintProtosCombinedFingerprint; +@class OWSFingerprintProtosCombinedFingerprintBuilder; +@class OWSFingerprintProtosFingerprintData; +@class OWSFingerprintProtosFingerprintDataBuilder; +@class ObjectiveCFileOptions; +@class ObjectiveCFileOptionsBuilder; +@class PBDescriptorProto; +@class PBDescriptorProtoBuilder; +@class PBDescriptorProtoExtensionRange; +@class PBDescriptorProtoExtensionRangeBuilder; +@class PBEnumDescriptorProto; +@class PBEnumDescriptorProtoBuilder; +@class PBEnumOptions; +@class PBEnumOptionsBuilder; +@class PBEnumValueDescriptorProto; +@class PBEnumValueDescriptorProtoBuilder; +@class PBEnumValueOptions; +@class PBEnumValueOptionsBuilder; +@class PBFieldDescriptorProto; +@class PBFieldDescriptorProtoBuilder; +@class PBFieldOptions; +@class PBFieldOptionsBuilder; +@class PBFileDescriptorProto; +@class PBFileDescriptorProtoBuilder; +@class PBFileDescriptorSet; +@class PBFileDescriptorSetBuilder; +@class PBFileOptions; +@class PBFileOptionsBuilder; +@class PBMessageOptions; +@class PBMessageOptionsBuilder; +@class PBMethodDescriptorProto; +@class PBMethodDescriptorProtoBuilder; +@class PBMethodOptions; +@class PBMethodOptionsBuilder; +@class PBOneofDescriptorProto; +@class PBOneofDescriptorProtoBuilder; +@class PBServiceDescriptorProto; +@class PBServiceDescriptorProtoBuilder; +@class PBServiceOptions; +@class PBServiceOptionsBuilder; +@class PBSourceCodeInfo; +@class PBSourceCodeInfoBuilder; +@class PBSourceCodeInfoLocation; +@class PBSourceCodeInfoLocationBuilder; +@class PBUninterpretedOption; +@class PBUninterpretedOptionBuilder; +@class PBUninterpretedOptionNamePart; +@class PBUninterpretedOptionNamePartBuilder; + + + +@interface OWSFingerprintProtosOwsfingerprintProtosRoot : NSObject { +} ++ (PBExtensionRegistry*) extensionRegistry; ++ (void) registerAllExtensions:(PBMutableExtensionRegistry*) registry; +@end + +#define FingerprintData_publicKey @"publicKey" +#define FingerprintData_identifier @"identifier" +@interface OWSFingerprintProtosFingerprintData : PBGeneratedMessage { +@private + BOOL hasPublicKey_:1; + BOOL hasIdentifier_:1; + NSData* publicKey; + NSData* identifier; +} +- (BOOL) hasPublicKey; +- (BOOL) hasIdentifier; +@property (readonly, strong) NSData* publicKey; +@property (readonly, strong) NSData* identifier; + ++ (instancetype) defaultInstance; +- (instancetype) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (OWSFingerprintProtosFingerprintDataBuilder*) builder; ++ (OWSFingerprintProtosFingerprintDataBuilder*) builder; ++ (OWSFingerprintProtosFingerprintDataBuilder*) builderWithPrototype:(OWSFingerprintProtosFingerprintData*) prototype; +- (OWSFingerprintProtosFingerprintDataBuilder*) toBuilder; + ++ (OWSFingerprintProtosFingerprintData*) parseFromData:(NSData*) data; ++ (OWSFingerprintProtosFingerprintData*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (OWSFingerprintProtosFingerprintData*) parseFromInputStream:(NSInputStream*) input; ++ (OWSFingerprintProtosFingerprintData*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (OWSFingerprintProtosFingerprintData*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (OWSFingerprintProtosFingerprintData*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface OWSFingerprintProtosFingerprintDataBuilder : PBGeneratedMessageBuilder { +@private + OWSFingerprintProtosFingerprintData* resultFingerprintData; +} + +- (OWSFingerprintProtosFingerprintData*) defaultInstance; + +- (OWSFingerprintProtosFingerprintDataBuilder*) clear; +- (OWSFingerprintProtosFingerprintDataBuilder*) clone; + +- (OWSFingerprintProtosFingerprintData*) build; +- (OWSFingerprintProtosFingerprintData*) buildPartial; + +- (OWSFingerprintProtosFingerprintDataBuilder*) mergeFrom:(OWSFingerprintProtosFingerprintData*) other; +- (OWSFingerprintProtosFingerprintDataBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (OWSFingerprintProtosFingerprintDataBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasPublicKey; +- (NSData*) publicKey; +- (OWSFingerprintProtosFingerprintDataBuilder*) setPublicKey:(NSData*) value; +- (OWSFingerprintProtosFingerprintDataBuilder*) clearPublicKey; + +- (BOOL) hasIdentifier; +- (NSData*) identifier; +- (OWSFingerprintProtosFingerprintDataBuilder*) setIdentifier:(NSData*) value; +- (OWSFingerprintProtosFingerprintDataBuilder*) clearIdentifier; +@end + +#define CombinedFingerprint_version @"version" +#define CombinedFingerprint_localFingerprint @"localFingerprint" +#define CombinedFingerprint_remoteFingerprint @"remoteFingerprint" +@interface OWSFingerprintProtosCombinedFingerprint : PBGeneratedMessage { +@private + BOOL hasLocalFingerprint_:1; + BOOL hasRemoteFingerprint_:1; + BOOL hasVersion_:1; + OWSFingerprintProtosFingerprintData* localFingerprint; + OWSFingerprintProtosFingerprintData* remoteFingerprint; + UInt32 version; +} +- (BOOL) hasVersion; +- (BOOL) hasLocalFingerprint; +- (BOOL) hasRemoteFingerprint; +@property (readonly) UInt32 version; +@property (readonly, strong) OWSFingerprintProtosFingerprintData* localFingerprint; +@property (readonly, strong) OWSFingerprintProtosFingerprintData* remoteFingerprint; + ++ (instancetype) defaultInstance; +- (instancetype) defaultInstance; + +- (BOOL) isInitialized; +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) builder; ++ (OWSFingerprintProtosCombinedFingerprintBuilder*) builder; ++ (OWSFingerprintProtosCombinedFingerprintBuilder*) builderWithPrototype:(OWSFingerprintProtosCombinedFingerprint*) prototype; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) toBuilder; + ++ (OWSFingerprintProtosCombinedFingerprint*) parseFromData:(NSData*) data; ++ (OWSFingerprintProtosCombinedFingerprint*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (OWSFingerprintProtosCombinedFingerprint*) parseFromInputStream:(NSInputStream*) input; ++ (OWSFingerprintProtosCombinedFingerprint*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; ++ (OWSFingerprintProtosCombinedFingerprint*) parseFromCodedInputStream:(PBCodedInputStream*) input; ++ (OWSFingerprintProtosCombinedFingerprint*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; +@end + +@interface OWSFingerprintProtosCombinedFingerprintBuilder : PBGeneratedMessageBuilder { +@private + OWSFingerprintProtosCombinedFingerprint* resultCombinedFingerprint; +} + +- (OWSFingerprintProtosCombinedFingerprint*) defaultInstance; + +- (OWSFingerprintProtosCombinedFingerprintBuilder*) clear; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) clone; + +- (OWSFingerprintProtosCombinedFingerprint*) build; +- (OWSFingerprintProtosCombinedFingerprint*) buildPartial; + +- (OWSFingerprintProtosCombinedFingerprintBuilder*) mergeFrom:(OWSFingerprintProtosCombinedFingerprint*) other; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; + +- (BOOL) hasVersion; +- (UInt32) version; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) setVersion:(UInt32) value; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) clearVersion; + +- (BOOL) hasLocalFingerprint; +- (OWSFingerprintProtosFingerprintData*) localFingerprint; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) setLocalFingerprint:(OWSFingerprintProtosFingerprintData*) value; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) setLocalFingerprintBuilder:(OWSFingerprintProtosFingerprintDataBuilder*) builderForValue; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) mergeLocalFingerprint:(OWSFingerprintProtosFingerprintData*) value; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) clearLocalFingerprint; + +- (BOOL) hasRemoteFingerprint; +- (OWSFingerprintProtosFingerprintData*) remoteFingerprint; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) setRemoteFingerprint:(OWSFingerprintProtosFingerprintData*) value; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) setRemoteFingerprintBuilder:(OWSFingerprintProtosFingerprintDataBuilder*) builderForValue; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) mergeRemoteFingerprint:(OWSFingerprintProtosFingerprintData*) value; +- (OWSFingerprintProtosCombinedFingerprintBuilder*) clearRemoteFingerprint; +@end + + +// @@protoc_insertion_point(global_scope) diff --git a/src/Security/OWSFingerprintProtos.pb.m b/src/Security/OWSFingerprintProtos.pb.m new file mode 100644 index 000000000..3abb47ac8 --- /dev/null +++ b/src/Security/OWSFingerprintProtos.pb.m @@ -0,0 +1,632 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! + +#import "OWSFingerprintProtos.pb.h" +// @@protoc_insertion_point(imports) + +@implementation OWSFingerprintProtosOwsfingerprintProtosRoot +static PBExtensionRegistry* extensionRegistry = nil; ++ (PBExtensionRegistry*) extensionRegistry { + return extensionRegistry; +} + ++ (void) initialize { + if (self == [OWSFingerprintProtosOwsfingerprintProtosRoot class]) { + PBMutableExtensionRegistry* registry = [PBMutableExtensionRegistry registry]; + [self registerAllExtensions:registry]; + [ObjectivecDescriptorRoot registerAllExtensions:registry]; + extensionRegistry = registry; + } +} ++ (void) registerAllExtensions:(PBMutableExtensionRegistry*) registry { +} +@end + +@interface OWSFingerprintProtosFingerprintData () +@property (strong) NSData* publicKey; +@property (strong) NSData* identifier; +@end + +@implementation OWSFingerprintProtosFingerprintData + +- (BOOL) hasPublicKey { + return !!hasPublicKey_; +} +- (void) setHasPublicKey:(BOOL) _value_ { + hasPublicKey_ = !!_value_; +} +@synthesize publicKey; +- (BOOL) hasIdentifier { + return !!hasIdentifier_; +} +- (void) setHasIdentifier:(BOOL) _value_ { + hasIdentifier_ = !!_value_; +} +@synthesize identifier; +- (instancetype) init { + if ((self = [super init])) { + self.publicKey = [NSData data]; + self.identifier = [NSData data]; + } + return self; +} +static OWSFingerprintProtosFingerprintData* defaultOWSFingerprintProtosFingerprintDataInstance = nil; ++ (void) initialize { + if (self == [OWSFingerprintProtosFingerprintData class]) { + defaultOWSFingerprintProtosFingerprintDataInstance = [[OWSFingerprintProtosFingerprintData alloc] init]; + } +} ++ (instancetype) defaultInstance { + return defaultOWSFingerprintProtosFingerprintDataInstance; +} +- (instancetype) defaultInstance { + return defaultOWSFingerprintProtosFingerprintDataInstance; +} +- (BOOL) isInitialized { + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasPublicKey) { + [output writeData:1 value:self.publicKey]; + } + if (self.hasIdentifier) { + [output writeData:2 value:self.identifier]; + } + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasPublicKey) { + size_ += computeDataSize(1, self.publicKey); + } + if (self.hasIdentifier) { + size_ += computeDataSize(2, self.identifier); + } + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (OWSFingerprintProtosFingerprintData*) parseFromData:(NSData*) data { + return (OWSFingerprintProtosFingerprintData*)[[[OWSFingerprintProtosFingerprintData builder] mergeFromData:data] build]; +} ++ (OWSFingerprintProtosFingerprintData*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (OWSFingerprintProtosFingerprintData*)[[[OWSFingerprintProtosFingerprintData builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (OWSFingerprintProtosFingerprintData*) parseFromInputStream:(NSInputStream*) input { + return (OWSFingerprintProtosFingerprintData*)[[[OWSFingerprintProtosFingerprintData builder] mergeFromInputStream:input] build]; +} ++ (OWSFingerprintProtosFingerprintData*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (OWSFingerprintProtosFingerprintData*)[[[OWSFingerprintProtosFingerprintData builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (OWSFingerprintProtosFingerprintData*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (OWSFingerprintProtosFingerprintData*)[[[OWSFingerprintProtosFingerprintData builder] mergeFromCodedInputStream:input] build]; +} ++ (OWSFingerprintProtosFingerprintData*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (OWSFingerprintProtosFingerprintData*)[[[OWSFingerprintProtosFingerprintData builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (OWSFingerprintProtosFingerprintDataBuilder*) builder { + return [[OWSFingerprintProtosFingerprintDataBuilder alloc] init]; +} ++ (OWSFingerprintProtosFingerprintDataBuilder*) builderWithPrototype:(OWSFingerprintProtosFingerprintData*) prototype { + return [[OWSFingerprintProtosFingerprintData builder] mergeFrom:prototype]; +} +- (OWSFingerprintProtosFingerprintDataBuilder*) builder { + return [OWSFingerprintProtosFingerprintData builder]; +} +- (OWSFingerprintProtosFingerprintDataBuilder*) toBuilder { + return [OWSFingerprintProtosFingerprintData builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasPublicKey) { + [output appendFormat:@"%@%@: %@\n", indent, @"publicKey", self.publicKey]; + } + if (self.hasIdentifier) { + [output appendFormat:@"%@%@: %@\n", indent, @"identifier", self.identifier]; + } + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (void) storeInDictionary:(NSMutableDictionary *)dictionary { + if (self.hasPublicKey) { + [dictionary setObject: self.publicKey forKey: @"publicKey"]; + } + if (self.hasIdentifier) { + [dictionary setObject: self.identifier forKey: @"identifier"]; + } + [self.unknownFields storeInDictionary:dictionary]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[OWSFingerprintProtosFingerprintData class]]) { + return NO; + } + OWSFingerprintProtosFingerprintData *otherMessage = other; + return + self.hasPublicKey == otherMessage.hasPublicKey && + (!self.hasPublicKey || [self.publicKey isEqual:otherMessage.publicKey]) && + self.hasIdentifier == otherMessage.hasIdentifier && + (!self.hasIdentifier || [self.identifier isEqual:otherMessage.identifier]) && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasPublicKey) { + hashCode = hashCode * 31 + [self.publicKey hash]; + } + if (self.hasIdentifier) { + hashCode = hashCode * 31 + [self.identifier hash]; + } + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface OWSFingerprintProtosFingerprintDataBuilder() +@property (strong) OWSFingerprintProtosFingerprintData* resultFingerprintData; +@end + +@implementation OWSFingerprintProtosFingerprintDataBuilder +@synthesize resultFingerprintData; +- (instancetype) init { + if ((self = [super init])) { + self.resultFingerprintData = [[OWSFingerprintProtosFingerprintData alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return resultFingerprintData; +} +- (OWSFingerprintProtosFingerprintDataBuilder*) clear { + self.resultFingerprintData = [[OWSFingerprintProtosFingerprintData alloc] init]; + return self; +} +- (OWSFingerprintProtosFingerprintDataBuilder*) clone { + return [OWSFingerprintProtosFingerprintData builderWithPrototype:resultFingerprintData]; +} +- (OWSFingerprintProtosFingerprintData*) defaultInstance { + return [OWSFingerprintProtosFingerprintData defaultInstance]; +} +- (OWSFingerprintProtosFingerprintData*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (OWSFingerprintProtosFingerprintData*) buildPartial { + OWSFingerprintProtosFingerprintData* returnMe = resultFingerprintData; + self.resultFingerprintData = nil; + return returnMe; +} +- (OWSFingerprintProtosFingerprintDataBuilder*) mergeFrom:(OWSFingerprintProtosFingerprintData*) other { + if (other == [OWSFingerprintProtosFingerprintData defaultInstance]) { + return self; + } + if (other.hasPublicKey) { + [self setPublicKey:other.publicKey]; + } + if (other.hasIdentifier) { + [self setIdentifier:other.identifier]; + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (OWSFingerprintProtosFingerprintDataBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (OWSFingerprintProtosFingerprintDataBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 10: { + [self setPublicKey:[input readData]]; + break; + } + case 18: { + [self setIdentifier:[input readData]]; + break; + } + } + } +} +- (BOOL) hasPublicKey { + return resultFingerprintData.hasPublicKey; +} +- (NSData*) publicKey { + return resultFingerprintData.publicKey; +} +- (OWSFingerprintProtosFingerprintDataBuilder*) setPublicKey:(NSData*) value { + resultFingerprintData.hasPublicKey = YES; + resultFingerprintData.publicKey = value; + return self; +} +- (OWSFingerprintProtosFingerprintDataBuilder*) clearPublicKey { + resultFingerprintData.hasPublicKey = NO; + resultFingerprintData.publicKey = [NSData data]; + return self; +} +- (BOOL) hasIdentifier { + return resultFingerprintData.hasIdentifier; +} +- (NSData*) identifier { + return resultFingerprintData.identifier; +} +- (OWSFingerprintProtosFingerprintDataBuilder*) setIdentifier:(NSData*) value { + resultFingerprintData.hasIdentifier = YES; + resultFingerprintData.identifier = value; + return self; +} +- (OWSFingerprintProtosFingerprintDataBuilder*) clearIdentifier { + resultFingerprintData.hasIdentifier = NO; + resultFingerprintData.identifier = [NSData data]; + return self; +} +@end + +@interface OWSFingerprintProtosCombinedFingerprint () +@property UInt32 version; +@property (strong) OWSFingerprintProtosFingerprintData* localFingerprint; +@property (strong) OWSFingerprintProtosFingerprintData* remoteFingerprint; +@end + +@implementation OWSFingerprintProtosCombinedFingerprint + +- (BOOL) hasVersion { + return !!hasVersion_; +} +- (void) setHasVersion:(BOOL) _value_ { + hasVersion_ = !!_value_; +} +@synthesize version; +- (BOOL) hasLocalFingerprint { + return !!hasLocalFingerprint_; +} +- (void) setHasLocalFingerprint:(BOOL) _value_ { + hasLocalFingerprint_ = !!_value_; +} +@synthesize localFingerprint; +- (BOOL) hasRemoteFingerprint { + return !!hasRemoteFingerprint_; +} +- (void) setHasRemoteFingerprint:(BOOL) _value_ { + hasRemoteFingerprint_ = !!_value_; +} +@synthesize remoteFingerprint; +- (instancetype) init { + if ((self = [super init])) { + self.version = 0; + self.localFingerprint = [OWSFingerprintProtosFingerprintData defaultInstance]; + self.remoteFingerprint = [OWSFingerprintProtosFingerprintData defaultInstance]; + } + return self; +} +static OWSFingerprintProtosCombinedFingerprint* defaultOWSFingerprintProtosCombinedFingerprintInstance = nil; ++ (void) initialize { + if (self == [OWSFingerprintProtosCombinedFingerprint class]) { + defaultOWSFingerprintProtosCombinedFingerprintInstance = [[OWSFingerprintProtosCombinedFingerprint alloc] init]; + } +} ++ (instancetype) defaultInstance { + return defaultOWSFingerprintProtosCombinedFingerprintInstance; +} +- (instancetype) defaultInstance { + return defaultOWSFingerprintProtosCombinedFingerprintInstance; +} +- (BOOL) isInitialized { + return YES; +} +- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { + if (self.hasVersion) { + [output writeUInt32:1 value:self.version]; + } + if (self.hasLocalFingerprint) { + [output writeMessage:2 value:self.localFingerprint]; + } + if (self.hasRemoteFingerprint) { + [output writeMessage:3 value:self.remoteFingerprint]; + } + [self.unknownFields writeToCodedOutputStream:output]; +} +- (SInt32) serializedSize { + __block SInt32 size_ = memoizedSerializedSize; + if (size_ != -1) { + return size_; + } + + size_ = 0; + if (self.hasVersion) { + size_ += computeUInt32Size(1, self.version); + } + if (self.hasLocalFingerprint) { + size_ += computeMessageSize(2, self.localFingerprint); + } + if (self.hasRemoteFingerprint) { + size_ += computeMessageSize(3, self.remoteFingerprint); + } + size_ += self.unknownFields.serializedSize; + memoizedSerializedSize = size_; + return size_; +} ++ (OWSFingerprintProtosCombinedFingerprint*) parseFromData:(NSData*) data { + return (OWSFingerprintProtosCombinedFingerprint*)[[[OWSFingerprintProtosCombinedFingerprint builder] mergeFromData:data] build]; +} ++ (OWSFingerprintProtosCombinedFingerprint*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (OWSFingerprintProtosCombinedFingerprint*)[[[OWSFingerprintProtosCombinedFingerprint builder] mergeFromData:data extensionRegistry:extensionRegistry] build]; +} ++ (OWSFingerprintProtosCombinedFingerprint*) parseFromInputStream:(NSInputStream*) input { + return (OWSFingerprintProtosCombinedFingerprint*)[[[OWSFingerprintProtosCombinedFingerprint builder] mergeFromInputStream:input] build]; +} ++ (OWSFingerprintProtosCombinedFingerprint*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (OWSFingerprintProtosCombinedFingerprint*)[[[OWSFingerprintProtosCombinedFingerprint builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (OWSFingerprintProtosCombinedFingerprint*) parseFromCodedInputStream:(PBCodedInputStream*) input { + return (OWSFingerprintProtosCombinedFingerprint*)[[[OWSFingerprintProtosCombinedFingerprint builder] mergeFromCodedInputStream:input] build]; +} ++ (OWSFingerprintProtosCombinedFingerprint*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + return (OWSFingerprintProtosCombinedFingerprint*)[[[OWSFingerprintProtosCombinedFingerprint builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build]; +} ++ (OWSFingerprintProtosCombinedFingerprintBuilder*) builder { + return [[OWSFingerprintProtosCombinedFingerprintBuilder alloc] init]; +} ++ (OWSFingerprintProtosCombinedFingerprintBuilder*) builderWithPrototype:(OWSFingerprintProtosCombinedFingerprint*) prototype { + return [[OWSFingerprintProtosCombinedFingerprint builder] mergeFrom:prototype]; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) builder { + return [OWSFingerprintProtosCombinedFingerprint builder]; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) toBuilder { + return [OWSFingerprintProtosCombinedFingerprint builderWithPrototype:self]; +} +- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent { + if (self.hasVersion) { + [output appendFormat:@"%@%@: %@\n", indent, @"version", [NSNumber numberWithInteger:self.version]]; + } + if (self.hasLocalFingerprint) { + [output appendFormat:@"%@%@ {\n", indent, @"localFingerprint"]; + [self.localFingerprint writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + } + if (self.hasRemoteFingerprint) { + [output appendFormat:@"%@%@ {\n", indent, @"remoteFingerprint"]; + [self.remoteFingerprint writeDescriptionTo:output + withIndent:[NSString stringWithFormat:@"%@ ", indent]]; + [output appendFormat:@"%@}\n", indent]; + } + [self.unknownFields writeDescriptionTo:output withIndent:indent]; +} +- (void) storeInDictionary:(NSMutableDictionary *)dictionary { + if (self.hasVersion) { + [dictionary setObject: [NSNumber numberWithInteger:self.version] forKey: @"version"]; + } + if (self.hasLocalFingerprint) { + NSMutableDictionary *messageDictionary = [NSMutableDictionary dictionary]; + [self.localFingerprint storeInDictionary:messageDictionary]; + [dictionary setObject:[NSDictionary dictionaryWithDictionary:messageDictionary] forKey:@"localFingerprint"]; + } + if (self.hasRemoteFingerprint) { + NSMutableDictionary *messageDictionary = [NSMutableDictionary dictionary]; + [self.remoteFingerprint storeInDictionary:messageDictionary]; + [dictionary setObject:[NSDictionary dictionaryWithDictionary:messageDictionary] forKey:@"remoteFingerprint"]; + } + [self.unknownFields storeInDictionary:dictionary]; +} +- (BOOL) isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[OWSFingerprintProtosCombinedFingerprint class]]) { + return NO; + } + OWSFingerprintProtosCombinedFingerprint *otherMessage = other; + return + self.hasVersion == otherMessage.hasVersion && + (!self.hasVersion || self.version == otherMessage.version) && + self.hasLocalFingerprint == otherMessage.hasLocalFingerprint && + (!self.hasLocalFingerprint || [self.localFingerprint isEqual:otherMessage.localFingerprint]) && + self.hasRemoteFingerprint == otherMessage.hasRemoteFingerprint && + (!self.hasRemoteFingerprint || [self.remoteFingerprint isEqual:otherMessage.remoteFingerprint]) && + (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields])); +} +- (NSUInteger) hash { + __block NSUInteger hashCode = 7; + if (self.hasVersion) { + hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.version] hash]; + } + if (self.hasLocalFingerprint) { + hashCode = hashCode * 31 + [self.localFingerprint hash]; + } + if (self.hasRemoteFingerprint) { + hashCode = hashCode * 31 + [self.remoteFingerprint hash]; + } + hashCode = hashCode * 31 + [self.unknownFields hash]; + return hashCode; +} +@end + +@interface OWSFingerprintProtosCombinedFingerprintBuilder() +@property (strong) OWSFingerprintProtosCombinedFingerprint* resultCombinedFingerprint; +@end + +@implementation OWSFingerprintProtosCombinedFingerprintBuilder +@synthesize resultCombinedFingerprint; +- (instancetype) init { + if ((self = [super init])) { + self.resultCombinedFingerprint = [[OWSFingerprintProtosCombinedFingerprint alloc] init]; + } + return self; +} +- (PBGeneratedMessage*) internalGetResult { + return resultCombinedFingerprint; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) clear { + self.resultCombinedFingerprint = [[OWSFingerprintProtosCombinedFingerprint alloc] init]; + return self; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) clone { + return [OWSFingerprintProtosCombinedFingerprint builderWithPrototype:resultCombinedFingerprint]; +} +- (OWSFingerprintProtosCombinedFingerprint*) defaultInstance { + return [OWSFingerprintProtosCombinedFingerprint defaultInstance]; +} +- (OWSFingerprintProtosCombinedFingerprint*) build { + [self checkInitialized]; + return [self buildPartial]; +} +- (OWSFingerprintProtosCombinedFingerprint*) buildPartial { + OWSFingerprintProtosCombinedFingerprint* returnMe = resultCombinedFingerprint; + self.resultCombinedFingerprint = nil; + return returnMe; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) mergeFrom:(OWSFingerprintProtosCombinedFingerprint*) other { + if (other == [OWSFingerprintProtosCombinedFingerprint defaultInstance]) { + return self; + } + if (other.hasVersion) { + [self setVersion:other.version]; + } + if (other.hasLocalFingerprint) { + [self mergeLocalFingerprint:other.localFingerprint]; + } + if (other.hasRemoteFingerprint) { + [self mergeRemoteFingerprint:other.remoteFingerprint]; + } + [self mergeUnknownFields:other.unknownFields]; + return self; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input { + return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry { + PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]; + while (YES) { + SInt32 tag = [input readTag]; + switch (tag) { + case 0: + [self setUnknownFields:[unknownFields build]]; + return self; + default: { + if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) { + [self setUnknownFields:[unknownFields build]]; + return self; + } + break; + } + case 8: { + [self setVersion:[input readUInt32]]; + break; + } + case 18: { + OWSFingerprintProtosFingerprintDataBuilder* subBuilder = [OWSFingerprintProtosFingerprintData builder]; + if (self.hasLocalFingerprint) { + [subBuilder mergeFrom:self.localFingerprint]; + } + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self setLocalFingerprint:[subBuilder buildPartial]]; + break; + } + case 26: { + OWSFingerprintProtosFingerprintDataBuilder* subBuilder = [OWSFingerprintProtosFingerprintData builder]; + if (self.hasRemoteFingerprint) { + [subBuilder mergeFrom:self.remoteFingerprint]; + } + [input readMessage:subBuilder extensionRegistry:extensionRegistry]; + [self setRemoteFingerprint:[subBuilder buildPartial]]; + break; + } + } + } +} +- (BOOL) hasVersion { + return resultCombinedFingerprint.hasVersion; +} +- (UInt32) version { + return resultCombinedFingerprint.version; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) setVersion:(UInt32) value { + resultCombinedFingerprint.hasVersion = YES; + resultCombinedFingerprint.version = value; + return self; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) clearVersion { + resultCombinedFingerprint.hasVersion = NO; + resultCombinedFingerprint.version = 0; + return self; +} +- (BOOL) hasLocalFingerprint { + return resultCombinedFingerprint.hasLocalFingerprint; +} +- (OWSFingerprintProtosFingerprintData*) localFingerprint { + return resultCombinedFingerprint.localFingerprint; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) setLocalFingerprint:(OWSFingerprintProtosFingerprintData*) value { + resultCombinedFingerprint.hasLocalFingerprint = YES; + resultCombinedFingerprint.localFingerprint = value; + return self; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) setLocalFingerprintBuilder:(OWSFingerprintProtosFingerprintDataBuilder*) builderForValue { + return [self setLocalFingerprint:[builderForValue build]]; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) mergeLocalFingerprint:(OWSFingerprintProtosFingerprintData*) value { + if (resultCombinedFingerprint.hasLocalFingerprint && + resultCombinedFingerprint.localFingerprint != [OWSFingerprintProtosFingerprintData defaultInstance]) { + resultCombinedFingerprint.localFingerprint = + [[[OWSFingerprintProtosFingerprintData builderWithPrototype:resultCombinedFingerprint.localFingerprint] mergeFrom:value] buildPartial]; + } else { + resultCombinedFingerprint.localFingerprint = value; + } + resultCombinedFingerprint.hasLocalFingerprint = YES; + return self; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) clearLocalFingerprint { + resultCombinedFingerprint.hasLocalFingerprint = NO; + resultCombinedFingerprint.localFingerprint = [OWSFingerprintProtosFingerprintData defaultInstance]; + return self; +} +- (BOOL) hasRemoteFingerprint { + return resultCombinedFingerprint.hasRemoteFingerprint; +} +- (OWSFingerprintProtosFingerprintData*) remoteFingerprint { + return resultCombinedFingerprint.remoteFingerprint; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) setRemoteFingerprint:(OWSFingerprintProtosFingerprintData*) value { + resultCombinedFingerprint.hasRemoteFingerprint = YES; + resultCombinedFingerprint.remoteFingerprint = value; + return self; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) setRemoteFingerprintBuilder:(OWSFingerprintProtosFingerprintDataBuilder*) builderForValue { + return [self setRemoteFingerprint:[builderForValue build]]; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) mergeRemoteFingerprint:(OWSFingerprintProtosFingerprintData*) value { + if (resultCombinedFingerprint.hasRemoteFingerprint && + resultCombinedFingerprint.remoteFingerprint != [OWSFingerprintProtosFingerprintData defaultInstance]) { + resultCombinedFingerprint.remoteFingerprint = + [[[OWSFingerprintProtosFingerprintData builderWithPrototype:resultCombinedFingerprint.remoteFingerprint] mergeFrom:value] buildPartial]; + } else { + resultCombinedFingerprint.remoteFingerprint = value; + } + resultCombinedFingerprint.hasRemoteFingerprint = YES; + return self; +} +- (OWSFingerprintProtosCombinedFingerprintBuilder*) clearRemoteFingerprint { + resultCombinedFingerprint.hasRemoteFingerprint = NO; + resultCombinedFingerprint.remoteFingerprint = [OWSFingerprintProtosFingerprintData defaultInstance]; + return self; +} +@end + + +// @@protoc_insertion_point(global_scope) diff --git a/src/Security/TSFingerprintGenerator.h b/src/Security/TSFingerprintGenerator.h deleted file mode 100644 index e33e397ee..000000000 --- a/src/Security/TSFingerprintGenerator.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// TSFingerprintGenerator.h -// Signal -// -// Created by Frederic Jacobs on 10/12/14. -// Copyright (c) 2014 Open Whisper Systems. All rights reserved. -// - -#import - -@interface TSFingerprintGenerator : NSObject - -+ (NSString *)getFingerprintForDisplay:(NSData *)identityKey; - -@end diff --git a/src/Security/TSFingerprintGenerator.m b/src/Security/TSFingerprintGenerator.m deleted file mode 100644 index 1562df976..000000000 --- a/src/Security/TSFingerprintGenerator.m +++ /dev/null @@ -1,37 +0,0 @@ -// -// TSFingerprintGenerator.m -// Signal -// -// Created by Frederic Jacobs on 10/12/14. -// Copyright (c) 2014 Open Whisper Systems. All rights reserved. -// - -#import -#import "NSData+hexString.h" - -#import "TSFingerprintGenerator.h" - -@implementation TSFingerprintGenerator - -+ (NSString *)getFingerprintForDisplay:(NSData *)identityKey { - // idea here is to insert a space every two characters. there is probably a cleverer/more native way to do this. - - identityKey = [identityKey prependKeyType]; - NSString *fingerprint = [identityKey hexadecimalString]; - __block NSString *formattedFingerprint = @""; - - - [fingerprint - enumerateSubstringsInRange:NSMakeRange(0, [fingerprint length]) - options:NSStringEnumerationByComposedCharacterSequences - usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) { - if (substringRange.location % 2 != 0 && substringRange.location != [fingerprint length] - 1) { - substring = [substring stringByAppendingString:@" "]; - } - formattedFingerprint = [formattedFingerprint stringByAppendingString:substring]; - }]; - return formattedFingerprint; -} - - -@end diff --git a/src/Storage/TSStorageManager+keyingMaterial.h b/src/Storage/TSStorageManager+keyingMaterial.h index 3a988662e..e87729898 100644 --- a/src/Storage/TSStorageManager+keyingMaterial.h +++ b/src/Storage/TSStorageManager+keyingMaterial.h @@ -33,6 +33,7 @@ * * @return E164 string of the registered phone number */ +- (NSString *)localNumber; + (NSString *)localNumber; - (void)runIfHasLocalNumber:(void (^)())block; diff --git a/src/Storage/TSStorageManager+keyingMaterial.m b/src/Storage/TSStorageManager+keyingMaterial.m index 0a8431400..aff0b7a08 100644 --- a/src/Storage/TSStorageManager+keyingMaterial.m +++ b/src/Storage/TSStorageManager+keyingMaterial.m @@ -10,8 +10,14 @@ @implementation TSStorageManager (keyingMaterial) -+ (NSString *)localNumber { - return [[self sharedManager] stringForKey:TSStorageRegisteredNumberKey inCollection:TSStorageUserAccountCollection]; ++ (NSString *)localNumber +{ + return [[self sharedManager] localNumber]; +} + +- (NSString *)localNumber +{ + return [self stringForKey:TSStorageRegisteredNumberKey inCollection:TSStorageUserAccountCollection]; } - (void)runIfHasLocalNumber:(void (^)())block diff --git a/src/Util/OWSError.h b/src/Util/OWSError.h index 3cc807eeb..ec1d054f2 100644 --- a/src/Util/OWSError.h +++ b/src/Util/OWSError.h @@ -8,7 +8,10 @@ typedef NS_ENUM(NSInteger, OWSErrorCode) { OWSErrorCodeInvalidMethodParameters = 11, OWSErrorCodeUnableToProcessServerResponse = 12, OWSErrorCodeFailedToDecodeJson = 13, - OWSErrorCodeFailedToEncodeJson = 14 + OWSErrorCodeFailedToEncodeJson = 14, + OWSErrorCodeFailedToDecodeQR = 15, + OWSErrorCodePrivacyVerificationFailure = 20 + }; extern NSError *OWSErrorWithCodeDescription(OWSErrorCode code, NSString *description); diff --git a/tests/Messages/TSMessagesManagerTest.m b/tests/Messages/TSMessagesManagerTest.m index ffd0a73eb..af9b1fbde 100644 --- a/tests/Messages/TSMessagesManagerTest.m +++ b/tests/Messages/TSMessagesManagerTest.m @@ -8,6 +8,7 @@ #import "TSMessagesManager.h" #import "TSNetworkManager.h" #import "TSStorageManager.h" +#import "ContactsManagerProtocol.h" #import "objc/runtime.h" @interface TSMessagesManagerTest : XCTestCase @@ -139,6 +140,38 @@ @end +@interface OWSFakeContactsManager : NSObject + +@end + +/** + * I don't know that this test relys on any of the specific behavior in this implementation. + * We're just trying to avoid setting up/accessing the TSEnv global. ~mjk + */ +@implementation OWSFakeContactsManager + +- (NSString *)nameStringForPhoneIdentifier:(NSString *)phoneNumber +{ + return @"Fake name"; +} + +- (NSArray *)signalContacts +{ + return @[]; +} + ++ (BOOL)name:(NSString *)nameString matchesQuery:(NSString *)queryString +{ + return YES; +} + +- (UIImage *)imageForPhoneIdentifier:(NSString *)phoneNumber +{ + return nil; +} + +@end + @implementation TSMessagesManagerTest - (void)testIncomingSyncContactMessage @@ -147,9 +180,11 @@ XCTestExpectation *messageWasSubmitted = [self expectationWithDescription:@"message was submitted"]; OWSTSMessagesManagerTestNetworkManager *fakeNetworkManager = [[OWSTSMessagesManagerTestNetworkManager alloc] initWithExpectation:messageWasSubmitted]; + OWSFakeContactsManager *fakeContactsManager = [OWSFakeContactsManager new]; TSMessagesManager *messagesManager = [[TSMessagesManager alloc] initWithNetworkManager:fakeNetworkManager dbConnection:[TSStorageManager sharedManager].newDatabaseConnection + contactsManager:fakeContactsManager contactsUpdater:fakeContactsUpdater]; OWSSignalServiceProtosEnvelopeBuilder *envelopeBuilder = [OWSSignalServiceProtosEnvelopeBuilder new]; diff --git a/tests/Security/OWSFingerprintTest.m b/tests/Security/OWSFingerprintTest.m new file mode 100644 index 000000000..97af4a43e --- /dev/null +++ b/tests/Security/OWSFingerprintTest.m @@ -0,0 +1,74 @@ +// Created by Michael Kirk on 9/14/16. +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +#import "OWSFingerprint.h" +#import <25519/Curve25519.h> +#import + +@interface OWSFingerprintTest : XCTestCase + + +@end + +@implementation OWSFingerprintTest + +- (void)testDisplayableTextInsertsSpaces +{ + NSString *aliceStableId = @"+13231111111"; + NSData *aliceIdentityKey = [Curve25519 generateKeyPair].publicKey; + NSString *bobStableId = @"+14152222222"; + NSData *bobIdentityKey = [Curve25519 generateKeyPair].publicKey; + + OWSFingerprint *aliceFingerprint = [OWSFingerprint fingerprintWithMyStableId:aliceStableId + myIdentityKey:aliceIdentityKey + theirStableId:bobStableId + theirIdentityKey:bobIdentityKey + hashIterations:2]; + + NSString *displayableText = aliceFingerprint.displayableText; + XCTAssertNotEqualObjects(@" ", [displayableText substringWithRange:NSMakeRange(0, 1)]); + XCTAssertNotEqualObjects(@" ", [displayableText substringWithRange:NSMakeRange(1, 1)]); + XCTAssertNotEqualObjects(@" ", [displayableText substringWithRange:NSMakeRange(2, 1)]); + XCTAssertNotEqualObjects(@" ", [displayableText substringWithRange:NSMakeRange(3, 1)]); + XCTAssertNotEqualObjects(@" ", [displayableText substringWithRange:NSMakeRange(4, 1)]); + XCTAssertEqualObjects(@" ", [displayableText substringWithRange:NSMakeRange(5, 1)]); + XCTAssertNotEqualObjects(@" ", [displayableText substringWithRange:NSMakeRange(6, 1)]); + XCTAssertNotEqualObjects(@" ", [displayableText substringWithRange:NSMakeRange(7, 1)]); + XCTAssertNotEqualObjects(@" ", [displayableText substringWithRange:NSMakeRange(8, 1)]); + XCTAssertNotEqualObjects(@" ", [displayableText substringWithRange:NSMakeRange(9, 1)]); + XCTAssertNotEqualObjects(@" ", [displayableText substringWithRange:NSMakeRange(10, 1)]); + XCTAssertEqualObjects(@" ", [displayableText substringWithRange:NSMakeRange(11, 1)]); +} + +- (void)testTextMatchesReciprocally +{ + NSString *aliceStableId = @"+13231111111"; + NSData *aliceIdentityKey = [Curve25519 generateKeyPair].publicKey; + NSString *bobStableId = @"+14152222222"; + NSData *bobIdentityKey = [Curve25519 generateKeyPair].publicKey; + NSString *charlieStableId = @"+14153333333"; + NSData *charlieIdentityKey = [Curve25519 generateKeyPair].publicKey; + + OWSFingerprint *aliceFingerprint = [OWSFingerprint fingerprintWithMyStableId:aliceStableId + myIdentityKey:aliceIdentityKey + theirStableId:bobStableId + theirIdentityKey:bobIdentityKey + hashIterations:2]; + + OWSFingerprint *bobFingerprint = [OWSFingerprint fingerprintWithMyStableId:bobStableId + myIdentityKey:bobIdentityKey + theirStableId:aliceStableId + theirIdentityKey:aliceIdentityKey + hashIterations:2]; + + OWSFingerprint *charlieFingerprint = [OWSFingerprint fingerprintWithMyStableId:charlieStableId + myIdentityKey:charlieIdentityKey + theirStableId:aliceStableId + theirIdentityKey:aliceIdentityKey + hashIterations:2]; + + XCTAssertEqualObjects(aliceFingerprint.displayableText, bobFingerprint.displayableText); + XCTAssertNotEqualObjects(aliceFingerprint.displayableText, charlieFingerprint.displayableText); +} + +@end