217 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
			
		
		
	
	
			217 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
| //
 | |
| //  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(<ThinkingDataCore/NSData+TDGzip.h>)
 | |
| #import <ThinkingDataCore/NSData+TDGzip.h>
 | |
| #else
 | |
| #import "NSData+TDGzip.h"
 | |
| #endif
 | |
| #if __has_include(<ThinkingDataCore/TDJSONUtil.h>)
 | |
| #import <ThinkingDataCore/TDJSONUtil.h>
 | |
| #else
 | |
| #import "TDJSONUtil.h"
 | |
| #endif
 | |
| #import "TDLogging.h"
 | |
| 
 | |
| @interface TDEncryptManager ()
 | |
| @property (nonatomic, strong) id<TDEncryptProtocol> encryptor;
 | |
| @property (nonatomic, copy) NSArray<id<TDEncryptProtocol>> *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<TDEncryptProtocol> 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<TDEncryptProtocol>)filterEncrptor:(TDSecretKey *)secretKey {
 | |
|     id<TDEncryptProtocol> 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<TDEncryptProtocol>)encryptorWithSecretKey:(TDSecretKey *)secretKey {
 | |
|     if (!secretKey) {
 | |
|         return nil;
 | |
|     }
 | |
|     __block id<TDEncryptProtocol> encryptor;
 | |
|     [self.encryptors enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id<TDEncryptProtocol> 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
 |