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.
166 lines
7.5 KiB
Objective-C
166 lines
7.5 KiB
Objective-C
#import "ConfirmPacket.h"
|
|
#import "Util.h"
|
|
#import "Conversions.h"
|
|
|
|
@implementation ConfirmPacket
|
|
|
|
@synthesize confirmMac, hashChainH0, unusedAndSignatureLengthAndFlags, cacheExperationInterval, isPart1, iv;
|
|
|
|
#define TRUNCATED_HMAC_LENGTH 8
|
|
#define CONFIRM_IV_LENGTH 16
|
|
#define WORD_LENGTH 4
|
|
|
|
+(ConfirmPacket*) confirm1PacketWithHashChain:(HashChain*)hashChain
|
|
andMacKey:(NSData*)macKey
|
|
andCipherKey:(NSData*)cipherKey
|
|
andIv:(NSData*)iv {
|
|
return [ConfirmPacket confirmPacketWithHashChainH0:[hashChain h0]
|
|
andUnusedAndSignatureLengthAndFlags:0
|
|
andCacheExpirationInterval:0xFFFFFFFF
|
|
andMacKey:macKey
|
|
andCipherKey:cipherKey
|
|
andIv:iv
|
|
andIsPart1:true];
|
|
}
|
|
|
|
+(ConfirmPacket*) confirm2PacketWithHashChain:(HashChain*)hashChain
|
|
andMacKey:(NSData*)macKey
|
|
andCipherKey:(NSData*)cipherKey
|
|
andIv:(NSData*)iv {
|
|
return [ConfirmPacket confirmPacketWithHashChainH0:[hashChain h0]
|
|
andUnusedAndSignatureLengthAndFlags:0
|
|
andCacheExpirationInterval:0xFFFFFFFF
|
|
andMacKey:macKey
|
|
andCipherKey:cipherKey
|
|
andIv:iv
|
|
andIsPart1:false];
|
|
}
|
|
|
|
+(ConfirmPacket*) confirmPacketParsedFromHandshakePacket:(HandshakePacket*)handshakePacket
|
|
withMacKey:(NSData*)macKey
|
|
andCipherKey:(NSData*)cipherKey
|
|
andIsPart1:(bool)isPart1 {
|
|
require(handshakePacket != nil);
|
|
require(macKey != nil);
|
|
require(cipherKey != nil);
|
|
NSData* expectedConfirmTypeId = isPart1 ? HANDSHAKE_TYPE_CONFIRM_1 : HANDSHAKE_TYPE_CONFIRM_2;
|
|
|
|
checkOperation([[handshakePacket typeId] isEqualToData:expectedConfirmTypeId]);
|
|
checkOperation([[handshakePacket payload] length] == TRUNCATED_HMAC_LENGTH + CONFIRM_IV_LENGTH + HASH_CHAIN_ITEM_LENGTH + WORD_LENGTH + WORD_LENGTH);
|
|
NSData* decryptedData = [self getDecryptedDataFromPayload:[handshakePacket payload] withMacKey:macKey andCipherKey:cipherKey];
|
|
|
|
return [ConfirmPacket confirmPacketParsedFrom:handshakePacket
|
|
withHashChainH0:[self getHashChainH0FromDecryptedData:decryptedData]
|
|
andUnusedAndSignatureLengthAndFlags:[self getUnusedAndSignatureLengthAndFlagsFromDecryptedData:decryptedData]
|
|
andCacheExpirationInterval:[self getCacheExpirationIntervalFromDecryptedData:decryptedData]
|
|
andIncludedHmac:[self getIncludedHmacFromPayload:[handshakePacket payload]]
|
|
andIv:[self getIvFromPayload:[handshakePacket payload]]
|
|
andIsPart1:isPart1];
|
|
}
|
|
+(ConfirmPacket*) confirmPacketWithHashChainH0:(NSData*)hashChainH0
|
|
andUnusedAndSignatureLengthAndFlags:(uint32_t)unused
|
|
andCacheExpirationInterval:(uint32_t)cacheExpirationInterval
|
|
andMacKey:(NSData*)macKey
|
|
andCipherKey:(NSData*)cipherKey
|
|
andIv:(NSData*)iv
|
|
andIsPart1:(bool)isPart1 {
|
|
require(macKey != nil);
|
|
require(cipherKey != nil);
|
|
require(hashChainH0 != nil);
|
|
require(iv != nil);
|
|
require(iv.length == CONFIRM_IV_LENGTH);
|
|
require(hashChainH0.length == HASH_CHAIN_ITEM_LENGTH);
|
|
|
|
ConfirmPacket* p = [ConfirmPacket new];
|
|
p->hashChainH0 = hashChainH0;
|
|
p->unusedAndSignatureLengthAndFlags = unused;
|
|
p->cacheExperationInterval = cacheExpirationInterval;
|
|
p->iv = iv;
|
|
p->isPart1 = isPart1;
|
|
p->embedding = [p generateEmbedding:cipherKey andMacKey:macKey];
|
|
return p;
|
|
}
|
|
|
|
-(HandshakePacket*) generateEmbedding:(NSData*)cipherKey andMacKey:(NSData*)macKey {
|
|
require(cipherKey != nil);
|
|
require(macKey != nil);
|
|
|
|
NSData* sensitiveData = [@[
|
|
hashChainH0,
|
|
[NSData dataWithBigEndianBytesOfUInt32:unusedAndSignatureLengthAndFlags],
|
|
[NSData dataWithBigEndianBytesOfUInt32:cacheExperationInterval]
|
|
] ows_concatDatas];
|
|
|
|
NSData* encrytedSensitiveData = [sensitiveData encryptWithAesInCipherFeedbackModeWithKey:cipherKey andIv:iv];
|
|
NSData* hmacForSensitiveData = [[encrytedSensitiveData hmacWithSha256WithKey:macKey] take:TRUNCATED_HMAC_LENGTH];
|
|
|
|
NSData* typeId = isPart1 ? HANDSHAKE_TYPE_CONFIRM_1 : HANDSHAKE_TYPE_CONFIRM_2;
|
|
|
|
NSData* payload = [@[
|
|
hmacForSensitiveData,
|
|
iv,
|
|
encrytedSensitiveData
|
|
] ows_concatDatas];
|
|
|
|
return [HandshakePacket handshakePacketWithTypeId:typeId andPayload:payload];
|
|
}
|
|
|
|
+(ConfirmPacket*) confirmPacketParsedFrom:(HandshakePacket*)source
|
|
withHashChainH0:(NSData*)hashChainH0
|
|
andUnusedAndSignatureLengthAndFlags:(uint32_t)unused
|
|
andCacheExpirationInterval:(uint32_t)cacheExpirationInterval
|
|
andIncludedHmac:(NSData*)includedHmac
|
|
andIv:(NSData*)iv
|
|
andIsPart1:(bool)isPart1 {
|
|
|
|
ConfirmPacket* p = [ConfirmPacket new];
|
|
|
|
p->hashChainH0 = hashChainH0;
|
|
p->unusedAndSignatureLengthAndFlags = unused;
|
|
p->cacheExperationInterval = cacheExpirationInterval;
|
|
p->iv = iv;
|
|
p->isPart1 = isPart1;
|
|
p->confirmMac = includedHmac;
|
|
p->embedding = source;
|
|
return p;
|
|
|
|
}
|
|
|
|
+(NSData*) getIncludedHmacFromPayload:(NSData*)payload {
|
|
return [payload take:TRUNCATED_HMAC_LENGTH];
|
|
}
|
|
+(NSData*) getIvFromPayload:(NSData*)payload {
|
|
return [payload subdataVolatileWithRange:NSMakeRange(TRUNCATED_HMAC_LENGTH, CONFIRM_IV_LENGTH)];
|
|
}
|
|
+(NSData*) getVolatileEncryptedDataFromPayload:(NSData*)payload {
|
|
return [payload skipVolatile:TRUNCATED_HMAC_LENGTH + CONFIRM_IV_LENGTH];
|
|
}
|
|
+(NSData*) getDecryptedDataFromPayload:(NSData*)payload
|
|
withMacKey:(NSData*)macKey
|
|
andCipherKey:(NSData*)cipherKey {
|
|
|
|
NSData* iv = [self getIvFromPayload:payload];
|
|
NSData* volatileEncryptedData = [self getVolatileEncryptedDataFromPayload:payload];
|
|
NSData* includedHmac = [self getIncludedHmacFromPayload:payload];
|
|
|
|
NSData* expectedHmac = [[volatileEncryptedData hmacWithSha256WithKey:macKey] take:TRUNCATED_HMAC_LENGTH];
|
|
checkOperation([includedHmac isEqualToData_TimingSafe:expectedHmac]);
|
|
|
|
return [volatileEncryptedData decryptWithAesInCipherFeedbackModeWithKey:cipherKey andIv:iv];
|
|
}
|
|
+(NSData*) getHashChainH0FromDecryptedData:(NSData*)decryptedData {
|
|
return [decryptedData take:HASH_CHAIN_ITEM_LENGTH];
|
|
}
|
|
+(uint32_t) getUnusedAndSignatureLengthAndFlagsFromDecryptedData:(NSData*)decryptedData {
|
|
return [decryptedData bigEndianUInt32At:HASH_CHAIN_ITEM_LENGTH];
|
|
}
|
|
+(uint32_t) getCacheExpirationIntervalFromDecryptedData:(NSData*)decryptedData {
|
|
return [decryptedData bigEndianUInt32At:HASH_CHAIN_ITEM_LENGTH+WORD_LENGTH];
|
|
}
|
|
|
|
-(HandshakePacket*) embeddedIntoHandshakePacket {
|
|
return embedding;
|
|
}
|
|
|
|
@end
|