aboutsummaryrefslogtreecommitdiff
path: root/xcode/OLMKit/OLMSession.m
diff options
context:
space:
mode:
Diffstat (limited to 'xcode/OLMKit/OLMSession.m')
-rw-r--r--xcode/OLMKit/OLMSession.m261
1 files changed, 261 insertions, 0 deletions
diff --git a/xcode/OLMKit/OLMSession.m b/xcode/OLMKit/OLMSession.m
new file mode 100644
index 0000000..41aef7e
--- /dev/null
+++ b/xcode/OLMKit/OLMSession.m
@@ -0,0 +1,261 @@
+//
+// OLMSession.m
+// olm
+//
+// Created by Chris Ballinger on 4/8/16.
+//
+//
+
+#import "OLMSession.h"
+#import "OLMUtility.h"
+#import "OLMAccount_Private.h"
+#import "OLMSession_Private.h"
+#include "olm/olm.h"
+
+@implementation OLMSession
+
+- (void) dealloc {
+ olm_clear_session(_session);
+ free(_session);
+}
+
+- (BOOL) initializeSessionMemory {
+ size_t size = olm_session_size();
+ _session = malloc(size);
+ NSParameterAssert(_session != nil);
+ if (!_session) {
+ return NO;
+ }
+ _session = olm_session(_session);
+ NSParameterAssert(_session != nil);
+ if (!_session) {
+ return NO;
+ }
+ return YES;
+}
+
+- (instancetype) init {
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+ BOOL success = [self initializeSessionMemory];
+ 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;
+}
+
+- (instancetype) initOutboundSessionWithAccount:(OLMAccount*)account theirIdentityKey:(NSString*)theirIdentityKey theirOneTimeKey:(NSString*)theirOneTimeKey {
+ self = [self initWithAccount:account];
+ if (!self) {
+ return nil;
+ }
+ NSMutableData *random = [OLMUtility randomBytesOfLength:olm_create_outbound_session_random_length(_session)];
+ NSData *idKey = [theirIdentityKey dataUsingEncoding:NSUTF8StringEncoding];
+ NSData *otKey = [theirOneTimeKey dataUsingEncoding:NSUTF8StringEncoding];
+ size_t result = olm_create_outbound_session(_session, account.account, idKey.bytes, idKey.length, otKey.bytes, otKey.length, random.mutableBytes, random.length);
+ if (result == olm_error()) {
+ const char *error = olm_session_last_error(_session);
+ NSAssert(NO, @"olm_create_outbound_session error: %s", error);
+ return nil;
+ }
+ return self;
+}
+
+- (instancetype) initInboundSessionWithAccount:(OLMAccount*)account oneTimeKeyMessage:(NSString*)oneTimeKeyMessage {
+ self = [self initWithAccount:account];
+ if (!self) {
+ 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()) {
+ const char *error = olm_session_last_error(_session);
+ NSAssert(NO, @"olm_create_inbound_session error: %s", error);
+ return nil;
+ }
+ return self;
+}
+
+- (instancetype) initInboundSessionWithAccount:(OLMAccount*)account theirIdentityKey:(NSString*)theirIdentityKey oneTimeKeyMessage:(NSString*)oneTimeKeyMessage {
+ self = [self initWithAccount:account];
+ if (!self) {
+ 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);
+ if (result == olm_error()) {
+ const char *error = olm_session_last_error(_session);
+ NSAssert(NO, @"olm_create_inbound_session_from error: %s", error);
+ return nil;
+ }
+ return self;
+}
+
+- (NSString*) sessionIdentifier {
+ size_t length = olm_session_id_length(_session);
+ NSMutableData *idData = [NSMutableData dataWithLength:length];
+ if (!idData) {
+ return nil;
+ }
+ size_t result = olm_session_id(_session, idData.mutableBytes, idData.length);
+ if (result == olm_error()) {
+ const char *error = olm_session_last_error(_session);
+ NSAssert(NO, @"olm_session_id error: %s", error);
+ return nil;
+ }
+ NSString *idString = [[NSString alloc] initWithData:idData encoding:NSUTF8StringEncoding];
+ return idString;
+}
+
+- (OLMMessage*) encryptMessage:(NSString*)message {
+ size_t messageType = olm_encrypt_message_type(_session);
+ size_t randomLength = olm_encrypt_random_length(_session);
+ NSMutableData *random = [OLMUtility randomBytesOfLength:randomLength];
+ NSData *plaintextData = [message dataUsingEncoding:NSUTF8StringEncoding];
+ size_t ciphertextLength = olm_encrypt_message_length(_session, plaintextData.length);
+ NSMutableData *ciphertext = [NSMutableData dataWithLength:ciphertextLength];
+ if (!ciphertext) {
+ return nil;
+ }
+ size_t result = olm_encrypt(_session, plaintextData.bytes, plaintextData.length, random.mutableBytes, random.length, ciphertext.mutableBytes, ciphertext.length);
+ if (result == olm_error()) {
+ const char *error = olm_session_last_error(_session);
+ NSAssert(NO, @"olm_encrypt error: %s", error);
+ return nil;
+ }
+ NSString *ciphertextString = [[NSString alloc] initWithData:ciphertext encoding:NSUTF8StringEncoding];
+ OLMMessage *encryptedMessage = [[OLMMessage alloc] initWithCiphertext:ciphertextString type:messageType];
+ return encryptedMessage;
+}
+
+- (NSString*) decryptMessage:(OLMMessage*)message {
+ NSParameterAssert(message != nil);
+ NSData *messageData = [message.ciphertext dataUsingEncoding:NSUTF8StringEncoding];
+ if (!messageData) {
+ return nil;
+ }
+ NSMutableData *mutMessage = messageData.mutableCopy;
+ size_t maxPlaintextLength = olm_decrypt_max_plaintext_length(_session, message.type, mutMessage.mutableBytes, mutMessage.length);
+ if (maxPlaintextLength == olm_error()) {
+ const char *error = olm_session_last_error(_session);
+ NSAssert(NO, @"olm_decrypt_max_plaintext_length error: %s", error);
+ return nil;
+ }
+ // message buffer is destroyed by olm_decrypt_max_plaintext_length
+ mutMessage = messageData.mutableCopy;
+ NSMutableData *plaintextData = [NSMutableData dataWithLength:maxPlaintextLength];
+ size_t plaintextLength = olm_decrypt(_session, message.type, mutMessage.mutableBytes, mutMessage.length, plaintextData.mutableBytes, plaintextData.length);
+ if (plaintextLength == olm_error()) {
+ const char *error = olm_session_last_error(_session);
+ NSAssert(NO, @"olm_decrypt error: %s", error);
+ return nil;
+ }
+ plaintextData.length = plaintextLength;
+ NSString *plaintext = [[NSString alloc] initWithData:plaintextData encoding:NSUTF8StringEncoding];
+ 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