iphone - 将 RSA key 添加到 iPhone 钥匙串(keychain)

标签 iphone cryptography rsa keychain

我正在尝试将 RSA 公钥和私钥添加到 iPhone 的钥匙串(keychain)中,以便我可以使用 CommonCrypto 库,但我不完全确定如何执行此操作。 MYCrypto 库目前似乎仅适用于 Mac,不适用于 iPhone。任何人都可以帮助并解释如何将私钥/公钥添加到钥匙串(keychain)并为其获取 SecKeyRef 吗?

最佳答案

所以在 iOS 中,钥匙串(keychain)是沙盒的,据我所知。这意味着除非您另有指定,否则您放入钥匙串(keychain)中的任何内容都只能由您的应用程序访问,并且只能由您的应用程序访问。您必须在项目设置的功能下启用钥匙串(keychain)共享

既然这一切都已经解决了,您当然可以导入数据了。由于它们是 NSString 对象,因此您首先必须将其转换为 NSData 对象才能正确导入它们。最有可能的是,它们是用 Base64 编码的,因此您必须反转它:

NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];

现在已经完成了,您可以使用此方法将 key 保存到钥匙串(keychain)并获取 SecKeyRef:

/**
 * key: the data you're importing
 * keySize: the length of the key (512, 1024, 2048)
 * isPrivate: is this a private key or public key?
 */
- (SecKeyRef)saveKeyToKeychain:(NSData *)key keySize:(NSUInteger)keySize private:(BOOL)isPrivate {
    OSStatus sanityCheck = noErr;
    NSData *tag;
    id keyClass;

    if (isPrivate) {
        tag = privateTag;
        keyClass = (__bridge id) kSecAttrKeyClassPrivate;
    }
    else {
        tag = publicTag;
        keyClass = (__bridge id) kSecAttrKeyClassPublic;
    }

    NSDictionary *saveDict = @{
            (__bridge id) kSecClass : (__bridge id) kSecClassKey,
            (__bridge id) kSecAttrKeyType : (__bridge id) kSecAttrKeyTypeRSA,
            (__bridge id) kSecAttrApplicationTag : tag,
            (__bridge id) kSecAttrKeyClass : keyClass,
            (__bridge id) kSecValueData : key,
            (__bridge id) kSecAttrKeySizeInBits : [NSNumber numberWithUnsignedInteger:keySize],
            (__bridge id) kSecAttrEffectiveKeySize : [NSNumber numberWithUnsignedInteger:keySize],
            (__bridge id) kSecAttrCanDerive : (__bridge id) kCFBooleanFalse,
            (__bridge id) kSecAttrCanEncrypt : (__bridge id) kCFBooleanTrue,
            (__bridge id) kSecAttrCanDecrypt : (__bridge id) kCFBooleanFalse,
            (__bridge id) kSecAttrCanVerify : (__bridge id) kCFBooleanTrue,
            (__bridge id) kSecAttrCanSign : (__bridge id) kCFBooleanFalse,
            (__bridge id) kSecAttrCanWrap : (__bridge id) kCFBooleanTrue,
            (__bridge id) kSecAttrCanUnwrap : (__bridge id) kCFBooleanFalse
    };

    SecKeyRef savedKeyRef = NULL;
    sanityCheck = SecItemAdd((__bridge CFDictionaryRef) saveDict, (CFTypeRef *)&savedKeyRef);
    if (sanityCheck != errSecSuccess) {
        LOGGING_FACILITY1(sanityCheck != noErr, @"Problem saving the key to keychain, OSStatus == %d.", sanityCheck);
    }

    return savedKeyRef;
}

稍后,如果您想从钥匙串(keychain)中检索 SecKeyRef,可以使用以下命令:

- (SecKeyRef)getKeyRef:(BOOL)isPrivate {
    OSStatus sanityCheck = noErr;
    NSData *tag;
    id keyClass;
    if (isPrivate) {
        if (privateKeyRef != NULL) {
            // already exists in memory, return
            return privateKeyRef;
        }
        tag = privateTag;
        keyClass = (__bridge id) kSecAttrKeyClassPrivate;
    }
    else {
        if (publicKeyRef != NULL) {
            // already exists in memory, return
            return publicKeyRef;
        }
        tag = publicTag;
        keyClass = (__bridge id) kSecAttrKeyClassPublic;
    }

    NSDictionary *queryDict = @{
            (__bridge id) kSecClass : (__bridge id) kSecClassKey,
            (__bridge id) kSecAttrKeyType : (__bridge id) kSecAttrKeyTypeRSA,
            (__bridge id) kSecAttrApplicationTag : tag,
            (__bridge id) kSecAttrKeyClass : keyClass,
            (__bridge id) kSecReturnRef : (__bridge id) kCFBooleanTrue
    };

    SecKeyRef keyReference = NULL;
    sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef) queryDict, (CFTypeRef *) &keyReference);
    if (sanityCheck != errSecSuccess) {
        NSLog(@"Error trying to retrieve key from server. isPrivate: %d. sanityCheck: %li", isPrivate, sanityCheck);
    }

    if (isPrivate) {
        privateKeyRef = keyReference;
    }
    else {
        publicKeyRef = keyReference;
    }
    return keyReference;
}

关于 privateTag 和 publicTag

privateTagpublicTag 用于标记定义使用此 key 的应用程序的 kSecAttrApplicationTag。您希望有一个单独的 privateTagpublicTag 来区分您的私钥和公钥。

这有点复杂,因为我遵循了示例代码,但我这样定义了 privateTagpublicTag:

SecKeyWrapper.h

#define kPublicKeyTag           "com.sample.app.publickey"
#define kPrivateKeyTag          "com.sample.app.privatekey"

SecKeyWrapper.m

// just under @implementation or @synthesize lines
static const uint8_t publicKeyIdentifier[] = kPublicKeyTag;
static const uint8_t privateKeyIdentifier[] = kPrivateKeyTag;

- (id)init {
    if (self = [super init]) {
        // Tag data to search for keys.
        privateTag = [[NSData alloc] initWithBytes:privateKeyIdentifier length:sizeof(privateKeyIdentifier)];
        publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
    }

    return self;
}

然后按照我上面提供的代码示例中的方式使用 privateTagpublicTag

关于iphone - 将 RSA key 添加到 iPhone 钥匙串(keychain),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/864331/

相关文章:

c - 哈希函数的 openssl 实现是面向位的还是面向字节的?

ubuntu - 私钥格式错误

ruby-on-rails - Rails 中的两步身份验证

delphi - LockBox3 生成相同的 RSA key 对

iphone - 帮助需要遍历大的 JSON 提要

iphone - Google 日历移动版 - 嵌入

javax.crypto.BadPaddingException : pad block corrupted exception

iphone - 在iphone sdk中的单行上对齐两个不同的文本

iphone - UIWebView旋转后调整文本大小: looking for explanation for magical bug or my stupidity

iOS 应用程序存在加密提交问题