【问题标题】:How to save and read the RSA key in the keychain?如何保存和读取钥匙串中的 RSA 密钥?
【发布时间】:2020-01-01 14:17:45
【问题描述】:

我现在遇到了一些麻烦。 这些天我正在研究objc的RSA加密功能。但是当我完成该功能时,我发现我对“Keychain”存储密钥一无所知。我检查了 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了半天也没有得到答案……

如果有任何帮助,我将不胜感激。谢谢!

【问题讨论】:

  • 你能看到我发布的图片吗?

标签: objective-c key rsa keychain


【解决方案1】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-21
    • 2018-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-30
    • 2012-09-21
    • 1970-01-01
    相关资源
    最近更新 更多