如何在钥匙串中保存和读取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很高兴,因为我发现了这个问题!
我现在遇到了一些麻烦。 这几天在研究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很高兴,因为我发现了这个问题!