// // TDRSAEncryptor.m // ThinkingSDK // // Created by wwango on 2022/1/21. // #import "TDRSAEncryptor.h" @implementation TDRSAEncryptor - (void)setKey:(NSString *)key { if (!key) { return; } NSString *publicKeyCopy = [key copy]; publicKeyCopy = [publicKeyCopy stringByReplacingOccurrencesOfString:@"\r" withString:@""]; publicKeyCopy = [publicKeyCopy stringByReplacingOccurrencesOfString:@"\n" withString:@""]; publicKeyCopy = [publicKeyCopy stringByReplacingOccurrencesOfString:@"\t" withString:@""]; publicKeyCopy = [publicKeyCopy stringByReplacingOccurrencesOfString:@" " withString:@""]; _key = publicKeyCopy; } - (NSString *)algorithm { return @"RSA"; } - (NSString *)encryptData:(NSData *)data { if (!data) { return nil; } NSString *asymmetricPublicKey = self.key; if (!asymmetricPublicKey) { return nil; } SecKeyRef keyRef = [self addPublicKey:asymmetricPublicKey]; if (!keyRef) { return nil; } const uint8_t *srcbuf = (const uint8_t *)[data bytes]; size_t srclen = (size_t)data.length; size_t block_size = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t); void *outbuf = malloc(block_size); size_t src_block_size = block_size - 11; NSMutableData *ret = [[NSMutableData alloc] init]; for(int idx=0; idx src_block_size) { data_len = src_block_size; } size_t outlen = block_size; OSStatus status = noErr; status = SecKeyEncrypt(keyRef, kSecPaddingPKCS1, srcbuf + idx, data_len, outbuf, &outlen ); if (status != 0) { ret = nil; break; }else{ [ret appendBytes:outbuf length:outlen]; } } free(outbuf); CFRelease(keyRef); return [ret base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]; } #pragma mark – Private Methods - (SecKeyRef)addPublicKey:(NSString *)aymmetricPublicKey { NSString *key = [aymmetricPublicKey copy]; NSData *data = [[NSData alloc] initWithBase64EncodedString:key options:NSDataBase64DecodingIgnoreUnknownCharacters]; data = [self stripPublicKeyHeader:data]; if (!data) { return nil; } //a tag to read/write keychain storage NSString *tag = @"RSAUtil_PubKey"; NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]]; // Delete any old lingering key with the same tag NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init]; [publicKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass]; [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; [publicKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag]; SecItemDelete((__bridge CFDictionaryRef)publicKey); // Add persistent version of the key to system keychain [publicKey setObject:data forKey:(__bridge id)kSecValueData]; [publicKey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id) kSecAttrKeyClass]; [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id) kSecReturnPersistentRef]; CFTypeRef persistKey = nil; OSStatus status = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey); if (persistKey != nil) { CFRelease(persistKey); } if ((status != noErr) && (status != errSecDuplicateItem)) { return nil; } [publicKey removeObjectForKey:(__bridge id)kSecValueData]; [publicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef]; [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef]; [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; // Now fetch the SecKeyRef version of the key SecKeyRef keyRef = nil; status = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey, (CFTypeRef *)&keyRef); if (status != noErr) { return nil; } return keyRef; } - (NSData *)stripPublicKeyHeader:(NSData *)d_key { // Skip ASN.1 public key header if (d_key == nil) { return(nil); } unsigned long len = [d_key length]; if (!len) { return(nil); } unsigned char *c_key = (unsigned char *)[d_key bytes]; unsigned int idx = 0; if (c_key[idx++] != 0x30) { return(nil); } if (c_key[idx] > 0x80) { idx += c_key[idx] - 0x80 + 1; } else { idx++; } // PKCS #1 rsaEncryption szOID_RSA_RSA static unsigned char seqiod[] = { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00 }; if (memcmp(&c_key[idx], seqiod, 15)) { return(nil); } idx += 15; if (c_key[idx++] != 0x03) { return(nil); } if (c_key[idx] > 0x80) { idx += c_key[idx] - 0x80 + 1; } else { idx++; } if (c_key[idx++] != '\0') { return(nil); } // Now make a new NSData from this buffer return([NSData dataWithBytes:&c_key[idx] length:len - idx]); } @end