From daab2a58af947cddd67fe9f30dd3a9fc327650c0 Mon Sep 17 00:00:00 2001 From: Chris Ballinger Date: Wed, 13 Apr 2016 16:53:47 -0700 Subject: OLMAccount and OLMSession serialization --- xcode/OLMKit/OLMAccount.h | 8 ++- xcode/OLMKit/OLMAccount.m | 113 +++++++++++++++++++++++++++++++++- xcode/OLMKit/OLMSerializable.h | 6 +- xcode/OLMKit/OLMSession.h | 6 +- xcode/OLMKit/OLMSession.m | 124 +++++++++++++++++++++++++++++++------- xcode/OLMKit/OLMSession_Private.h | 16 +++++ 6 files changed, 239 insertions(+), 34 deletions(-) create mode 100644 xcode/OLMKit/OLMSession_Private.h (limited to 'xcode/OLMKit') diff --git a/xcode/OLMKit/OLMAccount.h b/xcode/OLMKit/OLMAccount.h index cfa7129..a2923f9 100644 --- a/xcode/OLMKit/OLMAccount.h +++ b/xcode/OLMKit/OLMAccount.h @@ -9,7 +9,9 @@ #import #import "OLMSerializable.h" -@interface OLMAccount : NSObject +@class OLMSession; + +@interface OLMAccount : NSObject /** Creates new account */ - (instancetype) initNewAccount; @@ -18,11 +20,13 @@ - (NSDictionary*) identityKeys; /** signs message with ed25519 key for account */ -- (NSData*) signMessage:(NSData*)messageData; +- (NSString*) signMessage:(NSData*)messageData; /** Public parts of the unpublished one time keys for the account */ - (NSDictionary*) oneTimeKeys; +- (BOOL) removeOneTimeKeysForSession:(OLMSession*)session; + /** Marks the current set of one time keys as being published. */ - (void) markKeysAsPublished; diff --git a/xcode/OLMKit/OLMAccount.m b/xcode/OLMKit/OLMAccount.m index d56b6b4..4561a37 100644 --- a/xcode/OLMKit/OLMAccount.m +++ b/xcode/OLMKit/OLMAccount.m @@ -8,6 +8,8 @@ #import "OLMAccount.h" #import "OLMAccount_Private.h" +#import "OLMSession.h" +#import "OLMSession_Private.h" #import "OLMUtility.h" @import Security; @@ -34,7 +36,7 @@ return YES; } -- (instancetype) initNewAccount { +- (instancetype) init { self = [super init]; if (!self) { return nil; @@ -43,6 +45,14 @@ if (!success) { return nil; } + return self; +} + +- (instancetype) initNewAccount { + self = [self init]; + if (!self) { + return nil; + } size_t randomLength = olm_create_account_random_length(_account); NSMutableData *random = [OLMUtility randomBytesOfLength:randomLength]; size_t accountResult = olm_create_account(_account, random.mutableBytes, random.length); @@ -114,5 +124,106 @@ } } +- (BOOL) removeOneTimeKeysForSession:(OLMSession *)session { + NSParameterAssert(session != nil); + if (!session) { + return nil; + } + size_t result = olm_remove_one_time_keys(self.account, session.session); + if (result == olm_error()) { + const char *error = olm_session_last_error(session.session); + NSAssert(NO, @"olm_remove_one_time_keys error: %s", error); + return NO; + } + return YES; +} + +#pragma mark OLMSerializable + +/** Initializes from encrypted serialized data. Will throw error if invalid key or invalid base64. */ +- (instancetype) initWithSerializedData:(NSString*)serializedData key:(NSData*)key error:(NSError**)error { + self = [self init]; + if (!self) { + return nil; + } + NSParameterAssert(key.length > 0); + NSParameterAssert(serializedData.length > 0); + if (key.length == 0 || serializedData.length == 0) { + if (error) { + *error = [NSError errorWithDomain:@"org.matrix.olm" code:0 userInfo:@{NSLocalizedDescriptionKey: @"Bad length."}]; + } + return nil; + } + NSMutableData *pickle = [serializedData dataUsingEncoding:NSUTF8StringEncoding].mutableCopy; + size_t result = olm_unpickle_account(_account, key.bytes, key.length, pickle.mutableBytes, pickle.length); + if (result == olm_error()) { + const char *olm_error = olm_account_last_error(_account); + NSString *errorString = [NSString stringWithUTF8String:olm_error]; + if (error && errorString) { + *error = [NSError errorWithDomain:@"org.matrix.olm" code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}]; + } + return nil; + } + return self; +} + +/** Serializes and encrypts object data, outputs base64 blob */ +- (NSString*) serializeDataWithKey:(NSData*)key error:(NSError**)error { + NSParameterAssert(key.length > 0); + size_t length = olm_pickle_account_length(_account); + NSMutableData *pickled = [NSMutableData dataWithLength:length]; + size_t result = olm_pickle_account(_account, key.bytes, key.length, pickled.mutableBytes, pickled.length); + if (result == olm_error()) { + const char *olm_error = olm_account_last_error(_account); + NSString *errorString = [NSString stringWithUTF8String:olm_error]; + if (error && errorString) { + *error = [NSError errorWithDomain:@"org.matrix.olm" code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}]; + } + return nil; + } + NSString *pickleString = [[NSString alloc] initWithData:pickled encoding:NSUTF8StringEncoding]; + return pickleString; +} + +#pragma mark NSSecureCoding + ++ (BOOL) supportsSecureCoding { + return YES; +} + +#pragma mark NSCoding + +- (id)initWithCoder:(NSCoder *)decoder { + NSString *version = [decoder decodeObjectOfClass:[NSString class] forKey:@"version"]; + + NSError *error = nil; + + if ([version isEqualToString:@"1"]) { + NSString *pickle = [decoder decodeObjectOfClass:[NSString class] forKey:@"pickle"]; + NSData *key = [decoder decodeObjectOfClass:[NSData class] forKey:@"key"]; + + self = [self initWithSerializedData:pickle key:key error:&error]; + } + + NSParameterAssert(error == nil); + NSParameterAssert(self != nil); + if (!self) { + return nil; + } + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder { + NSData *key = [OLMUtility randomBytesOfLength:32]; + NSError *error = nil; + NSString *pickle = [self serializeDataWithKey:key error:&error]; + NSParameterAssert(pickle.length > 0 && error == nil); + + [encoder encodeObject:pickle forKey:@"pickle"]; + [encoder encodeObject:key forKey:@"key"]; + [encoder encodeObject:@"1" forKey:@"version"]; +} + @end diff --git a/xcode/OLMKit/OLMSerializable.h b/xcode/OLMKit/OLMSerializable.h index afacdaa..b4b115a 100644 --- a/xcode/OLMKit/OLMSerializable.h +++ b/xcode/OLMKit/OLMSerializable.h @@ -11,9 +11,9 @@ @protocol OLMSerializable /** Initializes from encrypted serialized data. Will throw error if invalid key or invalid base64. */ -- (instancetype) initWithSerializedData:(NSData*)serializedData key:(NSData*)key error:(NSError**)error; +- (instancetype) initWithSerializedData:(NSString*)serializedData key:(NSData*)key error:(NSError**)error; -/** Serializes and encrypts object data */ -- (NSData*) serializeDataWithKey:(NSData*)key; +/** Serializes and encrypts object data, outputs base64 blob */ +- (NSString*) serializeDataWithKey:(NSData*)key error:(NSError**)error; @end diff --git a/xcode/OLMKit/OLMSession.h b/xcode/OLMKit/OLMSession.h index 1a075e4..c209564 100644 --- a/xcode/OLMKit/OLMSession.h +++ b/xcode/OLMKit/OLMSession.h @@ -11,9 +11,7 @@ #import "OLMAccount.h" #import "OLMMessage.h" -@interface OLMSession : NSObject - -@property (nonatomic, strong) OLMAccount *account; +@interface OLMSession : NSObject - (instancetype) initOutboundSessionWithAccount:(OLMAccount*)account theirIdentityKey:(NSString*)theirIdentityKey theirOneTimeKey:(NSString*)theirOneTimeKey; @@ -27,8 +25,6 @@ - (BOOL) matchesInboundSessionFrom:(NSString*)theirIdentityKey oneTimeKeyMessage:(NSString *)oneTimeKeyMessage; -- (BOOL) removeOneTimeKeys; - /** UTF-8 plaintext -> base64 ciphertext */ - (OLMMessage*) encryptMessage:(NSString*)message; diff --git a/xcode/OLMKit/OLMSession.m b/xcode/OLMKit/OLMSession.m index fa7cb62..119079f 100644 --- a/xcode/OLMKit/OLMSession.m +++ b/xcode/OLMKit/OLMSession.m @@ -9,12 +9,9 @@ #import "OLMSession.h" #import "OLMUtility.h" #import "OLMAccount_Private.h" +#import "OLMSession_Private.h" @import olm; -@interface OLMSession() -@property (nonatomic) OlmSession *session; -@end - @implementation OLMSession - (void) dealloc { @@ -37,7 +34,7 @@ return YES; } -- (instancetype) initWithAccount:(OLMAccount*)account { +- (instancetype) init { self = [super init]; if (!self) { return nil; @@ -46,6 +43,18 @@ if (!success) { return nil; } + return self; +} + +- (instancetype) initWithAccount:(OLMAccount*)account { + self = [self init]; + if (!self) { + return nil; + } + NSParameterAssert(account != nil && account.account != NULL); + if (account == nil || account.account == NULL) { + return nil; + } _account = account; return self; } @@ -72,10 +81,6 @@ if (!self) { return nil; } - BOOL success = [self initializeSessionMemory]; - if (!success) { - return nil; - } NSMutableData *otk = [NSMutableData dataWithData:[oneTimeKeyMessage dataUsingEncoding:NSUTF8StringEncoding]]; size_t result = olm_create_inbound_session(_session, account.account, otk.mutableBytes, oneTimeKeyMessage.length); if (result == olm_error()) { @@ -91,10 +96,6 @@ if (!self) { return nil; } - BOOL success = [self initializeSessionMemory]; - if (!success) { - return nil; - } NSData *idKey = [theirIdentityKey dataUsingEncoding:NSUTF8StringEncoding]; NSMutableData *otk = [NSMutableData dataWithData:[oneTimeKeyMessage dataUsingEncoding:NSUTF8StringEncoding]]; size_t result = olm_create_inbound_session_from(_session, account.account, idKey.bytes, idKey.length, otk.mutableBytes, otk.length); @@ -143,16 +144,6 @@ return encryptedMessage; } -- (BOOL) removeOneTimeKeys { - size_t result = olm_remove_one_time_keys(_account.account, _session); - if (result == olm_error()) { - const char *error = olm_session_last_error(_session); - NSAssert(NO, @"olm_remove_one_time_keys error: %s", error); - return NO; - } - return YES; -} - - (NSString*) decryptMessage:(OLMMessage*)message { NSParameterAssert(message != nil); NSData *messageData = [message.ciphertext dataUsingEncoding:NSUTF8StringEncoding]; @@ -180,4 +171,91 @@ return plaintext; } +#pragma mark OLMSerializable + +/** Initializes from encrypted serialized data. Will throw error if invalid key or invalid base64. */ +- (instancetype) initWithSerializedData:(NSString*)serializedData key:(NSData*)key error:(NSError**)error { + self = [self init]; + if (!self) { + return nil; + } + NSParameterAssert(key.length > 0); + NSParameterAssert(serializedData.length > 0); + if (key.length == 0 || serializedData.length == 0) { + if (error) { + *error = [NSError errorWithDomain:@"org.matrix.olm" code:0 userInfo:@{NSLocalizedDescriptionKey: @"Bad length."}]; + } + return nil; + } + NSMutableData *pickle = [serializedData dataUsingEncoding:NSUTF8StringEncoding].mutableCopy; + size_t result = olm_unpickle_session(_session, key.bytes, key.length, pickle.mutableBytes, pickle.length); + if (result == olm_error()) { + const char *olm_error = olm_session_last_error(_session); + NSString *errorString = [NSString stringWithUTF8String:olm_error]; + if (error && errorString) { + *error = [NSError errorWithDomain:@"org.matrix.olm" code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}]; + } + return nil; + } + return self; +} + +/** Serializes and encrypts object data, outputs base64 blob */ +- (NSString*) serializeDataWithKey:(NSData*)key error:(NSError**)error { + NSParameterAssert(key.length > 0); + size_t length = olm_pickle_session_length(_session); + NSMutableData *pickled = [NSMutableData dataWithLength:length]; + size_t result = olm_pickle_session(_session, key.bytes, key.length, pickled.mutableBytes, pickled.length); + if (result == olm_error()) { + const char *olm_error = olm_session_last_error(_session); + NSString *errorString = [NSString stringWithUTF8String:olm_error]; + if (error && errorString) { + *error = [NSError errorWithDomain:@"org.matrix.olm" code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}]; + } + return nil; + } + NSString *pickleString = [[NSString alloc] initWithData:pickled encoding:NSUTF8StringEncoding]; + return pickleString; +} + +#pragma mark NSSecureCoding + ++ (BOOL) supportsSecureCoding { + return YES; +} + +#pragma mark NSCoding + +- (id)initWithCoder:(NSCoder *)decoder { + NSString *version = [decoder decodeObjectOfClass:[NSString class] forKey:@"version"]; + + NSError *error = nil; + + if ([version isEqualToString:@"1"]) { + NSString *pickle = [decoder decodeObjectOfClass:[NSString class] forKey:@"pickle"]; + NSData *key = [decoder decodeObjectOfClass:[NSData class] forKey:@"key"]; + + self = [self initWithSerializedData:pickle key:key error:&error]; + } + + NSParameterAssert(error == nil); + NSParameterAssert(self != nil); + if (!self) { + return nil; + } + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder { + NSData *key = [OLMUtility randomBytesOfLength:32]; + NSError *error = nil; + NSString *pickle = [self serializeDataWithKey:key error:&error]; + NSParameterAssert(pickle.length > 0 && error == nil); + + [encoder encodeObject:pickle forKey:@"pickle"]; + [encoder encodeObject:key forKey:@"key"]; + [encoder encodeObject:@"1" forKey:@"version"]; +} + @end diff --git a/xcode/OLMKit/OLMSession_Private.h b/xcode/OLMKit/OLMSession_Private.h new file mode 100644 index 0000000..d906b14 --- /dev/null +++ b/xcode/OLMKit/OLMSession_Private.h @@ -0,0 +1,16 @@ +// +// OLMSession_Private.h +// olm +// +// Created by Chris Ballinger on 4/13/16. +// +// + +@import olm; + +@interface OLMSession() + +@property (nonatomic) OlmSession *session; +@property (nonatomic, strong) OLMAccount *account; + +@end \ No newline at end of file -- cgit v1.2.3