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

How to save and read the RSA key in the keychain?

我现在遇到了一些麻烦。 这几天在研究objc的RSA加密功能。但是当我完成这个功能的时候,我发现我对"Keychain"存储键一无所知。我查看了 Apple 文档 "Storing Keys in the Keychain" 和 "Getting an Existing Key" 以及 "Generating New Cryptographic Keys"。并尝试使用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

很遗憾,这里运行时系统会报错,我googled了半天也没得到答案...

我将不胜感激 help.Thanks!

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

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,
    };

会成功的perfectly.I很高兴,因为我发现了这个问题!