Added ObjC fallbackKey support and updated tests.

This commit is contained in:
Stefan Ceriu 2021-08-18 16:44:34 +03:00
parent 8ddb72cfed
commit 91a619b745
3 changed files with 144 additions and 65 deletions

View file

@ -35,6 +35,9 @@
/** Public parts of the unpublished one time keys for the account */ /** Public parts of the unpublished one time keys for the account */
- (NSDictionary*) oneTimeKeys; - (NSDictionary*) oneTimeKeys;
/** Public part of the unpublished fallback key for the account */
- (NSDictionary*) fallbackKey;
- (BOOL) removeOneTimeKeysForSession:(OLMSession*)session; - (BOOL) removeOneTimeKeysForSession:(OLMSession*)session;
/** Marks the current set of one time keys as being published. */ /** Marks the current set of one time keys as being published. */
@ -48,4 +51,7 @@
* discarded. */ * discarded. */
- (void) generateOneTimeKeys:(NSUInteger)numberOfKeys; - (void) generateOneTimeKeys:(NSUInteger)numberOfKeys;
/** Generates a fallback key. */
- (void) generateFallbackKey;
@end @end

View file

@ -145,7 +145,6 @@
return keysDictionary; return keysDictionary;
} }
- (void) generateOneTimeKeys:(NSUInteger)numberOfKeys { - (void) generateOneTimeKeys:(NSUInteger)numberOfKeys {
size_t randomLength = olm_account_generate_one_time_keys_random_length(_account, numberOfKeys); size_t randomLength = olm_account_generate_one_time_keys_random_length(_account, numberOfKeys);
NSMutableData *random = [OLMUtility randomBytesOfLength:randomLength]; NSMutableData *random = [OLMUtility randomBytesOfLength:randomLength];
@ -157,6 +156,40 @@
} }
} }
- (NSDictionary *) fallbackKey {
size_t fallbackKeyLength = olm_account_fallback_key_length(_account);
uint8_t *fallbackKeyBytes = malloc(fallbackKeyLength);
if (!fallbackKeyBytes) {
return nil;
}
size_t result = olm_account_fallback_key(_account, fallbackKeyBytes, fallbackKeyLength);
if (result == olm_error()) {
const char *error = olm_account_last_error(_account);
NSLog(@"error getting fallback key: %s", error);
free(fallbackKeyBytes);
return nil;
}
NSData *fallbackKeyData = [NSData dataWithBytesNoCopy:fallbackKeyBytes length:fallbackKeyLength freeWhenDone:YES];
NSError *error = nil;
NSDictionary *keyDictionary = [NSJSONSerialization JSONObjectWithData:fallbackKeyData options:0 error:&error];
if (error) {
NSLog(@"Could not decode JSON: %@", error.localizedDescription);
}
return keyDictionary;
}
- (void) generateFallbackKey {
size_t randomLength = olm_account_generate_fallback_key_random_length(_account);
NSMutableData *random = [OLMUtility randomBytesOfLength:randomLength];
size_t result = olm_account_generate_fallback_key(_account, random.mutableBytes, random.length);
[random resetBytesInRange:NSMakeRange(0, random.length)];
if (result == olm_error()) {
const char *error = olm_account_last_error(_account);
NSLog(@"error generating keys: %s", error);
}
}
- (BOOL) removeOneTimeKeysForSession:(OLMSession *)session { - (BOOL) removeOneTimeKeysForSession:(OLMSession *)session {
NSParameterAssert(session != nil); NSParameterAssert(session != nil);
if (!session) { if (!session) {

View file

@ -25,35 +25,38 @@ limitations under the License.
@implementation OLMKitTests @implementation OLMKitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testAliceAndBob { - (void)testAliceAndBob {
NSError *error;
OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
OLMAccount *bob = [[OLMAccount alloc] initNewAccount]; OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
[bob generateOneTimeKeys:5]; [bob generateOneTimeKeys:5];
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 error:nil]; [self _testAliceAndBob:bob withBobKeys:bob.oneTimeKeys];
}
- (void)testAliceAndBobFallbackKey {
OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
[bob generateFallbackKey];
[self _testAliceAndBob:bob withBobKeys:bob.fallbackKey];
}
- (void)_testAliceAndBob:(OLMAccount *)bob withBobKeys:(NSDictionary *)bobKeys {
XCTAssertNotNil(bob);
XCTAssertNotNil(bobKeys);
NSError *error;
NSString *bobIdKey = bob.identityKeys[@"curve25519"];
XCTAssertNotNil(bobIdKey);
__block NSString *bobKeyValue = nil;
[bobKeys[@"curve25519"] enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
bobKeyValue = obj;
}];
XCTAssert([bobKeyValue isKindOfClass:[NSString class]]);
OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
OLMSession *aliceSession = [[OLMSession alloc] initOutboundSessionWithAccount:alice theirIdentityKey:bobIdKey theirOneTimeKey:bobKeyValue error:nil];
NSString *message = @"Hello!"; NSString *message = @"Hello!";
OLMMessage *aliceToBobMsg = [aliceSession encryptMessage:message error:&error]; OLMMessage *aliceToBobMsg = [aliceSession encryptMessage:message error:&error];
XCTAssertNil(error); XCTAssertNil(error);
@ -75,29 +78,43 @@ limitations under the License.
XCTAssertTrue(success); XCTAssertTrue(success);
} }
- (void) testBackAndForth { - (void)testBackAndForthWithOneTimeKeys {
OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
OLMAccount *bob = [[OLMAccount alloc] initNewAccount]; OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
[bob generateOneTimeKeys:1]; [bob generateOneTimeKeys:1];
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 error:nil]; [self _testBackAndForthWithBob:bob andBobKeys:bob.oneTimeKeys];
}
- (void)testBackAndForthWithFallbackKey {
OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
[bob generateFallbackKey];
[self _testBackAndForthWithBob:bob andBobKeys:bob.fallbackKey];
}
- (void)_testBackAndForthWithBob:(OLMAccount *)bob andBobKeys:(NSDictionary *)bobKeys {
XCTAssertNotNil(bob);
XCTAssertNotNil(bobKeys);
NSString *bobIdKey = bob.identityKeys[@"curve25519"];
XCTAssertNotNil(bobIdKey);
__block NSString *bobKeyValue = nil;
[bobKeys[@"curve25519"] enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
bobKeyValue = obj;
}];
XCTAssert([bobKeyValue isKindOfClass:[NSString class]]);
OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
OLMSession *aliceSession = [[OLMSession alloc] initOutboundSessionWithAccount:alice theirIdentityKey:bobIdKey theirOneTimeKey:bobKeyValue error:nil];
NSString *message = @"Hello I'm Alice!"; NSString *message = @"Hello I'm Alice!";
OLMMessage *aliceToBobMsg = [aliceSession encryptMessage:message error:nil]; OLMMessage *aliceToBobMsg = [aliceSession encryptMessage:message error:nil];
OLMSession *bobSession = [[OLMSession alloc] initInboundSessionWithAccount:bob oneTimeKeyMessage:aliceToBobMsg.ciphertext error:nil]; OLMSession *bobSession = [[OLMSession alloc] initInboundSessionWithAccount:bob oneTimeKeyMessage:aliceToBobMsg.ciphertext error:nil];
NSString *plaintext = [bobSession decryptMessage:aliceToBobMsg error:nil]; NSString *plaintext = [bobSession decryptMessage:aliceToBobMsg error:nil];
XCTAssertEqualObjects(message, plaintext); XCTAssertEqualObjects(message, plaintext);
BOOL success = [bob removeOneTimeKeysForSession:bobSession]; BOOL success = [bob removeOneTimeKeysForSession:bobSession];
XCTAssertTrue(success); XCTAssertTrue(success);
@ -120,46 +137,65 @@ limitations under the License.
- (void)testAccountSerialization { - (void)testAccountSerialization {
OLMAccount *bob = [[OLMAccount alloc] initNewAccount]; OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
[bob generateOneTimeKeys:5]; [bob generateOneTimeKeys:5];
[bob generateFallbackKey];
NSDictionary *bobIdKeys = bob.identityKeys; NSDictionary *bobIdKeys = bob.identityKeys;
NSDictionary *bobOneTimeKeys = bob.oneTimeKeys; NSDictionary *bobOneTimeKeys = bob.oneTimeKeys;
NSDictionary *bobFallbackKey = bob.fallbackKey;
NSData *bobData = [NSKeyedArchiver archivedDataWithRootObject:bob]; NSError *error;
NSData *bobData = [NSKeyedArchiver archivedDataWithRootObject:bob requiringSecureCoding:NO error:&error];
XCTAssertNil(error);
OLMAccount *bob2 = [NSKeyedUnarchiver unarchivedObjectOfClass:[OLMAccount class] fromData:bobData error:&error];
XCTAssertNil(error);
OLMAccount *bob2 = [NSKeyedUnarchiver unarchiveObjectWithData:bobData];
NSDictionary *bobIdKeys2 = bob2.identityKeys; NSDictionary *bobIdKeys2 = bob2.identityKeys;
NSDictionary *bobOneTimeKeys2 = bob2.oneTimeKeys; NSDictionary *bobOneTimeKeys2 = bob2.oneTimeKeys;
NSDictionary *bobFallbackKey2 = bob2.fallbackKey;
XCTAssertEqualObjects(bobIdKeys, bobIdKeys2); XCTAssertEqualObjects(bobIdKeys, bobIdKeys2);
XCTAssertEqualObjects(bobOneTimeKeys, bobOneTimeKeys2); XCTAssertEqualObjects(bobOneTimeKeys, bobOneTimeKeys2);
XCTAssertEqualObjects(bobFallbackKey, bobFallbackKey2);
} }
- (void) testSessionSerialization { - (void)testSessionSerializationWithOneTimeKey {
NSError *error;
OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
OLMAccount *bob = [[OLMAccount alloc] initNewAccount]; OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
[bob generateOneTimeKeys:1]; [bob generateOneTimeKeys:1];
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 error:nil]; [self _testSessionSerializationWithBob:bob bobKeys:bob.oneTimeKeys];
}
- (void)testSessionSerializationWithFallbackKey {
OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
[bob generateFallbackKey];
[self _testSessionSerializationWithBob:bob bobKeys:bob.fallbackKey];
}
- (void)_testSessionSerializationWithBob:(OLMAccount *)bob bobKeys:(NSDictionary *)bobKeys {
NSError *error;
NSString *bobIdKey = bob.identityKeys[@"curve25519"];
XCTAssertNotNil(bobIdKey);
__block NSString *bobKeyValue = nil;
[bobKeys[@"curve25519"] enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
bobKeyValue = obj;
}];
XCTAssert([bobKeyValue isKindOfClass:[NSString class]]);
OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
OLMSession *aliceSession = [[OLMSession alloc] initOutboundSessionWithAccount:alice theirIdentityKey:bobIdKey theirOneTimeKey:bobKeyValue error:nil];
NSString *message = @"Hello I'm Alice!"; NSString *message = @"Hello I'm Alice!";
OLMMessage *aliceToBobMsg = [aliceSession encryptMessage:message error:&error]; OLMMessage *aliceToBobMsg = [aliceSession encryptMessage:message error:&error];
XCTAssertNil(error); XCTAssertNil(error);
OLMSession *bobSession = [[OLMSession alloc] initInboundSessionWithAccount:bob oneTimeKeyMessage:aliceToBobMsg.ciphertext error:nil]; OLMSession *bobSession = [[OLMSession alloc] initInboundSessionWithAccount:bob oneTimeKeyMessage:aliceToBobMsg.ciphertext error:nil];
NSString *plaintext = [bobSession decryptMessage:aliceToBobMsg error:nil]; NSString *plaintext = [bobSession decryptMessage:aliceToBobMsg error:nil];
XCTAssertEqualObjects(message, plaintext); XCTAssertEqualObjects(message, plaintext);
BOOL success = [bob removeOneTimeKeysForSession:bobSession]; BOOL success = [bob removeOneTimeKeysForSession:bobSession];
XCTAssertTrue(success); XCTAssertTrue(success);
@ -171,8 +207,11 @@ limitations under the License.
OLMMessage *eMsg2 = [bobSession encryptMessage:msg2 error:nil]; OLMMessage *eMsg2 = [bobSession encryptMessage:msg2 error:nil];
OLMMessage *eMsg3 = [bobSession encryptMessage:msg3 error:nil]; OLMMessage *eMsg3 = [bobSession encryptMessage:msg3 error:nil];
NSData *aliceData = [NSKeyedArchiver archivedDataWithRootObject:aliceSession]; NSData *aliceData = [NSKeyedArchiver archivedDataWithRootObject:aliceSession requiringSecureCoding:NO error:&error];
OLMSession *alice2 = [NSKeyedUnarchiver unarchiveObjectWithData:aliceData]; XCTAssertNil(error);
OLMSession *alice2 = [NSKeyedUnarchiver unarchivedObjectOfClass:[OLMSession class] fromData:aliceData error:&error];
XCTAssertNil(error);
NSString *dMsg1 = [alice2 decryptMessage:eMsg1 error:nil]; NSString *dMsg1 = [alice2 decryptMessage:eMsg1 error:nil];
NSString *dMsg2 = [alice2 decryptMessage:eMsg2 error:nil]; NSString *dMsg2 = [alice2 decryptMessage:eMsg2 error:nil];
@ -183,6 +222,7 @@ limitations under the License.
} }
- (void)testEd25519Signing { - (void)testEd25519Signing {
NSError *error;
OLMUtility *olmUtility = [[OLMUtility alloc] init]; OLMUtility *olmUtility = [[OLMUtility alloc] init];
OLMAccount *alice = [[OLMAccount alloc] initNewAccount]; OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
@ -191,13 +231,13 @@ limitations under the License.
@"key1": @"value1", @"key1": @"value1",
@"key2": @"value2" @"key2": @"value2"
}; };
NSData *message = [NSKeyedArchiver archivedDataWithRootObject:aJSON]; NSData *message = [NSKeyedArchiver archivedDataWithRootObject:aJSON requiringSecureCoding:NO error:&error];
NSString *signature = [alice signMessage:message]; XCTAssertNil(error);
NSString *signature = [alice signMessage:message];
NSString *aliceEd25519Key = alice.identityKeys[@"ed25519"]; NSString *aliceEd25519Key = alice.identityKeys[@"ed25519"];
NSError *error;
BOOL result = [olmUtility verifyEd25519Signature:signature key:aliceEd25519Key message:message error:&error]; BOOL result = [olmUtility verifyEd25519Signature:signature key:aliceEd25519Key message:message error:&error];
XCTAssert(result); XCTAssert(result);
XCTAssertNil(error); XCTAssertNil(error);