aboutsummaryrefslogtreecommitdiff
path: root/xcode
diff options
context:
space:
mode:
authorChris Ballinger <chrisballinger@gmail.com>2016-04-09 14:00:30 -0700
committerChris Ballinger <chrisballinger@gmail.com>2016-04-09 14:00:30 -0700
commitf505113fb7a6d61015ad8050b3fb4e26df029150 (patch)
tree0bdaba8f07189f3adc828c2895ce7429d9b3cb3e /xcode
parent719eb543a8d08c4f536ea7933ffb3af0a8553e87 (diff)
Initial test passing
Diffstat (limited to 'xcode')
-rw-r--r--xcode/OLMKit/OLMAccount.m6
-rw-r--r--xcode/OLMKit/OLMMessage.h16
-rw-r--r--xcode/OLMKit/OLMMessage.m11
-rw-r--r--xcode/OLMKit/OLMSession.h23
-rw-r--r--xcode/OLMKit/OLMSession.m165
-rw-r--r--xcode/OLMKit/OLMUtility.h2
-rw-r--r--xcode/OLMKit/OLMUtility.m13
-rw-r--r--xcode/OLMKitTests/OLMKitTests.m25
8 files changed, 227 insertions, 34 deletions
diff --git a/xcode/OLMKit/OLMAccount.m b/xcode/OLMKit/OLMAccount.m
index 58dd4ad..d56b6b4 100644
--- a/xcode/OLMKit/OLMAccount.m
+++ b/xcode/OLMKit/OLMAccount.m
@@ -44,7 +44,8 @@
return nil;
}
size_t randomLength = olm_create_account_random_length(_account);
- size_t accountResult = olm_create_account(_account, (void*)[OLMUtility randomBytesOfLength:randomLength].bytes, randomLength);
+ NSMutableData *random = [OLMUtility randomBytesOfLength:randomLength];
+ size_t accountResult = olm_create_account(_account, random.mutableBytes, random.length);
if (accountResult == olm_error()) {
const char *error = olm_account_last_error(_account);
NSLog(@"error creating account: %s", error);
@@ -105,7 +106,8 @@
- (void) generateOneTimeKeys:(NSUInteger)numberOfKeys {
size_t randomLength = olm_account_generate_one_time_keys_random_length(_account, numberOfKeys);
- size_t result = olm_account_generate_one_time_keys(_account, numberOfKeys, (void*)[OLMUtility randomBytesOfLength:randomLength].bytes, randomLength);
+ NSMutableData *random = [OLMUtility randomBytesOfLength:randomLength];
+ size_t result = olm_account_generate_one_time_keys(_account, numberOfKeys, random.mutableBytes, random.length);
if (result == olm_error()) {
const char *error = olm_account_last_error(_account);
NSLog(@"error generating keys: %s", error);
diff --git a/xcode/OLMKit/OLMMessage.h b/xcode/OLMKit/OLMMessage.h
index 2b747fb..97c748f 100644
--- a/xcode/OLMKit/OLMMessage.h
+++ b/xcode/OLMKit/OLMMessage.h
@@ -8,17 +8,21 @@
#import <Foundation/Foundation.h>
-typedef NS_ENUM(NSUInteger, OLMMessageType) {
- OLMMessageTypeUnknown,
- OLMMessageTypePreKey,
- OLMMessageTypeMessage
+/*
+ from olm.hh
+ static const size_t OLM_MESSAGE_TYPE_PRE_KEY = 0;
+ static const size_t OLM_MESSAGE_TYPE_MESSAGE = 1;
+ */
+typedef NS_ENUM(NSInteger, OLMMessageType) {
+ OLMMessageTypePreKey = 0,
+ OLMMessageTypeMessage = 1
};
@interface OLMMessage : NSObject
-@property (nonatomic, readonly, nonnull) NSString *message;
+@property (nonatomic, copy, readonly, nonnull) NSString *ciphertext;
@property (readonly) OLMMessageType type;
-- (nonnull instancetype) initWithMessage:(nonnull NSString*)message type:(OLMMessageType)type;
+- (nullable instancetype) initWithCiphertext:(nonnull NSString*)ciphertext type:(OLMMessageType)type;
@end
diff --git a/xcode/OLMKit/OLMMessage.m b/xcode/OLMKit/OLMMessage.m
index ce732ec..d0cfb41 100644
--- a/xcode/OLMKit/OLMMessage.m
+++ b/xcode/OLMKit/OLMMessage.m
@@ -10,4 +10,15 @@
@implementation OLMMessage
+- (nullable instancetype) initWithCiphertext:(nonnull NSString*)ciphertext type:(OLMMessageType)type {
+ NSParameterAssert(ciphertext != nil);
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+ _ciphertext = [ciphertext copy];
+ _type = type;
+ return self;
+}
+
@end
diff --git a/xcode/OLMKit/OLMSession.h b/xcode/OLMKit/OLMSession.h
index 196900f..1a075e4 100644
--- a/xcode/OLMKit/OLMSession.h
+++ b/xcode/OLMKit/OLMSession.h
@@ -9,21 +9,30 @@
#import <Foundation/Foundation.h>
#import "OLMSerializable.h"
#import "OLMAccount.h"
+#import "OLMMessage.h"
@interface OLMSession : NSObject <OLMSerializable>
-- (instancetype) initOutboundSessionWithAccount:(OLMAccount*)account theirIdentityKey:(NSData*)theirIdentityKey theirOneTimeKey:(NSData*)theirOneTimeKey;
+@property (nonatomic, strong) OLMAccount *account;
-- (instancetype) initInboundSessionWithAccount:(OLMAccount*)account oneTimeKeyMessage:(NSData*)oneTimeKeyMessage;
+- (instancetype) initOutboundSessionWithAccount:(OLMAccount*)account theirIdentityKey:(NSString*)theirIdentityKey theirOneTimeKey:(NSString*)theirOneTimeKey;
-- (instancetype) initInboundSessionWithAccount:(OLMAccount*)account theirIdentityKey:(NSData*)theirIdentityKey oneTimeKeyMessage:(NSData*)oneTimeKeyMessage;
+- (instancetype) initInboundSessionWithAccount:(OLMAccount*)account oneTimeKeyMessage:(NSString*)oneTimeKeyMessage;
-- (NSData*) sessionIdentifier;
+- (instancetype) initInboundSessionWithAccount:(OLMAccount*)account theirIdentityKey:(NSString*)theirIdentityKey oneTimeKeyMessage:(NSString*)oneTimeKeyMessage;
-- (BOOL) matchesInboundSession:(NSData*)oneTimeKeyMessage;
+- (NSString*) sessionIdentifier;
-- (BOOL) matchesInboundSessionFrom:(NSData*)theirIdentityKey oneTimeKeyMessage:(NSData *)oneTimeKeyMessage;
+- (BOOL) matchesInboundSession:(NSString*)oneTimeKeyMessage;
-- (void) removeOneTimeKeys;
+- (BOOL) matchesInboundSessionFrom:(NSString*)theirIdentityKey oneTimeKeyMessage:(NSString *)oneTimeKeyMessage;
+
+- (BOOL) removeOneTimeKeys;
+
+/** UTF-8 plaintext -> base64 ciphertext */
+- (OLMMessage*) encryptMessage:(NSString*)message;
+
+/** base64 ciphertext -> UTF-8 plaintext */
+- (NSString*) decryptMessage:(OLMMessage*)message;
@end
diff --git a/xcode/OLMKit/OLMSession.m b/xcode/OLMKit/OLMSession.m
index 24a8b36..fa7cb62 100644
--- a/xcode/OLMKit/OLMSession.m
+++ b/xcode/OLMKit/OLMSession.m
@@ -7,6 +7,8 @@
//
#import "OLMSession.h"
+#import "OLMUtility.h"
+#import "OLMAccount_Private.h"
@import olm;
@interface OLMSession()
@@ -15,16 +17,167 @@
@implementation OLMSession
-- (instancetype) initOutboundSessionWithAccount:(OLMAccount*)account theirIdentityKey:(NSData*)theirIdentityKey theirOneTimeKey:(NSData*)theirOneTimeKey {
-
+- (void) dealloc {
+ olm_clear_session(_session);
+ free(_session);
}
-- (instancetype) initInboundSessionWithAccount:(OLMAccount*)account oneTimeKeyMessage:(NSData*)oneTimeKeyMessage {
-
+- (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) initInboundSessionWithAccount:(OLMAccount*)account theirIdentityKey:(NSData*)theirIdentityKey oneTimeKeyMessage:(NSData*)oneTimeKeyMessage {
-
+- (instancetype) initWithAccount:(OLMAccount*)account {
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+ BOOL success = [self initializeSessionMemory];
+ if (!success) {
+ 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;
+ }
+ 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()) {
+ 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;
+ }
+ 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);
+ 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;
+}
+
+- (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];
+ 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;
}
@end
diff --git a/xcode/OLMKit/OLMUtility.h b/xcode/OLMKit/OLMUtility.h
index 0de9725..8acbf40 100644
--- a/xcode/OLMKit/OLMUtility.h
+++ b/xcode/OLMKit/OLMUtility.h
@@ -10,6 +10,6 @@
@interface OLMUtility : NSObject
-+ (NSData*) randomBytesOfLength:(NSUInteger)length;
++ (NSMutableData*) randomBytesOfLength:(NSUInteger)length;
@end
diff --git a/xcode/OLMKit/OLMUtility.m b/xcode/OLMKit/OLMUtility.m
index 0148932..5dbe644 100644
--- a/xcode/OLMKit/OLMUtility.m
+++ b/xcode/OLMKit/OLMUtility.m
@@ -10,19 +10,16 @@
@implementation OLMUtility
-+ (NSData*) randomBytesOfLength:(NSUInteger)length {
- uint8_t *randomBytes = malloc(length * sizeof(uint8_t));
- NSParameterAssert(randomBytes != NULL);
- if (!randomBytes) {
++ (NSMutableData*) randomBytesOfLength:(NSUInteger)length {
+ NSMutableData *randomData = [NSMutableData dataWithLength:length];
+ if (!randomData) {
return nil;
}
- int result = SecRandomCopyBytes(kSecRandomDefault, length, randomBytes);
+ int result = SecRandomCopyBytes(kSecRandomDefault, randomData.length, randomData.mutableBytes);
if (result != 0) {
- free(randomBytes);
return nil;
}
- NSData *data = [NSData dataWithBytesNoCopy:randomBytes length:length freeWhenDone:YES];
- return data;
+ return randomData;
}
@end
diff --git a/xcode/OLMKitTests/OLMKitTests.m b/xcode/OLMKitTests/OLMKitTests.m
index 944d11c..7075057 100644
--- a/xcode/OLMKitTests/OLMKitTests.m
+++ b/xcode/OLMKitTests/OLMKitTests.m
@@ -31,10 +31,27 @@
OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
[bob generateOneTimeKeys:5];
- NSDictionary *identityKeys = bob.identityKeys;
- NSDictionary *oneTimeKeys = bob.oneTimeKeys;
- NSParameterAssert(identityKeys != nil);
- NSParameterAssert(oneTimeKeys != nil);
+ NSDictionary *bobIdKeys = bob.identityKeys;
+ NSString *bobIdKey = bobIdKeys[@"curve25519"];
+ NSDictionary *bobOneTimeKeys = bob.oneTimeKeys;
+ NSParameterAssert(bobIdKey != nil);
+ NSParameterAssert(bobOneTimeKeys != nil);
+ __block NSString *bobOneTimeKey = nil;
+ NSDictionary *bobOtkCurve25519 = bobOneTimeKeys[@"curve25519"];
+ [bobOtkCurve25519 enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
+ bobOneTimeKey = obj;
+ }];
+ XCTAssert([bobOneTimeKey isKindOfClass:[NSString class]]);
+
+ OLMSession *aliceSession = [[OLMSession alloc] initOutboundSessionWithAccount:alice theirIdentityKey:bobIdKey theirOneTimeKey:bobOneTimeKey];
+ NSString *message = @"Hello!";
+ OLMMessage *aliceToBobMsg = [aliceSession encryptMessage:message];
+
+ OLMSession *bobSession = [[OLMSession alloc] initInboundSessionWithAccount:bob oneTimeKeyMessage:aliceToBobMsg.ciphertext];
+ NSString *plaintext = [bobSession decryptMessage:aliceToBobMsg];
+ XCTAssertEqualObjects(message, plaintext);
+ BOOL success = [bobSession removeOneTimeKeys];
+ XCTAssertTrue(success);
}