I'm having some trouble now. These days I am working on the RSA encryption function of objc. But when I completed the function, I found out that I didn't know anything about the "Keychain" storage key. I checked the Apple documents "Storing Keys in the Keychain" and "Getting an Existing Key" and "Generating New Cryptographic Keys". And try to use SecKeyCopyPublicKey( ), SecKeyCreateEncryptedData( , , ), SecItemCopyMatching( , ), SecKeyCreateRandomKey( , )……… I also try to google to get some useful information.
But there are still problems. These are the complete codes I pieced together these days:
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
Unfortunately, the system will throw an error when running here, I googled for a long time and didn't get the answer...
I would be grateful for any help.Thanks!
Ok! I think i have solved this problem! The problem is here:
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,
};
delete “kSecReturnData” key. It turned out that the value it returned was not a keyRef, It's NSData! This is modified code:
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,
};
It will work perfectly.I am very happy because I found this problem!