Objective-C-RSA
Objective-C-RSA copied to clipboard
RSA 加密线上失败,调试无法重现
你好,我们 App 在发布到 App Store 后,RSA 加密失败率挺高的,但是我们本地开发调试时,没有遇到过,也无法重现。发生错误的机型和系统,基本全覆盖。
需要说明的是,在这之前我们对代码做过一些修改。首先是把 RSA 类改为了 NSString 的分类;其次,由于需要对钥匙串做 Delete -> Add -> Matching
的操作,在多线程环境下发生了错误,就对这一部分代码加了 @synchronized
同步锁,如下:
@synchronized ([UIApplication sharedApplication]) {
//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;
}
本地测试时,有没有做压力测试,看看会出现失败吗?这个库有点坑
做过压力测试的,没有出现失败过,但是线上就很多。只能在上层业务调用处,判断 RSA 加密返回是否为空🤷♂️
做过压力测试的,没有出现失败过,但是线上就很多。只能在上层业务调用处,判断 RSA 加密返回是否为空🤷♂️
如果是因为资源抢占的问题导致,我们是把源码中生成 SecKeyRef 的地方改成了通过公钥数据来创建。
检查一下锁里面的代码在其它位置是否有访问,如果其它地方也有访问,需要看下是否同样加锁了
[publicDictionary setObject:(__bridge id) kSecAttrAccessibleAlways forKey:(__bridge id)kSecAttrAccessible];
我这边是在后台的时候出现的。加上这句话
NSString *tag = @"RSAUtil_PubKey"; 把这个改一下 能改善很多。。。 估计你的App里面有其他SDK也用了这个库,tag冲突会导致异步的时候取到别人的公钥
“kSecAttrAccessibleAlways” iOS14弃用了,iOS14后有啥好办法?