mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Add temp keychain for backup requests
This commit is contained in:
parent
347155dbe7
commit
53f95864d3
@ -5,6 +5,6 @@
|
||||
|
||||
@interface MTBackupAddressSignals : NSObject
|
||||
|
||||
+ (MTSignal * _Nonnull)fetchBackupIps:(bool)isTestingEnvironment currentContext:(MTContext * _Nonnull)currentContext additionalSource:(MTSignal * _Nullable)additionalSource phoneNumber:(NSString * _Nullable)phoneNumber;
|
||||
+ (MTSignal * _Nonnull)fetchBackupIps:(bool)isTestingEnvironment currentContext:(MTContext * _Nonnull)currentContext additionalSource:(MTSignal * _Nullable)additionalSource phoneNumber:(NSString * _Nullable)phoneNumber mainDatacenterId:(NSInteger)mainDatacenterId;
|
||||
|
||||
@end
|
||||
|
@ -58,6 +58,8 @@
|
||||
|
||||
+ (void)performWithObjCTry:(dispatch_block_t _Nonnull)block;
|
||||
|
||||
+ (void)copyAuthInfoFrom:(id<MTKeychain> _Nonnull)keychain toTempKeychain:(id<MTKeychain> _Nonnull)tempKeychain;
|
||||
|
||||
- (instancetype _Nonnull)initWithSerialization:(id<MTSerialization> _Nonnull)serialization encryptionProvider:(id<EncryptionProvider> _Nonnull)encryptionProvider apiEnvironment:(MTApiEnvironment * _Nonnull)apiEnvironment isTestingEnvironment:(bool)isTestingEnvironment useTempAuthKeys:(bool)useTempAuthKeys;
|
||||
|
||||
- (void)performBatchUpdates:(void (^ _Nonnull)())block;
|
||||
|
@ -1,17 +1 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <MtProtoKit/MTKeychain.h>
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MTFileBasedKeychain : NSObject <MTKeychain>
|
||||
|
||||
+ (instancetype)unencryptedKeychainWithName:(NSString * _Nullable)name documentsPath:(NSString *)documentsPath;
|
||||
+ (instancetype)keychainWithName:(NSString * _Nullable)name documentsPath:(NSString * _Nullable)documentsPath;
|
||||
|
||||
- (NSDictionary<NSString *, id> *)contentsForGroup:(NSString *)group;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
@ -8,6 +8,4 @@
|
||||
- (id)objectForKey:(NSString *)aKey group:(NSString *)group;
|
||||
- (void)removeObjectForKey:(NSString *)aKey group:(NSString *)group;
|
||||
|
||||
- (void)dropGroup:(NSString *)group;
|
||||
|
||||
@end
|
||||
|
@ -20,7 +20,6 @@
|
||||
#import <MtProtoKit/MTDropResponseContext.h>
|
||||
#import <MtProtoKit/MTEncryption.h>
|
||||
#import <MtProtoKit/MTExportedAuthorizationData.h>
|
||||
#import <MtProtoKit/MTFileBasedKeychain.h>
|
||||
#import <MtProtoKit/MTGzip.h>
|
||||
#import <MtProtoKit/MTHttpRequestOperation.h>
|
||||
#import <MtProtoKit/MTIncomingMessage.h>
|
||||
@ -57,4 +56,4 @@
|
||||
#import <MtProtoKit/MTTimeSyncMessageService.h>
|
||||
#import <MtProtoKit/MTTransport.h>
|
||||
#import <MtProtoKit/MTTransportScheme.h>
|
||||
#import <MtProtoKit/MTTransportTransaction.h>
|
||||
#import <MtProtoKit/MTTransportTransaction.h>
|
||||
|
@ -13,6 +13,44 @@
|
||||
#import <MtProtoKit/MTProto.h>
|
||||
#import <MtProtoKit/MTSerialization.h>
|
||||
#import <MtProtoKit/MTLogging.h>
|
||||
#import <MtProtoKit/MTKeychain.h>
|
||||
|
||||
@interface MTTemporaryKeychain : NSObject<MTKeychain> {
|
||||
NSMutableDictionary<NSString *, id> *_dict;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTTemporaryKeychain
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_dict = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)itemKeyForGroup:(NSString *)group key:(NSString *)key {
|
||||
return [NSString stringWithFormat:@"%@:%@", group, key];
|
||||
}
|
||||
|
||||
- (void)setObject:(id)object forKey:(NSString *)aKey group:(NSString *)group {
|
||||
if (object == nil) {
|
||||
return;
|
||||
}
|
||||
_dict[[self itemKeyForGroup:group key:aKey]] = object;
|
||||
}
|
||||
|
||||
- (id)objectForKey:(NSString *)aKey group:(NSString *)group {
|
||||
return _dict[[self itemKeyForGroup:group key:aKey]];
|
||||
}
|
||||
|
||||
- (void)removeObjectForKey:(NSString *)aKey group:(NSString *)group {
|
||||
[_dict removeObjectForKey:[self itemKeyForGroup:group key:aKey]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static NSData *base64_decode(NSString *str) {
|
||||
if ([NSData instancesRespondToSelector:@selector(initWithBase64EncodedString:options:)]) {
|
||||
@ -224,7 +262,7 @@ static NSString *makeRandomPadding() {
|
||||
return [[MTSignal mergeSignals:signals] take:1];
|
||||
}
|
||||
|
||||
+ (MTSignal *)fetchConfigFromAddress:(MTBackupDatacenterAddress *)address currentContext:(MTContext *)currentContext {
|
||||
+ (MTSignal *)fetchConfigFromAddress:(MTBackupDatacenterAddress *)address currentContext:(MTContext *)currentContext mainDatacenterId:(NSInteger)mainDatacenterId {
|
||||
MTApiEnvironment *apiEnvironment = [currentContext.apiEnvironment copy];
|
||||
|
||||
apiEnvironment = [apiEnvironment withUpdatedSocksProxySettings:nil];
|
||||
@ -242,13 +280,24 @@ static NSString *makeRandomPadding() {
|
||||
|
||||
MTContext *context = [[MTContext alloc] initWithSerialization:currentContext.serialization encryptionProvider:currentContext.encryptionProvider apiEnvironment:apiEnvironment isTestingEnvironment:currentContext.isTestingEnvironment useTempAuthKeys:false];
|
||||
|
||||
NSInteger authTokenMasterDatacenterId = 0;
|
||||
NSNumber *requiredAuthToken = nil;
|
||||
bool allowUnboundEphemeralKeys = true;
|
||||
if (address.datacenterId != 0) {
|
||||
//context.keychain = currentContext.keychain;
|
||||
authTokenMasterDatacenterId = mainDatacenterId;
|
||||
requiredAuthToken = @(address.datacenterId);
|
||||
MTTemporaryKeychain *tempKeychain = [[MTTemporaryKeychain alloc] init];
|
||||
[MTContext copyAuthInfoFrom:currentContext.keychain toTempKeychain:tempKeychain];
|
||||
context.keychain = tempKeychain;
|
||||
allowUnboundEphemeralKeys = false;
|
||||
} else {
|
||||
MTTemporaryKeychain *tempKeychain = [[MTTemporaryKeychain alloc] init];
|
||||
context.keychain = tempKeychain;
|
||||
}
|
||||
|
||||
MTProto *mtProto = [[MTProto alloc] initWithContext:context datacenterId:address.datacenterId usageCalculationInfo:nil requiredAuthToken:nil authTokenMasterDatacenterId:0];
|
||||
MTProto *mtProto = [[MTProto alloc] initWithContext:context datacenterId:address.datacenterId usageCalculationInfo:nil requiredAuthToken:requiredAuthToken authTokenMasterDatacenterId:authTokenMasterDatacenterId];
|
||||
mtProto.useTempAuthKeys = true;
|
||||
mtProto.allowUnboundEphemeralKeys = true;
|
||||
mtProto.allowUnboundEphemeralKeys = allowUnboundEphemeralKeys;
|
||||
MTRequestMessageService *requestService = [[MTRequestMessageService alloc] initWithContext:context];
|
||||
[mtProto addMessageService:requestService];
|
||||
|
||||
@ -258,7 +307,6 @@ static NSString *makeRandomPadding() {
|
||||
|
||||
NSData *getConfigData = nil;
|
||||
MTRequestDatacenterAddressListParser responseParser = [currentContext.serialization requestDatacenterAddressWithData:&getConfigData];
|
||||
|
||||
[request setPayload:getConfigData metadata:@"getConfig" shortMetadata:@"getConfig" responseParser:responseParser];
|
||||
|
||||
__weak MTContext *weakCurrentContext = currentContext;
|
||||
@ -300,7 +348,7 @@ static NSString *makeRandomPadding() {
|
||||
}];
|
||||
}
|
||||
|
||||
+ (MTSignal * _Nonnull)fetchBackupIps:(bool)isTestingEnvironment currentContext:(MTContext * _Nonnull)currentContext additionalSource:(MTSignal * _Nullable)additionalSource phoneNumber:(NSString * _Nullable)phoneNumber {
|
||||
+ (MTSignal * _Nonnull)fetchBackupIps:(bool)isTestingEnvironment currentContext:(MTContext * _Nonnull)currentContext additionalSource:(MTSignal * _Nullable)additionalSource phoneNumber:(NSString * _Nullable)phoneNumber mainDatacenterId:(NSInteger)mainDatacenterId {
|
||||
NSMutableArray *signals = [[NSMutableArray alloc] init];
|
||||
[signals addObject:[self fetchBackupIpsResolveGoogle:isTestingEnvironment phoneNumber:phoneNumber currentContext:currentContext addressOverride:currentContext.apiEnvironment.accessHostOverride]];
|
||||
[signals addObject:[self fetchBackupIpsResolveCloudflare:isTestingEnvironment phoneNumber:phoneNumber currentContext:currentContext addressOverride:currentContext.apiEnvironment.accessHostOverride]];
|
||||
@ -322,7 +370,7 @@ static NSString *makeRandomPadding() {
|
||||
NSMutableArray *signals = [[NSMutableArray alloc] init];
|
||||
NSTimeInterval delay = 0.0;
|
||||
for (MTBackupDatacenterAddress *address in data.addressList) {
|
||||
MTSignal *signal = [self fetchConfigFromAddress:address currentContext:currentContext];
|
||||
MTSignal *signal = [self fetchConfigFromAddress:address currentContext:currentContext mainDatacenterId:mainDatacenterId];
|
||||
if (delay > DBL_EPSILON) {
|
||||
signal = [signal delay:delay onQueue:[[MTQueue alloc] init]];
|
||||
}
|
||||
|
@ -290,6 +290,21 @@ static int32_t fixedTimeDifferenceValue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void copyKeychainKey(NSString * _Nonnull group, NSString * _Nonnull key, id<MTKeychain> _Nonnull fromKeychain, id<MTKeychain> _Nonnull toKeychain) {
|
||||
id value = [fromKeychain objectForKey:key group:group];
|
||||
if (value) {
|
||||
[toKeychain setObject:value forKey:key group:group];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)copyAuthInfoFrom:(id<MTKeychain> _Nonnull)keychain toTempKeychain:(id<MTKeychain> _Nonnull)tempKeychain {
|
||||
copyKeychainKey(@"temp", @"globalTimeDifference", keychain, tempKeychain);
|
||||
copyKeychainKey(@"persistent", @"datacenterAddressSetById", keychain, tempKeychain);
|
||||
copyKeychainKey(@"persistent", @"datacenterAuthInfoById", keychain, tempKeychain);
|
||||
copyKeychainKey(@"ephemeral", @"datacenterPublicKeysById", keychain, tempKeychain);
|
||||
//copyKeychainKey(@"persistent", @"authTokenById", keychain, tempKeychain);
|
||||
}
|
||||
|
||||
- (void)cleanup
|
||||
{
|
||||
NSDictionary *datacenterAuthActions = _datacenterAuthActions;
|
||||
|
@ -1,403 +1 @@
|
||||
#import <MtProtoKit/MTFileBasedKeychain.h>
|
||||
|
||||
#import <MtProtoKit/MTLogging.h>
|
||||
|
||||
#import <pthread.h>
|
||||
|
||||
#define TG_SYNCHRONIZED_DEFINE(lock) pthread_mutex_t _TG_SYNCHRONIZED_##lock
|
||||
#define TG_SYNCHRONIZED_INIT(lock) pthread_mutex_init(&_TG_SYNCHRONIZED_##lock, NULL)
|
||||
#define TG_SYNCHRONIZED_BEGIN(lock) pthread_mutex_lock(&_TG_SYNCHRONIZED_##lock);
|
||||
#define TG_SYNCHRONIZED_END(lock) pthread_mutex_unlock(&_TG_SYNCHRONIZED_##lock);
|
||||
|
||||
#import <CommonCrypto/CommonCrypto.h>
|
||||
#import <MtProtoKit/MTEncryption.h>
|
||||
|
||||
static TG_SYNCHRONIZED_DEFINE(_keychains) = PTHREAD_MUTEX_INITIALIZER;
|
||||
static NSMutableDictionary *keychains()
|
||||
{
|
||||
static NSMutableDictionary *dict = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^
|
||||
{
|
||||
TG_SYNCHRONIZED_INIT(_keychains);
|
||||
dict = [[NSMutableDictionary alloc] init];
|
||||
});
|
||||
return dict;
|
||||
}
|
||||
|
||||
@interface MTFileBasedKeychain ()
|
||||
{
|
||||
NSString *_name;
|
||||
bool _encrypted;
|
||||
NSData *_aesKey;
|
||||
NSData *_aesIv;
|
||||
NSString *_documentsPath;
|
||||
|
||||
TG_SYNCHRONIZED_DEFINE(_dictByGroup);
|
||||
NSMutableDictionary *_dictByGroup;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTFileBasedKeychain
|
||||
|
||||
+ (instancetype)unencryptedKeychainWithName:(NSString *)name documentsPath:(NSString *)documentsPath
|
||||
{
|
||||
if (name == nil)
|
||||
return nil;
|
||||
|
||||
TG_SYNCHRONIZED_BEGIN(_keychains);
|
||||
MTFileBasedKeychain *keychain = [keychains() objectForKey:name];
|
||||
if (keychain == nil)
|
||||
{
|
||||
keychain = [[MTFileBasedKeychain alloc] initWithName:name documentsPath:documentsPath encrypted:false];
|
||||
[keychains() setObject:keychain forKey:name];
|
||||
}
|
||||
TG_SYNCHRONIZED_END(_keychains);
|
||||
|
||||
return keychain;
|
||||
}
|
||||
|
||||
+ (instancetype)keychainWithName:(NSString *)name documentsPath:(NSString *)documentsPath
|
||||
{
|
||||
if (name == nil)
|
||||
return nil;
|
||||
|
||||
TG_SYNCHRONIZED_BEGIN(_keychains);
|
||||
MTFileBasedKeychain *keychain = [keychains() objectForKey:name];
|
||||
if (keychain == nil)
|
||||
{
|
||||
keychain = [[MTFileBasedKeychain alloc] initWithName:name documentsPath:documentsPath encrypted:true];
|
||||
[keychains() setObject:keychain forKey:name];
|
||||
}
|
||||
TG_SYNCHRONIZED_END(_keychains);
|
||||
|
||||
return keychain;
|
||||
}
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name documentsPath:(NSString *)documentsPath encrypted:(bool)encrypted
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
TG_SYNCHRONIZED_INIT(_dictByGroup);
|
||||
_dictByGroup = [[NSMutableDictionary alloc] init];
|
||||
|
||||
_name = name;
|
||||
_documentsPath = documentsPath;
|
||||
_encrypted = encrypted;
|
||||
|
||||
if (name != nil)
|
||||
{
|
||||
if (_encrypted)
|
||||
{
|
||||
NSMutableDictionary *keychainReadQuery = [[NSMutableDictionary alloc] initWithDictionary:@{
|
||||
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
|
||||
(__bridge id)kSecAttrService: @"org.mtproto.MTKeychain",
|
||||
(__bridge id)kSecAttrAccount: [[NSString alloc] initWithFormat:@"MTKeychain:%@", name],
|
||||
#if TARGET_OS_IPHONE
|
||||
(__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly,
|
||||
#endif
|
||||
(__bridge id)kSecReturnData: (id)kCFBooleanTrue,
|
||||
(__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne
|
||||
}];
|
||||
|
||||
bool upgradeEncryption = false;
|
||||
|
||||
CFDataRef keyData = NULL;
|
||||
if (SecItemCopyMatching((__bridge CFDictionaryRef)keychainReadQuery, (CFTypeRef *)&keyData) == noErr && keyData != NULL)
|
||||
{
|
||||
NSData *data = (__bridge_transfer NSData *)keyData;
|
||||
if (data.length == 64)
|
||||
{
|
||||
_aesKey = [data subdataWithRange:NSMakeRange(0, 32)];
|
||||
_aesIv = [data subdataWithRange:NSMakeRange(32, 32)];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
keychainReadQuery[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
|
||||
if (SecItemCopyMatching((__bridge CFDictionaryRef)keychainReadQuery, (CFTypeRef *)&keyData) == noErr && keyData != NULL)
|
||||
{
|
||||
NSData *data = (__bridge_transfer NSData *)keyData;
|
||||
if (data.length == 64)
|
||||
{
|
||||
upgradeEncryption = true;
|
||||
|
||||
_aesKey = [data subdataWithRange:NSMakeRange(0, 32)];
|
||||
_aesIv = [data subdataWithRange:NSMakeRange(32, 32)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool storeKey = upgradeEncryption || _aesKey == nil || _aesIv == nil;
|
||||
|
||||
if (_aesKey == nil || _aesIv == nil)
|
||||
{
|
||||
uint8_t buf[32];
|
||||
|
||||
__unused int result = 0;
|
||||
result = SecRandomCopyBytes(kSecRandomDefault, 32, buf);
|
||||
_aesKey = [[NSData alloc] initWithBytes:buf length:32];
|
||||
|
||||
result = SecRandomCopyBytes(kSecRandomDefault, 32, buf);
|
||||
_aesIv = [[NSData alloc] initWithBytes:buf length:32];
|
||||
}
|
||||
|
||||
NSMutableData *newKeyData = [[NSMutableData alloc] init];
|
||||
[newKeyData appendData:_aesKey];
|
||||
[newKeyData appendData:_aesIv];
|
||||
|
||||
if (storeKey)
|
||||
{
|
||||
SecItemDelete((__bridge CFDictionaryRef)@{
|
||||
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
|
||||
(__bridge id)kSecAttrService: @"org.mtproto.MTKeychain",
|
||||
(__bridge id)kSecAttrAccount: [[NSString alloc] initWithFormat:@"MTKeychain:%@", name],
|
||||
#if TARGET_OS_IPHONE
|
||||
(__bridge id)kSecAttrAccessible: upgradeEncryption ? (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly : (__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly
|
||||
#endif
|
||||
});
|
||||
|
||||
SecItemAdd((__bridge CFDictionaryRef)@{
|
||||
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
|
||||
(__bridge id)kSecAttrService: @"org.mtproto.MTKeychain",
|
||||
(__bridge id)kSecAttrAccount: [[NSString alloc] initWithFormat:@"MTKeychain:%@", name],
|
||||
#if TARGET_OS_IPHONE
|
||||
(__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly,
|
||||
#endif
|
||||
(__bridge id)kSecValueData: newKeyData
|
||||
}, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)filePathForName:(NSString *)name group:(NSString *)group
|
||||
{
|
||||
static NSString *dataDirectory = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
dataDirectory = [_documentsPath stringByAppendingPathComponent:@"mtkeychain"];
|
||||
#elif TARGET_OS_MAC
|
||||
NSString *applicationSupportPath = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)[0];
|
||||
NSString *applicationName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
|
||||
dataDirectory = [[applicationSupportPath stringByAppendingPathComponent:applicationName] stringByAppendingPathComponent:@"mtkeychain"];
|
||||
#else
|
||||
# error "Unsupported OS"
|
||||
#endif
|
||||
|
||||
__autoreleasing NSError *error = nil;
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:dataDirectory withIntermediateDirectories:true attributes:nil error:&error];
|
||||
if (error != nil) {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain error creating keychain directory: %@]", error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return [dataDirectory stringByAppendingPathComponent:[[NSString alloc] initWithFormat:@"%@_%@.bin", name, group]];
|
||||
}
|
||||
|
||||
- (void)_loadKeychainIfNeeded:(NSString *)group
|
||||
{
|
||||
if (_dictByGroup[group] == nil)
|
||||
{
|
||||
if (_name != nil)
|
||||
{
|
||||
NSData *data = [[NSData alloc] initWithContentsOfFile:[self filePathForName:_name group:group]];
|
||||
if (data != nil && data.length >= 4)
|
||||
{
|
||||
uint32_t length = 0;
|
||||
[data getBytes:&length range:NSMakeRange(0, 4)];
|
||||
|
||||
uint32_t paddedLength = length;
|
||||
while (paddedLength % 16 != 0)
|
||||
{
|
||||
paddedLength++;
|
||||
}
|
||||
|
||||
if (data.length == 4 + paddedLength || data.length == 4 + paddedLength + 4)
|
||||
{
|
||||
NSMutableData *encryptedData = [[NSMutableData alloc] init];
|
||||
[encryptedData appendData:[data subdataWithRange:NSMakeRange(4, paddedLength)]];
|
||||
|
||||
NSMutableData *decryptedData = nil;
|
||||
if (_encrypted) {
|
||||
decryptedData = [[NSMutableData alloc] initWithData:MTAesDecrypt(encryptedData, _aesKey, _aesIv)];
|
||||
} else {
|
||||
decryptedData = encryptedData;
|
||||
}
|
||||
|
||||
[decryptedData setLength:length];
|
||||
|
||||
bool hashVerified = true;
|
||||
|
||||
if (data.length == 4 + paddedLength + 4)
|
||||
{
|
||||
int32_t hash = 0;
|
||||
[data getBytes:&hash range:NSMakeRange(4 + paddedLength, 4)];
|
||||
|
||||
int32_t decryptedHash = MTMurMurHash32(decryptedData.bytes, (int)decryptedData.length);
|
||||
if (hash != decryptedHash)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain invalid decrypted hash]");
|
||||
}
|
||||
hashVerified = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hashVerified)
|
||||
{
|
||||
@try
|
||||
{
|
||||
id object = [NSKeyedUnarchiver unarchiveObjectWithData:decryptedData];
|
||||
if ([object respondsToSelector:@selector(objectForKey:)] && [object respondsToSelector:@selector(setObject:forKey:)])
|
||||
_dictByGroup[group] = object;
|
||||
else {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain invalid root object %@]", object);
|
||||
}
|
||||
}
|
||||
}
|
||||
@catch (NSException *e)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain error parsing keychain: %@]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain error loading keychain: expected data length %d, got %d]", 4 + (int)paddedLength, (int)data.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_dictByGroup[group] == nil)
|
||||
_dictByGroup[group] = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_storeKeychain:(NSString *)group
|
||||
{
|
||||
if (_dictByGroup[group] != nil && _name != nil)
|
||||
{
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:_dictByGroup[group]];
|
||||
if (data != nil)
|
||||
{
|
||||
NSMutableData *encryptedData = [[NSMutableData alloc] initWithData:data];
|
||||
int32_t hash = MTMurMurHash32(encryptedData.bytes, (int)encryptedData.length);
|
||||
|
||||
while (encryptedData.length % 16 != 0)
|
||||
{
|
||||
uint8_t random = 0;
|
||||
arc4random_buf(&random, 1);
|
||||
[encryptedData appendBytes:&random length:1];
|
||||
}
|
||||
|
||||
if (_encrypted)
|
||||
MTAesEncryptInplace(encryptedData, _aesKey, _aesIv);
|
||||
|
||||
uint32_t length = (uint32_t)data.length;
|
||||
[encryptedData replaceBytesInRange:NSMakeRange(0, 0) withBytes:&length length:4];
|
||||
[encryptedData appendBytes:&hash length:4];
|
||||
|
||||
NSString *filePath = [self filePathForName:_name group:group];
|
||||
if (![encryptedData writeToFile:filePath atomically:true]) {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain error writing keychain to file]");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
__autoreleasing NSError *error = nil;
|
||||
[[NSURL fileURLWithPath:filePath] setResourceValue:[NSNumber numberWithBool:true] forKey:NSURLIsExcludedFromBackupKey error:&error];
|
||||
if (error != nil) {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain error setting \"exclude from backup\" flag]");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain error serializing keychain]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setObject:(id)object forKey:(id<NSCopying>)aKey group:(NSString *)group
|
||||
{
|
||||
if (object == nil || aKey == nil)
|
||||
return;
|
||||
|
||||
TG_SYNCHRONIZED_BEGIN(_dictByGroup);
|
||||
[self _loadKeychainIfNeeded:group];
|
||||
|
||||
_dictByGroup[group][aKey] = object;
|
||||
[self _storeKeychain:group];
|
||||
TG_SYNCHRONIZED_END(_dictByGroup);
|
||||
}
|
||||
|
||||
- (id)objectForKey:(id<NSCopying>)aKey group:(NSString *)group
|
||||
{
|
||||
if (aKey == nil)
|
||||
return nil;
|
||||
|
||||
TG_SYNCHRONIZED_BEGIN(_dictByGroup);
|
||||
[self _loadKeychainIfNeeded:group];
|
||||
|
||||
id result = _dictByGroup[group][aKey];
|
||||
TG_SYNCHRONIZED_END(_dictByGroup);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)removeObjectForKey:(id<NSCopying>)aKey group:(NSString *)group
|
||||
{
|
||||
if (aKey == nil)
|
||||
return;
|
||||
|
||||
TG_SYNCHRONIZED_BEGIN(_dictByGroup);
|
||||
[self _loadKeychainIfNeeded:group];
|
||||
|
||||
[_dictByGroup[group] removeObjectForKey:aKey];
|
||||
[self _storeKeychain:group];
|
||||
TG_SYNCHRONIZED_END(_dictByGroup);
|
||||
}
|
||||
|
||||
- (void)dropGroup:(NSString *)group
|
||||
{
|
||||
if (group == nil)
|
||||
return;
|
||||
|
||||
TG_SYNCHRONIZED_BEGIN(_dictByGroup);
|
||||
_dictByGroup[group] = [[NSMutableDictionary alloc] init];
|
||||
[self _storeKeychain:group];
|
||||
TG_SYNCHRONIZED_END(_dictByGroup);
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString *, id> *)contentsForGroup:(NSString *)group {
|
||||
NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
|
||||
TG_SYNCHRONIZED_BEGIN(_dictByGroup);
|
||||
[self _loadKeychainIfNeeded:group];
|
||||
[_dictByGroup[group] enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, __unused BOOL * _Nonnull stop) {
|
||||
result[key] = obj;
|
||||
}];
|
||||
TG_SYNCHRONIZED_END(_dictByGroup);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -518,7 +518,7 @@ func initializedNetwork(accountId: AccountRecordId, arguments: NetworkInitializa
|
||||
#endif
|
||||
|
||||
if !supplementary {
|
||||
context.setDiscoverBackupAddressListSignal(MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber))
|
||||
context.setDiscoverBackupAddressListSignal(MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber, mainDatacenterId: datacenterId))
|
||||
}
|
||||
|
||||
/*#if DEBUG
|
||||
@ -1090,10 +1090,6 @@ class Keychain: NSObject, MTKeychain {
|
||||
func removeObject(forKey aKey: String!, group: String!) {
|
||||
self.remove(group + ":" + aKey)
|
||||
}
|
||||
|
||||
func dropGroup(_ group: String!) {
|
||||
|
||||
}
|
||||
}
|
||||
#if os(iOS)
|
||||
func makeCloudDataContext(encryptionProvider: EncryptionProvider) -> CloudDataContext? {
|
||||
|
@ -240,7 +240,7 @@ public class Serialization: NSObject, MTSerialization {
|
||||
return Api.functions.auth.importAuthorization(id: authId, bytes: Buffer(data: bytes)).1.makeData()
|
||||
}
|
||||
|
||||
public func requestDatacenterAddress(with data: AutoreleasingUnsafeMutablePointer<NSData?>) -> MTRequestDatacenterAddressListParser! {
|
||||
public func requestDatacenterAddress(with data: AutoreleasingUnsafeMutablePointer<NSData?>) -> MTRequestDatacenterAddressListParser! {
|
||||
let (_, buffer, parser) = Api.functions.help.getConfig()
|
||||
data.pointee = buffer.makeData() as NSData
|
||||
return { response -> MTDatacenterAddressListData? in
|
||||
|
Loading…
x
Reference in New Issue
Block a user