// // TDEncryptManager.m // ThinkingSDK // // Created by wwango on 2022/1/21. // #import "TDEncryptManager.h" #import "TDEncryptProtocol.h" #import "TDSecretKey.h" #import "TDRSAEncryptorPlugin.h" #if __has_include() #import #else #import "NSData+TDGzip.h" #endif #if __has_include() #import #else #import "TDJSONUtil.h" #endif #import "TDLogging.h" @interface TDEncryptManager () @property (nonatomic, strong) id encryptor; @property (nonatomic, copy) NSArray> *encryptors; @property (nonatomic, copy) NSString *encryptedSymmetricKey; @property (nonatomic, strong) TDSecretKey *secretKey; @property (nonatomic, strong) TDSecretKey *customSecretKey; @end @implementation TDEncryptManager - (instancetype)initWithSecretKey:(TDSecretKey *)secretKey { self = [self init]; if (self) { self.customSecretKey = secretKey; [self updateEncryptor:secretKey]; } return self; } - (instancetype)init { self = [super init]; if (self) { NSMutableArray *encryptors = [NSMutableArray array]; [encryptors addObject:[TDRSAEncryptorPlugin new]]; self.encryptors = encryptors; } return self; } - (void)handleEncryptWithConfig:(NSDictionary *)encryptConfig { if (!encryptConfig || ![encryptConfig isKindOfClass:[NSDictionary class]]) { return; } if (![encryptConfig objectForKey:@"version"]) { return; } NSInteger version = [[encryptConfig objectForKey:@"version"] integerValue]; TDSecretKey *secretKey = [[TDSecretKey alloc] initWithVersion:version publicKey:encryptConfig[@"key"] asymmetricEncryption:encryptConfig[@"asymmetric"] symmetricEncryption:encryptConfig[@"symmetric"]]; if (![secretKey isValid]) { return; } if (![self encryptorWithSecretKey:secretKey]) { return; } [self updateEncryptor:secretKey]; } - (void)updateEncryptor:(TDSecretKey *)obj { @try { TDSecretKey *secretKey = obj; if (!secretKey.publicKey.length) { return; } if ([self needUpdateSecretKey:self.secretKey newSecretKey:secretKey]) { return; } id encryptor = [self filterEncrptor:secretKey]; if (!encryptor) { return; } NSString *encryptedSymmetricKey = [encryptor encryptSymmetricKeyWithPublicKey:secretKey.publicKey]; if (encryptedSymmetricKey.length) { self.secretKey = secretKey; self.encryptor = encryptor; self.encryptedSymmetricKey = encryptedSymmetricKey; TDLogDebug(@"\n****************secretKey****************\n public key: %@ \n encrypted symmetric key: %@\n****************secretKey****************", secretKey.publicKey, encryptedSymmetricKey); } } @catch (NSException *exception) { TDLogError(@"%@ error: %@", self, exception); } } - (BOOL)needUpdateSecretKey:(TDSecretKey *)oldSecretKey newSecretKey:(TDSecretKey *)newSecretKey { if (oldSecretKey.version != newSecretKey.version) { return NO; } if (![oldSecretKey.publicKey isEqualToString:newSecretKey.publicKey]) { return NO; } if (![oldSecretKey.symmetricEncryption isEqualToString:newSecretKey.symmetricEncryption]) { return NO; } if (![oldSecretKey.asymmetricEncryption isEqualToString:newSecretKey.asymmetricEncryption]) { return NO; } return YES; } - (id)filterEncrptor:(TDSecretKey *)secretKey { id encryptor = [self encryptorWithSecretKey:secretKey]; if (!encryptor) { NSString *format = @"\n You have used the [%@] key, but the corresponding encryption plugin has not been registered. \n"; NSString *type = [NSString stringWithFormat:@"%@+%@", secretKey.asymmetricEncryption, secretKey.symmetricEncryption]; NSString *message = [NSString stringWithFormat:format, type]; NSAssert(NO, message); return nil; } return encryptor; } - (id)encryptorWithSecretKey:(TDSecretKey *)secretKey { if (!secretKey) { return nil; } __block id encryptor; [self.encryptors enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) { BOOL isSameAsymmetricType = [[obj asymmetricEncryptType] isEqualToString:secretKey.asymmetricEncryption]; BOOL isSameSymmetricType = [[obj symmetricEncryptType] isEqualToString:secretKey.symmetricEncryption]; if (isSameAsymmetricType && isSameSymmetricType) { encryptor = obj; *stop = YES; } }]; return encryptor; } - (NSDictionary *)encryptJSONObject:(NSDictionary *)obj { @try { if (!obj) { TDLogDebug(@"Enable encryption but the input obj is invalid!"); return nil; } if (!self.encryptor) { TDLogDebug(@"Enable encryption but the secret key is invalid!"); return nil; } if (![self encryptSymmetricKey]) { TDLogDebug(@"Enable encryption but encrypt symmetric key is failed!"); return nil; } NSData *jsonData = [TDJSONUtil JSONSerializeForObject:obj]; NSString *encryptedString = [self.encryptor encryptEvent:jsonData]; if (!encryptedString) { TDLogDebug(@"Enable encryption but encrypted input obj is invalid!"); return nil; } NSMutableDictionary *secretObj = [NSMutableDictionary dictionary]; secretObj[@"pkv"] = @(self.secretKey.version); secretObj[@"ekey"] = self.encryptedSymmetricKey; secretObj[@"payload"] = encryptedString; return [NSDictionary dictionaryWithDictionary:secretObj]; } @catch (NSException *exception) { TDLogDebug(@"%@ error: %@", self, exception); return nil; } } - (BOOL)encryptSymmetricKey { if (self.encryptedSymmetricKey) { return YES; } NSString *publicKey = self.secretKey.publicKey; self.encryptedSymmetricKey = [self.encryptor encryptSymmetricKeyWithPublicKey:publicKey]; return self.encryptedSymmetricKey != nil; } - (BOOL)isValid { return _encryptor ? YES:NO; } @end