如何在钥匙串中保存和读取RSA钥匙?

时间:2020-01-01 14:17:45

标签: objective-c key rsa keychain

我现在遇到麻烦了。 这些天,我正在研究objc的RSA加密功能。但是当我完成该功能时,我发现我对“钥匙串”存储钥匙一无所知。我检查了Apple文档“在钥匙串中存储密钥”和“获取现有密钥”和“生成新的加密密钥”。并尝试使用SecKeyCopyPublicKey(),SecKeyCreateEncryptedData(、、),SecItemCopyMatching(,),SecKeyCreateRandomKey(,)...……我也尝试在Google上获取一些有用的信息。

但是仍然存在问题。这些是我最近拼凑的完整代码:

AppDelegate.h

//
//  AppDelegate.h
//  MessagesServer
//
//

#import <Cocoa/Cocoa.h>
#import <Security/Security.h>

@interface AppDelegate : NSObject <NSApplicationDelegate>


@end

AppDelegate.m

//
//  AppDelegate.m
//  MessagesServer
//

#import "AppDelegate.h"

@interface AppDelegate ()

@property (weak) IBOutlet NSWindow *window;
@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {

    NSError * error = nil;
    NSData * cipherText = [self encryptionDataUsingLocalRSAKey:[@"Hello! Nice to meet you!" dataUsingEncoding:NSUTF8StringEncoding] error:&error];

    if (!cipherText){
        NSLog(@"%@", error.description);
    } else {
        NSError * decryptErr = nil;
        NSData * clearText = [self decryptionDataUsingLocalRSAKey:cipherText error:&decryptErr];

        if (!clearText){
            NSLog(@"%@", decryptErr.description);
        } else {
            NSLog(@"%@", [[NSString alloc] initWithData:clearText encoding:NSUTF8StringEncoding]);
        }
    }


}

- (NSData *)encryptionDataUsingLocalRSAKey:(NSData *)data error:(NSError **)encryptErr{
    NSError * error = nil;
    SecKeyRef privateKey =  [self getRSAKeyInLocalWithError:&error];

    if (!privateKey){
        *encryptErr = error;
        return nil;
    }

    SecKeyRef publicKey = SecKeyCopyPublicKey(privateKey);

    CFErrorRef encryptDataErr = nil;

    NSData * cipherText = (NSData *)CFBridgingRelease(SecKeyCreateEncryptedData(publicKey, kSecKeyAlgorithmRSAEncryptionOAEPSHA512, (__bridge CFDataRef)data, &encryptDataErr));

    if (!cipherText){
        *encryptErr = CFBridgingRelease(encryptDataErr);
        return nil;
    } else {
        return cipherText;
    }
}

- (NSData *)decryptionDataUsingLocalRSAKey:(NSData *)cipherData error:(NSError **)decryptErr{
    NSError * error = nil;
    SecKeyRef privateKey =  [self getRSAKeyInLocalWithError:&error];

    if (!privateKey){
        *decryptErr = error;
        return nil;
    }

    CFErrorRef decryptDataErr = nil;

    NSData * clearText = (NSData *)CFBridgingRelease(SecKeyCreateDecryptedData(privateKey, kSecKeyAlgorithmRSAEncryptionOAEPSHA512, (__bridge CFDataRef)cipherData, &decryptDataErr));

    if (!clearText){
        *decryptErr = CFBridgingRelease(decryptDataErr);
        return nil;
    } else {
        return clearText;
    }
}

- (SecKeyRef)getRSAKeyInLocalWithError:(NSError **)error{

    NSDictionary * query = @{(id)kSecClass:                 (id)kSecClassKey,
                             (id)kSecAttrApplicationTag:    [@"com.MessageSender.Server.Signing.Key" dataUsingEncoding:NSUTF8StringEncoding],
                             (id)kSecAttrKeyType:           (id)kSecAttrKeyTypeRSA,
                             (id)kSecAttrKeyClass:          (id)kSecAttrKeyClassPrivate,
                             (id)kSecAttrIsPermanent:       @YES,
                             (id)kSecReturnData:            @YES,
                             (id)kSecAttrKeySizeInBits:     @2048,
                             (id)kSecMatchLimit:            (id)kSecMatchLimitOne,
    };

    SecKeyRef privateKey = nil;
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&privateKey);

    if (status != errSecSuccess){
        NSError * createError = nil;
        BOOL createSuccess = [self createAnRSAKeyWithError:&createError];
        if (!createSuccess){
            *error = createError;
            return nil;
        } else {
            privateKey = [self getRSAKeyInLocalWithError:nil];
        }
    }

    return privateKey;
}

- (BOOL)createAnRSAKeyWithError:(NSError **)error{
    NSDictionary * keyInfo = @{(id)kSecAttrType:                    (id)kSecAttrKeyTypeRSA,
                               (id)kSecAttrKeySizeInBits:           @2048,
                               (id)kSecPublicKeyAttrs:
                                   @{(id)kSecAttrLabel:             @"MessageSender Server Encryption Key",
                                     (id)kSecAttrIsPermanent:       @YES,
                                     (id)kSecAttrApplicationTag:    [@"com.MessageSender.Server.Encryption.Key" dataUsingEncoding:NSUTF8StringEncoding],},
                               (id)kSecPrivateKeyAttrs:
                                   @{(id)kSecAttrLabel:             @"MessageSender Server Signing Key",
                                     (id)kSecAttrIsPermanent:       @YES,
                                     (id)kSecAttrApplicationTag:    [@"com.MessageSender.Server.Signing.Key" dataUsingEncoding:NSUTF8StringEncoding],},};


    CFErrorRef createKeyError = nil;
    SecKeyRef privateKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)keyInfo, &createKeyError);

    if (!privateKey){
        NSError * createKeyErr = CFBridgingRelease(createKeyError);
        *error = createKeyErr;
        return NO;
    } else {

        return YES;
    }

}




- (void)applicationWillTerminate:(NSNotification *)aNotification {
    // Insert code here to tear down your application
}


@end

error information.png

不幸的是,在这里运行时,系统会引发错误,我用了很长时间的Google搜索,却没有得到答案...

我将不胜感激。谢谢!

1 个答案:

答案 0 :(得分:0)

好!我想我已经解决了这个问题! 问题在这里:

NSDictionary * query = @{(id)kSecClass:                 (id)kSecClassKey,
                             (id)kSecAttrApplicationTag:    [@"com.MessageSender.Server.Signing.Key" dataUsingEncoding:NSUTF8StringEncoding],
                             (id)kSecAttrKeyType:           (id)kSecAttrKeyTypeRSA,
                             (id)kSecAttrKeyClass:          (id)kSecAttrKeyClassPrivate,
                             (id)kSecAttrIsPermanent:       @YES,
                             (id)kSecReturnData:            @YES,
                             (id)kSecAttrKeySizeInBits:     @2048,
                             (id)kSecMatchLimit:            (id)kSecMatchLimitOne,
    };

删除“ kSecReturnData”键。 原来,它返回的值不是keyRef,而是NSData! 这是修改后的代码:

NSDictionary * query = @{(id)kSecClass:                 (id)kSecClassKey,
                             (id)kSecAttrApplicationTag:    [@"com.MessageSender.Server.Signing.Key" dataUsingEncoding:NSUTF8StringEncoding],
                             (id)kSecAttrKeyType:           (id)kSecAttrKeyTypeRSA,
                             (id)kSecAttrKeyClass:          (id)kSecAttrKeyClassPrivate,
                             (id)kSecAttrIsPermanent:       @YES,
                             (id)kSecAttrKeySizeInBits:     @2048,
                             (id)kSecMatchLimit:            (id)kSecMatchLimitOne,
    };

它将完美运行。我很高兴,因为我发现了这个问题!