// // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "PreKeyWhisperMessage.h" #import "AxolotlExceptions.h" #import "Constants.h" #import "SerializationUtilities.h" #import #import #import NS_ASSUME_NONNULL_BEGIN @interface PreKeyWhisperMessage () @property (nonatomic, readwrite) NSData *identityKey; @property (nonatomic, readwrite) NSData *baseKey; @property (nonatomic, readwrite) NSData *serialized; @end #pragma mark - @implementation PreKeyWhisperMessage - (instancetype)init_throws_withWhisperMessage:(WhisperMessage *)whisperMessage registrationId:(int)registrationId prekeyId:(int)prekeyId signedPrekeyId:(int)signedPrekeyId baseKey:(NSData *)baseKey identityKey:(NSData *)identityKey { OWSAssert(whisperMessage); OWSAssert(baseKey); OWSAssert(identityKey); if (self = [super init]) { _registrationId = registrationId; _version = whisperMessage.version; _prekeyID = prekeyId; _signedPrekeyId = signedPrekeyId; _baseKey = baseKey; _identityKey = identityKey; _message = whisperMessage; SPKProtoTSProtoPreKeyWhisperMessageBuilder *messageBuilder = [SPKProtoTSProtoPreKeyWhisperMessage builderWithSignedPreKeyID:signedPrekeyId baseKey:baseKey identityKey:identityKey message:whisperMessage.serialized]; [messageBuilder setRegistrationID:registrationId]; if (prekeyId != -1) { [messageBuilder setPreKeyID:prekeyId]; } Byte versionByte = [SerializationUtilities intsToByteHigh:_version low:CURRENT_VERSION]; NSMutableData *serialized = [NSMutableData dataWithBytes:&versionByte length:1]; NSError *error; NSData *_Nullable messageData = [messageBuilder buildSerializedDataAndReturnError:&error]; if (!messageData || error) { OWSFailDebug(@"Could not serialize proto: %@.", error); OWSRaiseException(InvalidMessageException, @"Could not serialize proto."); } [serialized appendData:messageData]; _serialized = [serialized copy]; } return self; } - (nullable instancetype)initWithData:(NSData *)serialized error:(NSError **)outError { @try { self = [self init_throws_withData:serialized]; return self; } @catch (NSException *exception) { *outError = SCKExceptionWrapperErrorMake(exception); return nil; } } - (instancetype)init_throws_withData:(NSData *)serialized { if (self = [super init]) { if (serialized.length < 1) { OWSFailDebug(@"Empty data"); OWSRaiseException(InvalidMessageException, @"Empty data"); } Byte version; [serialized getBytes:&version length:1]; _version = [SerializationUtilities highBitsToIntFromByte:version]; if (_version > CURRENT_VERSION && _version < MINIMUM_SUPPORTED_VERSION) { @throw [NSException exceptionWithName:InvalidVersionException reason:@"Unknown version" userInfo:@{ @"version" : [NSNumber numberWithInt:_version] }]; } NSUInteger messageDataLength; ows_sub_overflow(serialized.length, 1, &messageDataLength); NSData *messageData = [serialized subdataWithRange:NSMakeRange(1, messageDataLength)]; NSError *error; SPKProtoTSProtoPreKeyWhisperMessage *_Nullable preKeyWhisperMessage = [SPKProtoTSProtoPreKeyWhisperMessage parseData:messageData error:&error]; if (!preKeyWhisperMessage || error) { OWSFailDebug(@"Could not parse proto: %@.", error); OWSRaiseException(InvalidMessageException, @"Could not parse proto."); } _serialized = serialized; _registrationId = preKeyWhisperMessage.registrationID; // This method is called when decrypting a received PreKeyMessage, but to be symmetrical with // encrypting a PreKeyWhisperMessage before sending, we use "-1" to indicate *no* unsigned prekey was // included. _prekeyID = preKeyWhisperMessage.hasPreKeyID ? preKeyWhisperMessage.preKeyID : -1; _signedPrekeyId = preKeyWhisperMessage.signedPreKeyID; _baseKey = preKeyWhisperMessage.baseKey; _identityKey = preKeyWhisperMessage.identityKey; _message = [[WhisperMessage alloc] init_throws_withData:preKeyWhisperMessage.message]; } return self; } - (CipherMessageType)cipherMessageType { return CipherMessageType_Prekey; } #pragma mark - Logging + (NSString *)logTag { return [NSString stringWithFormat:@"[%@]", self.class]; } - (NSString *)logTag { return self.class.logTag; } @end NS_ASSUME_NONNULL_END