iOS SecKeyRef到NSData

ari*_*rik 16 rsa objective-c ios

我有两个密钥,public和private,都存储在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;
}
Run Code Online (Sandbox Code Playgroud)

但是,我有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;
}
Run Code Online (Sandbox Code Playgroud)

但仍有两个错误:

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

现在,我希望在你的帮助之后,第一个问题将不再是一个问题,因为我不想构建一个查询或什么来从密钥链中提取密钥.我把它放在变量中,我希望从那里提取它.变量的名称是givenPublicKey,这是我希望转换为NSData的密钥.

那么,我将如何做到这一点并解决这个ARC问题呢?

后续:如何将私钥导出到NSData,因为我已经多次读过我正在尝试使用的函数仅适用于公钥.

Mar*_*n R 15

  • 使用未声明的标识符'publicTag'

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

#define kPublicKeyTag "com.apple.sample.publickey"
static const uint8_t publicKeyIdentifier[] = kPublicKeyTag;
NSData *publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
Run Code Online (Sandbox Code Playgroud)
  • 使用ARC不允许使用指向'CFTypeRef'(又名'const void*')的Objective-C指针的间接指针

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

CFTypeRef result;
sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, &result);
if (sanityCheck == errSecSuccess) {
    publicKeyBits = CFBridgingRelease(result);
}
Run Code Online (Sandbox Code Playgroud)
  • 我不想构建查询或诸如此类来从密钥链中提取密钥.我把它放在变量中,我希望从那里提取它...

据我所知,你必须暂时将SecKeyRef存储到Keychain.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;
}
Run Code Online (Sandbox Code Playgroud)

我希望这个有效,我现在无法测试它.

  • 后续:如何将私钥导出到NSData,因为我已经多次读过我正在尝试使用的函数仅适用于公钥.

我不知道.