// // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "ChainKey.h" #import "TSDerivedSecrets.h" #import #import #import NS_ASSUME_NONNULL_BEGIN @implementation ChainKey static NSString *const kCoderKey = @"kCoderKey"; static NSString *const kCoderIndex = @"kCoderIndex"; #define kTSKeySeedLength 1 static uint8_t kMessageKeySeed[kTSKeySeedLength] = { 01 }; static uint8_t kChainKeySeed[kTSKeySeedLength] = { 02 }; + (BOOL)supportsSecureCoding { return YES; } - (nullable id)initWithCoder:(NSCoder *)aDecoder { NSData *key = [aDecoder decodeObjectOfClass:[NSData class] forKey:kCoderKey]; int index = [aDecoder decodeIntForKey:kCoderIndex]; return [self initWithData:key index:index]; } - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:_key forKey:kCoderKey]; [aCoder encodeInt:_index forKey:kCoderIndex]; } - (instancetype)initWithData:(NSData *)chainKey index:(int)index { OWSAssert(chainKey.length == 32); OWSAssert(index >= 0); self = [super init]; if (self) { _key = chainKey; _index = index; } return self; } - (instancetype)nextChainKey { NSData *nextCK = [self baseMaterial:[NSData dataWithBytes:kChainKeySeed length:kTSKeySeedLength]]; OWSAssert(nextCK.length == 32); int nextIndex; ows_add_overflow(self.index, 1, &nextIndex); return [[ChainKey alloc] initWithData:nextCK index:nextIndex]; } - (MessageKeys *)throws_messageKeys { NSData *inputKeyMaterial = [self baseMaterial:[NSData dataWithBytes:kMessageKeySeed length:kTSKeySeedLength]]; TSDerivedSecrets *derivedSecrets = [TSDerivedSecrets throws_derivedMessageKeysWithData:inputKeyMaterial]; return [[MessageKeys alloc] initWithCipherKey:derivedSecrets.cipherKey macKey:derivedSecrets.macKey iv:derivedSecrets.iv index:self.index]; } - (NSData *)baseMaterial:(NSData *)seed { OWSAssert(self.key); OWSAssert(self.key.length == 32); OWSAssert(seed); OWSAssert(seed.length == kTSKeySeedLength); NSMutableData *_Nullable bufferData = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH]; OWSAssert(bufferData); CCHmacContext ctx; CCHmacInit(&ctx, kCCHmacAlgSHA256, [self.key bytes], [self.key length]); CCHmacUpdate(&ctx, [seed bytes], [seed length]); CCHmacFinal(&ctx, bufferData.mutableBytes); return [bufferData copy]; } @end NS_ASSUME_NONNULL_END