mirror of https://github.com/oxen-io/session-ios
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
7.4 KiB
Objective-C
189 lines
7.4 KiB
Objective-C
//
|
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
|
//
|
|
|
|
#import "RatchetingSession.h"
|
|
#import "AliceAxolotlParameters.h"
|
|
#import "BobAxolotlParameters.h"
|
|
#import "ChainKey.h"
|
|
#import "RootKey.h"
|
|
#import "SessionState.h"
|
|
#import <Curve25519Kit/Curve25519.h>
|
|
#import <HKDFKit/HKDFKit.h>
|
|
#import <SignalCoreKit/SCKExceptionWrapper.h>
|
|
#import <SignalCoreKit/OWSAsserts.h>
|
|
|
|
@interface DHEResult : NSObject
|
|
|
|
@property (nonatomic, readonly) RootKey *rootKey;
|
|
@property (nonatomic, readonly) NSData *chainKey;
|
|
|
|
- (instancetype)init_throws_withMasterKey:(NSData *)data NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
|
|
|
@end
|
|
|
|
@implementation DHEResult
|
|
|
|
- (instancetype)init_throws_withMasterKey:(NSData *)data
|
|
{
|
|
// DHE Result is expected to be the result of 3 or 4 DHEs outputting 32 bytes each,
|
|
// plus the 32 discontinuity bytes added to make V3 incompatible with V2
|
|
OWSAssert([data length] == 32 * 4 || [data length] == 32 * 5);
|
|
|
|
self = [super init];
|
|
const char *HKDFDefaultSalt[4] = {0};
|
|
NSData *salt = [NSData dataWithBytes:HKDFDefaultSalt length:sizeof(HKDFDefaultSalt)];
|
|
NSData *info = [@"WhisperText" dataUsingEncoding:NSUTF8StringEncoding];
|
|
NSData *derivedMaterial = [HKDFKit deriveKey:data info:info salt:salt outputSize:64];
|
|
OWSAssert(derivedMaterial.length == 64);
|
|
_rootKey = [[RootKey alloc] initWithData:[derivedMaterial subdataWithRange:NSMakeRange(0, 32)]];
|
|
_chainKey = [derivedMaterial subdataWithRange:NSMakeRange(32, 32)];
|
|
|
|
return self;
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
@implementation RatchetingSession
|
|
|
|
+ (void)throws_initializeSession:(SessionState *)session
|
|
sessionVersion:(int)sessionVersion
|
|
AliceParameters:(AliceAxolotlParameters *)parameters
|
|
{
|
|
OWSAssert(session);
|
|
OWSAssert(parameters);
|
|
|
|
ECKeyPair *sendingRatchetKey = [Curve25519 generateKeyPair];
|
|
OWSAssert(sendingRatchetKey);
|
|
[self throws_initializeSession:session
|
|
sessionVersion:sessionVersion
|
|
AliceParameters:parameters
|
|
senderRatchet:sendingRatchetKey];
|
|
}
|
|
|
|
+ (BOOL)initializeSession:(SessionState *)session
|
|
sessionVersion:(int)sessionVersion
|
|
bobParameters:(BobAxolotlParameters *)bobParameters
|
|
error:(NSError **)outError
|
|
{
|
|
return [SCKExceptionWrapper
|
|
tryBlock:^{
|
|
[self throws_initializeSession:session sessionVersion:sessionVersion BobParameters:bobParameters];
|
|
}
|
|
error:outError];
|
|
}
|
|
|
|
+ (void)throws_initializeSession:(SessionState *)session
|
|
sessionVersion:(int)sessionVersion
|
|
BobParameters:(BobAxolotlParameters *)parameters
|
|
{
|
|
OWSAssert(session);
|
|
OWSAssert(parameters);
|
|
|
|
[session setVersion:sessionVersion];
|
|
[session setRemoteIdentityKey:parameters.theirIdentityKey];
|
|
[session setLocalIdentityKey:parameters.ourIdentityKeyPair.publicKey];
|
|
|
|
DHEResult *result = [self throws_DHEKeyAgreement:parameters];
|
|
OWSAssert(result);
|
|
|
|
[session setSenderChain:parameters.ourRatchetKey chainKey:[[ChainKey alloc]initWithData:result.chainKey index:0]];
|
|
[session setRootKey:result.rootKey];
|
|
}
|
|
|
|
+ (BOOL)initializeSession:(SessionState *)session
|
|
sessionVersion:(int)sessionVersion
|
|
aliceParameters:(AliceAxolotlParameters *)aliceParameters
|
|
error:(NSError **)outError
|
|
{
|
|
return [SCKExceptionWrapper
|
|
tryBlock:^{
|
|
[self throws_initializeSession:session sessionVersion:sessionVersion AliceParameters:aliceParameters];
|
|
}
|
|
error:outError];
|
|
}
|
|
|
|
+ (void)throws_initializeSession:(SessionState *)session
|
|
sessionVersion:(int)sessionVersion
|
|
AliceParameters:(AliceAxolotlParameters *)parameters
|
|
senderRatchet:(ECKeyPair *)sendingRatchet
|
|
{
|
|
|
|
OWSAssert(session);
|
|
OWSAssert(parameters);
|
|
OWSAssert(sendingRatchet);
|
|
|
|
[session setVersion:sessionVersion];
|
|
[session setRemoteIdentityKey:parameters.theirIdentityKey];
|
|
[session setLocalIdentityKey:parameters.ourIdentityKeyPair.publicKey];
|
|
|
|
DHEResult *result = [self throws_DHEKeyAgreement:parameters];
|
|
OWSAssert(result);
|
|
RKCK *sendingChain =
|
|
[result.rootKey throws_createChainWithTheirEphemeral:parameters.theirRatchetKey ourEphemeral:sendingRatchet];
|
|
OWSAssert(sendingChain);
|
|
|
|
[session addReceiverChain:parameters.theirRatchetKey chainKey:[[ChainKey alloc]initWithData:result.chainKey index:0]];
|
|
[session setSenderChain:sendingRatchet chainKey:sendingChain.chainKey];
|
|
[session setRootKey:sendingChain.rootKey];
|
|
}
|
|
|
|
+ (DHEResult *)throws_DHEKeyAgreement:(id<AxolotlParameters>)parameters
|
|
{
|
|
OWSAssert(parameters);
|
|
|
|
NSMutableData *masterKey = [NSMutableData data];
|
|
|
|
[masterKey appendData:[self discontinuityBytes]];
|
|
|
|
if ([parameters isKindOfClass:[AliceAxolotlParameters class]]) {
|
|
AliceAxolotlParameters *params = (AliceAxolotlParameters*)parameters;
|
|
|
|
[masterKey appendData:[Curve25519 throws_generateSharedSecretFromPublicKey:params.theirSignedPreKey
|
|
andKeyPair:params.ourIdentityKeyPair]];
|
|
[masterKey appendData:[Curve25519 throws_generateSharedSecretFromPublicKey:params.theirIdentityKey
|
|
andKeyPair:params.ourBaseKey]];
|
|
[masterKey appendData:[Curve25519 throws_generateSharedSecretFromPublicKey:params.theirSignedPreKey
|
|
andKeyPair:params.ourBaseKey]];
|
|
if (params.theirOneTimePrekey) {
|
|
[masterKey appendData:[Curve25519 throws_generateSharedSecretFromPublicKey:params.theirOneTimePrekey
|
|
andKeyPair:params.ourBaseKey]];
|
|
}
|
|
} else if ([parameters isKindOfClass:[BobAxolotlParameters class]]){
|
|
BobAxolotlParameters *params = (BobAxolotlParameters*)parameters;
|
|
|
|
[masterKey appendData:[Curve25519 throws_generateSharedSecretFromPublicKey:params.theirIdentityKey
|
|
andKeyPair:params.ourSignedPrekey]];
|
|
[masterKey appendData:[Curve25519 throws_generateSharedSecretFromPublicKey:params.theirBaseKey
|
|
andKeyPair:params.ourIdentityKeyPair]];
|
|
[masterKey appendData:[Curve25519 throws_generateSharedSecretFromPublicKey:params.theirBaseKey
|
|
andKeyPair:params.ourSignedPrekey]];
|
|
if (params.ourOneTimePrekey) {
|
|
[masterKey appendData:[Curve25519 throws_generateSharedSecretFromPublicKey:params.theirBaseKey
|
|
andKeyPair:params.ourOneTimePrekey]];
|
|
}
|
|
}
|
|
|
|
return [[DHEResult alloc] init_throws_withMasterKey:masterKey];
|
|
}
|
|
|
|
/**
|
|
* The discontinuity bytes enforce that the session initialization is different between protocol V2 and V3.
|
|
*
|
|
* @return Returns 32-bytes of 0xFF
|
|
*/
|
|
|
|
+ (NSData*)discontinuityBytes{
|
|
NSMutableData *discontinuity = [NSMutableData data];
|
|
int8_t byte = 0xFF;
|
|
|
|
for (int i = 0; i < 32; i++) {
|
|
[discontinuity appendBytes:&byte length:sizeof(int8_t)];
|
|
}
|
|
return [NSData dataWithData:discontinuity];
|
|
}
|
|
|
|
|
|
@end
|