16

我有两个密钥,公共的和私有的,它们都存储在 SecKeyRef 变量中。为简单起见,让我们从公共的开始。我想做的是将它导出到一个 NSData 对象。为此,Apple 提供了一个几乎著名的代码片段,如下所示:

- (NSData *)getPublicKeyBits {
    OSStatus sanityCheck = noErr;
    NSData * publicKeyBits = nil;

    NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];

    // Set the public key query dictionary.
    [queryPublicKey setObject:(id)kSecClassKey forKey:(id)kSecClass];
    [queryPublicKey setObject:publicTag forKey:(id)kSecAttrApplicationTag];
    [queryPublicKey setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
    [queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnData];

    // Get the key bits.
    sanityCheck = SecItemCopyMatching((CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKeyBits);

    if (sanityCheck != noErr)
    {
        publicKeyBits = nil;
    }

    [queryPublicKey release];

    return publicKeyBits;
}

但是,我有 Xcode 4.6.2,并且代码出现错误(在每次转换为 id 之前添加了“__bridge”)。新版本如下所示:

- (NSData *)getPublicKeyBitsFromKey:(SecKeyRef)givenKey {
    OSStatus sanityCheck = noErr;
    NSData * publicKeyBits = nil;

    NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];

    // Set the public key query dictionary.
    [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)kSecReturnData];

    // Get the key bits.
    sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKeyBits);

    if (sanityCheck != noErr)
    {
        publicKeyBits = nil;
    }

    return publicKeyBits;
}

但是仍然有两个错误:

  • 使用未声明的标识符“publicTag”
  • ARC 不允许使用指向“CFTypeRef ”(又名“const void * ”)的 Objective-C 指针的间接指针强制转换

现在,我希望在您的帮助下,第一个问题将不再是问题,因为我不想构建查询或其他从钥匙串中提取密钥的东西。我把它放在一个变量中,我希望从那里提取它。变量的名称是givenPublicKey,这是我希望转换为 NSData 的键。

那么,我将如何去做这件事并解决这个 ARC 问题?

跟进:如何将私钥导出到 NSData,因为我已经多次阅读我尝试使用的功能仅适用于公钥。

4

1 回答 1

16
  • 使用未声明的标识符“publicTag”

publicTag只是添加到钥匙串项目的一些唯一标识符。在 CryptoExercise 示例项目中,它被定义为

#define kPublicKeyTag "com.apple.sample.publickey"
static const uint8_t publicKeyIdentifier[] = kPublicKeyTag;
NSData *publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
  • ARC 不允许将间接指针转换为指向“CFTypeRef”(又名“const void *”)的 Objective-C 指针

这可以通过使用临时CFTypeRef变量来解决:

CFTypeRef result;
sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, &result);
if (sanityCheck == errSecSuccess) {
    publicKeyBits = CFBridgingRelease(result);
}
  • 我不想构建查询或诸如此类的东西来从钥匙串中提取钥匙。我把它放在一个变量中,我希望从那里提取它......

据我所知,您必须将 SecKeyRef 临时存储到钥匙串中。SecItemAdd 可以选择将添加的项目作为数据返回。从文档中:

要将添加项的数据作为类型的对象获取CFDataRef,请将返回类型键指定kSecReturnData为 值 kCFBooleanTrue

将所有这些放在一起,以下代码应该可以满足您的要求:

- (NSData *)getPublicKeyBitsFromKey:(SecKeyRef)givenKey {

    static const uint8_t publicKeyIdentifier[] = "com.your.company.publickey";
    NSData *publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];

    OSStatus sanityCheck = noErr;
    NSData * publicKeyBits = nil;

    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];

    // Temporarily add key to the Keychain, return as data:
    NSMutableDictionary * attributes = [queryPublicKey mutableCopy];
    [attributes setObject:(__bridge id)givenKey forKey:(__bridge id)kSecValueRef];
    [attributes setObject:@YES forKey:(__bridge id)kSecReturnData];
    CFTypeRef result;
    sanityCheck = SecItemAdd((__bridge CFDictionaryRef) attributes, &result);
    if (sanityCheck == errSecSuccess) {
        publicKeyBits = CFBridgingRelease(result);

        // Remove from Keychain again:
        (void)SecItemDelete((__bridge CFDictionaryRef) queryPublicKey);
    }

    return publicKeyBits;
}

我希望这可行,目前我无法对其进行测试。

  • 跟进:如何将私钥导出到 NSData,因为我已经多次阅读我尝试使用的功能仅适用于公钥。

我不知道。

于 2013-05-25T13:16:23.743 回答