diff --git a/MTProtoKit/MTHttpWorker.m b/MTProtoKit/MTHttpWorker.m index b15796820f..8732083027 100644 --- a/MTProtoKit/MTHttpWorker.m +++ b/MTProtoKit/MTHttpWorker.m @@ -69,6 +69,12 @@ MTInternalIdClass(MTHttpWorker) int32_t randomId = 0; arc4random_buf(&randomId, 4); +/*#ifdef DEBUG + if (![address isIpv6]) { + address = [[MTDatacenterAddress alloc] initWithIp:@"127.0.0.1" port:443 preferForMedia:address.preferForMedia restrictToTcp:address.restrictToTcp]; + } +#endif*/ + NSString *urlString = [[NSString alloc] initWithFormat:@"http://%@:%d/api%" PRIx32 "", address.ip, (int)address.port, randomId]; self = [super initWithBaseURL:[[NSURL alloc] initWithString:urlString]]; diff --git a/MTProtoKit/MTInputStream.m b/MTProtoKit/MTInputStream.m index 32d229d565..d0f012a13d 100644 --- a/MTProtoKit/MTInputStream.m +++ b/MTProtoKit/MTInputStream.m @@ -68,6 +68,8 @@ static inline int roundUpInput(int numToRound, int multiple) { if (MTLogEnabled()) { MTLog(@"***** Couldn't read int32"); + + @throw [[NSException alloc] initWithName:@"MTInputStreamException" reason:@"readInt32 end of stream" userInfo:@{}]; } } diff --git a/MTProtoKit/MTMessageEncryptionKey.h b/MTProtoKit/MTMessageEncryptionKey.h index 2f82ace6e8..364cef36a6 100644 --- a/MTProtoKit/MTMessageEncryptionKey.h +++ b/MTProtoKit/MTMessageEncryptionKey.h @@ -14,6 +14,8 @@ @property (nonatomic, strong, readonly) NSData *iv; + (instancetype)messageEncryptionKeyForAuthKey:(NSData *)authKey messageKey:(NSData *)messageKey toClient:(bool)toClient; ++ (instancetype)messageEncryptionKeyV2ForAuthKey:(NSData *)authKey messageKey:(NSData *)messageKey toClient:(bool)toClient; + - (instancetype)initWithKey:(NSData *)key iv:(NSData *)iv; @end diff --git a/MTProtoKit/MTMessageEncryptionKey.m b/MTProtoKit/MTMessageEncryptionKey.m index 6695f7418f..8fdb96d0ad 100644 --- a/MTProtoKit/MTMessageEncryptionKey.m +++ b/MTProtoKit/MTMessageEncryptionKey.m @@ -19,8 +19,6 @@ NSAssert(messageKey != nil, @"message key should not be nil"); #endif -#warning TODO more precise length check - if (authKey == nil || authKey.length == 0 || messageKey == nil || messageKey.length == 0) return nil; @@ -77,6 +75,55 @@ return result; } ++ (instancetype)messageEncryptionKeyV2ForAuthKey:(NSData *)authKey messageKey:(NSData *)messageKey toClient:(bool)toClient { +#ifdef DEBUG + NSAssert(authKey != nil, @"authKey should not be nil"); + NSAssert(messageKey != nil, @"message key should not be nil"); +#endif + + if (authKey == nil || authKey.length == 0 || messageKey == nil || messageKey.length == 0) + return nil; + + /* + sha256_a = SHA256 (msg_key + substr (auth_key, x, 36)); + + sha256_b = SHA256 (substr (auth_key, 40+x, 36) + msg_key); + + aes_key = substr (sha256_a, 0, 8) + substr (sha256_b, 8, 16) + substr (sha256_a, 24, 8); + aes_iv = substr (sha256_b, 0, 8) + substr (sha256_a, 8, 16) + substr (sha256_b, 24, 8); + */ + + int xValue = toClient ? 8 : 0; + + NSMutableData *sha256_a_data = [[NSMutableData alloc] init]; + [sha256_a_data appendData:messageKey]; + [sha256_a_data appendBytes:authKey.bytes + xValue length:36]; + + NSData *sha256_a = MTSha256(sha256_a_data); + + NSMutableData *sha256_b_data = [[NSMutableData alloc] init]; + [sha256_b_data appendBytes:authKey.bytes + 40 + xValue length:36]; + [sha256_b_data appendData:messageKey]; + + NSData *sha256_b = MTSha256(sha256_b_data); + + NSMutableData *aesKey = [[NSMutableData alloc] init]; + [aesKey appendBytes:sha256_a.bytes + 0 length:8]; + [aesKey appendBytes:sha256_b.bytes + 8 length:16]; + [aesKey appendBytes:sha256_a.bytes + 24 length:8]; + + NSMutableData *aesIv = [[NSMutableData alloc] init]; + [aesIv appendBytes:sha256_b.bytes + 0 length:8]; + [aesIv appendBytes:sha256_a.bytes + 8 length:16]; + [aesIv appendBytes:sha256_b.bytes + 24 length:8]; + + MTMessageEncryptionKey *result = [[MTMessageEncryptionKey alloc] init]; + result->_key = [[NSData alloc] initWithData:aesKey]; + result->_iv = [[NSData alloc] initWithData:aesIv]; + + return result; +} + - (instancetype)initWithKey:(NSData *)key iv:(NSData *)iv { self = [super init]; diff --git a/MTProtoKit/MTProto.m b/MTProtoKit/MTProto.m index 562a471175..fff06f4ebe 100644 --- a/MTProtoKit/MTProto.m +++ b/MTProtoKit/MTProto.m @@ -55,6 +55,8 @@ #import "MTTime.h" +#define MTProtoV2 1 + typedef enum { MTProtoStateAwaitingDatacenterScheme = 1, MTProtoStateAwaitingDatacenterAuthorization = 2, @@ -1148,21 +1150,25 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; [decryptedOs writeInt32:(int32_t)messageData.length]; [decryptedOs writeData:messageData]; - uint8_t randomBytes[15]; - arc4random_buf(randomBytes, 15); - for (int i = 0; ((int)messageData.length + i) % 16 != 0; i++) - { - [decryptedOs write:&randomBytes[i] maxLength:1]; - } + NSData *decryptedData = [self paddedData:[decryptedOs currentBytes]]; - NSData *decryptedData = [decryptedOs currentBytes]; +#if MTProtoV2 + int xValue = 0; + NSMutableData *msgKeyLargeData = [[NSMutableData alloc] init]; + [msgKeyLargeData appendBytes:_authInfo.authKey.bytes + 88 + xValue length:32]; + [msgKeyLargeData appendData:decryptedData]; + NSData *msgKeyLarge = MTSha256(msgKeyLargeData); + NSData *messageKey = [msgKeyLarge subdataWithRange:NSMakeRange(8, 16)]; + MTMessageEncryptionKey *encryptionKey = [MTMessageEncryptionKey messageEncryptionKeyV2ForAuthKey:_authInfo.authKey messageKey:messageKey toClient:false]; +#else NSData *messageKeyFull = MTSubdataSha1(decryptedData, 0, 32 + messageData.length); NSData *messageKey = [[NSData alloc] initWithBytes:(((int8_t *)messageKeyFull.bytes) + messageKeyFull.length - 16) length:16]; + MTMessageEncryptionKey *encryptionKey = [MTMessageEncryptionKey messageEncryptionKeyForAuthKey:_authInfo.authKey messageKey:messageKey toClient:false]; +#endif NSData *transactionData = nil; - MTMessageEncryptionKey *encryptionKey = [MTMessageEncryptionKey messageEncryptionKeyForAuthKey:_authInfo.authKey messageKey:messageKey toClient:false]; if (encryptionKey != nil) { NSMutableData *encryptedData = [[NSMutableData alloc] initWithCapacity:14 + decryptedData.length]; @@ -1263,27 +1269,32 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; [decryptedOs writeInt32:(int32_t)containerData.length]; [decryptedOs writeData:containerData]; - uint8_t randomBytes[15]; - arc4random_buf(randomBytes, 15); - for (int i = 0; ((int)containerData.length + i) % 16 != 0; i++) - { - [decryptedOs write:&randomBytes[i] maxLength:1]; - } + NSData *decryptedData = [self paddedData:[decryptedOs currentBytes]]; - NSData *decryptedData = [decryptedOs currentBytes]; +#if MTProtoV2 + int xValue = 0; + NSMutableData *msgKeyLargeData = [[NSMutableData alloc] init]; + [msgKeyLargeData appendBytes:_authInfo.authKey.bytes + 88 + xValue length:32]; + [msgKeyLargeData appendData:decryptedData]; + NSData *msgKeyLarge = MTSha256(msgKeyLargeData); + NSData *messageKey = [msgKeyLarge subdataWithRange:NSMakeRange(8, 16)]; + MTMessageEncryptionKey *encryptionKey = [MTMessageEncryptionKey messageEncryptionKeyV2ForAuthKey:_authInfo.authKey messageKey:messageKey toClient:false]; + int32_t nQuickAckId = *((int32_t *)(msgKeyLarge.bytes)); +#else NSData *messageKeyFull = MTSubdataSha1(decryptedData, 0, 32 + containerData.length); NSData *messageKey = [[NSData alloc] initWithBytes:(((int8_t *)messageKeyFull.bytes) + messageKeyFull.length - 16) length:16]; - + MTMessageEncryptionKey *encryptionKey = [MTMessageEncryptionKey messageEncryptionKeyForAuthKey:_authInfo.authKey messageKey:messageKey toClient:false]; int32_t nQuickAckId = *((int32_t *)(messageKeyFull.bytes)); +#endif + nQuickAckId = nQuickAckId & 0x7fffffff; if (quickAckId != NULL) *quickAckId = nQuickAckId; - MTMessageEncryptionKey *encryptionKey = [MTMessageEncryptionKey messageEncryptionKeyForAuthKey:_authInfo.authKey messageKey:messageKey toClient:false]; if (encryptionKey != nil) { - NSMutableData *encryptedData = [[NSMutableData alloc] initWithCapacity:14 + decryptedData.length]; + NSMutableData *encryptedData = [[NSMutableData alloc] init]; [encryptedData appendData:decryptedData]; MTAesEncryptInplace(encryptedData, encryptionKey.key, encryptionKey.iv); @@ -1311,6 +1322,39 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; return messageData; } +- (NSData *)paddedData:(NSData *)data { + NSMutableData *padded = [[NSMutableData alloc] initWithData:data]; + uint8_t randomBytes[128]; + arc4random_buf(randomBytes, 128); +#if MTProtoV2 + int take = 0; + while (take < 12) { + [padded appendBytes:randomBytes + take length:1]; + take++; + } + + while (padded.length % 16 != 0) { + [padded appendBytes:randomBytes + take length:1]; + take++; + } + + int remainingCount = arc4random_uniform(72 + 1 - take); + while (remainingCount % 16 != 0) { + remainingCount--; + } + + for (int i = 0; i < remainingCount; i++) { + [padded appendBytes:randomBytes + take length:1]; + take++; + } +#else + for (int i = 0; ((int)data.length + i) % 16 != 0; i++) { + [padded appendBytes:randomBytes + i length:1]; + } +#endif + return padded; +} + - (NSData *)_dataForEncryptedMessage:(MTPreparedMessage *)preparedMessage sessionInfo:(MTSessionInfo *)sessionInfo quickAckId:(int32_t *)quickAckId { MTOutputStream *decryptedOs = [[MTOutputStream alloc] init]; @@ -1323,15 +1367,18 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; [decryptedOs writeInt32:(int32_t)preparedMessage.data.length]; [decryptedOs writeData:preparedMessage.data]; - uint8_t randomBytes[15]; - arc4random_buf(randomBytes, 15); - for (int i = 0; ((int)preparedMessage.data.length + i) % 16 != 0; i++) - { - [decryptedOs write:&randomBytes[i] maxLength:1]; - } + NSData *decryptedData = [self paddedData:[decryptedOs currentBytes]]; - NSData *decryptedData = [decryptedOs currentBytes]; +#if MTProtoV2 + int xValue = 0; + NSMutableData *msgKeyLargeData = [[NSMutableData alloc] init]; + [msgKeyLargeData appendBytes:_authInfo.authKey.bytes + 88 + xValue length:32]; + [msgKeyLargeData appendData:decryptedData]; + NSData *msgKeyLarge = MTSha256(msgKeyLargeData); + NSData *messageKey = [msgKeyLarge subdataWithRange:NSMakeRange(8, 16)]; + MTMessageEncryptionKey *encryptionKey = [MTMessageEncryptionKey messageEncryptionKeyV2ForAuthKey:_authInfo.authKey messageKey:messageKey toClient:false]; +#else NSData *messageKeyFull = MTSubdataSha1(decryptedData, 0, 32 + preparedMessage.data.length); NSData *messageKey = [[NSData alloc] initWithBytes:(((int8_t *)messageKeyFull.bytes) + messageKeyFull.length - 16) length:16]; @@ -1341,6 +1388,8 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; *quickAckId = nQuickAckId; MTMessageEncryptionKey *encryptionKey = [MTMessageEncryptionKey messageEncryptionKeyForAuthKey:_authInfo.authKey messageKey:messageKey toClient:false]; +#endif + if (encryptionKey != nil) { NSMutableData *encryptedData = [[NSMutableData alloc] initWithCapacity:14 + decryptedData.length]; @@ -1441,7 +1490,11 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; if (keyId != 0 && _authInfo != nil) { NSData *messageKey = [is readData:16]; +#if MTProtoV2 + MTMessageEncryptionKey *encryptionKey = [MTMessageEncryptionKey messageEncryptionKeyV2ForAuthKey:_authInfo.authKey messageKey:messageKey toClient:true]; +#else MTMessageEncryptionKey *encryptionKey = [MTMessageEncryptionKey messageEncryptionKeyForAuthKey:_authInfo.authKey messageKey:messageKey toClient:true]; +#endif NSMutableData *encryptedMessageData = [is readMutableData:(data.length - 24)]; while (encryptedMessageData.length % 16 != 0) { @@ -1687,7 +1740,13 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; return nil; NSData *embeddedMessageKey = [data subdataWithRange:NSMakeRange(8, 16)]; + +#if MTProtoV2 + MTMessageEncryptionKey *encryptionKey = [MTMessageEncryptionKey messageEncryptionKeyV2ForAuthKey:_authInfo.authKey messageKey:embeddedMessageKey toClient:true]; +#else MTMessageEncryptionKey *encryptionKey = [MTMessageEncryptionKey messageEncryptionKeyForAuthKey:_authInfo.authKey messageKey:embeddedMessageKey toClient:true]; +#endif + if (encryptionKey == nil) return nil; @@ -1696,11 +1755,22 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; int32_t messageDataLength = 0; [decryptedData getBytes:&messageDataLength range:NSMakeRange(28, 4)]; - if (messageDataLength < 0 || messageDataLength < (int32_t)decryptedData.length - 32 - 16 || messageDataLength > (int32_t)decryptedData.length - 32) + if (messageDataLength < 0 || messageDataLength > (int32_t)decryptedData.length) return nil; +#if MTProtoV2 + int xValue = 8; + NSMutableData *msgKeyLargeData = [[NSMutableData alloc] init]; + [msgKeyLargeData appendBytes:_authInfo.authKey.bytes + 88 + xValue length:32]; + [msgKeyLargeData appendData:decryptedData]; + + NSData *msgKeyLarge = MTSha256(msgKeyLargeData); + NSData *messageKey = [msgKeyLarge subdataWithRange:NSMakeRange(8, 16)]; +#else NSData *messageKeyFull = MTSubdataSha1(decryptedData, 0, 32 + messageDataLength); NSData *messageKey = [[NSData alloc] initWithBytes:(((int8_t *)messageKeyFull.bytes) + messageKeyFull.length - 16) length:16]; +#endif + if (![messageKey isEqualToData:embeddedMessageKey]) return nil; diff --git a/MTProtoKit/MTTcpConnection.m b/MTProtoKit/MTTcpConnection.m index 39039c23c4..cb0640e17e 100644 --- a/MTProtoKit/MTTcpConnection.m +++ b/MTProtoKit/MTTcpConnection.m @@ -102,7 +102,14 @@ static void init_ctr(struct ctr_state *state, const unsigned char *iv) { _internalId = [[MTInternalId(MTTcpConnection) alloc] init]; +/*#ifdef DEBUG + if (![address isIpv6]) { + address = [[MTDatacenterAddress alloc] initWithIp:@"127.0.0.1" port:443 preferForMedia:address.preferForMedia restrictToTcp:address.restrictToTcp]; + } +#endif*/ + _address = address; + _interface = interface; if (context.apiEnvironment.datacenterAddressOverrides[@(datacenterId)] != nil) { diff --git a/MtProtoKit.xcodeproj/project.pbxproj b/MtProtoKit.xcodeproj/project.pbxproj index 30192ef615..ff95b01abc 100644 --- a/MtProtoKit.xcodeproj/project.pbxproj +++ b/MtProtoKit.xcodeproj/project.pbxproj @@ -515,6 +515,7 @@ D0D225101B4D817B0085E26D /* MtProtoKitDynamic.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D2250F1B4D817B0085E26D /* MtProtoKitDynamic.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0D225161B4D817B0085E26D /* MtProtoKitDynamic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D2250B1B4D817B0085E26D /* MtProtoKitDynamic.framework */; }; D0D2251D1B4D817B0085E26D /* MtProtoKitDynamicTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D2251C1B4D817B0085E26D /* MtProtoKitDynamicTests.m */; }; + D0D2689E1D7A055400C422DA /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D0CD990F1D75C16100F41187 /* libcrypto.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -785,6 +786,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D0D2689E1D7A055400C422DA /* libcrypto.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2453,6 +2455,7 @@ ); MACH_O_TYPE = staticlib; MTL_ENABLE_DEBUG_INFO = NO; + ONLY_ACTIVE_ARCH = NO; OTHER_LDFLAGS = "-lz"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_MODULE_NAME = MtProtoKit; @@ -2627,6 +2630,7 @@ ); MACH_O_TYPE = staticlib; MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = NO; OTHER_LDFLAGS = "-lz"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_MODULE_NAME = MtProtoKit; @@ -2679,6 +2683,7 @@ ); MACH_O_TYPE = staticlib; MTL_ENABLE_DEBUG_INFO = NO; + ONLY_ACTIVE_ARCH = NO; OTHER_LDFLAGS = "-lz"; PRODUCT_BUNDLE_IDENTIFIER = "org.telegram.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_MODULE_NAME = MtProtoKit;