【发布时间】:2016-10-05 11:57:25
【问题描述】:
下面是我的代码,它在 iOS 9 之前都可以正常工作。
- (NSData *)encryptWithDataPublicKey:(NSString*)data keyTag:(NSString*)tag
{
SecKeyRef publicKey = NULL;
NSData *publicTag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];
NSMutableDictionary *queryPublicKey =
[[NSMutableDictionary alloc] init];
[queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
[queryPublicKey setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
[queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
OSStatus status = SecItemCopyMatching
((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKey);
NSData *encodedData = nil;
if (status == noErr && publicKey) {
NSData *dataToEncrypt = [data dataUsingEncoding:NSUTF8StringEncoding];
encodedData = [self encryptData:dataToEncrypt withKeyRef:publicKey];
CFRelease(publicKey);
}
return encodedData;
}
这种方法在 iOS 9.x 之前可以正常工作,但是今天我将 XCode 更新到 8 并在 iOS 10 设备上运行。应用程序在
CFRelease(publicKey) 处崩溃。
下面是来自控制台的日志。
无法加载任何 Objective-C 类信息。这会 显着降低可用类型信息的质量
无法准确解决问题。
当我启用 Zombie 并重现崩溃时。以下是控制台的日志。
*** -[Not A Type release]:消息发送到已释放实例 0x170225880
提前致谢。
我得到了问题。 有一个内部方法 encodedData = [self encryptData:dataToEncrypt withKeyRef:publicKey];
SecKeyRef 对象在哪里被释放。
但我想知道这在 iOS9 之前是如何工作的???????
-(NSData *)encryptData:(NSData *)data withKeyRef:(SecKeyRef) keyRef{
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<srclen; idx+=src_block_size){
size_t data_len = srclen - idx;
if(data_len > 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;
}
【问题讨论】:
-
首先,运行静态分析器并确保它没有返回任何警告。
encryptData:withKeyRef:是否对publicKey应用任何内存管理?我同意这次崩溃有点令人惊讶。 -
你为什么要释放一个你没有拥有的对象?
-
@holex,因为
SecItemCopyMatching包括Copy。它必须与释放平衡。 -
@holex 我不明白你的意思。对
SecItemCopyMatching的调用使调用者成为publicKey的所有者。调用者必须用CFRelease平衡该调用,并且正确地做到了。 (或者我在这里错过了你的意思吗?)编辑后的代码包含不正确的keyRef版本,该方法不拥有该版本(因为它没有调用Create、Copy或Retain),并且必须删除无关的释放,但不能删除引用publicKey的释放(是的,publicKey和keyRef最终是同一个对象,但这在这里不相关)。 -
@RobNapier,当他想要释放该对象时,OP 不拥有该对象;他们在调用
SecItemCopyMatching方法时拥有 所有权,而在尝试调用CFRelease(publicKey)时他们失去所有权;这发生在这里,这就是我的评论——我不打算证明或澄清如何、为什么或何时他们失去了它,并且what 将是管理它的正确方法......想要因回答问题而获得荣誉的人应该调查情况。没有必要因为我已经准确地发现并停在那里而与我为敌。
标签: objective-c ios10 xcode8 core-foundation seckeyref