Refactor Bignum into EncryptionProvider

This commit is contained in:
Peter 2019-10-15 18:47:56 +04:00
parent aebd073934
commit 4543af75b3
39 changed files with 1009 additions and 576 deletions

2
BUCK
View File

@ -335,6 +335,7 @@ apple_binary(
deps = [ deps = [
"//submodules/BuildConfig:BuildConfig", "//submodules/BuildConfig:BuildConfig",
"//submodules/MtProtoKit:MtProtoKit#shared", "//submodules/MtProtoKit:MtProtoKit#shared",
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider",
], ],
frameworks = [ frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework", "$SDKROOT/System/Library/Frameworks/Foundation.framework",
@ -381,6 +382,7 @@ apple_binary(
"//submodules/Postbox:Postbox#shared", "//submodules/Postbox:Postbox#shared",
"//submodules/TelegramCore:TelegramCore#shared", "//submodules/TelegramCore:TelegramCore#shared",
"//submodules/BuildConfig:BuildConfig", "//submodules/BuildConfig:BuildConfig",
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider",
], ],
frameworks = [ frameworks = [
"$SDKROOT/System/Library/Frameworks/UIKit.framework", "$SDKROOT/System/Library/Frameworks/UIKit.framework",

View File

@ -1,10 +1,7 @@
#import "FetchImage.h" #import "FetchImage.h"
#ifdef BUCK
#import <MTProtoKit/MTProtoKit.h> #import <MTProtoKit/MTProtoKit.h>
#else #import <OpenSSLEncryptionProvider/OpenSSLEncryptionProvider.h>
#import <MTProtoKitDynamic/MTProtoKitDynamic.h>
#endif
#import "Serialization.h" #import "Serialization.h"
@ -87,7 +84,7 @@ dispatch_block_t fetchImage(BuildConfig *buildConfig, AccountProxyConnection * _
apiEnvironment = [apiEnvironment withUpdatedSocksProxySettings:[[MTSocksProxySettings alloc] initWithIp:proxyConnection.host port:(uint16_t)proxyConnection.port username:proxyConnection.username password:proxyConnection.password secret:proxyConnection.secret]]; apiEnvironment = [apiEnvironment withUpdatedSocksProxySettings:[[MTSocksProxySettings alloc] initWithIp:proxyConnection.host port:(uint16_t)proxyConnection.port username:proxyConnection.username password:proxyConnection.password secret:proxyConnection.secret]];
} }
MTContext *context = [[MTContext alloc] initWithSerialization:serialization apiEnvironment:apiEnvironment isTestingEnvironment:account.isTestingEnvironment useTempAuthKeys:false]; MTContext *context = [[MTContext alloc] initWithSerialization:serialization encryptionProvider:[[OpenSSLEncryptionProvider alloc] init] apiEnvironment:apiEnvironment isTestingEnvironment:account.isTestingEnvironment useTempAuthKeys:false];
NSDictionary *seedAddressList = @{}; NSDictionary *seedAddressList = @{};
@ -135,7 +132,7 @@ dispatch_block_t fetchImage(BuildConfig *buildConfig, AccountProxyConnection * _
[context updateAuthInfoForDatacenterWithId:[datacenterId intValue] authInfo:[[MTDatacenterAuthInfo alloc] initWithAuthKey:info.masterKey.data authKeyId:info.masterKey.keyId saltSet:@[] authKeyAttributes:@{} mainTempAuthKey:nil mediaTempAuthKey:nil]]; [context updateAuthInfoForDatacenterWithId:[datacenterId intValue] authInfo:[[MTDatacenterAuthInfo alloc] initWithAuthKey:info.masterKey.data authKeyId:info.masterKey.keyId saltSet:@[] authKeyAttributes:@{} mainTempAuthKey:nil mediaTempAuthKey:nil]];
} }
MTProto * mtProto = [[MTProto alloc] initWithContext:context datacenterId:datacenterId usageCalculationInfo:nil]; MTProto *mtProto = [[MTProto alloc] initWithContext:context datacenterId:datacenterId usageCalculationInfo:nil requiredAuthToken:nil authTokenMasterDatacenterId:0];
mtProto.useTempAuthKeys = context.useTempAuthKeys; mtProto.useTempAuthKeys = context.useTempAuthKeys;
mtProto.checkForProxyConnectionIssues = false; mtProto.checkForProxyConnectionIssues = false;

View File

@ -5,6 +5,7 @@ import Postbox
import SwiftSignalKit import SwiftSignalKit
import BuildConfig import BuildConfig
import Contacts import Contacts
import OpenSSLEncryptionProvider
private var accountCache: Account? private var accountCache: Account?
@ -97,7 +98,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
let deviceSpecificEncryptionParameters = BuildConfig.deviceSpecificEncryptionParameters(rootPath, baseAppBundleId: baseAppBundleId) let deviceSpecificEncryptionParameters = BuildConfig.deviceSpecificEncryptionParameters(rootPath, baseAppBundleId: baseAppBundleId)
let encryptionParameters = ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: deviceSpecificEncryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: deviceSpecificEncryptionParameters.salt)!) let encryptionParameters = ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: deviceSpecificEncryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: deviceSpecificEncryptionParameters.salt)!)
account = currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0, appData: .single(buildConfig.bundleData(withAppToken: nil))), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: accountAuxiliaryMethods, encryptionParameters: encryptionParameters) account = currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0, appData: .single(buildConfig.bundleData(withAppToken: nil)), encryptionProvider: OpenSSLEncryptionProvider()), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: accountAuxiliaryMethods, encryptionParameters: encryptionParameters)
|> mapToSignal { account -> Signal<Account?, NoError> in |> mapToSignal { account -> Signal<Account?, NoError> in
if let account = account { if let account = account {
switch account { switch account {

View File

@ -2,6 +2,7 @@ import Foundation
import CloudKit import CloudKit
import MtProtoKit import MtProtoKit
import SwiftSignalKit import SwiftSignalKit
import EncryptionProvider
private enum FetchError { private enum FetchError {
case generic case generic
@ -119,9 +120,12 @@ public protocol CloudDataContext {
@available(iOS 10.0, *) @available(iOS 10.0, *)
public final class CloudDataContextImpl: CloudDataContext { public final class CloudDataContextImpl: CloudDataContext {
private let queue = Queue() private let queue = Queue()
private let encryptionProvider: EncryptionProvider
private let impl: QueueLocalObject<CloudDataContextObject> private let impl: QueueLocalObject<CloudDataContextObject>
public init() { public init(encryptionProvider: EncryptionProvider) {
self.encryptionProvider = encryptionProvider
let queue = self.queue let queue = self.queue
self.impl = QueueLocalObject(queue: queue, generate: { self.impl = QueueLocalObject(queue: queue, generate: {
return CloudDataContextObject(queue: queue) return CloudDataContextObject(queue: queue)
@ -129,6 +133,7 @@ public final class CloudDataContextImpl: CloudDataContext {
} }
public func get(phoneNumber: Signal<String?, NoError>) -> Signal<MTBackupDatacenterData, NoError> { public func get(phoneNumber: Signal<String?, NoError>) -> Signal<MTBackupDatacenterData, NoError> {
let encryptionProvider = self.encryptionProvider
return phoneNumber return phoneNumber
|> take(1) |> take(1)
|> mapToSignal { phoneNumber -> Signal<MTBackupDatacenterData, NoError> in |> mapToSignal { phoneNumber -> Signal<MTBackupDatacenterData, NoError> in
@ -140,7 +145,7 @@ public final class CloudDataContextImpl: CloudDataContext {
let disposable = MetaDisposable() let disposable = MetaDisposable()
self.impl.with { impl in self.impl.with { impl in
disposable.set(impl.get(prefix: prefix).start(next: { data in disposable.set(impl.get(prefix: prefix).start(next: { data in
if let data = data, let datacenterData = MTIPDataDecode(data, phoneNumber ?? "") { if let data = data, let datacenterData = MTIPDataDecode(encryptionProvider, data, phoneNumber ?? "") {
subscriber.putNext(datacenterData) subscriber.putNext(datacenterData)
subscriber.putCompletion() subscriber.putCompletion()
} else { } else {

View File

@ -0,0 +1,19 @@
load("//Config:buck_rule_macros.bzl", "static_library")
static_library(
name = "EncryptionProvider",
srcs = glob([
"Sources/**/*.m",
]),
headers = glob([
"Sources/**/*.h",
]),
exported_headers = glob([
"Sources/**/*.h",
]),
deps = [
],
frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
],
)

View File

@ -0,0 +1,60 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol MTBignum <NSObject>
@end
@protocol MTRsaPublicKey <NSObject>
@end
@protocol MTBignumContext <NSObject>
- (id<MTBignum>)create;
- (id<MTBignum>)clone:(id<MTBignum>)other;
- (void)setConstantTime:(id<MTBignum>)other;
- (void)assignWordTo:(id<MTBignum>)bignum value:(unsigned long)value;
- (void)assignHexTo:(id<MTBignum>)bignum value:(NSString *)value;
- (void)assignBinTo:(id<MTBignum>)bignum value:(NSData *)value;
- (void)assignOneTo:(id<MTBignum>)bignum;
- (void)assignZeroTo:(id<MTBignum>)bignum;
- (bool)isOne:(id<MTBignum>)bignum;
- (bool)isZero:(id<MTBignum>)bignum;
- (NSData *)getBin:(id<MTBignum>)bignum;
- (int)isPrime:(id<MTBignum>)bignum numberOfChecks:(int)numberOfChecks;
- (int)compare:(id<MTBignum>)a with:(id<MTBignum>)b;
- (bool)modAddInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b mod:(id<MTBignum>)mod;
- (bool)modSubInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b mod:(id<MTBignum>)mod;
- (bool)modMulInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b mod:(id<MTBignum>)mod;
- (bool)modExpInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b mod:(id<MTBignum>)mod;
- (bool)addInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b;
- (bool)subInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b;
- (bool)mulInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b;
- (bool)expInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b;
- (bool)modInverseInto:(id<MTBignum>)result a:(id<MTBignum>)a mod:(id<MTBignum>)mod;
- (unsigned long)modWord:(id<MTBignum>)a mod:(unsigned long)mod;
- (bool)rightShift1Bit:(id<MTBignum>)result a:(id<MTBignum>)a;
- (id<MTBignum>)rsaGetE:(id<MTRsaPublicKey>)publicKey;
- (id<MTBignum>)rsaGetN:(id<MTRsaPublicKey>)publicKey;
@end
@protocol EncryptionProvider <NSObject>
- (id<MTBignumContext>)createBignumContext;
- (NSData * _Nullable)rsaEncryptWithPublicKey:(NSString *)publicKey data:(NSData *)data;
- (NSData * _Nullable)rsaEncryptPKCS1OAEPWithPublicKey:(NSString *)publicKey data:(NSData *)data;
- (id<MTRsaPublicKey>)parseRSAPublicKey:(NSString *)publicKey;
@end
NS_ASSUME_NONNULL_END

View File

@ -10,3 +10,4 @@
void MyAesIgeEncrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv); void MyAesIgeEncrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv);
void MyAesIgeDecrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv); void MyAesIgeDecrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv);
void MyAesCbcDecrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv);

View File

@ -161,6 +161,13 @@ void MyAesIgeDecrypt(const void *inBytes, int length, void *outBytes, const void
} }
} }
void MyAesCbcDecrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv) {
int outLength = 0;
CCCryptorStatus status = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, 0, key, keyLength, iv, inBytes, length, outBytes, length, &outLength);
assert(status == kCCSuccess);
assert(outLength == length);
}
static void ctr128_inc(unsigned char *counter) static void ctr128_inc(unsigned char *counter)
{ {
uint32_t n = 16, c = 1; uint32_t n = 16, c = 1;

View File

@ -75,6 +75,8 @@ static NSData *base64_decode(NSString *str) {
@[@"www.google.com", @"dns.google.com"], @[@"www.google.com", @"dns.google.com"],
]; ];
id<EncryptionProvider> encryptionProvider = currentContext.encryptionProvider;
NSMutableArray *signals = [[NSMutableArray alloc] init]; NSMutableArray *signals = [[NSMutableArray alloc] init];
for (NSArray *hostAndHostname in hosts) { for (NSArray *hostAndHostname in hosts) {
NSString *host = hostAndHostname[0]; NSString *host = hostAndHostname[0];
@ -117,7 +119,7 @@ static NSData *base64_decode(NSString *str) {
NSData *result = base64_decode(finalString); NSData *result = base64_decode(finalString);
NSMutableData *finalData = [[NSMutableData alloc] initWithData:result]; NSMutableData *finalData = [[NSMutableData alloc] initWithData:result];
[finalData setLength:256]; [finalData setLength:256];
MTBackupDatacenterData *datacenterData = MTIPDataDecode(finalData, phoneNumber); MTBackupDatacenterData *datacenterData = MTIPDataDecode(encryptionProvider, finalData, phoneNumber);
if (datacenterData != nil && [self checkIpData:datacenterData timestamp:(int32_t)[currentContext globalTime] source:@"resolveGoogle"]) { if (datacenterData != nil && [self checkIpData:datacenterData timestamp:(int32_t)[currentContext globalTime] source:@"resolveGoogle"]) {
return [MTSignal single:datacenterData]; return [MTSignal single:datacenterData];
} }
@ -154,6 +156,8 @@ static NSString *makeRandomPadding() {
} }
+ (MTSignal *)fetchBackupIpsResolveCloudflare:(bool)isTesting phoneNumber:(NSString *)phoneNumber currentContext:(MTContext *)currentContext addressOverride:(NSString *)addressOverride { + (MTSignal *)fetchBackupIpsResolveCloudflare:(bool)isTesting phoneNumber:(NSString *)phoneNumber currentContext:(MTContext *)currentContext addressOverride:(NSString *)addressOverride {
id<EncryptionProvider> encryptionProvider = currentContext.encryptionProvider;
NSArray *hosts = @[ NSArray *hosts = @[
@[@"mozilla.cloudflare-dns.com", @""], @[@"mozilla.cloudflare-dns.com", @""],
]; ];
@ -201,7 +205,7 @@ static NSString *makeRandomPadding() {
NSData *result = base64_decode(finalString); NSData *result = base64_decode(finalString);
NSMutableData *finalData = [[NSMutableData alloc] initWithData:result]; NSMutableData *finalData = [[NSMutableData alloc] initWithData:result];
[finalData setLength:256]; [finalData setLength:256];
MTBackupDatacenterData *datacenterData = MTIPDataDecode(finalData, phoneNumber); MTBackupDatacenterData *datacenterData = MTIPDataDecode(encryptionProvider, finalData, phoneNumber);
if (datacenterData != nil && [self checkIpData:datacenterData timestamp:(int32_t)[currentContext globalTime] source:@"resolveCloudflare"]) { if (datacenterData != nil && [self checkIpData:datacenterData timestamp:(int32_t)[currentContext globalTime] source:@"resolveCloudflare"]) {
return [MTSignal single:datacenterData]; return [MTSignal single:datacenterData];
} }
@ -234,13 +238,13 @@ static NSString *makeRandomPadding() {
apiEnvironment.disableUpdates = true; apiEnvironment.disableUpdates = true;
apiEnvironment.langPack = currentContext.apiEnvironment.langPack; apiEnvironment.langPack = currentContext.apiEnvironment.langPack;
MTContext *context = [[MTContext alloc] initWithSerialization:currentContext.serialization apiEnvironment:apiEnvironment isTestingEnvironment:currentContext.isTestingEnvironment useTempAuthKeys:address.datacenterId != 0 ? currentContext.useTempAuthKeys : false]; MTContext *context = [[MTContext alloc] initWithSerialization:currentContext.serialization encryptionProvider:currentContext.encryptionProvider apiEnvironment:apiEnvironment isTestingEnvironment:currentContext.isTestingEnvironment useTempAuthKeys:address.datacenterId != 0 ? currentContext.useTempAuthKeys : false];
if (address.datacenterId != 0) { if (address.datacenterId != 0) {
//context.keychain = currentContext.keychain; //context.keychain = currentContext.keychain;
} }
MTProto *mtProto = [[MTProto alloc] initWithContext:context datacenterId:address.datacenterId usageCalculationInfo:nil]; MTProto *mtProto = [[MTProto alloc] initWithContext:context datacenterId:address.datacenterId usageCalculationInfo:nil requiredAuthToken:nil authTokenMasterDatacenterId:0];
if (address.datacenterId != 0) { if (address.datacenterId != 0) {
mtProto.useTempAuthKeys = currentContext.useTempAuthKeys; mtProto.useTempAuthKeys = currentContext.useTempAuthKeys;
} }

View File

@ -8,6 +8,8 @@
# import <MtProtoKit/MTDatacenterAuthInfo.h> # import <MtProtoKit/MTDatacenterAuthInfo.h>
#endif #endif
#import <EncryptionProvider/EncryptionProvider.h>
@class MTDatacenterAddress; @class MTDatacenterAddress;
@class MTDatacenterAddressSet; @class MTDatacenterAddressSet;
@protocol MTSerialization; @protocol MTSerialization;
@ -47,11 +49,12 @@
@property (nonatomic, strong) id<MTKeychain> keychain; @property (nonatomic, strong) id<MTKeychain> keychain;
@property (nonatomic, strong, readonly) id<MTSerialization> serialization; @property (nonatomic, strong, readonly) id<MTSerialization> serialization;
@property (nonatomic, strong) id<EncryptionProvider> encryptionProvider;
@property (nonatomic, strong, readonly) MTApiEnvironment *apiEnvironment; @property (nonatomic, strong, readonly) MTApiEnvironment *apiEnvironment;
@property (nonatomic, readonly) bool isTestingEnvironment; @property (nonatomic, readonly) bool isTestingEnvironment;
@property (nonatomic, readonly) bool useTempAuthKeys; @property (nonatomic, readonly) bool useTempAuthKeys;
- (instancetype)initWithSerialization:(id<MTSerialization>)serialization apiEnvironment:(MTApiEnvironment *)apiEnvironment isTestingEnvironment:(bool)isTestingEnvironment useTempAuthKeys:(bool)useTempAuthKeys; - (instancetype)initWithSerialization:(id<MTSerialization>)serialization encryptionProvider:(id<EncryptionProvider>)encryptionProvider apiEnvironment:(MTApiEnvironment *)apiEnvironment isTestingEnvironment:(bool)isTestingEnvironment useTempAuthKeys:(bool)useTempAuthKeys;
- (void)performBatchUpdates:(void (^)())block; - (void)performBatchUpdates:(void (^)())block;

View File

@ -181,12 +181,11 @@
return self; return self;
} }
- (instancetype)initWithSerialization:(id<MTSerialization>)serialization apiEnvironment:(MTApiEnvironment *)apiEnvironment isTestingEnvironment:(bool)isTestingEnvironment useTempAuthKeys:(bool)useTempAuthKeys - (instancetype)initWithSerialization:(id<MTSerialization>)serialization encryptionProvider:(id<EncryptionProvider>)encryptionProvider apiEnvironment:(MTApiEnvironment *)apiEnvironment isTestingEnvironment:(bool)isTestingEnvironment useTempAuthKeys:(bool)useTempAuthKeys
{ {
#ifdef DEBUG
NSAssert(serialization != nil, @"serialization should not be nil"); NSAssert(serialization != nil, @"serialization should not be nil");
NSAssert(apiEnvironment != nil, @"apiEnvironment should not be nil"); NSAssert(apiEnvironment != nil, @"apiEnvironment should not be nil");
#endif NSAssert(encryptionProvider != nil, @"encryptionProvider should not be nil");
self = [super init]; self = [super init];
if (self != nil) if (self != nil)
@ -194,6 +193,7 @@
arc4random_buf(&_uniqueId, sizeof(_uniqueId)); arc4random_buf(&_uniqueId, sizeof(_uniqueId));
_serialization = serialization; _serialization = serialization;
_encryptionProvider = encryptionProvider;
_apiEnvironment = apiEnvironment; _apiEnvironment = apiEnvironment;
_isTestingEnvironment = isTestingEnvironment; _isTestingEnvironment = isTestingEnvironment;
_useTempAuthKeys = useTempAuthKeys; _useTempAuthKeys = useTempAuthKeys;

View File

@ -129,6 +129,8 @@ typedef enum {
@interface MTDatacenterAuthMessageService () @interface MTDatacenterAuthMessageService ()
{ {
id<EncryptionProvider> _encryptionProvider;
bool _tempAuth; bool _tempAuth;
MTSessionInfo *_sessionInfo; MTSessionInfo *_sessionInfo;
@ -161,6 +163,7 @@ typedef enum {
self = [super init]; self = [super init];
if (self != nil) if (self != nil)
{ {
_encryptionProvider = context.encryptionProvider;
_tempAuth = tempAuth; _tempAuth = tempAuth;
_sessionInfo = [[MTSessionInfo alloc] initWithRandomSessionIdAndContext:context]; _sessionInfo = [[MTSessionInfo alloc] initWithRandomSessionIdAndContext:context];
} }
@ -571,7 +574,7 @@ typedef enum {
NSData *innerDataGA = dhInnerData.gA; NSData *innerDataGA = dhInnerData.gA;
NSData *innerDataDhPrime = dhInnerData.dhPrime; NSData *innerDataDhPrime = dhInnerData.dhPrime;
if (!MTCheckIsSafeGAOrB(innerDataGA, innerDataDhPrime)) if (!MTCheckIsSafeGAOrB(_encryptionProvider, innerDataGA, innerDataDhPrime))
{ {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH g_a]", self); MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH g_a]", self);
@ -581,7 +584,7 @@ typedef enum {
return; return;
} }
if (!MTCheckMod(innerDataDhPrime, (unsigned int)innerDataG, mtProto.context.keychain)) if (!MTCheckMod(_encryptionProvider, innerDataDhPrime, (unsigned int)innerDataG, mtProto.context.keychain))
{ {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH g (2)]", self); MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH g (2)]", self);
@ -591,7 +594,7 @@ typedef enum {
return; return;
} }
if (!MTCheckIsSafePrime(innerDataDhPrime, mtProto.context.keychain)) if (!MTCheckIsSafePrime(_encryptionProvider, innerDataDhPrime, mtProto.context.keychain))
{ {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH prime]", self); MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH prime]", self);
@ -609,9 +612,9 @@ typedef enum {
tmpG = (int32_t)OSSwapInt32(tmpG); tmpG = (int32_t)OSSwapInt32(tmpG);
NSData *g = [[NSData alloc] initWithBytes:&tmpG length:4]; NSData *g = [[NSData alloc] initWithBytes:&tmpG length:4];
NSData *g_b = MTExp(g, b, innerDataDhPrime); NSData *g_b = MTExp(_encryptionProvider, g, b, innerDataDhPrime);
NSData *authKey = MTExp(innerDataGA, b, innerDataDhPrime); NSData *authKey = MTExp(_encryptionProvider, innerDataGA, b, innerDataDhPrime);
NSData *authKeyHash = MTSha1(authKey); NSData *authKeyHash = MTSha1(authKey);

View File

@ -1,10 +1,10 @@
#ifndef MTEncryption_H #ifndef MTEncryption_H
#define MTEncryption_H #define MTEncryption_H
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <EncryptionProvider/EncryptionProvider.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -29,22 +29,22 @@ void MTAesDecryptBytesInplaceAndModifyIv(void *data, NSInteger length, NSData *k
NSData *MTAesEncrypt(NSData *data, NSData *key, NSData *iv); NSData *MTAesEncrypt(NSData *data, NSData *key, NSData *iv);
NSData *MTAesDecrypt(NSData *data, NSData *key, NSData *iv); NSData *MTAesDecrypt(NSData *data, NSData *key, NSData *iv);
NSData *MTRsaEncrypt(NSString *publicKey, NSData *data); NSData *MTRsaEncrypt(NSString *publicKey, NSData *data);
NSData *MTExp(NSData *base, NSData *exp, NSData *modulus); NSData *MTExp(id<EncryptionProvider> provider, NSData *base, NSData *exp, NSData *modulus);
NSData *MTModSub(NSData *a, NSData *b, NSData *modulus); NSData *MTModSub(id<EncryptionProvider> provider, NSData *a, NSData *b, NSData *modulus);
NSData *MTModMul(NSData *a, NSData *b, NSData *modulus); NSData *MTModMul(id<EncryptionProvider> provider, NSData *a, NSData *b, NSData *modulus);
NSData *MTMul(NSData *a, NSData *b); NSData *MTMul(id<EncryptionProvider> provider, NSData *a, NSData *b);
NSData *MTAdd(NSData *a, NSData *b); NSData *MTAdd(id<EncryptionProvider> provider, NSData *a, NSData *b);
bool MTFactorize(uint64_t what, uint64_t *resA, uint64_t *resB); bool MTFactorize(uint64_t what, uint64_t *resA, uint64_t *resB);
bool MTIsZero(NSData *value); bool MTIsZero(id<EncryptionProvider> provider, NSData *value);
NSData *MTAesCtrDecrypt(NSData *data, NSData *key, NSData *iv); NSData *MTAesCtrDecrypt(NSData *data, NSData *key, NSData *iv);
@protocol MTKeychain; @protocol MTKeychain;
bool MTCheckIsSafeG(unsigned int g); bool MTCheckIsSafeG(unsigned int g);
bool MTCheckIsSafeB(NSData *b, NSData *p); bool MTCheckIsSafeB(id<EncryptionProvider> provider, NSData *b, NSData *p);
bool MTCheckIsSafePrime(NSData *numberBytes, id<MTKeychain> keychain); bool MTCheckIsSafePrime(id<EncryptionProvider> provider, NSData *numberBytes, id<MTKeychain> keychain);
bool MTCheckIsSafeGAOrB(NSData *gAOrB, NSData *p); bool MTCheckIsSafeGAOrB(id<EncryptionProvider> provider, NSData *gAOrB, NSData *p);
bool MTCheckMod(NSData *numberBytes, unsigned int g, id<MTKeychain> keychain); bool MTCheckMod(id<EncryptionProvider> provider, NSData *numberBytes, unsigned int g, id<MTKeychain> keychain);
@interface MTAesCtr : NSObject @interface MTAesCtr : NSObject
@ -59,9 +59,9 @@ bool MTCheckMod(NSData *numberBytes, unsigned int g, id<MTKeychain> keychain);
@end @end
uint64_t MTRsaFingerprint(NSString *key); uint64_t MTRsaFingerprint(id<EncryptionProvider> provider, NSString *key);
NSData *MTRsaEncryptPKCS1OAEP(NSString *key, NSData *data); NSData *MTRsaEncryptPKCS1OAEP(id<EncryptionProvider> provider, NSString *key, NSData *data);
@interface MTBackupDatacenterAddress : NSObject @interface MTBackupDatacenterAddress : NSObject
@ -80,7 +80,7 @@ NSData *MTRsaEncryptPKCS1OAEP(NSString *key, NSData *data);
@end @end
MTBackupDatacenterData *MTIPDataDecode(NSData *data, NSString *phoneNumber); MTBackupDatacenterData *MTIPDataDecode(id<EncryptionProvider> provider, NSData *data, NSString *phoneNumber);
NSData * _Nullable MTPBKDF2(NSData * _Nonnull data, NSData * _Nonnull salt, int rounds); NSData * _Nullable MTPBKDF2(NSData * _Nonnull data, NSData * _Nonnull salt, int rounds);

View File

@ -8,23 +8,13 @@
#import <CommonCrypto/CommonCrypto.h> #import <CommonCrypto/CommonCrypto.h>
#import <CommonCrypto/CommonDigest.h> #import <CommonCrypto/CommonDigest.h>
#include <openssl/bn.h> #import <EncryptionProvider/EncryptionProvider.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#import "MTAes.h" #import "MTAes.h"
#import "MTRsa.h" #import "MTRsa.h"
#import "MTBuffer.h" #import "MTBuffer.h"
#if TARGET_OS_IOS
# include <openssl/pem.h>
#else
# include <openssl/pem.h>
#endif
#include <openssl/aes.h>
#import "MTBufferReader.h" #import "MTBufferReader.h"
NSData *MTSha1(NSData *data) NSData *MTSha1(NSData *data)
@ -340,167 +330,124 @@ NSData *MTRsaEncrypt(NSString *publicKey, NSData *data)
#endif #endif
} }
NSData *MTExp(NSData *base, NSData *exp, NSData *modulus) NSData *MTExp(id<EncryptionProvider> provider, NSData *base, NSData *exp, NSData *modulus)
{ {
BN_CTX *ctx = BN_CTX_new(); id<MTBignumContext> context = [provider createBignumContext];
BIGNUM *bnBase = BN_bin2bn(base.bytes, (int)base.length, NULL);
BN_set_flags(bnBase, BN_FLG_CONSTTIME);
BIGNUM *bnExp = BN_bin2bn(exp.bytes, (int)exp.length, NULL);
BN_set_flags(bnExp, BN_FLG_CONSTTIME);
BIGNUM *bnModulus = BN_bin2bn(modulus.bytes, (int)modulus.length, NULL); id<MTBignum> bnBase = [context create];
BN_set_flags(bnModulus, BN_FLG_CONSTTIME); [context assignBinTo:bnBase value:base];
[context setConstantTime:bnBase];
BIGNUM *bnRes = BN_new(); id<MTBignum> bnExp = [context create];
BN_set_flags(bnModulus, BN_FLG_CONSTTIME); [context assignBinTo:bnExp value:exp];
[context setConstantTime:bnExp];
BN_mod_exp(bnRes, bnBase, bnExp, bnModulus, ctx); id<MTBignum> bnModulus = [context create];
[context assignBinTo:bnModulus value:modulus];
[context setConstantTime:bnModulus];
unsigned char *res = malloc((size_t)BN_num_bytes(bnRes)); id<MTBignum> bnRes = [context create];
int resLen = BN_bn2bin(bnRes, res); [context setConstantTime:bnRes];
BN_CTX_free(ctx); [context modExpInto:bnRes a:bnBase b:bnExp mod:bnModulus];
BN_free(bnBase);
BN_free(bnExp);
BN_free(bnModulus);
BN_free(bnRes);
NSData *result = [[NSData alloc] initWithBytes:res length:(NSUInteger)resLen]; NSData *result = [context getBin:bnRes];
free(res);
return result; return result;
} }
NSData *MTModSub(NSData *a, NSData *b, NSData *modulus) { NSData *MTModSub(id<EncryptionProvider> provider, NSData *a, NSData *b, NSData *modulus) {
BN_CTX *ctx = BN_CTX_new(); id<MTBignumContext> context = [provider createBignumContext];
BIGNUM *bnA = BN_bin2bn(a.bytes, (int)a.length, NULL);
BIGNUM *bnB = BN_bin2bn(b.bytes, (int)b.length, NULL); id<MTBignum> bnA = [context create];
[context assignBinTo:bnA value:a];
BIGNUM *bnModulus = BN_bin2bn(modulus.bytes, (int)modulus.length, NULL); id<MTBignum> bnB = [context create];
[context assignBinTo:bnB value:b];
BIGNUM *bnRes = BN_new(); id<MTBignum> bnModulus = [context create];
[context assignBinTo:bnModulus value:modulus];
BN_mod_sub(bnRes, bnA, bnB, bnModulus, ctx); id<MTBignum> bnRes = [context create];
unsigned char *res = malloc((size_t)BN_num_bytes(bnRes)); [context modSubInto:bnRes a:bnA b:bnB mod:bnModulus];
int resLen = BN_bn2bin(bnRes, res);
BN_CTX_free(ctx); return [context getBin:bnRes];
BN_free(bnA);
BN_free(bnB);
BN_free(bnModulus);
BN_free(bnRes);
NSData *result = [[NSData alloc] initWithBytes:res length:(NSUInteger)resLen];
free(res);
return result;
} }
NSData *MTModMul(NSData *a, NSData *b, NSData *modulus) { NSData *MTModMul(id<EncryptionProvider> provider, NSData *a, NSData *b, NSData *modulus) {
BN_CTX *ctx = BN_CTX_new(); id<MTBignumContext> context = [provider createBignumContext];
BIGNUM *bnA = BN_bin2bn(a.bytes, (int)a.length, NULL);
BIGNUM *bnB = BN_bin2bn(b.bytes, (int)b.length, NULL); id<MTBignum> bnA = [context create];
[context assignBinTo:bnA value:a];
BIGNUM *bnModulus = BN_bin2bn(modulus.bytes, (int)modulus.length, NULL); id<MTBignum> bnB = [context create];
[context assignBinTo:bnB value:b];
BIGNUM *bnRes = BN_new(); id<MTBignum> bnModulus = [context create];
[context assignBinTo:bnModulus value:modulus];
BN_mod_mul(bnRes, bnA, bnB, bnModulus, ctx); id<MTBignum> bnRes = [context create];
unsigned char *res = malloc((size_t)BN_num_bytes(bnRes)); [context modMulInto:bnRes a:bnA b:bnB mod:bnModulus];
int resLen = BN_bn2bin(bnRes, res);
BN_CTX_free(ctx); return [context getBin:bnRes];
BN_free(bnA);
BN_free(bnB);
BN_free(bnModulus);
BN_free(bnRes);
NSData *result = [[NSData alloc] initWithBytes:res length:(NSUInteger)resLen];
free(res);
return result;
} }
NSData *MTMul(NSData *a, NSData *b) { NSData *MTMul(id<EncryptionProvider> provider, NSData *a, NSData *b) {
BN_CTX *ctx = BN_CTX_new(); id<MTBignumContext> context = [provider createBignumContext];
BIGNUM *bnA = BN_bin2bn(a.bytes, (int)a.length, NULL);
BIGNUM *bnB = BN_bin2bn(b.bytes, (int)b.length, NULL); id<MTBignum> bnA = [context create];
[context assignBinTo:bnA value:a];
BIGNUM *bnRes = BN_new(); id<MTBignum> bnB = [context create];
[context assignBinTo:bnB value:b];
BN_mul(bnRes, bnA, bnB, ctx); id<MTBignum> bnRes = [context create];
unsigned char *res = malloc((size_t)BN_num_bytes(bnRes)); [context mulInto:bnRes a:bnA b:bnB];
int resLen = BN_bn2bin(bnRes, res);
BN_CTX_free(ctx); return [context getBin:bnRes];
BN_free(bnA);
BN_free(bnB);
BN_free(bnRes);
NSData *result = [[NSData alloc] initWithBytes:res length:(NSUInteger)resLen];
free(res);
return result;
} }
NSData *MTAdd(NSData *a, NSData *b) { NSData *MTAdd(id<EncryptionProvider> provider, NSData *a, NSData *b) {
BN_CTX *ctx = BN_CTX_new(); id<MTBignumContext> context = [provider createBignumContext];
BIGNUM *bnA = BN_bin2bn(a.bytes, (int)a.length, NULL);
BIGNUM *bnB = BN_bin2bn(b.bytes, (int)b.length, NULL); id<MTBignum> bnA = [context create];
[context assignBinTo:bnA value:a];
BIGNUM *bnRes = BN_new(); id<MTBignum> bnB = [context create];
[context assignBinTo:bnB value:b];
BN_add(bnRes, bnA, bnB); id<MTBignum> bnRes = [context create];
unsigned char *res = malloc((size_t)BN_num_bytes(bnRes)); [context addInto:bnRes a:bnA b:bnB];
int resLen = BN_bn2bin(bnRes, res);
BN_CTX_free(ctx); return [context getBin:bnRes];
BN_free(bnA);
BN_free(bnB);
BN_free(bnRes);
NSData *result = [[NSData alloc] initWithBytes:res length:(NSUInteger)resLen];
free(res);
return result;
} }
bool MTIsZero(NSData *value) { bool MTIsZero(id<EncryptionProvider> provider, NSData *value) {
BN_CTX *ctx = BN_CTX_new(); id<MTBignumContext> context = [provider createBignumContext];
BIGNUM *bnValue = BN_bin2bn(value.bytes, (int)value.length, NULL);
bool isZero = BN_is_zero(bnValue); id<MTBignum> bnA = [context create];
[context assignBinTo:bnA value:value];
BN_free(bnValue); return [context isZero:bnA];
BN_CTX_free(ctx);
return isZero;
} }
bool MTCheckIsSafeB(NSData *b, NSData *p) { bool MTCheckIsSafeB(id<EncryptionProvider> provider, NSData *b, NSData *p) {
BN_CTX *ctx = BN_CTX_new(); id<MTBignumContext> context = [provider createBignumContext];
BIGNUM *bnB = BN_bin2bn(b.bytes, (int)b.length, NULL);
BIGNUM *bnP = BN_bin2bn(p.bytes, (int)p.length, NULL);
BIGNUM *bnZero = BN_new();
BN_zero(bnZero);
bool result = BN_cmp(bnB, bnZero) == 1 && BN_cmp(bnB, bnP) == -1; id<MTBignum> bnB = [context create];
[context assignBinTo:bnB value:b];
BN_free(bnB); id<MTBignum> bnP = [context create];
BN_free(bnP); [context assignBinTo:bnP value:p];
BN_free(bnZero);
BN_CTX_free(ctx);
return result; id<MTBignum> bnZero = [context create];
[context assignZeroTo:bnZero];
return [context compare:bnB with:bnZero] == 1 && [context compare:bnB with:bnP] == -1;
} }
static inline uint64_t mygcd(uint64_t a, uint64_t b) static inline uint64_t mygcd(uint64_t a, uint64_t b)
@ -616,27 +563,20 @@ static NSString *hexStringFromData(NSData *data)
return string; return string;
} }
bool MTCheckIsSafePrime(NSData *numberBytes, id<MTKeychain> keychain) bool MTCheckIsSafePrime(id<EncryptionProvider> provider, NSData *numberBytes, id<MTKeychain> keychain)
{ {
NSString *primeKey = [[NSString alloc] initWithFormat:@"isPrimeSafe_%@", hexStringFromData(numberBytes)]; NSString *primeKey = [[NSString alloc] initWithFormat:@"isPrimeSafe_%@", hexStringFromData(numberBytes)];
NSNumber *nCachedResult = [keychain objectForKey:primeKey group:@"primes"]; NSNumber *nCachedResult = [keychain objectForKey:primeKey group:@"primes"];
if (nCachedResult != nil) if (nCachedResult != nil) {
return [nCachedResult boolValue]; return [nCachedResult boolValue];
}
if (numberBytes.length != 256) if (numberBytes.length != 256) {
{
[[NSUserDefaults standardUserDefaults] setObject:[[NSNumber alloc] initWithBool:false] forKey:primeKey];
[[NSUserDefaults standardUserDefaults] synchronize];
return false; return false;
} }
if (!(((uint8_t *)numberBytes.bytes)[0] & (1 << 7))) if (!(((uint8_t *)numberBytes.bytes)[0] & (1 << 7))) {
{
[[NSUserDefaults standardUserDefaults] setObject:[[NSNumber alloc] initWithBool:false] forKey:primeKey];
[[NSUserDefaults standardUserDefaults] synchronize];
return false; return false;
} }
@ -665,114 +605,108 @@ bool MTCheckIsSafePrime(NSData *numberBytes, id<MTKeychain> keychain)
0xb9, 0x2f, 0xcc, 0x5b 0xb9, 0x2f, 0xcc, 0x5b
}; };
if (memcmp(goodPrime0, numberBytes.bytes, 256) == 0) if (memcmp(goodPrime0, numberBytes.bytes, 256) == 0) {
return true; return true;
BN_CTX *ctx = BN_CTX_new();
BIGNUM *bnNumber = BN_bin2bn(numberBytes.bytes, (int)numberBytes.length, NULL);
int result = BN_is_prime_ex(bnNumber, 30, ctx, NULL);
if (result == 1)
{
BIGNUM *bnNumberMinus1 = BN_new();
BN_sub(bnNumberMinus1, bnNumber, BN_value_one());
BIGNUM *bnNumberMinus1DivBy2 = BN_new();
BN_rshift1(bnNumberMinus1DivBy2, bnNumberMinus1);
result = BN_is_prime_ex(bnNumberMinus1DivBy2, 30, ctx, NULL);
BN_free(bnNumberMinus1);
BN_free(bnNumberMinus1DivBy2);
} }
BN_free(bnNumber); id<MTBignumContext> context = [provider createBignumContext];
BN_CTX_free(ctx);
id<MTBignum> bnNumber = [context create];
[context assignBinTo:bnNumber value:numberBytes];
int result = [context isPrime:bnNumber numberOfChecks:30];
if (result == 1) {
id<MTBignum> bnNumberOne = [context create];
[context assignOneTo:bnNumberOne];
id<MTBignum> bnNumberMinusOne = [context create];
[context subInto:bnNumberMinusOne a:bnNumber b:bnNumberOne];
id<MTBignum> bnNumberMinusOneDivByTwo = [context create];
[context rightShift1Bit:bnNumberMinusOneDivByTwo a:bnNumberMinusOne];
int result = [context isPrime:bnNumberMinusOneDivByTwo numberOfChecks:30];
}
[keychain setObject:@(result == 1) forKey:primeKey group:@"primes"]; [keychain setObject:@(result == 1) forKey:primeKey group:@"primes"];
return result == 1; return result == 1;
} }
bool MTCheckIsSafeGAOrB(NSData *gAOrB, NSData *p) bool MTCheckIsSafeGAOrB(id<EncryptionProvider> provider, NSData *gAOrB, NSData *p) {
{ id<MTBignumContext> context = [provider createBignumContext];
BN_CTX *ctx = BN_CTX_new();
BIGNUM *bnNumber = BN_bin2bn(gAOrB.bytes, (int)gAOrB.length, NULL); id<MTBignum> bnNumber = [context create];
BIGNUM *bnP = BN_bin2bn(p.bytes, (int)p.length, NULL); [context assignBinTo:bnNumber value:gAOrB];
id<MTBignum> bnP = [context create];
[context assignBinTo:bnP value:p];
id<MTBignum> bnOne = [context create];
[context assignOneTo:bnOne];
bool result = false; bool result = false;
if (BN_cmp(bnNumber, BN_value_one()) == 1) if ([context compare:bnNumber with:bnOne] == 1) {
{ id<MTBignum> bnPMinusOne = [context create];
BIGNUM *pMinus1 = BN_new(); [context subInto:bnPMinusOne a:bnP b:bnOne];
BN_sub(pMinus1, bnP, BN_value_one());
if (BN_cmp(bnNumber, pMinus1) == -1) if ([context compare:bnNumber with:bnPMinusOne] == -1) {
{
result = true; result = true;
} }
BN_free(pMinus1);
} }
BN_free(bnNumber);
BN_free(bnP);
BN_CTX_free(ctx);
return result; return result;
} }
bool MTCheckMod(NSData *numberBytes, unsigned int g, id<MTKeychain> keychain) bool MTCheckMod(id<EncryptionProvider> provider, NSData *numberBytes, unsigned int g, id<MTKeychain> keychain)
{ {
NSString *modKey = [[NSString alloc] initWithFormat:@"isPrimeModSafe_%@_%d", hexStringFromData(numberBytes), g]; NSString *modKey = [[NSString alloc] initWithFormat:@"isPrimeModSafe_%@_%d", hexStringFromData(numberBytes), g];
NSNumber *nCachedResult = [keychain objectForKey:modKey group:@"primes"]; NSNumber *nCachedResult = [keychain objectForKey:modKey group:@"primes"];
if (nCachedResult != nil) if (nCachedResult != nil) {
return [nCachedResult boolValue]; return [nCachedResult boolValue];
}
BN_CTX *ctx = BN_CTX_new(); id<MTBignumContext> context = [provider createBignumContext];
BIGNUM *bnNumber = BN_bin2bn(numberBytes.bytes, (int)numberBytes.length, NULL);
id<MTBignum> bnNumber = [context create];
[context assignBinTo:bnNumber value:numberBytes];
bool result = false; bool result = false;
switch (g) switch (g) {
{ case 2: {
case 2: unsigned long modResult = [context modWord:bnNumber mod:8];
{
BN_ULONG modResult = BN_mod_word(bnNumber, 8);
result = modResult == 7; result = modResult == 7;
break; break;
} }
case 3: case 3: {
{ unsigned long modResult = [context modWord:bnNumber mod:3];
BN_ULONG modResult = BN_mod_word(bnNumber, 3);
result = modResult == 2; result = modResult == 2;
break; break;
} }
case 4: case 4: {
{
result = true; result = true;
break; break;
} }
case 5: case 5: {
{ unsigned long modResult = [context modWord:bnNumber mod:5];
BN_ULONG modResult = BN_mod_word(bnNumber, 5);
result = modResult == 1 || modResult == 4; result = modResult == 1 || modResult == 4;
break; break;
} }
case 6: case 6: {
{ unsigned long modResult = [context modWord:bnNumber mod:24];
BN_ULONG modResult = BN_mod_word(bnNumber, 24);
result = modResult == 19 || modResult == 23; result = modResult == 19 || modResult == 23;
break; break;
} }
case 7: case 7: {
{ unsigned long modResult = [context modWord:bnNumber mod:7];
BN_ULONG modResult = BN_mod_word(bnNumber, 7);
result = modResult == 3 || modResult == 5 || modResult == 6; result = modResult == 3 || modResult == 5 || modResult == 6;
break; break;
@ -781,9 +715,6 @@ bool MTCheckMod(NSData *numberBytes, unsigned int g, id<MTKeychain> keychain)
break; break;
} }
BN_free(bnNumber);
BN_CTX_free(ctx);
[keychain setObject:@(result) forKey:modKey group:@"primes"]; [keychain setObject:@(result) forKey:modKey group:@"primes"];
return result; return result;
@ -796,27 +727,21 @@ NSData *MTAesCtrDecrypt(NSData *data, NSData *key, NSData *iv) {
return outData; return outData;
} }
uint64_t MTRsaFingerprint(NSString *key) { uint64_t MTRsaFingerprint(id<EncryptionProvider> provider, NSString *key) {
BIO *keyBio = BIO_new(BIO_s_mem()); id<MTBignumContext> context = [provider createBignumContext];
id<MTRsaPublicKey> rsaKey = [provider parseRSAPublicKey:key];
if (rsaKey == nil) {
return 0;
}
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding]; id<MTBignum> rsaKeyN = [context rsaGetN:rsaKey];
BIO_write(keyBio, keyData.bytes, (int)keyData.length); id<MTBignum> rsaKeyE = [context rsaGetE:rsaKey];
RSA *rsaKey = PEM_read_bio_RSAPublicKey(keyBio, NULL, NULL, NULL);
BIGNUM *rsaKeyN = RSA_get0_n(rsaKey); NSData *nData = [context getBin:rsaKeyN];
BIGNUM *rsaKeyE = RSA_get0_e(rsaKey); NSData *eData = [context getBin:rsaKeyE];
int nBytes = BN_num_bytes(rsaKeyN);
int eBytes = BN_num_bytes(rsaKeyE);
MTBuffer *buffer = [[MTBuffer alloc] init]; MTBuffer *buffer = [[MTBuffer alloc] init];
NSMutableData *nData = [[NSMutableData alloc] initWithLength:nBytes];
BN_bn2bin(rsaKeyN, nData.mutableBytes);
[buffer appendTLBytes:nData]; [buffer appendTLBytes:nData];
NSMutableData *eData = [[NSMutableData alloc] initWithLength:eBytes];
BN_bn2bin(rsaKeyE, eData.mutableBytes);
[buffer appendTLBytes:eData]; [buffer appendTLBytes:eData];
NSData *sha1Data = MTSha1(buffer.data); NSData *sha1Data = MTSha1(buffer.data);
@ -831,40 +756,15 @@ uint64_t MTRsaFingerprint(NSString *key) {
(((uint64_t) sha1Buffer[14]) << 16) | (((uint64_t) sha1Buffer[14]) << 16) |
(((uint64_t) sha1Buffer[13]) << 8) | (((uint64_t) sha1Buffer[13]) << 8) |
((uint64_t) sha1Buffer[12]); ((uint64_t) sha1Buffer[12]);
RSA_free(rsaKey);
BIO_free(keyBio);
return fingerprint; return fingerprint;
} }
NSData *MTRsaEncryptPKCS1OAEP(NSString *key, NSData *data) { NSData *MTRsaEncryptPKCS1OAEP(id<EncryptionProvider> provider, NSString *key, NSData *data) {
BIO *keyBio = BIO_new(BIO_s_mem()); return [provider rsaEncryptPKCS1OAEPWithPublicKey:key data:data];
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
BIO_write(keyBio, keyData.bytes, (int)keyData.length);
RSA *rsaKey = PEM_read_bio_RSA_PUBKEY(keyBio, NULL, NULL, NULL);
if (rsaKey == nil) {
BIO_free(keyBio);
return nil;
}
NSMutableData *outData = [[NSMutableData alloc] initWithLength:data.length + 2048];
int encryptedLength = RSA_public_encrypt((int)data.length, data.bytes, outData.mutableBytes, rsaKey, RSA_PKCS1_OAEP_PADDING);
RSA_free(rsaKey);
BIO_free(keyBio);
if (encryptedLength < 0) {
return nil;
}
assert(encryptedLength <= outData.length);
[outData setLength:encryptedLength];
return outData;
} }
static NSData *decrypt_TL_data(unsigned char buffer[256]) { static NSData *decrypt_TL_data(id<EncryptionProvider> provider, unsigned char buffer[256]) {
NSString *keyString = @"-----BEGIN RSA PUBLIC KEY-----\n" NSString *keyString = @"-----BEGIN RSA PUBLIC KEY-----\n"
"MIIBCgKCAQEAyr+18Rex2ohtVy8sroGPBwXD3DOoKCSpjDqYoXgCqB7ioln4eDCF\n" "MIIBCgKCAQEAyr+18Rex2ohtVy8sroGPBwXD3DOoKCSpjDqYoXgCqB7ioln4eDCF\n"
"fOBUlfXUEvM/fnKCpF46VkAftlb4VuPDeQSS/ZxZYEGqHaywlroVnXHIjgqoxiAd\n" "fOBUlfXUEvM/fnKCpF46VkAftlb4VuPDeQSS/ZxZYEGqHaywlroVnXHIjgqoxiAd\n"
@ -873,66 +773,73 @@ static NSData *decrypt_TL_data(unsigned char buffer[256]) {
"fDK/NWcvGqa0w/nriMD6mDjKOryamw0OP9QuYgMN0C9xMW9y8SmP4h92OAWodTYg\n" "fDK/NWcvGqa0w/nriMD6mDjKOryamw0OP9QuYgMN0C9xMW9y8SmP4h92OAWodTYg\n"
"Y1hZCxdv6cs5UnW9+PWvS+WIbkh+GaWYxwIDAQAB\n" "Y1hZCxdv6cs5UnW9+PWvS+WIbkh+GaWYxwIDAQAB\n"
"-----END RSA PUBLIC KEY-----"; "-----END RSA PUBLIC KEY-----";
NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
BIO *keyBio = BIO_new(BIO_s_mem()); id<MTRsaPublicKey> rsaKey = [provider parseRSAPublicKey:keyString];
BIO_write(keyBio, keyData.bytes, (int)keyData.length);
RSA *rsaKey = PEM_read_bio_RSAPublicKey(keyBio, NULL, NULL, NULL);
if (rsaKey == nil) { if (rsaKey == nil) {
return nil; return nil;
} }
BIGNUM *x = BN_new();
BIGNUM *y = BN_new();
BN_CTX *bnContext = BN_CTX_new();
uint8_t *bytes = buffer; uint8_t *bytes = buffer;
BN_bin2bn(bytes, 256, x);
BIGNUM *rsaKeyN = RSA_get0_n(rsaKey); id<MTBignumContext> context = [provider createBignumContext];
BIGNUM *rsaKeyE = RSA_get0_e(rsaKey);
id<MTBignum> x = [context create];
id<MTBignum> y = [context create];
[context assignBinTo:x value:[NSData dataWithBytesNoCopy:buffer length:256 freeWhenDone:false]];
id<MTBignum> rsaKeyN = [context rsaGetN:rsaKey];
id<MTBignum> rsaKeyE = [context rsaGetE:rsaKey];
NSData *result = nil; NSData *result = nil;
if (BN_mod_exp(y, x, rsaKeyE, rsaKeyN, bnContext) == 1) {
unsigned l = 256 - BN_num_bytes(y); if ([context modExpInto:y a:x b:rsaKeyE mod:rsaKeyN]) {
NSData *yBytes = [context getBin:y];
unsigned l = 256 - (unsigned)yBytes.length;
memset(bytes, 0, l); memset(bytes, 0, l);
if (BN_bn2bin(y, bytes + l) == 256 - l) {
AES_KEY aeskey; [yBytes getBytes:bytes + l length:256 - l];
unsigned char iv[16];
memcpy(iv, bytes + 16, 16); NSMutableData *iv = [[NSMutableData alloc] initWithLength:16];
AES_set_decrypt_key(bytes, 256, &aeskey); memcpy(iv.mutableBytes, bytes + 16, 16);
AES_cbc_encrypt(bytes + 32, bytes + 32, 256 - 32, &aeskey, iv, AES_DECRYPT);
NSData *encryptedBytes = [[NSData alloc] initWithBytes:bytes + 32 length:256 - 32];
NSData *keyBytes = [[NSData alloc] initWithBytes:bytes length:32];
NSMutableData *decryptedBytes = [[NSMutableData alloc] initWithLength:encryptedBytes.length];
MyAesCbcDecrypt(encryptedBytes.bytes, encryptedBytes.length, decryptedBytes.mutableBytes, keyBytes.bytes, keyBytes.length, iv.mutableBytes);
if (decryptedBytes == nil) {
return nil;
}
NSData *sha256Bytes = MTSha256([decryptedBytes subdataWithRange:NSMakeRange(0, 256 - 32 - 16)]);
unsigned char sha256_out[32];
[sha256Bytes getBytes:sha256_out length:32];
NSData *sha256Part = [sha256Bytes subdataWithRange:NSMakeRange(0, 16)];
NSData *testSha256 = [decryptedBytes subdataWithRange:NSMakeRange(decryptedBytes.length - 16, 16)];
if ([sha256Part isEqualToData:testSha256]) {
memcpy(bytes + 32, decryptedBytes.bytes, 256 - 32);
EVP_MD_CTX *ctx = EVP_MD_CTX_new(); unsigned data_len = *(unsigned *) (bytes + 32);
unsigned char sha256_out[32]; if (data_len && data_len <= 256 - 32 - 16 && !(data_len & 3)) {
unsigned olen = 0; result = [NSData dataWithBytes:buffer + 32 + 4 length:data_len];
EVP_DigestInit_ex(ctx, EVP_sha256(), NULL); } else {
EVP_DigestUpdate(ctx, bytes + 32, 256 - 32 - 16); if (MTLogEnabled()) {
EVP_DigestFinal_ex(ctx, sha256_out, &olen); MTLog(@"TL data length field invalid - %d", data_len);
EVP_MD_CTX_free(ctx);
if (olen == 32) {
if (memcmp(bytes + 256 - 16, sha256_out, 16) == 0) {
unsigned data_len = *(unsigned *) (bytes + 32);
if (data_len && data_len <= 256 - 32 - 16 && !(data_len & 3)) {
result = [NSData dataWithBytes:buffer + 32 + 4 length:data_len];
} else {
if (MTLogEnabled()) {
MTLog(@"TL data length field invalid - %d", data_len);
}
}
} else {
if (MTLogEnabled()) {
MTLog(@"RSA signature check FAILED (SHA256 mismatch)");
}
} }
} }
} else {
if (MTLogEnabled()) {
MTLog(@"RSA signature check FAILED (SHA256 mismatch)");
}
} }
} }
BN_free(x);
BN_free(y);
RSA_free(rsaKey);
BIO_free(keyBio);
BN_CTX_free(bnContext);
return result; return result;
} }
@ -965,13 +872,13 @@ static NSData *decrypt_TL_data(unsigned char buffer[256]) {
@end @end
MTBackupDatacenterData *MTIPDataDecode(NSData *data, NSString *phoneNumber) { MTBackupDatacenterData *MTIPDataDecode(id<EncryptionProvider> provider, NSData *data, NSString *phoneNumber) {
if (data.length < 256) { if (data.length < 256) {
return nil; return nil;
} }
unsigned char buffer[256]; unsigned char buffer[256];
memcpy(buffer, data.bytes, 256); memcpy(buffer, data.bytes, 256);
NSData *result = decrypt_TL_data(buffer); NSData *result = decrypt_TL_data(provider, buffer);
if (result != nil) { if (result != nil) {
MTBufferReader *reader = [[MTBufferReader alloc] initWithData:result]; MTBufferReader *reader = [[MTBufferReader alloc] initWithData:result];

View File

@ -23,97 +23,87 @@
#import "MTSignal.h" #import "MTSignal.h"
#import "MTDNS.h" #import "MTDNS.h"
#import <openssl/bn.h> #import <EncryptionProvider/EncryptionProvider.h>
static BIGNUM *get_y2(BIGNUM *x, const BIGNUM *mod, BN_CTX *big_num_context) { static id<MTBignum> get_y2(id<MTBignum> x, id<MTBignum> mod, id<MTBignumContext> context) {
// returns y^2 = x^3 + 486662 * x^2 + x // returns y^2 = x^3 + 486662 * x^2 + x
BIGNUM *y = BN_dup(x); id<MTBignum> y = [context clone:x];
assert(y != NULL); assert(y != NULL);
BIGNUM *coef = BN_new(); id<MTBignum> coef = [context create];
BN_set_word(coef, 486662); [context assignWordTo:coef value:486662];
BN_mod_add(y, y, coef, mod, big_num_context); [context modAddInto:y a:y b:coef mod:mod];
BN_mod_mul(y, y, x, mod, big_num_context); [context modMulInto:y a:y b:x mod:mod];
BN_one(coef); [context assignOneTo:coef];
BN_mod_add(y, y, coef, mod, big_num_context); [context modAddInto:y a:y b:coef mod:mod];
BN_mod_mul(y, y, x, mod, big_num_context); [context modMulInto:y a:y b:x mod:mod];
BN_clear_free(coef);
return y; return y;
} }
static BIGNUM *get_double_x(BIGNUM *x, const BIGNUM *mod, BN_CTX *big_num_context) { static id<MTBignum> get_double_x(id<MTBignum> x, id<MTBignum> mod, id<MTBignumContext> context) {
// returns x_2 =(x^2 - 1)^2/(4*y^2) // returns x_2 =(x^2 - 1)^2/(4*y^2)
BIGNUM *denominator = get_y2(x, mod, big_num_context); id<MTBignum> denominator = get_y2(x, mod, context);
assert(denominator != NULL); assert(denominator != NULL);
BIGNUM *coef = BN_new(); id<MTBignum> coef = [context create];
BN_set_word(coef, 4); [context assignWordTo:coef value:4];
BN_mod_mul(denominator, denominator, coef, mod, big_num_context); [context modMulInto:denominator a:denominator b:coef mod:mod];
BIGNUM *numerator = BN_new(); id<MTBignum> numerator = [context create];
assert(numerator != NULL); assert(numerator != NULL);
BN_mod_mul(numerator, x, x, mod, big_num_context); [context modMulInto:numerator a:x b:x mod:mod];
BN_one(coef); [context assignOneTo:coef];
BN_mod_sub(numerator, numerator, coef, mod, big_num_context); [context modSubInto:numerator a:numerator b:coef mod:mod];
BN_mod_mul(numerator, numerator, numerator, mod, big_num_context); [context modMulInto:numerator a:numerator b:numerator mod:mod];
BN_mod_inverse(denominator, denominator, mod, big_num_context); [context modInverseInto:denominator a:denominator mod:mod];
BN_mod_mul(numerator, numerator, denominator, mod, big_num_context); [context modMulInto:numerator a:numerator b:denominator mod:mod];
BN_clear_free(coef);
BN_clear_free(denominator);
return numerator; return numerator;
} }
static void generate_public_key(unsigned char key[32]) { static void generate_public_key(unsigned char key[32], id<EncryptionProvider> provider) {
BIGNUM *mod = NULL; id<MTBignumContext> context = [provider createBignumContext];
BN_hex2bn(&mod, "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"); assert(context != NULL);
BIGNUM *pow = NULL; id<MTBignum> mod = [context create];
BN_hex2bn(&pow, "3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6"); [context assignHexTo:mod value:@"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"];
BN_CTX *big_num_context = BN_CTX_new(); id<MTBignum> pow = [context create];
assert(big_num_context != NULL); [context assignHexTo:pow value:@"3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6"];
BIGNUM *x = BN_new(); id<MTBignum> x = [context create];
while (1) { while (1) {
int randomResult = SecRandomCopyBytes(kSecRandomDefault, 32, key); int randomResult = SecRandomCopyBytes(kSecRandomDefault, 32, key);
assert(randomResult == errSecSuccess); assert(randomResult == errSecSuccess);
key[31] &= 127; key[31] &= 127;
BN_bin2bn(key, 32, x); [context assignBinTo:x value:[NSData dataWithBytesNoCopy:key length:32 freeWhenDone:false]];
assert(x != NULL);
BN_mod_mul(x, x, x, mod, big_num_context);
BIGNUM *y = get_y2(x, mod, big_num_context); [context modMulInto:x a:x b:x mod:mod];
BIGNUM *r = BN_new(); id<MTBignum> y = get_y2(x, mod, context);
BN_mod_exp(r, y, pow, mod, big_num_context);
BN_clear_free(y); id<MTBignum> r = [context create];
if (BN_is_one(r)) { [context modExpInto:r a:y b:pow mod:mod];
BN_clear_free(r); if ([context isOne:r]) {
break; break;
} }
BN_clear_free(r);
} }
int i; int i;
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
BIGNUM *x2 = get_double_x(x, mod, big_num_context); id<MTBignum> x2 = get_double_x(x, mod, context);
BN_clear_free(x);
x = x2; x = x2;
} }
int num_size = BN_num_bytes(x); NSData *xBytes = [context getBin:x];
int num_size = (int)[xBytes length];
assert(num_size <= 32); assert(num_size <= 32);
memset(key, '\0', 32 - num_size); memset(key, '\0', 32 - num_size);
BN_bn2bin(x, key + (32 - num_size)); [xBytes getBytes:key + (32 - num_size) length:[xBytes length]];
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
unsigned char t = key[i]; unsigned char t = key[i];
key[i] = key[31 - i]; key[i] = key[31 - i];
key[31 - i] = t; key[31 - i] = t;
} }
BN_clear_free(x);
BN_CTX_free(big_num_context);
BN_clear_free(pow);
BN_clear_free(mod);
} }
@interface MTTcpConnectionData : NSObject @interface MTTcpConnectionData : NSObject
@ -265,7 +255,9 @@ struct ctr_state {
@end @end
@interface MTTcpConnection () <GCDAsyncSocketDelegate> @interface MTTcpConnection () <GCDAsyncSocketDelegate>
{ {
id<EncryptionProvider> _encryptionProvider;
GCDAsyncSocket *_socket; GCDAsyncSocket *_socket;
bool _closed; bool _closed;
@ -341,6 +333,8 @@ struct ctr_state {
{ {
_internalId = [[MTInternalId(MTTcpConnection) alloc] init]; _internalId = [[MTInternalId(MTTcpConnection) alloc] init];
_encryptionProvider = context.encryptionProvider;
_scheme = scheme; _scheme = scheme;
_interface = interface; _interface = interface;
@ -590,7 +584,7 @@ struct ctr_state {
[helloData appendBytes:s6 length:117]; [helloData appendBytes:s6 length:117];
uint8_t r2[32]; uint8_t r2[32];
generate_public_key(r2); generate_public_key(r2, strongSelf->_encryptionProvider);
[helloData appendBytes:r2 length:32]; [helloData appendBytes:r2 length:32];

View File

@ -64,7 +64,7 @@
MTPayloadData payloadData; MTPayloadData payloadData;
NSData *data = [MTDiscoverConnectionSignals payloadData:&payloadData context:context address:address]; NSData *data = [MTDiscoverConnectionSignals payloadData:&payloadData context:context address:address];
MTContext *proxyContext = [[MTContext alloc] initWithSerialization:context.serialization apiEnvironment:[[context apiEnvironment] withUpdatedSocksProxySettings:settings] isTestingEnvironment:context.isTestingEnvironment useTempAuthKeys:context.useTempAuthKeys]; MTContext *proxyContext = [[MTContext alloc] initWithSerialization:context.serialization encryptionProvider:context.encryptionProvider apiEnvironment:[[context apiEnvironment] withUpdatedSocksProxySettings:settings] isTestingEnvironment:context.isTestingEnvironment useTempAuthKeys:context.useTempAuthKeys];
MTTcpConnection *connection = [[MTTcpConnection alloc] initWithContext:proxyContext datacenterId:datacenterId scheme:[[MTTransportScheme alloc] initWithTransportClass:[MTTcpConnection class] address:address media:false] interface:nil usageCalculationInfo:nil]; MTTcpConnection *connection = [[MTTcpConnection alloc] initWithContext:proxyContext datacenterId:datacenterId scheme:[[MTTransportScheme alloc] initWithTransportClass:[MTTcpConnection class] address:address media:false] interface:nil usageCalculationInfo:nil];
__weak MTTcpConnection *weakConnection = connection; __weak MTTcpConnection *weakConnection = connection;

View File

@ -0,0 +1,21 @@
load("//Config:buck_rule_macros.bzl", "static_library")
static_library(
name = "OpenSSLEncryptionProvider",
srcs = glob([
"Sources/**/*.m",
]),
headers = glob([
"Sources/**/*.h",
]),
exported_headers = glob([
"Sources/**/*.h",
]),
deps = [
"//submodules/EncryptionProvider:EncryptionProvider",
"//submodules/openssl:openssl",
],
frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
],
)

View File

@ -0,0 +1,9 @@
#import <EncryptionProvider/EncryptionProvider.h>
NS_ASSUME_NONNULL_BEGIN
@interface OpenSSLEncryptionProvider : NSObject <EncryptionProvider>
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,375 @@
#import "OpenSSLEncryptionProvider.h"
#import <openssl/bn.h>
#import <openssl/rsa.h>
#import <openssl/pem.h>
NS_ASSUME_NONNULL_BEGIN
@interface MTBignumImpl : NSObject <MTBignum, NSCopying> {
@public
BIGNUM *_value;
}
@end
@implementation MTBignumImpl
- (instancetype)init {
self = [super init];
if (self != nil) {
_value = BN_new();
}
return self;
}
- (instancetype)initWithValue:(BIGNUM *)value {
self = [super init];
if (self != nil) {
_value = value;
}
return self;
}
- (void)dealloc {
BN_clear_free(_value);
}
- (instancetype)copyWithZone:(NSZone * _Nullable)__unused zone {
return [[MTBignumImpl alloc] initWithValue:BN_dup(_value)];
}
@end
@interface MTRsaPublicKeyImpl : NSObject <MTRsaPublicKey> {
@public
RSA *_value;
}
@end
@implementation MTRsaPublicKeyImpl
- (instancetype)initWithValue:(RSA *)value {
self = [super init];
if (self != nil) {
_value = value;
}
return self;
}
- (void)dealloc {
RSA_free(_value);
}
@end
@interface MTBignumContextImpl : NSObject <MTBignumContext> {
BN_CTX *_context;
}
@end
@implementation MTBignumContextImpl
- (instancetype)init {
self = [super init];
if (self != nil) {
_context = BN_CTX_new();
}
return self;
}
- (void)dealloc {
BN_CTX_free(_context);
}
- (id<MTBignum>)create {
return [[MTBignumImpl alloc] init];
}
- (id<MTBignum>)clone:(id<MTBignum>)other {
assert([other isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *otherImpl = other;
return [otherImpl copy];
}
- (void)setConstantTime:(id<MTBignum>)other {
assert([other isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *otherImpl = other;
BN_set_flags(otherImpl->_value, BN_FLG_CONSTTIME);
}
- (void)assignWordTo:(id<MTBignum>)bignum value:(unsigned long)value {
assert([bignum isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *bignumImpl = bignum;
BN_set_word(bignumImpl->_value, value);
}
- (void)assignHexTo:(id<MTBignum>)bignum value:(NSString *)value {
assert([bignum isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *bignumImpl = bignum;
BN_hex2bn(&bignumImpl->_value, [value UTF8String]);
}
- (void)assignBinTo:(id<MTBignum>)bignum value:(NSData *)value {
assert([bignum isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *bignumImpl = bignum;
BN_bin2bn(value.bytes, value.length, bignumImpl->_value);
}
- (void)assignOneTo:(id<MTBignum>)bignum {
assert([bignum isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *bignumImpl = bignum;
BN_one(bignumImpl->_value);
}
- (void)assignZeroTo:(id<MTBignum>)bignum {
assert([bignum isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *bignumImpl = bignum;
BN_zero(bignumImpl->_value);
}
- (bool)isOne:(id<MTBignum>)bignum {
assert([bignum isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *bignumImpl = bignum;
return BN_is_one(bignumImpl->_value);
}
- (bool)isZero:(id<MTBignum>)bignum {
assert([bignum isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *bignumImpl = bignum;
return BN_is_zero(bignumImpl->_value);
}
- (NSData *)getBin:(id<MTBignum>)bignum {
assert([bignum isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *bignumImpl = bignum;
int numBytes = BN_num_bytes(bignumImpl->_value);
NSMutableData *data = [[NSMutableData alloc] initWithLength:numBytes];
BN_bn2bin(bignumImpl->_value, data.mutableBytes);
return data;
}
- (int)isPrime:(id<MTBignum>)bignum numberOfChecks:(int)numberOfChecks {
assert([bignum isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *bignumImpl = bignum;
return BN_is_prime_ex(bignumImpl->_value, numberOfChecks, _context, NULL);
}
- (int)compare:(id<MTBignum>)a with:(id<MTBignum>)b {
assert([a isKindOfClass:[MTBignumImpl class]]);
assert([b isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *aImpl = a;
MTBignumImpl *bImpl = b;
return BN_cmp(aImpl->_value, bImpl->_value);
}
- (bool)modAddInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b mod:(id<MTBignum>)mod {
assert([result isKindOfClass:[MTBignumImpl class]]);
assert([a isKindOfClass:[MTBignumImpl class]]);
assert([b isKindOfClass:[MTBignumImpl class]]);
assert([mod isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *resultImpl = result;
MTBignumImpl *aImpl = a;
MTBignumImpl *bImpl = b;
MTBignumImpl *modImpl = mod;
return BN_mod_add(resultImpl->_value, aImpl->_value, bImpl->_value, modImpl->_value, _context) != 0;
}
- (bool)modSubInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b mod:(id<MTBignum>)mod {
assert([result isKindOfClass:[MTBignumImpl class]]);
assert([a isKindOfClass:[MTBignumImpl class]]);
assert([b isKindOfClass:[MTBignumImpl class]]);
assert([mod isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *resultImpl = result;
MTBignumImpl *aImpl = a;
MTBignumImpl *bImpl = b;
MTBignumImpl *modImpl = mod;
return BN_mod_sub(resultImpl->_value, aImpl->_value, bImpl->_value, modImpl->_value, _context) != 0;
}
- (bool)modMulInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b mod:(id<MTBignum>)mod {
assert([result isKindOfClass:[MTBignumImpl class]]);
assert([a isKindOfClass:[MTBignumImpl class]]);
assert([b isKindOfClass:[MTBignumImpl class]]);
assert([mod isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *resultImpl = result;
MTBignumImpl *aImpl = a;
MTBignumImpl *bImpl = b;
MTBignumImpl *modImpl = mod;
return BN_mod_mul(resultImpl->_value, aImpl->_value, bImpl->_value, modImpl->_value, _context) != 0;
}
- (bool)modExpInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b mod:(id<MTBignum>)mod {
assert([result isKindOfClass:[MTBignumImpl class]]);
assert([a isKindOfClass:[MTBignumImpl class]]);
assert([b isKindOfClass:[MTBignumImpl class]]);
assert([mod isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *resultImpl = result;
MTBignumImpl *aImpl = a;
MTBignumImpl *bImpl = b;
MTBignumImpl *modImpl = mod;
return BN_mod_exp(resultImpl->_value, aImpl->_value, bImpl->_value, modImpl->_value, _context) != 0;
}
- (bool)addInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b {
assert([result isKindOfClass:[MTBignumImpl class]]);
assert([a isKindOfClass:[MTBignumImpl class]]);
assert([b isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *resultImpl = result;
MTBignumImpl *aImpl = a;
MTBignumImpl *bImpl = b;
return BN_add(resultImpl->_value, aImpl->_value, bImpl->_value) != 0;
}
- (bool)subInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b {
assert([result isKindOfClass:[MTBignumImpl class]]);
assert([a isKindOfClass:[MTBignumImpl class]]);
assert([b isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *resultImpl = result;
MTBignumImpl *aImpl = a;
MTBignumImpl *bImpl = b;
return BN_sub(resultImpl->_value, aImpl->_value, bImpl->_value) != 0;
}
- (bool)mulInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b {
assert([result isKindOfClass:[MTBignumImpl class]]);
assert([a isKindOfClass:[MTBignumImpl class]]);
assert([b isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *resultImpl = result;
MTBignumImpl *aImpl = a;
MTBignumImpl *bImpl = b;
return BN_mul(resultImpl->_value, aImpl->_value, bImpl->_value, _context) != 0;
}
- (bool)expInto:(id<MTBignum>)result a:(id<MTBignum>)a b:(id<MTBignum>)b {
assert([result isKindOfClass:[MTBignumImpl class]]);
assert([a isKindOfClass:[MTBignumImpl class]]);
assert([b isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *resultImpl = result;
MTBignumImpl *aImpl = a;
MTBignumImpl *bImpl = b;
return BN_exp(resultImpl->_value, aImpl->_value, bImpl->_value, _context) != 0;
}
- (bool)modInverseInto:(id<MTBignum>)result a:(id<MTBignum>)a mod:(id<MTBignum>)mod {
assert([result isKindOfClass:[MTBignumImpl class]]);
assert([a isKindOfClass:[MTBignumImpl class]]);
assert([mod isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *resultImpl = result;
MTBignumImpl *aImpl = a;
MTBignumImpl *modImpl = mod;
return BN_mod_inverse(resultImpl->_value, aImpl->_value, modImpl->_value, _context) != 0;
}
- (unsigned long)modWord:(id<MTBignum>)a mod:(unsigned long)mod {
assert([a isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *aImpl = a;
return BN_mod_word(aImpl->_value, mod);
}
- (bool)rightShift1Bit:(id<MTBignum>)result a:(id<MTBignum>)a {
assert([result isKindOfClass:[MTBignumImpl class]]);
assert([a isKindOfClass:[MTBignumImpl class]]);
MTBignumImpl *resultImpl = result;
MTBignumImpl *aImpl = a;
return BN_rshift1(resultImpl->_value, aImpl->_value);
}
- (id<MTBignum>)rsaGetE:(id<MTRsaPublicKey>)publicKey {
assert([publicKey isKindOfClass:[MTRsaPublicKeyImpl class]]);
MTRsaPublicKeyImpl *publicKeyImpl = publicKey;
return [[MTBignumImpl alloc] initWithValue:BN_dup(RSA_get0_e(publicKeyImpl->_value))];
}
- (id<MTBignum>)rsaGetN:(id<MTRsaPublicKey>)publicKey {
assert([publicKey isKindOfClass:[MTRsaPublicKeyImpl class]]);
MTRsaPublicKeyImpl *publicKeyImpl = publicKey;
return [[MTBignumImpl alloc] initWithValue:BN_dup(RSA_get0_n(publicKeyImpl->_value))];
}
@end
@implementation OpenSSLEncryptionProvider
- (id<MTBignumContext>)createBignumContext {
return [[MTBignumContextImpl alloc] init];
}
- (NSData * _Nullable)rsaEncryptWithPublicKey:(NSString *)publicKey data:(NSData *)data {
MTRsaPublicKeyImpl *rsaKey = [self parseRSAPublicKey:publicKey];
if (rsaKey == nil) {
return nil;
}
MTBignumContextImpl *context = [[MTBignumContextImpl alloc] init];
MTBignumImpl *a = [context create];
[context assignBinTo:a value:data];
MTBignumImpl *r = [context create];
[context modExpInto:r a:a b:[context rsaGetE:rsaKey] mod:[context rsaGetN:rsaKey]];
return [context getBin:r];
}
- (NSData * _Nullable)rsaEncryptPKCS1OAEPWithPublicKey:(NSString *)publicKey data:(NSData *)data {
MTRsaPublicKeyImpl *rsaKey = [self parseRSAPublicKey:publicKey];
if (rsaKey == nil) {
return nil;
}
NSMutableData *outData = [[NSMutableData alloc] initWithLength:data.length + 2048];
int encryptedLength = RSA_public_encrypt((int)data.length, data.bytes, outData.mutableBytes, rsaKey->_value, RSA_PKCS1_OAEP_PADDING);
if (encryptedLength < 0) {
return nil;
}
assert(encryptedLength <= outData.length);
[outData setLength:encryptedLength];
return outData;
}
- (id<MTRsaPublicKey>)parseRSAPublicKey:(NSString *)publicKey {
BIO *keyBio = BIO_new(BIO_s_mem());
NSData *keyData = [publicKey dataUsingEncoding:NSUTF8StringEncoding];
if (keyData == nil) {
return nil;
}
BIO_write(keyBio, keyData.bytes, (int)keyData.length);
RSA *rsaKey = PEM_read_bio_RSAPublicKey(keyBio, NULL, NULL, NULL);
BIO_free(keyBio);
if (rsaKey == nil) {
return nil;
}
return [[MTRsaPublicKeyImpl alloc] initWithValue:rsaKey];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -24,7 +24,8 @@ framework(
"//submodules/MtProtoKit:MtProtoKit#shared", "//submodules/MtProtoKit:MtProtoKit#shared",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared",
"//submodules/Postbox:Postbox#shared", "//submodules/Postbox:Postbox#shared",
"//submodules/CloudData:CloudData", "//submodules/CloudData:CloudData",
"//submodules/EncryptionProvider:EncryptionProvider",
], ],
frameworks = [ frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework", "$SDKROOT/System/Library/Frameworks/Foundation.framework",

View File

@ -15,7 +15,7 @@ import Foundation
#endif #endif
import UIKit import UIKit
#endif #endif
import EncryptionProvider
public protocol AccountState: PostboxCoding { public protocol AccountState: PostboxCoding {
func equalsTo(_ other: AccountState) -> Bool func equalsTo(_ other: AccountState) -> Bool
@ -571,7 +571,7 @@ func sha512Digest(_ data : Data) -> Data {
} }
} }
func passwordUpdateKDF(password: String, derivation: TwoStepPasswordDerivation) -> (Data, TwoStepPasswordDerivation)? { func passwordUpdateKDF(encryptionProvider: EncryptionProvider, password: String, derivation: TwoStepPasswordDerivation) -> (Data, TwoStepPasswordDerivation)? {
guard let passwordData = password.data(using: .utf8, allowLossyConversion: true) else { guard let passwordData = password.data(using: .utf8, allowLossyConversion: true) else {
return nil return nil
} }
@ -609,7 +609,7 @@ func passwordUpdateKDF(password: String, derivation: TwoStepPasswordDerivation)
let x = sha256Digest(nextSalt2 + pbkdfResult + nextSalt2) let x = sha256Digest(nextSalt2 + pbkdfResult + nextSalt2)
let gx = MTExp(g, x, p)! let gx = MTExp(encryptionProvider, g, x, p)!
return (gx, .sha256_sha256_PBKDF2_HMAC_sha512_sha256_srp(salt1: nextSalt1, salt2: nextSalt2, iterations: iterations, g: gValue, p: p)) return (gx, .sha256_sha256_PBKDF2_HMAC_sha512_sha256_srp(salt1: nextSalt1, salt2: nextSalt2, iterations: iterations, g: gValue, p: p))
} }
@ -653,7 +653,7 @@ private func paddedXor(_ a: Data, _ b: Data) -> Data {
return a return a
} }
func passwordKDF(password: String, derivation: TwoStepPasswordDerivation, srpSessionData: TwoStepSRPSessionData) -> PasswordKDFResult? { func passwordKDF(encryptionProvider: EncryptionProvider, password: String, derivation: TwoStepPasswordDerivation, srpSessionData: TwoStepSRPSessionData) -> PasswordKDFResult? {
guard let passwordData = password.data(using: .utf8, allowLossyConversion: true) else { guard let passwordData = password.data(using: .utf8, allowLossyConversion: true) else {
return nil return nil
} }
@ -679,15 +679,15 @@ func passwordKDF(password: String, derivation: TwoStepPasswordDerivation, srpSes
}) })
} }
if !MTCheckIsSafeB(srpSessionData.B, p) { if !MTCheckIsSafeB(encryptionProvider, srpSessionData.B, p) {
return nil return nil
} }
let B = paddedToLength(what: srpSessionData.B, to: p) let B = paddedToLength(what: srpSessionData.B, to: p)
let A = paddedToLength(what: MTExp(g, a, p)!, to: p) let A = paddedToLength(what: MTExp(encryptionProvider, g, a, p)!, to: p)
let u = sha256Digest(A + B) let u = sha256Digest(A + B)
if MTIsZero(u) { if MTIsZero(encryptionProvider, u) {
return nil return nil
} }
@ -699,18 +699,18 @@ func passwordKDF(password: String, derivation: TwoStepPasswordDerivation, srpSes
let x = sha256Digest(salt2 + pbkdfResult + salt2) let x = sha256Digest(salt2 + pbkdfResult + salt2)
let gx = MTExp(g, x, p)! let gx = MTExp(encryptionProvider, g, x, p)!
let k = sha256Digest(p + paddedToLength(what: g, to: p)) let k = sha256Digest(p + paddedToLength(what: g, to: p))
let s1 = MTModSub(B, MTModMul(k, gx, p)!, p)! let s1 = MTModSub(encryptionProvider, B, MTModMul(encryptionProvider, k, gx, p)!, p)!
if !MTCheckIsSafeGAOrB(s1, p) { if !MTCheckIsSafeGAOrB(encryptionProvider, s1, p) {
return nil return nil
} }
let s2 = MTAdd(a, MTMul(u, x)!)! let s2 = MTAdd(encryptionProvider, a, MTMul(encryptionProvider, u, x)!)!
let S = MTExp(s1, s2, p)! let S = MTExp(encryptionProvider, s1, s2, p)!
let K = sha256Digest(paddedToLength(what: S, to: p)) let K = sha256Digest(paddedToLength(what: S, to: p))
let m1 = paddedXor(sha256Digest(p), sha256Digest(paddedToLength(what: g, to: p))) let m1 = paddedXor(sha256Digest(p), sha256Digest(paddedToLength(what: g, to: p)))
let m2 = sha256Digest(salt1) let m2 = sha256Digest(salt1)
@ -788,7 +788,7 @@ func verifyPassword(_ account: UnauthorizedAccount, password: String) -> Signal<
return .fail(MTRpcError(errorCode: 400, errorDescription: "INTERNAL_NO_PASSWORD")) return .fail(MTRpcError(errorCode: 400, errorDescription: "INTERNAL_NO_PASSWORD"))
} }
let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) let kdfResult = passwordKDF(encryptionProvider: account.network.encryptionProvider, password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData)
if let kdfResult = kdfResult { if let kdfResult = kdfResult {
return account.network.request(Api.functions.auth.checkPassword(password: .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1))), automaticFloodWait: false) return account.network.request(Api.functions.auth.checkPassword(password: .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1))), automaticFloodWait: false)

View File

@ -2093,7 +2093,7 @@ private func recordPeerActivityTimestamp(peerId: PeerId, timestamp: Int32, into
} }
} }
func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountPeerId: PeerId, mediaBox: MediaBox, transaction: Transaction, auxiliaryMethods: AccountAuxiliaryMethods, finalState: AccountFinalState) -> AccountReplayedFinalState? { func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountPeerId: PeerId, mediaBox: MediaBox, encryptionProvider: EncryptionProvider, transaction: Transaction, auxiliaryMethods: AccountAuxiliaryMethods, finalState: AccountFinalState) -> AccountReplayedFinalState? {
let verified = verifyTransaction(transaction, finalState: finalState.state) let verified = verifyTransaction(transaction, finalState: finalState.state)
if !verified { if !verified {
Logger.shared.log("State", "failed to verify final state") Logger.shared.log("State", "failed to verify final state")
@ -2551,7 +2551,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
} }
updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: presences) updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: presences)
case let .UpdateSecretChat(chat, _): case let .UpdateSecretChat(chat, _):
updateSecretChat(accountPeerId: accountPeerId, transaction: transaction, chat: chat, requestData: nil) updateSecretChat(encryptionProvider: encryptionProvider, accountPeerId: accountPeerId, transaction: transaction, chat: chat, requestData: nil)
case let .AddSecretMessages(messages): case let .AddSecretMessages(messages):
for message in messages { for message in messages {
let peerId = message.peerId let peerId = message.peerId
@ -2869,7 +2869,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
inner: while true { inner: while true {
let keychain = (transaction.getPeerChatState(peerId) as? SecretChatState)?.keychain let keychain = (transaction.getPeerChatState(peerId) as? SecretChatState)?.keychain
if processSecretChatIncomingEncryptedOperations(transaction: transaction, peerId: peerId) { if processSecretChatIncomingEncryptedOperations(transaction: transaction, peerId: peerId) {
let processResult = processSecretChatIncomingDecryptedOperations(mediaBox: mediaBox, transaction: transaction, peerId: peerId) let processResult = processSecretChatIncomingDecryptedOperations(encryptionProvider: encryptionProvider, mediaBox: mediaBox, transaction: transaction, peerId: peerId)
if !processResult.addedMessages.isEmpty { if !processResult.addedMessages.isEmpty {
let currentInclusion = transaction.getPeerChatListInclusion(peerId) let currentInclusion = transaction.getPeerChatListInclusion(peerId)
if let groupId = currentInclusion.groupId, groupId == Namespaces.PeerGroup.archive { if let groupId = currentInclusion.groupId, groupId == Namespaces.PeerGroup.archive {

View File

@ -439,7 +439,7 @@ public final class AccountStateManager {
} }
return postbox.transaction { transaction -> (difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool) in return postbox.transaction { transaction -> (difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool) in
let startTime = CFAbsoluteTimeGetCurrent() let startTime = CFAbsoluteTimeGetCurrent()
let replayedState = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState) let replayedState = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, encryptionProvider: network.encryptionProvider, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState)
let deltaTime = CFAbsoluteTimeGetCurrent() - startTime let deltaTime = CFAbsoluteTimeGetCurrent() - startTime
if deltaTime > 1.0 { if deltaTime > 1.0 {
Logger.shared.log("State", "replayFinalState took \(deltaTime)s") Logger.shared.log("State", "replayFinalState took \(deltaTime)s")
@ -554,7 +554,7 @@ public final class AccountStateManager {
return postbox.transaction { transaction -> AccountReplayedFinalState? in return postbox.transaction { transaction -> AccountReplayedFinalState? in
let startTime = CFAbsoluteTimeGetCurrent() let startTime = CFAbsoluteTimeGetCurrent()
let result = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState) let result = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, encryptionProvider: network.encryptionProvider, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState)
let deltaTime = CFAbsoluteTimeGetCurrent() - startTime let deltaTime = CFAbsoluteTimeGetCurrent() - startTime
if deltaTime > 1.0 { if deltaTime > 1.0 {
Logger.shared.log("State", "replayFinalState took \(deltaTime)s") Logger.shared.log("State", "replayFinalState took \(deltaTime)s")
@ -756,10 +756,11 @@ public final class AccountStateManager {
let accountManager = self.accountManager let accountManager = self.accountManager
let postbox = self.postbox let postbox = self.postbox
let mediaBox = self.postbox.mediaBox let mediaBox = self.postbox.mediaBox
let network = self.network
let auxiliaryMethods = self.auxiliaryMethods let auxiliaryMethods = self.auxiliaryMethods
let signal = self.postbox.transaction { transaction -> AccountReplayedFinalState? in let signal = self.postbox.transaction { transaction -> AccountReplayedFinalState? in
let startTime = CFAbsoluteTimeGetCurrent() let startTime = CFAbsoluteTimeGetCurrent()
let result = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState) let result = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, encryptionProvider: network.encryptionProvider, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState)
let deltaTime = CFAbsoluteTimeGetCurrent() - startTime let deltaTime = CFAbsoluteTimeGetCurrent() - startTime
if deltaTime > 1.0 { if deltaTime > 1.0 {
Logger.shared.log("State", "replayFinalState took \(deltaTime)s") Logger.shared.log("State", "replayFinalState took \(deltaTime)s")

View File

@ -505,10 +505,10 @@ private final class CallSessionManagerContext {
switch context.state { switch context.state {
case let .requested(_, accessHash, a, gA, config, _): case let .requested(_, accessHash, a, gA, config, _):
let p = config.p.makeData() let p = config.p.makeData()
if !MTCheckIsSafeGAOrB(gA, p) { if !MTCheckIsSafeGAOrB(self.network.encryptionProvider, gA, p) {
self.drop(internalId: internalId, reason: .disconnect) self.drop(internalId: internalId, reason: .disconnect)
} }
var key = MTExp(gB.makeData(), a, p)! var key = MTExp(self.network.encryptionProvider, gB.makeData(), a, p)!
if key.count > 256 { if key.count > 256 {
key.count = 256 key.count = 256
@ -654,7 +654,7 @@ private final class CallSessionManagerContext {
} }
private func makeSessionEncryptionKey(config: SecretChatEncryptionConfig, gAHash: Data, b: Data, gA: Data) -> (key: Data, keyId: Int64, keyVisualHash: Data)? { private func makeSessionEncryptionKey(config: SecretChatEncryptionConfig, gAHash: Data, b: Data, gA: Data) -> (key: Data, keyId: Int64, keyVisualHash: Data)? {
var key = MTExp(gA, b, config.p.makeData())! var key = MTExp(self.network.encryptionProvider, gA, b, config.p.makeData())!
if key.count > 256 { if key.count > 256 {
key.count = 256 key.count = 256
@ -831,9 +831,9 @@ private func acceptCallSession(postbox: Postbox, network: Network, stableId: Cal
let bData = b let bData = b
let gb = MTExp(g, bData, p)! let gb = MTExp(network.encryptionProvider, g, bData, p)!
if !MTCheckIsSafeGAOrB(gb, p) { if !MTCheckIsSafeGAOrB(network.encryptionProvider, gb, p) {
return .single(.failed) return .single(.failed)
} }
@ -893,8 +893,8 @@ private func requestCallSession(postbox: Postbox, network: Network, peerId: Peer
let g = Data(bytes: &gValue, count: 4) let g = Data(bytes: &gValue, count: 4)
let p = config.p.makeData() let p = config.p.makeData()
let ga = MTExp(g, a, p)! let ga = MTExp(network.encryptionProvider, g, a, p)!
if !MTCheckIsSafeGAOrB(ga, p) { if !MTCheckIsSafeGAOrB(network.encryptionProvider, ga, p) {
return .single(.failed(.generic)) return .single(.failed(.generic))
} }

View File

@ -110,7 +110,7 @@ public func updateChannelOwnership(account: Account, accountStateManager: Accoun
} }
|> mapToSignal { authData -> Signal<Api.InputCheckPasswordSRP, ChannelOwnershipTransferError> in |> mapToSignal { authData -> Signal<Api.InputCheckPasswordSRP, ChannelOwnershipTransferError> in
if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData { if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData {
guard let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { guard let kdfResult = passwordKDF(encryptionProvider: account.network.encryptionProvider, password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else {
return .fail(.generic) return .fail(.generic)
} }
return .single(.inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1))) return .single(.inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)))

View File

@ -34,9 +34,9 @@ public func createSecretChat(account: Account, peerId: PeerId) -> Signal<PeerId,
let p = config.p.makeData() let p = config.p.makeData()
let aData = a.makeData() let aData = a.makeData()
let ga = MTExp(g, aData, p)! let ga = MTExp(account.network.encryptionProvider, g, aData, p)!
if !MTCheckIsSafeGAOrB(ga, p) { if !MTCheckIsSafeGAOrB(account.network.encryptionProvider, ga, p) {
return .fail(.generic) return .fail(.generic)
} }
@ -46,7 +46,7 @@ public func createSecretChat(account: Account, peerId: PeerId) -> Signal<PeerId,
} }
|> mapToSignal { result -> Signal<PeerId, CreateSecretChatError> in |> mapToSignal { result -> Signal<PeerId, CreateSecretChatError> in
return account.postbox.transaction { transaction -> PeerId in return account.postbox.transaction { transaction -> PeerId in
updateSecretChat(accountPeerId: account.peerId, transaction: transaction, chat: result, requestData: SecretChatRequestData(g: config.g, p: config.p, a: a)) updateSecretChat(encryptionProvider: account.network.encryptionProvider, accountPeerId: account.peerId, transaction: transaction, chat: result, requestData: SecretChatRequestData(g: config.g, p: config.p, a: a))
return result.peerId return result.peerId
} |> mapError { _ -> CreateSecretChatError in return .generic } } |> mapError { _ -> CreateSecretChatError in return .generic }

View File

@ -333,7 +333,7 @@ public func grantSecureIdAccess(network: Network, peerId: PeerId, publicKey: Str
guard let (encryptedCredentialsData, decryptedCredentialsHash) = encryptedCredentialsData(data: credentialsData, secretData: credentialsSecretData) else { guard let (encryptedCredentialsData, decryptedCredentialsHash) = encryptedCredentialsData(data: credentialsData, secretData: credentialsSecretData) else {
return .fail(.generic) return .fail(.generic)
} }
guard let encryptedSecretData = MTRsaEncryptPKCS1OAEP(publicKey, credentialsSecretData) else { guard let encryptedSecretData = MTRsaEncryptPKCS1OAEP(network.encryptionProvider, publicKey, credentialsSecretData) else {
return .fail(.generic) return .fail(.generic)
} }

View File

@ -195,7 +195,7 @@ private func initialHandshakeAccept(postbox: Postbox, network: Network, peerId:
|> mapToSignal { config -> Signal<Void, NoError> in |> mapToSignal { config -> Signal<Void, NoError> in
let p = config.p.makeData() let p = config.p.makeData()
if !MTCheckIsSafeGAOrB(gA.makeData(), p) { if !MTCheckIsSafeGAOrB(network.encryptionProvider, gA.makeData(), p) {
return postbox.transaction { transaction -> Void in return postbox.transaction { transaction -> Void in
let removed = transaction.operationLogRemoveEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: tagLocalIndex) let removed = transaction.operationLogRemoveEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: tagLocalIndex)
assert(removed) assert(removed)
@ -219,9 +219,9 @@ private func initialHandshakeAccept(postbox: Postbox, network: Network, peerId:
let bData = b.makeData() let bData = b.makeData()
let gb = MTExp(g, bData, p)! let gb = MTExp(network.encryptionProvider, g, bData, p)!
var key = MTExp(gA.makeData(), bData, p)! var key = MTExp(network.encryptionProvider, gA.makeData(), bData, p)!
if key.count > 256 { if key.count > 256 {
key.count = 256 key.count = 256
@ -293,7 +293,7 @@ private func pfsRequestKey(postbox: Postbox, network: Network, peerId: PeerId, l
let p = config.p.makeData() let p = config.p.makeData()
let aData = a.makeData() let aData = a.makeData()
let ga = MTExp(g, aData, p)! let ga = MTExp(network.encryptionProvider, g, aData, p)!
return postbox.transaction { transaction -> Signal<Void, NoError> in return postbox.transaction { transaction -> Signal<Void, NoError> in
if let state = transaction.getPeerChatState(peerId) as? SecretChatState { if let state = transaction.getPeerChatState(peerId) as? SecretChatState {
@ -321,9 +321,9 @@ private func pfsAcceptKey(postbox: Postbox, network: Network, peerId: PeerId, la
let bData = b.makeData() let bData = b.makeData()
let gb = MTExp(g, bData, p)! let gb = MTExp(network.encryptionProvider, g, bData, p)!
var key = MTExp(gA.makeData(), bData, p)! var key = MTExp(network.encryptionProvider, gA.makeData(), bData, p)!
if key.count > 256 { if key.count > 256 {
key.count = 256 key.count = 256

View File

@ -16,6 +16,8 @@ import Foundation
import CloudData import CloudData
#endif #endif
import EncryptionProvider
public enum ConnectionStatus: Equatable { public enum ConnectionStatus: Equatable {
case waitingForNetwork case waitingForNetwork
case connecting(proxyAddress: String?, proxyHasConnectionIssues: Bool) case connecting(proxyAddress: String?, proxyHasConnectionIssues: Bool)
@ -407,19 +409,20 @@ public struct NetworkInitializationArguments {
public let appVersion: String public let appVersion: String
public let voipMaxLayer: Int32 public let voipMaxLayer: Int32
public let appData: Signal<Data?, NoError> public let appData: Signal<Data?, NoError>
public let encryptionProvider: EncryptionProvider
public init(apiId: Int32, languagesCategory: String, appVersion: String, voipMaxLayer: Int32, appData: Signal<Data?, NoError>) { public init(apiId: Int32, languagesCategory: String, appVersion: String, voipMaxLayer: Int32, appData: Signal<Data?, NoError>, encryptionProvider: EncryptionProvider) {
self.apiId = apiId self.apiId = apiId
self.languagesCategory = languagesCategory self.languagesCategory = languagesCategory
self.appVersion = appVersion self.appVersion = appVersion
self.voipMaxLayer = voipMaxLayer self.voipMaxLayer = voipMaxLayer
self.appData = appData self.appData = appData
self.encryptionProvider = encryptionProvider
} }
} }
#if os(iOS) private let cloudDataContext = Atomic<CloudDataContext?>(value: nil)
private let cloudDataContext = makeCloudDataContext()
#endif
func initializedNetwork(arguments: NetworkInitializationArguments, supplementary: Bool, datacenterId: Int, keychain: Keychain, basePath: String, testingEnvironment: Bool, languageCode: String?, proxySettings: ProxySettings?, networkSettings: NetworkSettings?, phoneNumber: String?) -> Signal<Network, NoError> { func initializedNetwork(arguments: NetworkInitializationArguments, supplementary: Bool, datacenterId: Int, keychain: Keychain, basePath: String, testingEnvironment: Bool, languageCode: String?, proxySettings: ProxySettings?, networkSettings: NetworkSettings?, phoneNumber: String?) -> Signal<Network, NoError> {
return Signal { subscriber in return Signal { subscriber in
let queue = Queue() let queue = Queue()
@ -460,7 +463,7 @@ func initializedNetwork(arguments: NetworkInitializationArguments, supplementary
} }
} }
let context = MTContext(serialization: serialization, apiEnvironment: apiEnvironment, isTestingEnvironment: testingEnvironment, useTempAuthKeys: false)! let context = MTContext(serialization: serialization, encryptionProvider: arguments.encryptionProvider, apiEnvironment: apiEnvironment, isTestingEnvironment: testingEnvironment, useTempAuthKeys: false)!
let seedAddressList: [Int: [String]] let seedAddressList: [Int: [String]]
@ -487,7 +490,15 @@ func initializedNetwork(arguments: NetworkInitializationArguments, supplementary
var wrappedAdditionalSource: MTSignal? var wrappedAdditionalSource: MTSignal?
#if os(iOS) #if os(iOS)
if #available(iOS 10.0, *) { if #available(iOS 10.0, *) {
if let cloudDataContext = cloudDataContext { var cloudDataContextValue: CloudDataContext?
if let value = cloudDataContext.with({ $0 }) {
cloudDataContextValue = value
} else {
cloudDataContextValue = makeCloudDataContext(encryptionProvider: arguments.encryptionProvider)
let _ = cloudDataContext.swap(cloudDataContextValue)
}
if let cloudDataContext = cloudDataContextValue {
wrappedAdditionalSource = MTSignal(generator: { subscriber in wrappedAdditionalSource = MTSignal(generator: { subscriber in
let disposable = cloudDataContext.get(phoneNumber: .single(phoneNumber)).start(next: { value in let disposable = cloudDataContext.get(phoneNumber: .single(phoneNumber)).start(next: { value in
subscriber?.putNext(value) subscriber?.putNext(value)
@ -504,10 +515,10 @@ func initializedNetwork(arguments: NetworkInitializationArguments, supplementary
context.setDiscoverBackupAddressListSignal(MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber)) context.setDiscoverBackupAddressListSignal(MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber))
#if DEBUG #if DEBUG
//let _ = MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber).start(next: nil) let _ = MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber).start(next: nil)
#endif #endif
let mtProto = MTProto(context: context, datacenterId: datacenterId, usageCalculationInfo: usageCalculationInfo(basePath: basePath, category: nil))! let mtProto = MTProto(context: context, datacenterId: datacenterId, usageCalculationInfo: usageCalculationInfo(basePath: basePath, category: nil), requiredAuthToken: nil, authTokenMasterDatacenterId: 0)!
mtProto.useTempAuthKeys = context.useTempAuthKeys mtProto.useTempAuthKeys = context.useTempAuthKeys
mtProto.checkForProxyConnectionIssues = true mtProto.checkForProxyConnectionIssues = true
@ -537,7 +548,7 @@ func initializedNetwork(arguments: NetworkInitializationArguments, supplementary
mtProto.delegate = connectionStatusDelegate mtProto.delegate = connectionStatusDelegate
mtProto.add(requestService) mtProto.add(requestService)
let network = Network(queue: queue, datacenterId: datacenterId, context: context, mtProto: mtProto, requestService: requestService, connectionStatusDelegate: connectionStatusDelegate, _connectionStatus: connectionStatus, basePath: basePath, appDataDisposable: appDataDisposable) let network = Network(queue: queue, datacenterId: datacenterId, context: context, mtProto: mtProto, requestService: requestService, connectionStatusDelegate: connectionStatusDelegate, _connectionStatus: connectionStatus, basePath: basePath, appDataDisposable: appDataDisposable, encryptionProvider: arguments.encryptionProvider)
appDataUpdatedImpl = { [weak network] data in appDataUpdatedImpl = { [weak network] data in
guard let data = data else { guard let data = data else {
return return
@ -653,6 +664,8 @@ public enum NetworkRequestResult<T> {
} }
public final class Network: NSObject, MTRequestMessageServiceDelegate { public final class Network: NSObject, MTRequestMessageServiceDelegate {
public let encryptionProvider: EncryptionProvider
private let queue: Queue private let queue: Queue
public let datacenterId: Int public let datacenterId: Int
public let context: MTContext public let context: MTContext
@ -703,7 +716,9 @@ public final class Network: NSObject, MTRequestMessageServiceDelegate {
return "Network context: \(self.context)" return "Network context: \(self.context)"
} }
fileprivate init(queue: Queue, datacenterId: Int, context: MTContext, mtProto: MTProto, requestService: MTRequestMessageService, connectionStatusDelegate: MTProtoConnectionStatusDelegate, _connectionStatus: Promise<ConnectionStatus>, basePath: String, appDataDisposable: Disposable) { fileprivate init(queue: Queue, datacenterId: Int, context: MTContext, mtProto: MTProto, requestService: MTRequestMessageService, connectionStatusDelegate: MTProtoConnectionStatusDelegate, _connectionStatus: Promise<ConnectionStatus>, basePath: String, appDataDisposable: Disposable, encryptionProvider: EncryptionProvider) {
self.encryptionProvider = encryptionProvider
self.queue = queue self.queue = queue
self.datacenterId = datacenterId self.datacenterId = datacenterId
self.context = context self.context = context
@ -740,7 +755,7 @@ public final class Network: NSObject, MTRequestMessageServiceDelegate {
if id == Int(dcId) { if id == Int(dcId) {
let dict = NSMutableDictionary() let dict = NSMutableDictionary()
dict["key"] = publicKey dict["key"] = publicKey
dict["fingerprint"] = MTRsaFingerprint(publicKey) dict["fingerprint"] = MTRsaFingerprint(encryptionProvider, publicKey)
array.add(dict) array.add(dict)
} }
} }
@ -1050,9 +1065,9 @@ class Keychain: NSObject, MTKeychain {
} }
} }
#if os(iOS) #if os(iOS)
func makeCloudDataContext() -> CloudDataContext? { func makeCloudDataContext(encryptionProvider: EncryptionProvider) -> CloudDataContext? {
if #available(iOS 10.0, *) { if #available(iOS 10.0, *) {
return CloudDataContextImpl() return CloudDataContextImpl(encryptionProvider: encryptionProvider)
} else { } else {
return nil return nil
} }

View File

@ -8,6 +8,8 @@ import Foundation
import TelegramApi import TelegramApi
#endif #endif
import EncryptionProvider
private enum MessageParsingError: Error { private enum MessageParsingError: Error {
case contentParsingError case contentParsingError
case unsupportedLayer case unsupportedLayer
@ -64,7 +66,7 @@ struct SecretChatOperationProcessResult {
let addedMessages: [StoreMessage] let addedMessages: [StoreMessage]
} }
func processSecretChatIncomingDecryptedOperations(mediaBox: MediaBox, transaction: Transaction, peerId: PeerId) -> SecretChatOperationProcessResult { func processSecretChatIncomingDecryptedOperations(encryptionProvider: EncryptionProvider, mediaBox: MediaBox, transaction: Transaction, peerId: PeerId) -> SecretChatOperationProcessResult {
if let state = transaction.getPeerChatState(peerId) as? SecretChatState, let peer = transaction.getPeer(peerId) as? TelegramSecretChat { if let state = transaction.getPeerChatState(peerId) as? SecretChatState, let peer = transaction.getPeer(peerId) as? TelegramSecretChat {
var removeTagLocalIndices: [Int32] = [] var removeTagLocalIndices: [Int32] = []
var updatedState = state var updatedState = state
@ -257,7 +259,7 @@ func processSecretChatIncomingDecryptedOperations(mediaBox: MediaBox, transactio
updatedPeer = updatedPeer.withUpdatedMessageAutoremoveTimeout(timeout == 0 ? nil : timeout) updatedPeer = updatedPeer.withUpdatedMessageAutoremoveTimeout(timeout == 0 ? nil : timeout)
updatedState = updatedState.withUpdatedMessageAutoremoveTimeout(timeout == 0 ? nil : timeout) updatedState = updatedState.withUpdatedMessageAutoremoveTimeout(timeout == 0 ? nil : timeout)
case let .rekeyAction(action): case let .rekeyAction(action):
updatedState = secretChatAdvanceRekeySessionIfNeeded(transaction: transaction, peerId: peerId, state: updatedState, action: action) updatedState = secretChatAdvanceRekeySessionIfNeeded(encryptionProvider: encryptionProvider, transaction: transaction, peerId: peerId, state: updatedState, action: action)
case let .deleteMessages(globallyUniqueIds): case let .deleteMessages(globallyUniqueIds):
var messageIds: [MessageId] = [] var messageIds: [MessageId] = []
for id in globallyUniqueIds { for id in globallyUniqueIds {

View File

@ -286,40 +286,40 @@ public func deleteSecureIdValues(network: Network, keys: Set<SecureIdValueKey>)
public func dropSecureId(network: Network, currentPassword: String) -> Signal<Void, AuthorizationPasswordVerificationError> { public func dropSecureId(network: Network, currentPassword: String) -> Signal<Void, AuthorizationPasswordVerificationError> {
return twoStepAuthData(network) return twoStepAuthData(network)
|> mapError { _ -> AuthorizationPasswordVerificationError in |> mapError { _ -> AuthorizationPasswordVerificationError in
return .generic return .generic
} }
|> mapToSignal { authData -> Signal<Void, AuthorizationPasswordVerificationError> in |> mapToSignal { authData -> Signal<Void, AuthorizationPasswordVerificationError> in
let checkPassword: Api.InputCheckPasswordSRP let checkPassword: Api.InputCheckPasswordSRP
if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData { if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData {
let kdfResult = passwordKDF(password: currentPassword, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) let kdfResult = passwordKDF(encryptionProvider: network.encryptionProvider, password: currentPassword, derivation: currentPasswordDerivation, srpSessionData: srpSessionData)
if let kdfResult = kdfResult { if let kdfResult = kdfResult {
checkPassword = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)) checkPassword = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1))
} else {
return .fail(.generic)
}
} else { } else {
checkPassword = .inputCheckPasswordEmpty return .fail(.generic)
} }
} else {
let settings = network.request(Api.functions.account.getPasswordSettings(password: checkPassword), automaticFloodWait: false) checkPassword = .inputCheckPasswordEmpty
|> mapError { error in }
return AuthorizationPasswordVerificationError.generic
} let settings = network.request(Api.functions.account.getPasswordSettings(password: checkPassword), automaticFloodWait: false)
|> mapError { error in
return settings return AuthorizationPasswordVerificationError.generic
|> mapToSignal { value -> Signal<Void, AuthorizationPasswordVerificationError> in }
switch value {
case .passwordSettings: return settings
var flags: Int32 = 0 |> mapToSignal { value -> Signal<Void, AuthorizationPasswordVerificationError> in
flags |= (1 << 2) switch value {
return network.request(Api.functions.account.updatePasswordSettings(password: .inputCheckPasswordEmpty, newSettings: .passwordInputSettings(flags: flags, newAlgo: nil, newPasswordHash: nil, hint: nil, email: nil, newSecureSettings: nil)), automaticFloodWait: false) case .passwordSettings:
|> map { _ in } var flags: Int32 = 0
|> mapError { _ in flags |= (1 << 2)
return AuthorizationPasswordVerificationError.generic return network.request(Api.functions.account.updatePasswordSettings(password: .inputCheckPasswordEmpty, newSettings: .passwordInputSettings(flags: flags, newAlgo: nil, newPasswordHash: nil, hint: nil, email: nil, newSecureSettings: nil)), automaticFloodWait: false)
} |> map { _ in }
|> mapError { _ in
return AuthorizationPasswordVerificationError.generic
} }
} }
}
} }
} }

View File

@ -50,12 +50,12 @@ func validatedEncryptionConfig(postbox: Postbox, network: Network) -> Signal<Sec
return .complete() return .complete()
} }
if !MTCheckMod(p.makeData(), UInt32(g), network.context.keychain) { if !MTCheckMod(network.encryptionProvider, p.makeData(), UInt32(g), network.context.keychain) {
Logger.shared.log("SecretChatEncryptionConfig", "Invalid p or g") Logger.shared.log("SecretChatEncryptionConfig", "Invalid p or g")
return .complete() return .complete()
} }
if !MTCheckIsSafePrime(p.makeData(), network.context.keychain) { if !MTCheckIsSafePrime(network.encryptionProvider, p.makeData(), network.context.keychain) {
Logger.shared.log("SecretChatEncryptionConfig", "Invalid p") Logger.shared.log("SecretChatEncryptionConfig", "Invalid p")
return .never() return .never()
} }

View File

@ -11,6 +11,8 @@ import Foundation
#endif #endif
#endif #endif
import EncryptionProvider
private let keyUseCountThreshold: Int32 = 100 private let keyUseCountThreshold: Int32 = 100
func secretChatInitiateRekeySessionIfNeeded(transaction: Transaction, peerId: PeerId, state: SecretChatState) -> SecretChatState { func secretChatInitiateRekeySessionIfNeeded(transaction: Transaction, peerId: PeerId, state: SecretChatState) -> SecretChatState {
@ -36,105 +38,105 @@ func secretChatInitiateRekeySessionIfNeeded(transaction: Transaction, peerId: Pe
return state return state
} }
func secretChatAdvanceRekeySessionIfNeeded(transaction: Transaction, peerId: PeerId, state: SecretChatState, action: SecretChatRekeyServiceAction) -> SecretChatState { func secretChatAdvanceRekeySessionIfNeeded(encryptionProvider: EncryptionProvider, transaction: Transaction, peerId: PeerId, state: SecretChatState, action: SecretChatRekeyServiceAction) -> SecretChatState {
switch state.embeddedState { switch state.embeddedState {
case let .sequenceBasedLayer(sequenceState): case let .sequenceBasedLayer(sequenceState):
switch action { switch action {
case let .pfsAbortSession(rekeySessionId): case let .pfsAbortSession(rekeySessionId):
if let rekeySession = sequenceState.rekeyState, rekeySession.id == rekeySessionId { if let rekeySession = sequenceState.rekeyState, rekeySession.id == rekeySessionId {
return state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(nil))) return state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(nil)))
}
case let .pfsAcceptKey(rekeySessionId, gB, remoteKeyFingerprint):
if let rekeySession = sequenceState.rekeyState, rekeySession.id == rekeySessionId {
switch rekeySession.data {
case let .requested(a, config):
var gValue: Int32 = config.g.byteSwapped
let p = config.p.makeData()
let aData = a.makeData()
if !MTCheckIsSafeGAOrB(gB.makeData(), p) {
return state.withUpdatedEmbeddedState(.terminated)
}
var key = MTExp(gB.makeData(), aData, p)!
if key.count > 256 {
key.count = 256
} else {
while key.count < 256 {
key.insert(0, at: 0)
}
}
let keyHash = MTSha1(key)!
var keyFingerprint: Int64 = 0
keyHash.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8)
}
assert(remoteKeyFingerprint == keyFingerprint)
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SecretChatOutgoingOperation(contents: .pfsCommitKey(layer: sequenceState.layerNegotiationState.activeLayer, actionGloballyUniqueId: arc4random64(), rekeySessionId: rekeySession.id, keyFingerprint: keyFingerprint), mutable: true, delivered: false))
let keyValidityOperationIndex = transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing)
let keyValidityOperationCanonicalIndex = sequenceState.canonicalOutgoingOperationIndex(keyValidityOperationIndex)
return state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(nil))).withUpdatedKeychain(state.keychain.withUpdatedKey(fingerprint: keyFingerprint, { _ in
return SecretChatKey(fingerprint: keyFingerprint, key: MemoryBuffer(data: key), validity: .sequenceBasedIndexRange(fromCanonicalIndex: keyValidityOperationCanonicalIndex), useCount: 0)
}))
default:
assertionFailure()
break
}
}
case let .pfsCommitKey(rekeySessionId, keyFingerprint):
if let rekeySession = sequenceState.rekeyState, rekeySession.id == rekeySessionId {
if case let .accepted(key, localKeyFingerprint) = rekeySession.data, keyFingerprint == localKeyFingerprint {
let keyValidityOperationIndex = transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing)
let keyValidityOperationCanonicalIndex = sequenceState.canonicalOutgoingOperationIndex(keyValidityOperationIndex)
let updatedState = state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(nil))).withUpdatedKeychain(state.keychain.withUpdatedKey(fingerprint: keyFingerprint, { _ in
return SecretChatKey(fingerprint: keyFingerprint, key: key, validity: .sequenceBasedIndexRange(fromCanonicalIndex: keyValidityOperationCanonicalIndex), useCount: 0)
}))
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SecretChatOutgoingOperation(contents: .noop(layer: sequenceState.layerNegotiationState.activeLayer, actionGloballyUniqueId: arc4random64()), mutable: true, delivered: false))
return updatedState
} else {
assertionFailure()
}
} else {
assertionFailure()
}
case let .pfsRequestKey(rekeySessionId, gA):
var acceptSession = true
if let rekeySession = sequenceState.rekeyState {
switch rekeySession.data {
case .requesting, .requested:
if rekeySessionId < rekeySession.id {
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SecretChatOutgoingOperation(contents: .pfsAbortSession(layer: sequenceState.layerNegotiationState.activeLayer, actionGloballyUniqueId: arc4random64(), rekeySessionId: rekeySession.id), mutable: true, delivered: false))
} else {
acceptSession = false
}
case .accepting, .accepted:
break
}
}
if acceptSession {
let bBytes = malloc(256)!
let _ = SecRandomCopyBytes(nil, 256, bBytes.assumingMemoryBound(to: UInt8.self))
let b = MemoryBuffer(memory: bBytes, capacity: 256, length: 256, freeWhenDone: true)
let rekeySession = SecretChatRekeySessionState(id: rekeySessionId, data: .accepting)
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SecretChatOutgoingOperation(contents: .pfsAcceptKey(layer: sequenceState.layerNegotiationState.activeLayer, actionGloballyUniqueId: arc4random64(), rekeySessionId: rekeySession.id, gA: gA, b: b), mutable: true, delivered: false))
return state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(rekeySession)))
}
} }
default: case let .pfsAcceptKey(rekeySessionId, gB, remoteKeyFingerprint):
break if let rekeySession = sequenceState.rekeyState, rekeySession.id == rekeySessionId {
switch rekeySession.data {
case let .requested(a, config):
var gValue: Int32 = config.g.byteSwapped
let p = config.p.makeData()
let aData = a.makeData()
if !MTCheckIsSafeGAOrB(encryptionProvider, gB.makeData(), p) {
return state.withUpdatedEmbeddedState(.terminated)
}
var key = MTExp(encryptionProvider, gB.makeData(), aData, p)!
if key.count > 256 {
key.count = 256
} else {
while key.count < 256 {
key.insert(0, at: 0)
}
}
let keyHash = MTSha1(key)!
var keyFingerprint: Int64 = 0
keyHash.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8)
}
assert(remoteKeyFingerprint == keyFingerprint)
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SecretChatOutgoingOperation(contents: .pfsCommitKey(layer: sequenceState.layerNegotiationState.activeLayer, actionGloballyUniqueId: arc4random64(), rekeySessionId: rekeySession.id, keyFingerprint: keyFingerprint), mutable: true, delivered: false))
let keyValidityOperationIndex = transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing)
let keyValidityOperationCanonicalIndex = sequenceState.canonicalOutgoingOperationIndex(keyValidityOperationIndex)
return state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(nil))).withUpdatedKeychain(state.keychain.withUpdatedKey(fingerprint: keyFingerprint, { _ in
return SecretChatKey(fingerprint: keyFingerprint, key: MemoryBuffer(data: key), validity: .sequenceBasedIndexRange(fromCanonicalIndex: keyValidityOperationCanonicalIndex), useCount: 0)
}))
default:
assertionFailure()
break
}
}
case let .pfsCommitKey(rekeySessionId, keyFingerprint):
if let rekeySession = sequenceState.rekeyState, rekeySession.id == rekeySessionId {
if case let .accepted(key, localKeyFingerprint) = rekeySession.data, keyFingerprint == localKeyFingerprint {
let keyValidityOperationIndex = transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing)
let keyValidityOperationCanonicalIndex = sequenceState.canonicalOutgoingOperationIndex(keyValidityOperationIndex)
let updatedState = state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(nil))).withUpdatedKeychain(state.keychain.withUpdatedKey(fingerprint: keyFingerprint, { _ in
return SecretChatKey(fingerprint: keyFingerprint, key: key, validity: .sequenceBasedIndexRange(fromCanonicalIndex: keyValidityOperationCanonicalIndex), useCount: 0)
}))
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SecretChatOutgoingOperation(contents: .noop(layer: sequenceState.layerNegotiationState.activeLayer, actionGloballyUniqueId: arc4random64()), mutable: true, delivered: false))
return updatedState
} else {
assertionFailure()
}
} else {
assertionFailure()
}
case let .pfsRequestKey(rekeySessionId, gA):
var acceptSession = true
if let rekeySession = sequenceState.rekeyState {
switch rekeySession.data {
case .requesting, .requested:
if rekeySessionId < rekeySession.id {
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SecretChatOutgoingOperation(contents: .pfsAbortSession(layer: sequenceState.layerNegotiationState.activeLayer, actionGloballyUniqueId: arc4random64(), rekeySessionId: rekeySession.id), mutable: true, delivered: false))
} else {
acceptSession = false
}
case .accepting, .accepted:
break
}
}
if acceptSession {
let bBytes = malloc(256)!
let _ = SecRandomCopyBytes(nil, 256, bBytes.assumingMemoryBound(to: UInt8.self))
let b = MemoryBuffer(memory: bBytes, capacity: 256, length: 256, freeWhenDone: true)
let rekeySession = SecretChatRekeySessionState(id: rekeySessionId, data: .accepting)
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: SecretChatOutgoingOperation(contents: .pfsAcceptKey(layer: sequenceState.layerNegotiationState.activeLayer, actionGloballyUniqueId: arc4random64(), rekeySessionId: rekeySession.id, gA: gA, b: b), mutable: true, delivered: false))
return state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(rekeySession)))
}
}
default:
break
} }
return state return state
} }

View File

@ -62,7 +62,7 @@ public func requestTwoStepVerifiationSettings(network: Network, password: String
return .fail(.generic) return .fail(.generic)
} }
guard let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { guard let kdfResult = passwordKDF(encryptionProvider: network.encryptionProvider, password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else {
return .fail(.generic) return .fail(.generic)
} }
@ -150,7 +150,7 @@ public func updateTwoStepVerificationPassword(network: Network, currentPassword:
|> mapToSignal { authData, secureSecret -> Signal<UpdateTwoStepVerificationPasswordResult, UpdateTwoStepVerificationPasswordError> in |> mapToSignal { authData, secureSecret -> Signal<UpdateTwoStepVerificationPasswordResult, UpdateTwoStepVerificationPasswordError> in
let checkPassword: Api.InputCheckPasswordSRP let checkPassword: Api.InputCheckPasswordSRP
if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData { if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData {
if let kdfResult = passwordKDF(password: currentPassword ?? "", derivation: currentPasswordDerivation, srpSessionData: srpSessionData) { if let kdfResult = passwordKDF(encryptionProvider: network.encryptionProvider, password: currentPassword ?? "", derivation: currentPasswordDerivation, srpSessionData: srpSessionData) {
checkPassword = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)) checkPassword = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1))
} else { } else {
return .fail(.generic) return .fail(.generic)
@ -179,7 +179,7 @@ public func updateTwoStepVerificationPassword(network: Network, currentPassword:
flags |= (1 << 1) flags |= (1 << 1)
} }
guard let (updatedPasswordHash, updatedPasswordDerivation) = passwordUpdateKDF(password: password, derivation: authData.nextPasswordDerivation) else { guard let (updatedPasswordHash, updatedPasswordDerivation) = passwordUpdateKDF(encryptionProvider: network.encryptionProvider, password: password, derivation: authData.nextPasswordDerivation) else {
return .fail(.generic) return .fail(.generic)
} }
@ -251,7 +251,7 @@ func updateTwoStepVerificationSecureSecret(network: Network, password: String, s
return .fail(.generic) return .fail(.generic)
} }
guard let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { guard let kdfResult = passwordKDF(encryptionProvider: network.encryptionProvider, password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else {
return .fail(.generic) return .fail(.generic)
} }
@ -280,7 +280,7 @@ public func updateTwoStepVerificationEmail(network: Network, currentPassword: St
|> mapToSignal { authData -> Signal<UpdateTwoStepVerificationPasswordResult, UpdateTwoStepVerificationPasswordError> in |> mapToSignal { authData -> Signal<UpdateTwoStepVerificationPasswordResult, UpdateTwoStepVerificationPasswordError> in
let checkPassword: Api.InputCheckPasswordSRP let checkPassword: Api.InputCheckPasswordSRP
if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData { if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData {
guard let kdfResult = passwordKDF(password: currentPassword, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { guard let kdfResult = passwordKDF(encryptionProvider: network.encryptionProvider, password: currentPassword, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else {
return .fail(.generic) return .fail(.generic)
} }
checkPassword = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)) checkPassword = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1))
@ -415,7 +415,7 @@ public func requestTemporaryTwoStepPasswordToken(account: Account, password: Str
guard let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData else { guard let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData else {
return .fail(MTRpcError(errorCode: 400, errorDescription: "NO_PASSWORD")) return .fail(MTRpcError(errorCode: 400, errorDescription: "NO_PASSWORD"))
} }
guard let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { guard let kdfResult = passwordKDF(encryptionProvider: account.network.encryptionProvider, password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else {
return .fail(MTRpcError(errorCode: 400, errorDescription: "KDF_ERROR")) return .fail(MTRpcError(errorCode: 400, errorDescription: "KDF_ERROR"))
} }

View File

@ -21,7 +21,7 @@ struct SecretChatRequestData {
let a: MemoryBuffer let a: MemoryBuffer
} }
func updateSecretChat(accountPeerId: PeerId, transaction: Transaction, chat: Api.EncryptedChat, requestData: SecretChatRequestData?) { func updateSecretChat(encryptionProvider: EncryptionProvider, accountPeerId: PeerId, transaction: Transaction, chat: Api.EncryptedChat, requestData: SecretChatRequestData?) {
let currentPeer = transaction.getPeer(chat.peerId) as? TelegramSecretChat let currentPeer = transaction.getPeer(chat.peerId) as? TelegramSecretChat
let currentState = transaction.getPeerChatState(chat.peerId) as? SecretChatState let currentState = transaction.getPeerChatState(chat.peerId) as? SecretChatState
let settings = transaction.getPreferencesEntry(key: PreferencesKeys.secretChatSettings) as? SecretChatSettings ?? SecretChatSettings.defaultSettings let settings = transaction.getPreferencesEntry(key: PreferencesKeys.secretChatSettings) as? SecretChatSettings ?? SecretChatSettings.defaultSettings
@ -33,14 +33,14 @@ func updateSecretChat(accountPeerId: PeerId, transaction: Transaction, chat: Api
let pData = p.makeData() let pData = p.makeData()
let aData = a.makeData() let aData = a.makeData()
if !MTCheckIsSafeGAOrB(gAOrB.makeData(), pData) { if !MTCheckIsSafeGAOrB(encryptionProvider, gAOrB.makeData(), pData) {
var updatedState = currentState var updatedState = currentState
updatedState = updatedState.withUpdatedEmbeddedState(.terminated) updatedState = updatedState.withUpdatedEmbeddedState(.terminated)
transaction.setPeerChatState(chat.peerId, state: updatedState) transaction.setPeerChatState(chat.peerId, state: updatedState)
return return
} }
var key = MTExp(gAOrB.makeData(), aData, pData)! var key = MTExp(encryptionProvider, gAOrB.makeData(), aData, pData)!
if key.count > 256 { if key.count > 256 {
key.count = 256 key.count = 256

View File

@ -190,6 +190,7 @@ framework(
"//submodules/Markdown:Markdown", "//submodules/Markdown:Markdown",
"//submodules/SearchPeerMembers:SearchPeerMembers", "//submodules/SearchPeerMembers:SearchPeerMembers",
"//submodules/WidgetItems:WidgetItems", "//submodules/WidgetItems:WidgetItems",
"//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider",
], ],
frameworks = [ frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework", "$SDKROOT/System/Library/Frameworks/Foundation.framework",

View File

@ -28,6 +28,7 @@ import WalletUI
import UrlHandling import UrlHandling
import WalletUrl import WalletUrl
import WalletCore import WalletCore
import OpenSSLEncryptionProvider
private let handleVoipNotifications = false private let handleVoipNotifications = false
@ -387,7 +388,7 @@ final class SharedApplicationContext {
Logger.shared.log("data", "can't deserialize") Logger.shared.log("data", "can't deserialize")
} }
return data return data
}) }, encryptionProvider: OpenSSLEncryptionProvider())
guard let appGroupUrl = maybeAppGroupUrl else { guard let appGroupUrl = maybeAppGroupUrl else {
UIAlertView(title: nil, message: "Error 2", delegate: nil, cancelButtonTitle: "OK").show() UIAlertView(title: nil, message: "Error 2", delegate: nil, cancelButtonTitle: "OK").show()

View File

@ -13,6 +13,7 @@ import StickerResources
import PhotoResources import PhotoResources
import AnimatedStickerNode import AnimatedStickerNode
import TelegramAnimatedStickerNode import TelegramAnimatedStickerNode
import OpenSSLEncryptionProvider
private enum NotificationContentAuthorizationError { private enum NotificationContentAuthorizationError {
case unauthorized case unauthorized
@ -143,7 +144,7 @@ public final class NotificationViewControllerImpl {
f(false) f(false)
}) })
sharedAccountContext = SharedAccountContextImpl(mainWindow: nil, basePath: rootPath, encryptionParameters: ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: self.initializationData.encryptionParameters.0)!, salt: ValueBoxEncryptionParameters.Salt(data: self.initializationData.encryptionParameters.1)!), accountManager: accountManager, applicationBindings: applicationBindings, initialPresentationDataAndSettings: initialPresentationDataAndSettings!, networkArguments: NetworkInitializationArguments(apiId: self.initializationData.apiId, languagesCategory: self.initializationData.languagesCategory, appVersion: self.initializationData.appVersion, voipMaxLayer: 0, appData: .single(self.initializationData.bundleData)), rootPath: rootPath, legacyBasePath: nil, legacyCache: nil, apsNotificationToken: .never(), voipNotificationToken: .never(), setNotificationCall: { _ in }, navigateToChat: { _, _, _ in }) sharedAccountContext = SharedAccountContextImpl(mainWindow: nil, basePath: rootPath, encryptionParameters: ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: self.initializationData.encryptionParameters.0)!, salt: ValueBoxEncryptionParameters.Salt(data: self.initializationData.encryptionParameters.1)!), accountManager: accountManager, applicationBindings: applicationBindings, initialPresentationDataAndSettings: initialPresentationDataAndSettings!, networkArguments: NetworkInitializationArguments(apiId: self.initializationData.apiId, languagesCategory: self.initializationData.languagesCategory, appVersion: self.initializationData.appVersion, voipMaxLayer: 0, appData: .single(self.initializationData.bundleData), encryptionProvider: OpenSSLEncryptionProvider()), rootPath: rootPath, legacyBasePath: nil, legacyCache: nil, apsNotificationToken: .never(), voipNotificationToken: .never(), setNotificationCall: { _ in }, navigateToChat: { _, _, _ in })
} }
} }

View File

@ -11,6 +11,7 @@ import LegacyUI
import PeerInfoUI import PeerInfoUI
import ShareItems import ShareItems
import SettingsUI import SettingsUI
import OpenSSLEncryptionProvider
private let inForeground = ValuePromise<Bool>(false, ignoreRepeated: true) private let inForeground = ValuePromise<Bool>(false, ignoreRepeated: true)
@ -171,7 +172,7 @@ public class ShareRootControllerImpl {
}) })
semaphore.wait() semaphore.wait()
let sharedContext = SharedAccountContextImpl(mainWindow: nil, basePath: rootPath, encryptionParameters: ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: self.initializationData.encryptionParameters.0)!, salt: ValueBoxEncryptionParameters.Salt(data: self.initializationData.encryptionParameters.1)!), accountManager: accountManager, applicationBindings: applicationBindings, initialPresentationDataAndSettings: initialPresentationDataAndSettings!, networkArguments: NetworkInitializationArguments(apiId: self.initializationData.apiId, languagesCategory: self.initializationData.languagesCategory, appVersion: self.initializationData.appVersion, voipMaxLayer: 0, appData: .single(self.initializationData.bundleData)), rootPath: rootPath, legacyBasePath: nil, legacyCache: nil, apsNotificationToken: .never(), voipNotificationToken: .never(), setNotificationCall: { _ in }, navigateToChat: { _, _, _ in }) let sharedContext = SharedAccountContextImpl(mainWindow: nil, basePath: rootPath, encryptionParameters: ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: self.initializationData.encryptionParameters.0)!, salt: ValueBoxEncryptionParameters.Salt(data: self.initializationData.encryptionParameters.1)!), accountManager: accountManager, applicationBindings: applicationBindings, initialPresentationDataAndSettings: initialPresentationDataAndSettings!, networkArguments: NetworkInitializationArguments(apiId: self.initializationData.apiId, languagesCategory: self.initializationData.languagesCategory, appVersion: self.initializationData.appVersion, voipMaxLayer: 0, appData: .single(self.initializationData.bundleData), encryptionProvider: OpenSSLEncryptionProvider()), rootPath: rootPath, legacyBasePath: nil, legacyCache: nil, apsNotificationToken: .never(), voipNotificationToken: .never(), setNotificationCall: { _ in }, navigateToChat: { _, _, _ in })
internalContext = InternalContext(sharedContext: sharedContext) internalContext = InternalContext(sharedContext: sharedContext)
globalInternalContext = internalContext globalInternalContext = internalContext
} }