Skip to content
Snippets Groups Projects
Commit f505113f authored by Chris Ballinger's avatar Chris Ballinger
Browse files

Initial test passing

parent 719eb543
No related branches found
No related tags found
No related merge requests found
......@@ -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);
......
......@@ -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
......@@ -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
......@@ -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
......@@ -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
......@@ -10,6 +10,6 @@
@interface OLMUtility : NSObject
+ (NSData*) randomBytesOfLength:(NSUInteger)length;
+ (NSMutableData*) randomBytesOfLength:(NSUInteger)length;
@end
......@@ -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
......@@ -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);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment