Compare commits
2 Commits
master
...
mkirk/sess
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab57c9cf5c | ||
|
|
55630ef624 |
@ -1,3 +1,5 @@
|
||||
language: objective-c
|
||||
|
||||
osx_image: xcode8
|
||||
|
||||
script: bin/ci
|
||||
|
||||
@ -46,6 +46,28 @@
|
||||
[self runInteractionWithAliceRecord:aliceSessionRecord bobRecord:bobSessionRecord];
|
||||
}
|
||||
|
||||
- (void)testBasicSessionCipherDispatchQueue {
|
||||
SessionRecord *aliceSessionRecord = [SessionRecord new];
|
||||
SessionRecord *bobSessionRecord = [SessionRecord new];
|
||||
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"session cipher completed"];
|
||||
|
||||
dispatch_queue_t sessionCipherDispatchQueue = dispatch_queue_create("session cipher queue", DISPATCH_QUEUE_SERIAL);
|
||||
|
||||
[SessionCipher setSessionCipherDispatchQueue:sessionCipherDispatchQueue];
|
||||
dispatch_async(sessionCipherDispatchQueue, ^{
|
||||
[self sessionInitialization:aliceSessionRecord.sessionState bobSessionState:bobSessionRecord.sessionState];
|
||||
[self runInteractionWithAliceRecord:aliceSessionRecord bobRecord:bobSessionRecord];
|
||||
[expectation fulfill];
|
||||
});
|
||||
|
||||
[self waitForExpectationsWithTimeout:5.0 handler:^(NSError * _Nullable error) {
|
||||
if (error) {
|
||||
XCTFail(@"Expectation failed with error: %@", error);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)sessionInitialization:(SessionState*)aliceSessionState bobSessionState:(SessionState*)bobSessionState{
|
||||
|
||||
ECKeyPair *aliceIdentityKeyPair = [Curve25519 generateKeyPair];
|
||||
|
||||
@ -19,6 +19,16 @@
|
||||
|
||||
@interface SessionCipher : NSObject
|
||||
|
||||
/**
|
||||
* To keep Session state synchronized, encryption and decryption must happen on the same (serial) dispatch queue. If no
|
||||
* queue is specified, the main queue will be used by default. We only assert that this invariant is held. Dispatching
|
||||
* to this thread is the responsibility of the caller.
|
||||
*
|
||||
* @param dispatchQueue serial dispatch queue on which all encryption/decryption must be dispatched.
|
||||
*/
|
||||
+ (void)setSessionCipherDispatchQueue:(dispatch_queue_t)dispatchQueue;
|
||||
+ (dispatch_queue_t)getSessionCipherDispatchQueue;
|
||||
|
||||
- (instancetype)initWithAxolotlStore:(id<AxolotlStore>)sessionStore recipientId:(NSString*)recipientId deviceId:(int)deviceId;
|
||||
|
||||
- (instancetype)initWithSessionStore:(id<SessionStore>)sessionStore preKeyStore:(id<PreKeyStore>)preKeyStore signedPreKeyStore:(id<SignedPreKeyStore>)signedPreKeyStore identityKeyStore:(id<IdentityKeyStore>)identityKeyStore recipientId:(NSString*)recipientId deviceId:(int)deviceId;
|
||||
@ -30,4 +40,4 @@
|
||||
- (int)remoteRegistrationId;
|
||||
- (int)sessionVersion;
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@ -29,6 +29,11 @@
|
||||
|
||||
#import <HKDFKit/HKDFKit.h>
|
||||
|
||||
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(major, minor) \
|
||||
([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){.majorVersion = major, .minorVersion = minor, .patchVersion = 0}])
|
||||
|
||||
static dispatch_queue_t _sessionCipherDispatchQueue;
|
||||
|
||||
@interface SessionCipher ()
|
||||
|
||||
@property NSString* recipientId;
|
||||
@ -77,8 +82,31 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - dispatch queue
|
||||
|
||||
+ (dispatch_queue_t)getSessionCipherDispatchQueue;
|
||||
{
|
||||
if (_sessionCipherDispatchQueue) {
|
||||
return _sessionCipherDispatchQueue;
|
||||
} else {
|
||||
return dispatch_get_main_queue();
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)setSessionCipherDispatchQueue:(dispatch_queue_t)dispatchQueue
|
||||
{
|
||||
_sessionCipherDispatchQueue = dispatchQueue;
|
||||
}
|
||||
|
||||
- (void)assertOnSessionCipherDispatchQueue
|
||||
{
|
||||
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(10, 0)) {
|
||||
dispatch_assert_queue([[self class] getSessionCipherDispatchQueue]);
|
||||
} // else, skip assert as it's a development convenience.
|
||||
}
|
||||
|
||||
- (id<CipherMessage>)encryptMessage:(NSData*)paddedMessage{
|
||||
|
||||
[self assertOnSessionCipherDispatchQueue];
|
||||
SessionRecord *sessionRecord = [self.sessionStore loadSession:self.recipientId deviceId:self.deviceId];
|
||||
SessionState *session = sessionRecord.sessionState;
|
||||
ChainKey *chainKey = session.senderChainKey;
|
||||
@ -118,6 +146,7 @@
|
||||
}
|
||||
|
||||
- (NSData*)decrypt:(id<CipherMessage>)whisperMessage{
|
||||
[self assertOnSessionCipherDispatchQueue];
|
||||
if ([whisperMessage isKindOfClass:[PreKeyWhisperMessage class]]) {
|
||||
return [self decryptPreKeyWhisperMessage:(PreKeyWhisperMessage*)whisperMessage];
|
||||
} else{
|
||||
@ -126,6 +155,7 @@
|
||||
}
|
||||
|
||||
- (NSData*)decryptPreKeyWhisperMessage:(PreKeyWhisperMessage*)preKeyWhisperMessage{
|
||||
[self assertOnSessionCipherDispatchQueue];
|
||||
SessionRecord *sessionRecord = [self.sessionStore loadSession:self.recipientId deviceId:self.deviceId];
|
||||
int unsignedPreKeyId = [self.sessionBuilder processPrekeyWhisperMessage:preKeyWhisperMessage withSession:sessionRecord];
|
||||
NSData *plaintext = [self decryptWithSessionRecord:sessionRecord whisperMessage:preKeyWhisperMessage.message];
|
||||
@ -140,6 +170,7 @@
|
||||
}
|
||||
|
||||
- (NSData*)decryptWhisperMessage:(WhisperMessage*)message{
|
||||
[self assertOnSessionCipherDispatchQueue];
|
||||
if (![self.sessionStore containsSession:self.recipientId deviceId:self.deviceId]) {
|
||||
@throw [NSException exceptionWithName:NoSessionException reason:[NSString stringWithFormat:@"No session for: %@, %d", self.recipientId, self.deviceId] userInfo:nil];
|
||||
}
|
||||
@ -154,6 +185,7 @@
|
||||
|
||||
|
||||
-(NSData*)decryptWithSessionRecord:(SessionRecord*)sessionRecord whisperMessage:(WhisperMessage*)message{
|
||||
[self assertOnSessionCipherDispatchQueue];
|
||||
SessionState *sessionState = [sessionRecord sessionState];
|
||||
NSArray *previousStates = [sessionRecord previousSessionStates];
|
||||
NSMutableArray *exceptions = [NSMutableArray array];
|
||||
@ -182,6 +214,7 @@
|
||||
}
|
||||
|
||||
-(NSData*)decryptWithSessionState:(SessionState*)sessionState whisperMessage:(WhisperMessage*)message{
|
||||
[self assertOnSessionCipherDispatchQueue];
|
||||
if (![sessionState hasSenderChain]) {
|
||||
@throw [NSException exceptionWithName:InvalidMessageException reason:@"Uninitialized session!" userInfo:nil];
|
||||
}
|
||||
@ -206,6 +239,7 @@
|
||||
}
|
||||
|
||||
- (ChainKey*)getOrCreateChainKeys:(SessionState*)sessionState theirEphemeral:(NSData*)theirEphemeral{
|
||||
[self assertOnSessionCipherDispatchQueue];
|
||||
@try {
|
||||
if ([sessionState hasReceiverChain:theirEphemeral]) {
|
||||
return [sessionState receiverChainKey:theirEphemeral];
|
||||
@ -230,7 +264,7 @@
|
||||
}
|
||||
|
||||
- (MessageKeys*)getOrCreateMessageKeysForSession:(SessionState*)sessionState theirEphemeral:(NSData*)theirEphemeral chainKey:(ChainKey*)chainKey counter:(int)counter{
|
||||
|
||||
[self assertOnSessionCipherDispatchQueue];
|
||||
if (chainKey.index > counter) {
|
||||
if ([sessionState hasMessageKeys:theirEphemeral counter:counter]) {
|
||||
return [sessionState removeMessageKeys:theirEphemeral counter:counter];
|
||||
@ -268,6 +302,7 @@
|
||||
|
||||
|
||||
- (int)remoteRegistrationId{
|
||||
[self assertOnSessionCipherDispatchQueue];
|
||||
SessionRecord *record = [self.sessionStore loadSession:self.recipientId deviceId:_deviceId];
|
||||
|
||||
if (!record) {
|
||||
@ -278,6 +313,7 @@
|
||||
}
|
||||
|
||||
- (int)sessionVersion{
|
||||
[self assertOnSessionCipherDispatchQueue];
|
||||
SessionRecord *record = [self.sessionStore loadSession:self.recipientId deviceId:_deviceId];
|
||||
|
||||
if (!record) {
|
||||
@ -287,4 +323,4 @@
|
||||
return record.sessionState.version;
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
53
Gemfile.lock
53
Gemfile.lock
@ -35,38 +35,33 @@ GEM
|
||||
fuzzy_match (~> 2.0.4)
|
||||
nap (~> 1.0)
|
||||
cocoapods-deintegrate (1.0.1)
|
||||
cocoapods-downloader (1.1.2)
|
||||
cocoapods-downloader (1.1.3)
|
||||
cocoapods-plugins (1.0.0)
|
||||
nap
|
||||
cocoapods-search (1.0.0)
|
||||
cocoapods-stats (1.0.0)
|
||||
cocoapods-trunk (1.1.1)
|
||||
cocoapods-trunk (1.1.2)
|
||||
nap (>= 0.8, < 2.0)
|
||||
netrc (= 0.7.8)
|
||||
cocoapods-try (1.1.0)
|
||||
colored (1.2)
|
||||
commander (4.4.1)
|
||||
commander (4.4.3)
|
||||
highline (~> 1.7.2)
|
||||
credentials_manager (0.16.2)
|
||||
colored
|
||||
commander (>= 4.3.5)
|
||||
highline (>= 1.7.1)
|
||||
security
|
||||
domain_name (0.5.20161129)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.1.1)
|
||||
dotenv (2.1.2)
|
||||
escape (0.0.4)
|
||||
excon (0.54.0)
|
||||
faraday (0.10.0)
|
||||
faraday (0.11.0)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday-cookie_jar (0.0.6)
|
||||
faraday (>= 0.7.4)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday_middleware (0.10.1)
|
||||
faraday_middleware (0.11.0.1)
|
||||
faraday (>= 0.7.4, < 1.0)
|
||||
fastimage (2.0.1)
|
||||
addressable (~> 2)
|
||||
fastlane (2.0.1)
|
||||
fastlane (2.9.0)
|
||||
activesupport (< 5)
|
||||
addressable (>= 2.3, < 3.0.0)
|
||||
babosa (>= 1.0.2, < 2.0.0)
|
||||
@ -80,7 +75,7 @@ GEM
|
||||
faraday_middleware (~> 0.9)
|
||||
fastimage (>= 1.6)
|
||||
gh_inspector (>= 1.0.1, < 2.0.0)
|
||||
google-api-client (~> 0.9.1)
|
||||
google-api-client (~> 0.9.2)
|
||||
highline (>= 1.7.2, < 2.0.0)
|
||||
json (< 3.0.0)
|
||||
mini_magick (~> 4.5.1)
|
||||
@ -88,20 +83,19 @@ GEM
|
||||
multi_xml (~> 0.5)
|
||||
multipart-post (~> 2.0.0)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
rubyzip (>= 1.2.0, < 2.0.0)
|
||||
rubyzip (>= 1.1.0, < 2.0.0)
|
||||
security (= 0.1.3)
|
||||
slack-notifier (>= 1.3, < 2.0.0)
|
||||
terminal-notifier (>= 1.6.2, < 2.0.0)
|
||||
terminal-table (>= 1.4.5, < 2.0.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
xcode-install (~> 2.0.0)
|
||||
xcodeproj (>= 0.20, < 2.0.0)
|
||||
xcpretty (>= 0.2.4, < 1.0.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3)
|
||||
fourflusher (2.0.1)
|
||||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.0.2)
|
||||
google-api-client (0.9.20)
|
||||
gh_inspector (1.0.3)
|
||||
google-api-client (0.9.23)
|
||||
addressable (~> 2.3)
|
||||
googleauth (~> 0.5)
|
||||
httpclient (~> 2.7)
|
||||
@ -124,7 +118,7 @@ GEM
|
||||
httpclient (2.8.3)
|
||||
hurley (0.2)
|
||||
i18n (0.7.0)
|
||||
json (1.8.3)
|
||||
json (1.8.6)
|
||||
jwt (1.5.6)
|
||||
little-plugger (1.1.4)
|
||||
logging (2.1.0)
|
||||
@ -136,7 +130,7 @@ GEM
|
||||
mime-types-data (3.2016.0521)
|
||||
mini_magick (4.5.1)
|
||||
minitest (5.10.1)
|
||||
molinillo (0.5.4)
|
||||
molinillo (0.5.5)
|
||||
multi_json (1.12.1)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.0.0)
|
||||
@ -145,7 +139,7 @@ GEM
|
||||
netrc (0.7.8)
|
||||
os (0.9.6)
|
||||
plist (3.2.0)
|
||||
public_suffix (2.0.4)
|
||||
public_suffix (2.0.5)
|
||||
representable (2.3.0)
|
||||
uber (~> 0.0.7)
|
||||
retriable (2.1.0)
|
||||
@ -158,16 +152,6 @@ GEM
|
||||
jwt (~> 1.5)
|
||||
multi_json (~> 1.10)
|
||||
slack-notifier (1.5.1)
|
||||
spaceship (0.39.0)
|
||||
babosa (= 1.0.2)
|
||||
colored
|
||||
credentials_manager (>= 0.16.0)
|
||||
faraday (~> 0.9)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
faraday_middleware (~> 0.9)
|
||||
fastimage (>= 1.6)
|
||||
multi_xml (~> 0.5)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
terminal-notifier (1.7.1)
|
||||
terminal-table (1.7.3)
|
||||
unicode-display_width (~> 1.1.1)
|
||||
@ -178,17 +162,14 @@ GEM
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.2)
|
||||
unicode-display_width (1.1.2)
|
||||
unicode-display_width (1.1.3)
|
||||
word_wrap (1.0.0)
|
||||
xcode-install (2.0.9)
|
||||
claide (>= 0.9.1, < 1.1.0)
|
||||
spaceship (>= 0.25.1, < 1.0.0)
|
||||
xcodeproj (1.4.1)
|
||||
xcodeproj (1.4.2)
|
||||
CFPropertyList (~> 2.3.3)
|
||||
activesupport (>= 3)
|
||||
claide (>= 1.0.1, < 2.0)
|
||||
colored (~> 1.2)
|
||||
nanaimo (~> 0.2.0)
|
||||
nanaimo (~> 0.2.3)
|
||||
xcpretty (0.2.4)
|
||||
rouge (~> 1.8)
|
||||
xcpretty-travis-formatter (0.0.4)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user