首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将RSA密钥添加到iPhone密钥链

将RSA密钥添加到iPhone密钥链
EN

Stack Overflow用户
提问于 2009-05-14 16:22:03
回答 4查看 4.3K关注 0票数 2

我正在尝试将公钥和私钥添加到iPhone的密钥链中,这样我就可以使用CommonCrypto库了,但我不完全确定如何做到这一点。目前,MYCrypto库似乎只能在Mac上运行,而不能在iPhone上运行。有没有人可以帮助和解释如何将私钥/公钥添加到密钥链中,并获得它们的SecKeyRef?

EN

回答 4

Stack Overflow用户

发布于 2014-05-20 12:58:54

所以在iOS中,钥匙链被放在沙盒中。这意味着,除非您另行指定,否则您放入密钥链的任何内容都只能由您的应用程序和您的应用程序访问。您必须在项目设置中的Capabilities下启用Keychain共享。

既然这样就没问题了,你当然可以导入数据了。由于它们是NSString对象,您必须首先将其转换为NSData对象才能正确地导入它们。最有可能的是,它们是用Base64编码的,所以你必须颠倒过来:

代码语言:javascript
复制
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];

现在,您可以使用此方法将密钥保存到密钥链并获取SecKeyRef:

代码语言:javascript
复制
/**
 * 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;
}

稍后,如果您想要从密钥链中检索SecKeyRef,可以使用以下命令:

代码语言:javascript
复制
- (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用于标记定义使用该密钥的应用程序的kSecAttrApplicationTag。您希望有一个单独的privateTagpublicTag来区分您的私钥和公钥。

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

SecKeyWrapper.h

代码语言:javascript
复制
#define kPublicKeyTag           "com.sample.app.publickey"
#define kPrivateKeyTag          "com.sample.app.privatekey"

SecKeyWrapper.m

代码语言:javascript
复制
// 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

票数 5
EN

Stack Overflow用户

发布于 2009-06-23 21:46:01

你是在iPhone上生成它们的吗?如果是这样的话,this message加上证书、密钥和信任服务编程指南中的example code应该会指引您朝着正确的方向前进。如果没有,我正在编写一些代码来实现这一点--它还没有完全实现。

票数 1
EN

Stack Overflow用户

发布于 2009-05-14 16:36:42

这似乎是this SO question的副本。

MyCrypto says that it works on the iPhone。您看到了什么类型的问题?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/864331

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档