Skip to content

Commit

Permalink
Merge pull request #10 from ivRodriguezCA/doubleratchet_state
Browse files Browse the repository at this point in the history
Fix Double Ratchet Setup and Restoring State
  • Loading branch information
ivRodriguezCA authored Sep 22, 2017
2 parents fb0ef7b + 5f90795 commit 6184ab8
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 82 deletions.
28 changes: 24 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ NSData *aliceSharedSecret = //some shared secret, for example ECDH(alice.private

IRDoubleRatchetService *bobDoubleRatchet = [IRDoubleRatchetService new];
NSData *bobSharedSecret = //some shared secret, for example ECDH(bob.privateKey,alice.publicKey)
[bobDoubleRatchet setupRatchetForReceivingWithSharedKey:bobSharedSecret andSignedPreKeyPair:alice.signedPreKeyPair];
[bobDoubleRatchet setupRatchetForReceivingWithSharedKey:bobSharedSecret andDHSenderKey:alice.signedPreKeyPair];

//Sending messages
NSData *message = //some message
Expand All @@ -267,13 +267,14 @@ if (error == nil) {
```
Swift
```Swift
//Alice is the sender and Bob is the receiver
let aliceDoubleRatchet = IRDoubleRatchetService()
let aliceSharedSecret = //some shared secret, for example ECDH(alice.privateKey,bob.publicKey)
aliceDoubleRatchet.setupRatchetForSending(withSharedKey: aliceSharedSecret, andDHReceiverKey: bobKeyPair)
let bobDoubleRatchet = IRDoubleRatchetService()
let bobSharedSecret = //some shared secret, for example ECDH(bob.privateKey,alice.publicKey)
bobDoubleRatchet.setupRatchetForReceiving(withSharedKey: bobSharedSecret, andSignedPreKeyPair: alice.signedPreKeyPair)
bobDoubleRatchet.setupRatchetForReceiving(withSharedKey: bobSharedSecret, andDHSenderKey: alice.signedPreKeyPair)
//Sending messages
let message = //some message
Expand All @@ -289,6 +290,25 @@ do {
}
```
### Double Ratchet: setup from stored state
Objc
```Objc
NSDictionary<NSString *, NSString *> *state = [someDoubleRatchet doubleRatchetState];
//store state in local encrypted db

IRDoubleRatchetService *doubleRatchet = [IRDoubleRatchetService new];
NSDictionary<NSString *, NSString *> *state = //get double ratchet state from local encrypted DB
[doubleRatchet setupWithRatchetState:state];
```
Swift
```Swift
let state = someDoubleRatchet.doubleRatchetState()
//store state in local encrypted db
let doubleRatchet = IRDoubleRatchetService()
let state = //get double ratchet state from local encrypted DB
doubleRatchet.setup(withRatchetState: state)
```
### Triple Diffie-Hellman: setup, shared secret generation
Objc
```Objc
Expand All @@ -301,14 +321,14 @@ IRTripleDHService *tripleDH = [[IRTripleDHService alloc] initWithIdentityKeyPair
IRCurve25519KeyPair *rIdentityKey = //get receiver's identity key from server or db
IRCurve25519KeyPair *rSignedPreKey = //get receiver's signed pre-key from server or db
IRCurve25519KeyPair *rEphemeralKey = //get one of the receiver's ephemeral keys from server
NSData *sharedKey = tripleDH.sharedKeyFromReceiverIdentityKey:rIdentityKey receiverSignedPreKey:rSignedPreKey receiverEphemeralKey:rEphemeralKey
NSData *sharedKey = [tripleDH sharedKeyFromReceiverIdentityKey:rIdentityKey receiverSignedPreKey:rSignedPreKey receiverEphemeralKey:rEphemeralKey];
//Use sharedKey

//When receiving a message
IRCurve25519KeyPair *sIdentityKey = //get sender's identity key from server or db
IRCurve25519KeyPair *sEphemeralKey = //get sender's signed pre-key from server or db
NSString *rEphemeralKeyID = //get ephemeral key id from received message's heeader
NSData *sharedKey = tripleDH.sharedKeyFromSenderIdentityKey:sIdentityKey senderEphemeralKey:sEphemeralKey receiverEphemeralKeyID:rEphemeralKeyID];
NSData *sharedKey = [tripleDH sharedKeyFromSenderIdentityKey:sIdentityKey senderEphemeralKey:sEphemeralKey receiverEphemeralKeyID:rEphemeralKeyID];
//Use sharedKey

```
Expand Down
2 changes: 1 addition & 1 deletion nuntius.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Pod::Spec.new do |s|
s.name = "nuntius"
s.version = "0.0.8"
s.version = "0.0.9"
s.summary = "iOS Framework for end-to-end encrypted messages"
s.description = <<-DESC
Expand Down
1 change: 1 addition & 0 deletions nuntius/IRConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

extern NSString * _Nonnull const kDHSenderKey_Key;
extern NSString * _Nonnull const kDHReceiverKey_Key;
extern NSString * _Nonnull const kRootKey_Key;
extern NSString * _Nonnull const kChainKeySender_Key;
extern NSString * _Nonnull const kChainKeyReceiver_Key;
extern NSString * _Nonnull const kSkippedMessagesKeys_Key;
Expand Down
1 change: 1 addition & 0 deletions nuntius/IRConstants.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ @implementation IRConstants

NSString * const kDHSenderKey_Key = @"DHSenderKey_Key";
NSString * const kDHReceiverKey_Key = @"DHReceiverKey_Key";
NSString * const kRootKey_Key = @"RootKey_Key";
NSString * const kChainKeySender_Key = @"ChainKeySender_Key";
NSString * const kChainKeyReceiver_Key = @"ChainKeyReceiver_Key";
NSString * const kSkippedMessagesKeys_Key = @"SkippedMessagesKeys_Key";
Expand Down
12 changes: 5 additions & 7 deletions nuntius/IRDoubleRatchetService.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,19 @@

#pragma mark - Setup Ratchet

//Restore state

- (void)setupWithRatchetState:(NSDictionary<NSString *, NSString *> * _Nullable)doubleRatchetState;

//Setup for sending
- (void)setupRatchetForSendingWithSharedKey:(NSData * _Nonnull)sharedKey
andDHReceiverKey:(IRCurve25519KeyPair * _Nonnull)DHReceiverKey
doubleRatchetState:(NSDictionary<NSString *, NSString *> * _Nullable)doubleRatchetState;

- (void)setupRatchetForSendingWithSharedKey:(NSData * _Nonnull)sharedKey
andDHReceiverKey:(IRCurve25519KeyPair * _Nonnull)DHReceiverKey;

//Setup for receiving
- (void)setupRatchetForReceivingWithSharedKey:(NSData * _Nonnull)sharedKey
andSignedPreKeyPair:(IRCurve25519KeyPair * _Nonnull)signedPreKeyPair
doubleRatchetState:(NSDictionary<NSString *, NSString *> * _Nullable)doubleRatchetState;

- (void)setupRatchetForReceivingWithSharedKey:(NSData * _Nonnull)sharedKey
andSignedPreKeyPair:(IRCurve25519KeyPair * _Nonnull)signedPreKeyPair;
andDHSenderKey:(IRCurve25519KeyPair * _Nonnull)DHSenderKey;

#pragma mark - Encrypt

Expand Down
138 changes: 73 additions & 65 deletions nuntius/IRDoubleRatchetService.m
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,25 @@ - (instancetype)init {
return self;
}

#pragma mark - Restore State

- (void)setupWithRatchetState:(NSDictionary<NSString *, NSString *> * _Nullable)doubleRatchetState {
self.DHSenderKey = [self DHSenderKeyFromDoubleRatchetState:doubleRatchetState];
self.DHReceiverKey = [self DHReceiverKeyFromDoubleRatchetState:doubleRatchetState];
self.rootKey = [self rootKeyFromDoubleRatchetState:doubleRatchetState];
self.chainKeySender = [self chainKeySenderFromDoubleRatchetState:doubleRatchetState];
self.chainKeyReceiver = [self chainKeyReceiverFromDoubleRatchetState:doubleRatchetState];
self.numberOfSentMessages = [self numberOfSentMessagesFromDoubleRatchetState:doubleRatchetState];
self.numberOfReceivedMessages = [self numberOfReceivedMessagesFromDoubleRatchetState:doubleRatchetState];
self.numberOfPreviousChainSentMessages = [self numberOfPreviousChainSentMessagesFromDoubleRatchetState:doubleRatchetState];
self.skippedMessagesKeys = [self skippedMessagesKeysFromDoubleRatchetState:doubleRatchetState];
}

#pragma mark - Sending Setup

- (void)setupRatchetForSendingWithSharedKey:(NSData * _Nonnull)sharedKey
andDHReceiverKey:(IRCurve25519KeyPair * _Nonnull)DHReceiverKey
doubleRatchetState:(NSDictionary<NSString *, NSString *> * _Nullable)doubleRatchetState {
andDHReceiverKey:(IRCurve25519KeyPair * _Nonnull)DHReceiverKey {

self.DHSenderKey = [self.encryptionService generateKeyPair];
self.DHReceiverKey = DHReceiverKey;

Expand All @@ -80,53 +94,27 @@ - (void)setupRatchetForSendingWithSharedKey:(NSData * _Nonnull)sharedKey
NSRange chainKeySenderRange = NSMakeRange(32, 32);
self.chainKeySender = [rootKeyKDFOutput subdataWithRange:chainKeySenderRange];

//Parse Double Ratchet State
self.chainKeyReceiver = [self chainKeyReceiverFromDoubleRatchetState:doubleRatchetState];

self.skippedMessagesKeys = [self skippedMessagesKeysFromDoubleRatchetState:doubleRatchetState];

self.numberOfSentMessages = [self numberOfSentMessagesFromDoubleRatchetState:doubleRatchetState];
self.numberOfReceivedMessages = [self numberOfReceivedMessagesFromDoubleRatchetState:doubleRatchetState];
self.numberOfPreviousChainSentMessages = [self numberOfPreviousChainSentMessagesFromDoubleRatchetState:doubleRatchetState];
}

- (void)setupRatchetForSendingWithSharedKey:(NSData * _Nonnull)sharedKey
andDHReceiverKey:(IRCurve25519KeyPair * _Nonnull)DHReceiverKey {

[self setupRatchetForSendingWithSharedKey:sharedKey
andDHReceiverKey:DHReceiverKey
doubleRatchetState:nil];
self.chainKeyReceiver = nil;
self.skippedMessagesKeys = [@{} mutableCopy];
self.numberOfSentMessages = 0;
self.numberOfReceivedMessages = 0;
self.numberOfPreviousChainSentMessages = 0;
}

#pragma mark - Receiving Setup

- (void)setupRatchetForReceivingWithSharedKey:(NSData * _Nonnull)sharedKey
andSignedPreKeyPair:(IRCurve25519KeyPair * _Nonnull)signedPreKeyPair
doubleRatchetState:(NSDictionary * _Nullable)doubleRatchetState {
andDHSenderKey:(IRCurve25519KeyPair * _Nonnull)DHSenderKey {

IRCurve25519KeyPair *ratchetKey = [self DHSenderKeyFromDoubleRatchetState:doubleRatchetState];
self.DHSenderKey = ratchetKey != nil ? ratchetKey : signedPreKeyPair;
self.DHSenderKey = DHSenderKey;
self.DHReceiverKey = nil;
self.rootKey = sharedKey;

//Parse Double Ratchet State

self.DHReceiverKey = [self DHReceiverKeyFromDoubleRatchetState:doubleRatchetState];
self.chainKeySender = [self chainKeySenderFromDoubleRatchetState:doubleRatchetState];
self.chainKeyReceiver = [self chainKeyReceiverFromDoubleRatchetState:doubleRatchetState];

self.skippedMessagesKeys = [self skippedMessagesKeysFromDoubleRatchetState:doubleRatchetState];

self.numberOfSentMessages = [self numberOfSentMessagesFromDoubleRatchetState:doubleRatchetState];
self.numberOfReceivedMessages = [self numberOfReceivedMessagesFromDoubleRatchetState:doubleRatchetState];
self.numberOfPreviousChainSentMessages = [self numberOfPreviousChainSentMessagesFromDoubleRatchetState:doubleRatchetState];
}

- (void)setupRatchetForReceivingWithSharedKey:(NSData * _Nonnull)sharedKey
andSignedPreKeyPair:(IRCurve25519KeyPair * _Nonnull)signedPreKeyPair {

[self setupRatchetForReceivingWithSharedKey:sharedKey
andSignedPreKeyPair:signedPreKeyPair
doubleRatchetState:nil];
self.chainKeySender = nil;
self.chainKeyReceiver = nil;
self.numberOfSentMessages = 0;
self.numberOfReceivedMessages = 0;
self.numberOfPreviousChainSentMessages = 0;
self.skippedMessagesKeys = [@{} mutableCopy];
}

#pragma mark - Encrypt
Expand Down Expand Up @@ -287,11 +275,22 @@ - (void)performDHRatchet:(IRCurve25519KeyPair * _Nonnull)ratchetKey {
- (NSDictionary<NSString *, NSString *> * _Nonnull)doubleRatchetState {
NSMutableDictionary *state = [NSMutableDictionary new];

//DHSenderKey
NSDictionary *senderSerialized = [self.DHSenderKey serialized];
NSData *senderJSON = [NSJSONSerialization dataWithJSONObject:senderSerialized options:0 error:nil];
NSString *senderValue = [senderJSON base64EncodedStringWithOptions:0];
[state setValue:senderValue forKey:kDHSenderKey_Key];

//DHReceiverKey
NSDictionary *serialized = [self.DHReceiverKey serialized];
NSData *json = [NSJSONSerialization dataWithJSONObject:serialized options:0 error:nil];
NSString *value = [json base64EncodedStringWithOptions:0];
[state setValue:value forKey:kDHReceiverKey_Key];
NSDictionary *receiverSerialized = [self.DHReceiverKey serialized];
NSData *receiverJSON = [NSJSONSerialization dataWithJSONObject:receiverSerialized options:0 error:nil];
NSString *receiverValue = [receiverJSON base64EncodedStringWithOptions:0];
[state setValue:receiverValue forKey:kDHReceiverKey_Key];

//RootKey
if (self.rootKey) {
[state setValue:[self.rootKey base64EncodedStringWithOptions:0] forKey:kRootKey_Key];
}

//ChainKeySender
if (self.chainKeySender) {
Expand All @@ -303,10 +302,6 @@ - (void)performDHRatchet:(IRCurve25519KeyPair * _Nonnull)ratchetKey {
[state setValue:[self.chainKeyReceiver base64EncodedStringWithOptions:0] forKey:kChainKeyReceiver_Key];
}

//SkippedMessagesKeys
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.skippedMessagesKeys];
[state setValue:[data base64EncodedStringWithOptions:0] forKey:kSkippedMessagesKeys_Key];

//NumberOfSentMessages
[state setValue:[@(self.numberOfSentMessages) stringValue] forKey:kNumberOfSentMessages_Key];

Expand All @@ -316,6 +311,10 @@ - (void)performDHRatchet:(IRCurve25519KeyPair * _Nonnull)ratchetKey {
//NumberOfPreviousChainSentMessages
[state setValue:[@(self.numberOfPreviousChainSentMessages) stringValue] forKey:kNumberOfPreviousChainSentMessages_Key];

//SkippedMessagesKeys
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.skippedMessagesKeys];
[state setValue:[data base64EncodedStringWithOptions:0] forKey:kSkippedMessagesKeys_Key];

return [state copy];
}

Expand Down Expand Up @@ -343,6 +342,15 @@ - (IRCurve25519KeyPair *)DHReceiverKeyFromDoubleRatchetState:(NSDictionary *)dou
return [IRCurve25519KeyPair keyPairWithSerializedData:serialized];
}

- (NSData *)rootKeyFromDoubleRatchetState:(NSDictionary *)doubleRatchetState {
NSString *rootKey = doubleRatchetState[kRootKey_Key];
if (rootKey == nil) {
return nil;
}

return [[NSData alloc] initWithBase64EncodedString:rootKey options:0];
}

- (NSData *)chainKeySenderFromDoubleRatchetState:(NSDictionary *)doubleRatchetState {
NSString *chainKey = doubleRatchetState[kChainKeySender_Key];
if (chainKey == nil) {
Expand All @@ -361,21 +369,6 @@ - (NSData *)chainKeyReceiverFromDoubleRatchetState:(NSDictionary *)doubleRatchet
return [[NSData alloc] initWithBase64EncodedString:chainKey options:0];
}

- (NSMutableDictionary *)skippedMessagesKeysFromDoubleRatchetState:(NSDictionary *)doubleRatchetState {
NSString *string = doubleRatchetState[kSkippedMessagesKeys_Key];
if (string == nil) {
return [NSMutableDictionary new];
}

NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
if (data == nil) {
return [NSMutableDictionary new];
}

NSDictionary *messages = [NSKeyedUnarchiver unarchiveObjectWithData:data];
return [messages mutableCopy];
}

- (NSUInteger)numberOfSentMessagesFromDoubleRatchetState:(NSDictionary *)doubleRatchetState {
NSString *string = doubleRatchetState[kNumberOfSentMessages_Key];
if (string == nil) {
Expand Down Expand Up @@ -403,6 +396,21 @@ - (NSUInteger)numberOfPreviousChainSentMessagesFromDoubleRatchetState:(NSDiction
return [string integerValue];
}

- (NSMutableDictionary *)skippedMessagesKeysFromDoubleRatchetState:(NSDictionary *)doubleRatchetState {
NSString *string = doubleRatchetState[kSkippedMessagesKeys_Key];
if (string == nil) {
return [NSMutableDictionary new];
}

NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
if (data == nil) {
return [NSMutableDictionary new];
}

NSDictionary *messages = [NSKeyedUnarchiver unarchiveObjectWithData:data];
return [messages mutableCopy];
}

#pragma mark - Helpers

- (IRAEADInfo * _Nullable)aeadInfoFromMessageKey:(NSData * _Nonnull)messageKey {
Expand Down
Loading

0 comments on commit 6184ab8

Please sign in to comment.