createKeychainValue from a NSString - ios

I'm trying to add a certificate to the keychain. I saw several posts that make this from a file, but I want to create one from a NSString.
My NSString is on RSA - 64base and is like:
-----BEGIN CERTIFICATE-----
MIIDoDCCAoigAwIBAgIJAL8qgXMVVVhPMA0GCSqGSIb3DQEBBQUAMGwxCzAJBgNVBAYTAkJSMRIw
...
FT70at8bty9ocDaXuI3j6mfw2SI=
-----END CERTIFICATE-----
And I'm trying to do something like this:
+ (NSMutableDictionary *)newSearchDictionary:(NSString *)identifier {
NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
[searchDictionary setObject:(__bridge id)kSecClassCertificate forKey:(__bridge id)kSecClass];
NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrGeneric];
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrAccount];
[searchDictionary setObject:SERVICE_NAME forKey:(__bridge id)kSecAttrService];
return searchDictionary;
}
+ (BOOL)createKeychainValue:(NSString *)certificado forIdentifier:(NSString *)identifier {
NSMutableDictionary *dictionary = [self newSearchDictionary:identifier];
NSData *certificadoData = [certificado dataUsingEncoding:NSUTF8StringEncoding];
SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) certificadoData);
[dictionary setObject:(__bridge id)(cert) forKey:(__bridge id<NSCopying>)(kSecValueRef)];
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dictionary, NULL);
CFRelease(cert);
if (status == errSecSuccess) {
return YES;
}
return NO;
}
But is getting back the cert as nil. Probably because my certificate is PEM and I need a DER. How can I convert? I'm using openssl on my project.

The function that works for me and created the SecCertificateRef was:
+ (NSData *)derFromPem:(NSString *)pem {
BIO *certBio = BIO_new(BIO_s_mem());
BIO_write(certBio, [pem UTF8String], strlen([pem UTF8String]));
X509 *x = PEM_read_bio_X509(certBio,NULL,0,NULL);
BIO *outBio = BIO_new(BIO_s_mem());
i2d_X509_bio(outBio, x);
int len = BIO_pending(outBio);
char *out = calloc(len + 1, 1);
int i = BIO_read(outBio, out, len);
return [NSData dataWithBytes:out length:i];
}

Convert RSA public key from PEM to DER:
UPDATE
- (NSData *)derFromPem:(NSString *)pem
{
if (pem.length == 0) {
return nil;
}
NSData *result = nil;
const char *pem_str = [pem UTF8String];
BIO *bio;
RSA *rsa;
// X509 *x509;
bio = BIO_new_mem_buf(pem_str, strlen(pem_str));
if (bio) {
rsa = PEM_read_bio_RSAPublicKey(bio, &rsa, NULL, NULL);
// x509 = PEM_read_bio_X509(bio, &x509, NULL/*password*/, NULL);
if (rsa) { // or if (x509)
uint8_t *buf, *bufp;
int len = i2d_RSAPublicKey(rsa, NULL);
// int len = i2d_X509(x509, NULL);
if (len >= 0) {
buf = bufp = malloc(len);
i2d_RSAPublicKey(rsa, &bufp);
// i2d_X509(x509, &bufp);
}
if (len >= 0) {
result = [NSData dataWithBytes:buf length:len];
free(buf);
}
RSA_free(rsa);
// X509_free(x509);
}
BIO_free(bio);
}
return result;
}

Related

Objective-C The specified item already exists in the keychain [iOS]

I am not sure why this code fails. I am always getting errSecDuplicateItem
First I am trying to call SecPKCS12Import.
CFDataRef inId = (CFDataRef)certToImport_;
OSStatus securityError = errSecSuccess;
CFStringRef pw = (CFStringRef)password;
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { pw };
CFDictionaryRef myDict = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
securityError = SecPKCS12Import(inId, myDict, &items);
if (securityError == errSecSuccess) {
securityError = [self addIdentityToKeychain:items];
if (securityError == errSecSuccess)
{
securityError = [self addRootCaToKeychain:items];
....
So from the code above, I am calling addIdentityToKeychain which returns success.
- (OSStatus)addIdentityToKeychain:(CFArrayRef)importDict
{
CFDictionaryRef myId = CFArrayGetValueAtIndex(importDict, 0);
const void *tempId = NULL;
tempId = CFDictionaryGetValue(myId,kSecImportItemIdentity);
SecIdentityRef secId = (SecIdentityRef)tempId;
SecCertificateRef certRef;
OSStatus securityError = SecIdentityCopyCertificate(secId, &certRef);
if (securityError == errSecSuccess) {
uniqueLabel_ = [[NSString alloc] initWithString:[self GetUniqueLabel:certRef]];
NSMutableDictionary *secIdentityParams = [[NSMutableDictionary alloc] init];
[secIdentityParams setObject:(id)secId forKey:(id)kSecValueRef];
securityError = SecItemAdd((CFDictionaryRef) secIdentityParams, NULL);
[secIdentityParams release];
}
return securityError;
}
But when I am trying finally to call addRootCaToKeychain fails, complaining that we have a duplicate entry. it failed the very first time with a random certificate that could not have been imported in any case.
- (OSStatus)addRootCaToKeychain:(CFArrayRef)importDict
{
OSStatus securityError = errSecSuccess;
CFDictionaryRef myId = CFArrayGetValueAtIndex(importDict, 0);
NSArray *certs = (NSArray*)CFDictionaryGetValue(myId, kSecImportItemCertChain);
CFIndex cnt = [certs count];
if (cnt)
{
CFIndex i = 0;
while ((i < cnt)) {
SecCertificateRef certRef = (SecCertificateRef)[certs objectAtIndex:i];
NSMutableDictionary *secCertParams = [[NSMutableDictionary alloc] init];
[secCertParams setObject:(id)certRef forKey:(id)kSecValueRef];
[secCertParams setObject:(id)uniqueLabel_ forKey:(id)kSecAttrLabel];
securityError = SecItemAdd((CFDictionaryRef) secCertParams, NULL);
[secCertParams release];
// if we get something other than success or duplicate, we will quit right here and report the error.
if ((securityError != errSecSuccess) && (securityError != errSecDuplicateItem)) {
return securityError;
}
i++;
}
}
return securityError;
}
What is wrong with the code? Any idea?
In addRootCaToKeychain check before adding in SecItemAdd if Item already there like below:
//adding access key
[secCertParams setObject:(id)key forKey:(id) kSecValueRef];
[secCertParams setObject:(id)uniqueLabel_ forKey:(id) kSecAttrLabel];
//check and removing item if it exists
SecItemDelete((CFDictionaryRef) secCertParams);
//setting data (private key)
[secCertParams setObject:(id) secCertParams forKey:(id)kSecValueData];
Also check answer here for more detail: https://stackoverflow.com/a/12387678/5575752

How can we encrypt bytes through DES/CBC/NOPADDING in Objective C?

I am trying to encrypt bytes data through DES/CBS/NOPADDING algorithm but unable to get correct output. What I have tried is given below in code. Please have a look and suggest.
#import "STEncryptViewController.h"
#import <CommonCrypto/CommonCryptor.h>
#import "STEncryptorDES.h"
#import "NSData+Base64.h"
#import <CommonCrypto/CommonDigest.h>
#define KEY #"MY_TEST_KEY"
#interface STEncryptViewController ()
#end
#implementation STEncryptViewController
#synthesize message;
#synthesize encrypted;
#synthesize decrypted;
#synthesize key;
#synthesize outputMessage;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (IBAction)encrypt:(id)sender
{
const unsigned char bytes[] = {65,17,17,17,17,17,17,17};
NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
NSString *str = self.key.text;
NSData* data12 = [str dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger len = str.length;
uint8_t *bytes1 = (uint8_t *)[data12 bytes];
NSMutableString *result = [NSMutableString stringWithCapacity:len * 3];
// [result appendString:#"["];
//Key convertion
int i = 0;
while(i < len){
if (i) {
[result appendString:#","];
}
[result appendFormat:#"%d", bytes1[i]];
i++;
}
// [result appendString:#"]"];
NSLog (#"String is %#",str);
NSLog (#"Byte array is %#",result);
//
Byte iv1 [] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
Byte iv [] = {1, 35, 69, 103, -119, -85, -51, -17};
NSData *ivData = [NSData dataWithBytes:iv length:sizeof(iv)];
NSData *encryptedData = [STEncryptorDES encryptData1:data key:[NSData dataWithBytes:iv1 length:sizeof(iv1)] iv:ivData];
NSLog(#"encrypted : %#", [encryptedData base64EncodedString]);
self.outputMessage.text = [NSString stringWithFormat:#"Encrypted String ::>> %#",[encryptedData base64EncodedString]];
[self doCipher:nil enc:kCCEncrypt];
}
- (NSData *)md5DataFromString:(NSString *)input
{
const char *cStr = [input UTF8String];
unsigned char digest[16];
CC_MD5( cStr, strlen(cStr), digest ); // This is the md5 call
return [NSData dataWithBytes:digest length:CC_MD5_DIGEST_LENGTH];
}
- (IBAction)decrypt:(id)sender
{
NSData *valueData = [self hexToBytes:self.decrypted.text];
NSData *keyData = [self md5DataFromString:self.key.text];
Byte iv [] = {1, 35, 69, 103, -119, -85, -51, -17};
NSData *ivData = [NSData dataWithBytes:iv length:sizeof(iv)];
NSData *decryptedData = [STEncryptorDES decryptData:valueData key:keyData iv:ivData];
NSLog(#"decrypted : %#", [[NSString alloc] initWithData:decryptedData encoding:NSASCIIStringEncoding]);
self.outputMessage.text = [NSString stringWithFormat:#"Decrypted String ::>> %#", [[NSString alloc] initWithData:decryptedData encoding:NSASCIIStringEncoding]];
}
- (NSString*)doCipher:(NSString*)plainText enc:(CCOperation)encryptOrDecrypt{
NSData *key123 = [self hexToBytes:#"MY_TEST_KEY"];
const void *vplainText;
size_t plainTextBufferSize;
if (encryptOrDecrypt == kCCDecrypt)
{
NSData *EncryptData = [self hexToBytes:#"5454545454545454"];
// NSData *EncryptData =[NSData dataWithBase64EncodedString:plainText];
plainTextBufferSize = [EncryptData length];
vplainText = [EncryptData bytes];
}
else
{
plainTextBufferSize = [plainText length];
vplainText = (const void *) [plainText UTF8String];
}
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t movedBytes = 0;
// uint8_t ivkCCBlockSize3DES;
bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x0, bufferPtrSize);
unsigned char cKey[FBENCRYPT_KEY_SIZE];
bzero(cKey, sizeof(cKey));
[key123 getBytes:cKey length:FBENCRYPT_KEY_SIZE];
//unsigned char result1[24]= {0,0,0,0,0,0,0,0,0,0,0,00,0,0,0,0,0,0,0,00,00,00,00,0};
unsigned char IV3[8]={1, 35, 69, 103, -119, -85, -51, -17};
uint8_t iv[kCCBlockSize3DES];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
ccStatus = CCCrypt(encryptOrDecrypt,
kCCAlgorithm3DES,
0x0000 ,
cKey, //"123456789012345678901234", //key
kCCKeySize3DES,
IV3 , //iv,
vplainText, //plainText,
plainTextBufferSize,
(void *)bufferPtr,
bufferPtrSize,
&movedBytes);
//if (ccStatus == kCCSuccess) NSLog(#"SUCCESS");
/*else*/ if (ccStatus == kCCParamError) return #"PARAM ERROR";
else if (ccStatus == kCCBufferTooSmall) return #"BUFFER TOO SMALL";
else if (ccStatus == kCCMemoryFailure) return #"MEMORY FAILURE";
else if (ccStatus == kCCAlignmentError) return #"ALIGNMENT";
else if (ccStatus == kCCDecodeError) return #"DECODE ERROR";
else if (ccStatus == kCCUnimplemented) return #"UNIMPLEMENTED";
NSString *result;
if (encryptOrDecrypt == kCCDecrypt)
{
result = [ [NSString alloc] initWithData: [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes] encoding:NSASCIIStringEncoding];
}
else
{
NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
NSLog(#"data is: %#", myData);
// result = [NSData base64StringFromData:myData length:myData.length];
// result = [[NSString alloc]initWithData:myData encoding:NSUTF8StringEncoding];
result = nil;
}
return result;
}
-(NSData*)hexToBytes:(NSString *)hex {
NSString *safeStr = [hex stringByReplacingOccurrencesOfString:#"0" withString:#"A"];
NSMutableData* data = [NSMutableData data];
int idx;
for (idx = 0; idx+2 <= safeStr.length; idx+=2) {
NSRange range = NSMakeRange(idx, 2);
NSString* hexStr = [safeStr substringWithRange:range];
NSScanner* scanner = [NSScanner scannerWithString:hexStr];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[data appendBytes:&intValue length:1];
}
NSLog(#"%lu",(unsigned long)data.hash);
return data;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This was my all effort. Currently it is working but not expected output getting. Please suggest me what am I missing here?
One glaring error is that STEncryptorDES is used and is specifies padding but the question states that padding should be used.
Observations:
- You call doCipher with nil and do not use it's return value, delete the unneeded/unused code from the question.
- There is a lot of code to perform a rather simple operation.
- It seems that the test data variable is named iv1, use a better name if that is correct.
- DES should not be used for new work, only when necessary to interoperate with existing work, it is not very secure. New work should use AES.
- #synthesize has not been needed for several years.
In cryptography "DESede/CBC/NoPadding" use following code might be help for you.
Byte iv [] = {1, 35, 69, 103, -119, -85, -51, -17};
NSData *ivData = [NSData dataWithBytes:iv length:sizeof(iv)];
NSData key = ["MY_TEST_KEY" dataUsingEncoding:NSUTF8StringEncoding]
char cKey[key.length];
bzero(cKey, sizeof(cKey));
[key getBytes:cKey length:key.length];
// setup iv
char cIv[kCCBlockSizeDES];
bzero(cIv, kCCBlockSizeDES);
if (ivData) {
[ivData getBytes:cIv length:kCCBlockSizeDES];
}
// setup output buffer
size_t bufferSize = [data length] + kCCBlockSizeDES;
void *buffer = malloc(bufferSize);
// do encrypt
size_t encryptedSize = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithm3DES,
ccNoPadding,
cKey,
key.length,
cIv,
[data bytes],
[data length],
buffer,
bufferSize,
&encryptedSize);
if (cryptStatus == kCCSuccess) {
resultData = [NSData dataWithBytes:buffer length:encryptedSize];
free(buffer);
} else {
free(buffer);
NSLog(#"[ERROR] failed to encrypt|CCCryptoStatus: %d", cryptStatus);
return nil;
}

Get Modulus and Exponent from Public Key iOS

I am looking to get the Modulus and Exponent from a public key in iOS. I have looked at many different sites and looked at Apple, but cannot just get it working.
This is my code so far:
- (void)generateKeyPairPlease
{
OSStatus status = noErr;
NSMutableDictionary *privateKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary *publicKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary *keyPairAttr = [[NSMutableDictionary alloc] init];
NSData * publicTag = [NSData dataWithBytes:publicKeyIdentifier
length:strlen((const char *)publicKeyIdentifier)];
NSData * privateTag = [NSData dataWithBytes:privateKeyIdentifier
length:strlen((const char *)privateKeyIdentifier)];
SecKeyRef publicKey = NULL;
SecKeyRef privateKey = NULL;
[keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA
forKey:(__bridge id)kSecAttrKeyType];
[keyPairAttr setObject:[NSNumber numberWithInt:2048]
forKey:(__bridge id)kSecAttrKeySizeInBits];
[privateKeyAttr setObject:[NSNumber numberWithBool:YES]
forKey:(__bridge id)kSecAttrIsPermanent];
[privateKeyAttr setObject:privateTag
forKey:(__bridge id)kSecAttrApplicationTag];
[publicKeyAttr setObject:[NSNumber numberWithBool:YES]
forKey:(__bridge id)kSecAttrIsPermanent];
[publicKeyAttr setObject:publicTag
forKey:(__bridge id)kSecAttrApplicationTag];
[keyPairAttr setObject:privateKeyAttr
forKey:(__bridge id)kSecPrivateKeyAttrs];
[keyPairAttr setObject:publicKeyAttr
forKey:(__bridge id)kSecPublicKeyAttrs];
status = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr,
&publicKey, &privateKey);
// error handling...
NSData *ppp = [NSData dataWithBytes:publicKey length:strlen((const char *)publicKey)];
NSString *responseString, *responseStringASCII, *responseStringUTF8;
responseStringASCII = [[NSString alloc] initWithData:ppp encoding:NSASCIIStringEncoding];
if (!responseStringASCII)
{
responseString = [[NSString alloc] initWithData:ppp encoding:NSUTF8StringEncoding];
}
else
{
responseStringUTF8 = [[NSString alloc] initWithData:ppp encoding:NSUTF8StringEncoding];
if(responseStringUTF8 != nil && [responseStringUTF8 length] < [responseStringASCII length])
{
responseString = [responseStringUTF8 retain];
}
else
{
responseString = [responseStringASCII retain];
}
[responseStringUTF8 release];
}
publicKeyString = responseString;
if(publicKey) CFRelease(publicKey);
if(privateKey) CFRelease(privateKey);
NSData *exp = [self getPublicKeyExp];
NSData *mod = [self getPublicKeyMod];
NSString *expString = [[NSString alloc] initWithData:exp encoding:NSUTF8StringEncoding];
NSString *modString = [[NSString alloc] initWithData:mod encoding:NSUTF8StringEncoding];
NSLog(#"exponent = %# \n modulus = %#", expString, modString);
}
- (NSData *)getPublicKeyBits: (NSString*) publicKeyIdentifier {
OSStatus sanityCheck = noErr;
NSData * publicKeyBits = nil;
CFTypeRef pk = NULL;
NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];
NSData* publicTag = [publicKeyIdentifier dataUsingEncoding:NSUTF8StringEncoding];
// Set the public key query dictionary.
[queryPublicKey setObject:(__bridge_transfer id)kSecClassKey forKey:(__bridge_transfer id)kSecClass];
[queryPublicKey setObject:publicTag forKey:(__bridge_transfer id)kSecAttrApplicationTag];
[queryPublicKey setObject:(__bridge_transfer id)kSecAttrKeyTypeRSA forKey:(__bridge_transfer id)kSecAttrKeyType];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge_transfer id)kSecReturnData];
// Get the key bits.
sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, &pk);
if (sanityCheck != noErr)
{
publicKeyBits = nil;
}
publicKeyBits = (__bridge id)pk;
NSLog(#"public bits %#",publicKeyBits);
return publicKeyBits;
}
- (NSData *)getPublicKeyExp
{
NSData* pk = [self getPublicKeyBits:publicKeyString];
if (pk == NULL) {
return NULL;
}
int iterator = 0;
iterator++; // TYPE - bit stream - mod + exp
[self derEncodingGetSizeFrom:pk at:&iterator]; // Total size
iterator++; // TYPE - bit stream mod
int mod_size = [self derEncodingGetSizeFrom:pk at:&iterator];
iterator += mod_size;
iterator++; // TYPE - bit stream exp
int exp_size = [self derEncodingGetSizeFrom:pk at:&iterator];
return [pk subdataWithRange:NSMakeRange(iterator, exp_size)];
return pk;
}
- (NSData *)getPublicKeyMod
{
NSData* pk = [self getPublicKeyBits:publicKeyString];
if (pk == NULL) {
return NULL;
}
int iterator = 0;
iterator++; // TYPE - bit stream - mod + exp
[self derEncodingGetSizeFrom:pk at:&iterator]; // Total size
iterator++; // TYPE - bit stream mod
int mod_size = [self derEncodingGetSizeFrom:pk at:&iterator];
return [pk subdataWithRange:NSMakeRange(iterator, mod_size)];
}
- (int)derEncodingGetSizeFrom:(NSData*)buf at:(int*)iterator
{
const uint8_t* data = [buf bytes];
int itr = *iterator;
int num_bytes = 1;
int ret = 0;
if (data[itr] > 0x80) {
num_bytes = data[itr] - 0x80;
itr++;
}
for (int i = 0 ; i < num_bytes; i++) ret = (ret * 0x100) + data[itr + i];
*iterator = itr + num_bytes;
return ret;
}
However, when I get to retrieving the Modulus and Exponent from the relevant methods, they keep returning NULL?

Keychain Access Not Returning kSecValueData

I'm using the following code:
+ (void)createKeychainItem:(NSString *)name
{
// Don't create if one already exists
if ([self getKeychainItem:name] != nil) return;
NSData *encodedName = [name dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *attributes = #{
(id)kSecAttrAccount : encodedName,
(id)kSecAttrGeneric : encodedName,
(id)kSecAttrLabel : name,
(id)kSecAttrService : name,
(id)kSecClass : (id)kSecClassGenericPassword,
};
OSStatus result = SecItemAdd((CFDictionaryRef)attributes, NULL);
}
+ (NSDictionary *)getKeychainItem:(NSString *)name
{
// Build the query
NSData *encodedName = [name dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *query = #{
(id)kSecAttrAccount : encodedName,
(id)kSecAttrGeneric : encodedName,
(id)kSecAttrService : name,
(id)kSecClass : (id)kSecClassGenericPassword,
(id)kSecMatchLimit : (id)kSecMatchLimitOne,
(id)kSecReturnAttributes : (id)kCFBooleanTrue,
};
NSDictionary *output = nil;
OSStatus result = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&output);
// Convert the password if it exists
NSData *passwordData = [output objectForKey:kSecValueData];
if (passwordData != nil) {
NSMutableDictionary *mutableOutput = [[output mutableCopy] autorelease];
NSString *password = [[[NSString alloc] initWithBytes:passwordData length:passwordData.length encoding:NSUTF8StringEncoding] autorelease];
[mutableOutput setObject:password forKey:(id)kSecValueData];
output = [[mutableOutput copy] autorelease];
}
return output;
}
+ (void)updateKeychainItem:(NSString *)name value:(NSString *)value attribute:(id)attribute
{
// Get the item
NSDictionary *values = [self getKeychainItem:name];
// If we got nothing back, build it
if (values == nil) {
[self createKeychainItem:name];
}
// Create a query to update
NSData *encodedName = [name dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *query = #{
(id)kSecAttrAccount : encodedName,
(id)kSecAttrGeneric : encodedName,
(id)kSecAttrService : name,
(id)kSecClass : (id)kSecClassGenericPassword,
};
NSDictionary *attributes = nil;
if (attribute == kSecValueData) {
attributes = #{ (id)kSecValueData : [value dataUsingEncoding:NSUTF8StringEncoding] };
} else {
attributes = #{ attribute : value };
}
OSStatus result = SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attributes);
}
Setting a value with [self updateKeychainItem:AuthTokenIdentifer value:authToken attribute:kSecValueData]; works and I can see it in Keychain Access.
Fetching the results with NSDictionary *values = [self getKeychainItem:AuthTokenIdentifer]; works, but the kSecValueData is not set in the dictionary. Everything else is set, like the create and modified dates, just not the secure data.
Any ideas? This happens on iOS and Mac.
You need to use the attributes dictionary from getKeychainItem: to fetch the value. Something like
NSMutableDictionary *dataQuery = [attrs mutableCopy];
[dataQuery setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
[dataQuery setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
CFTypeRef resultData;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)(dataQuery), &resultData);
NSData *tokenData = CFBridgingRelease(resultData);

RSA implementations in Objective C

I am working on a simple app in objective-C that uses RSA Algorithm. I want to use it on Server/Client Communications. I need help in RSA Algorithm Implementation in iOS/iPhone.
I have knowledge of encryption and decryption.
I want an opensource library or code to add into my project.
I have to go though CommonCryptor.h.
I have tried RSA Encryption and Decryption for NSString. Here is the code:
Add Security.Framework to your project bundle.
ViewController.h code is as follows:
#import <UIKit/UIKit.h>
#import <Security/Security.h>
#interface ViewController : UIViewController
{
SecKeyRef publicKey;
SecKeyRef privateKey;
NSData *publicTag;
NSData *privateTag;
}
- (void)encryptWithPublicKey:(uint8_t *)plainBuffer cipherBuffer:(uint8_t *)cipherBuffer;
- (void)decryptWithPrivateKey:(uint8_t *)cipherBuffer plainBuffer:(uint8_t *)plainBuffer;
- (SecKeyRef)getPublicKeyRef;
- (SecKeyRef)getPrivateKeyRef;
- (void)testAsymmetricEncryptionAndDecryption;
- (void)generateKeyPair:(NSUInteger)keySize;
#end
ViewController.m file code is as follows:
#import "ViewController.h"
const size_t BUFFER_SIZE = 64;
const size_t CIPHER_BUFFER_SIZE = 1024;
const uint32_t PADDING = kSecPaddingNone;
static const UInt8 publicKeyIdentifier[] = "com.apple.sample.publickey";
static const UInt8 privateKeyIdentifier[] = "com.apple.sample.privatekey";
#implementation ViewController
-(SecKeyRef)getPublicKeyRef {
OSStatus sanityCheck = noErr;
SecKeyRef publicKeyReference = NULL;
if (publicKeyReference == NULL) {
[self generateKeyPair:512];
NSMutableDictionary *queryPublicKey = [[NSMutableDictionary alloc] init];
// Set the public key query dictionary.
[queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
[queryPublicKey setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
[queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
// Get the key.
sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKeyReference);
if (sanityCheck != noErr)
{
publicKeyReference = NULL;
}
// [queryPublicKey release];
} else { publicKeyReference = publicKey; }
return publicKeyReference; }
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)testAsymmetricEncryptionAndDecryption {
uint8_t *plainBuffer;
uint8_t *cipherBuffer;
uint8_t *decryptedBuffer;
const char inputString[] = "This is a test demo for RSA Implementation in Objective C";
int len = strlen(inputString);
// TODO: this is a hack since i know inputString length will be less than BUFFER_SIZE
if (len > BUFFER_SIZE) len = BUFFER_SIZE-1;
plainBuffer = (uint8_t *)calloc(BUFFER_SIZE, sizeof(uint8_t));
cipherBuffer = (uint8_t *)calloc(CIPHER_BUFFER_SIZE, sizeof(uint8_t));
decryptedBuffer = (uint8_t *)calloc(BUFFER_SIZE, sizeof(uint8_t));
strncpy( (char *)plainBuffer, inputString, len);
NSLog(#"init() plainBuffer: %s", plainBuffer);
//NSLog(#"init(): sizeof(plainBuffer): %d", sizeof(plainBuffer));
[self encryptWithPublicKey:(UInt8 *)plainBuffer cipherBuffer:cipherBuffer];
NSLog(#"encrypted data: %s", cipherBuffer);
//NSLog(#"init(): sizeof(cipherBuffer): %d", sizeof(cipherBuffer));
[self decryptWithPrivateKey:cipherBuffer plainBuffer:decryptedBuffer];
NSLog(#"decrypted data: %s", decryptedBuffer);
//NSLog(#"init(): sizeof(decryptedBuffer): %d", sizeof(decryptedBuffer));
NSLog(#"====== /second test =======================================");
free(plainBuffer);
free(cipherBuffer);
free(decryptedBuffer);
}
/* Borrowed from:
* https://developer.apple.com/library/mac/#documentation/security/conceptual/CertKeyTrustProgGuide/iPhone_Tasks/iPhone_Tasks.html
*/
- (void)encryptWithPublicKey:(uint8_t *)plainBuffer cipherBuffer:(uint8_t *)cipherBuffer
{
NSLog(#"== encryptWithPublicKey()");
OSStatus status = noErr;
NSLog(#"** original plain text 0: %s", plainBuffer);
size_t plainBufferSize = strlen((char *)plainBuffer);
size_t cipherBufferSize = CIPHER_BUFFER_SIZE;
NSLog(#"SecKeyGetBlockSize() public = %lu", SecKeyGetBlockSize([self getPublicKeyRef]));
// Error handling
// Encrypt using the public.
status = SecKeyEncrypt([self getPublicKeyRef],
PADDING,
plainBuffer,
plainBufferSize,
&cipherBuffer[0],
&cipherBufferSize
);
NSLog(#"encryption result code: %ld (size: %lu)", status, cipherBufferSize);
NSLog(#"encrypted text: %s", cipherBuffer);
}
- (void)decryptWithPrivateKey:(uint8_t *)cipherBuffer plainBuffer:(uint8_t *)plainBuffer
{
OSStatus status = noErr;
size_t cipherBufferSize = strlen((char *)cipherBuffer);
NSLog(#"decryptWithPrivateKey: length of buffer: %lu", BUFFER_SIZE);
NSLog(#"decryptWithPrivateKey: length of input: %lu", cipherBufferSize);
// DECRYPTION
size_t plainBufferSize = BUFFER_SIZE;
// Error handling
status = SecKeyDecrypt([self getPrivateKeyRef],
PADDING,
&cipherBuffer[0],
cipherBufferSize,
&plainBuffer[0],
&plainBufferSize
);
NSLog(#"decryption result code: %ld (size: %lu)", status, plainBufferSize);
NSLog(#"FINAL decrypted text: %s", plainBuffer);
}
- (SecKeyRef)getPrivateKeyRef {
OSStatus resultCode = noErr;
SecKeyRef privateKeyReference = NULL;
// NSData *privateTag = [NSData dataWithBytes:#"ABCD" length:strlen((const char *)#"ABCD")];
// if(privateKey == NULL) {
[self generateKeyPair:512];
NSMutableDictionary * queryPrivateKey = [[NSMutableDictionary alloc] init];
// Set the private key query dictionary.
[queryPrivateKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
[queryPrivateKey setObject:privateTag forKey:(__bridge id)kSecAttrApplicationTag];
[queryPrivateKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[queryPrivateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
// Get the key.
resultCode = SecItemCopyMatching((__bridge CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKeyReference);
NSLog(#"getPrivateKey: result code: %ld", resultCode);
if(resultCode != noErr)
{
privateKeyReference = NULL;
}
// [queryPrivateKey release];
// } else {
// privateKeyReference = privateKey;
// }
return privateKeyReference;
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
privateTag = [[NSData alloc] initWithBytes:privateKeyIdentifier length:sizeof(privateKeyIdentifier)];
publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
[self testAsymmetricEncryptionAndDecryption];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
- (void)generateKeyPair:(NSUInteger)keySize {
OSStatus sanityCheck = noErr;
publicKey = NULL;
privateKey = NULL;
// LOGGING_FACILITY1( keySize == 512 || keySize == 1024 || keySize == 2048, #"%d is an invalid and unsupported key size.", keySize );
// First delete current keys.
// [self deleteAsymmetricKeys];
// Container dictionaries.
NSMutableDictionary * privateKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary * publicKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary * keyPairAttr = [[NSMutableDictionary alloc] init];
// Set top level dictionary for the keypair.
[keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[keyPairAttr setObject:[NSNumber numberWithUnsignedInteger:keySize] forKey:(__bridge id)kSecAttrKeySizeInBits];
// Set the private key dictionary.
[privateKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
[privateKeyAttr setObject:privateTag forKey:(__bridge id)kSecAttrApplicationTag];
// See SecKey.h to set other flag values.
// Set the public key dictionary.
[publicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
[publicKeyAttr setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
// See SecKey.h to set other flag values.
// Set attributes to top level dictionary.
[keyPairAttr setObject:privateKeyAttr forKey:(__bridge id)kSecPrivateKeyAttrs];
[keyPairAttr setObject:publicKeyAttr forKey:(__bridge id)kSecPublicKeyAttrs];
// SecKeyGeneratePair returns the SecKeyRefs just for educational purposes.
sanityCheck = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr, &publicKey, &privateKey);
// LOGGING_FACILITY( sanityCheck == noErr && publicKey != NULL && privateKey != NULL, #"Something really bad went wrong with generating the key pair." );
if(sanityCheck == noErr && publicKey != NULL && privateKey != NULL)
{
NSLog(#"Successful");
}
// [privateKeyAttr release];
// [publicKeyAttr release];
// [keyPairAttr release];
}
#end
Here is where I originally posted my answer : Iphone - How to encrypt NSData with public key and decrypt with private key?
Let me know if you need more help.
Hope this helps.
It's very cool!
However i think it should not be a subclass of a UIViewController, but an NSObject, i changed and it works for me, here it is:
NOTE: ALL WORK IS THANKED TO #Parth Bath
RSAManager.h
#interface RSAManager : NSObject
{
SecKeyRef publicKey;
SecKeyRef privateKey;
NSData *publicTag;
NSData *privateTag;
}
- (void)encryptWithPublicKey:(uint8_t *)plainBuffer cipherBuffer:(uint8_t *)cipherBuffer;
- (void)decryptWithPrivateKey:(uint8_t *)cipherBuffer plainBuffer:(uint8_t *)plainBuffer;
- (SecKeyRef)getPublicKeyRef;
- (SecKeyRef)getPrivateKeyRef;
- (void)testAsymmetricEncryptionAndDecryption;
- (void)generateKeyPair:(NSUInteger)keySize;
#end
RSAManager.m
#import "RSAManager.h"
const size_t BUFFER_SIZE = 64;
const size_t CIPHER_BUFFER_SIZE = 1024;
const uint32_t PADDING = kSecPaddingNone;
static const UInt8 publicKeyIdentifier[] = "com.apple.sample.publickey";
static const UInt8 privateKeyIdentifier[] = "com.apple.sample.privatekey";
#implementation RSAManager
- (id)init
{
self = [super init];
if(self) {
privateTag = [[NSData alloc] initWithBytes:privateKeyIdentifier length:sizeof(privateKeyIdentifier)];
publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
[self testAsymmetricEncryptionAndDecryption];
}
return self;
}
-(SecKeyRef)getPublicKeyRef {
OSStatus sanityCheck = noErr;
SecKeyRef publicKeyReference = NULL;
if (publicKeyReference == NULL) {
[self generateKeyPair:512];
NSMutableDictionary *queryPublicKey = [[NSMutableDictionary alloc] init];
// Set the public key query dictionary.
[queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
[queryPublicKey setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
[queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
// Get the key.
sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKeyReference);
if (sanityCheck != noErr)
{
publicKeyReference = NULL;
}
// [queryPublicKey release];
} else { publicKeyReference = publicKey; }
return publicKeyReference;
}
- (void)testAsymmetricEncryptionAndDecryption {
uint8_t *plainBuffer;
uint8_t *cipherBuffer;
uint8_t *decryptedBuffer;
const char inputString[] = "This is a test demo for RSA Implementation in Objective C";
int len = strlen(inputString);
// TODO: this is a hack since i know inputString length will be less than BUFFER_SIZE
if (len > BUFFER_SIZE) len = BUFFER_SIZE-1;
plainBuffer = (uint8_t *)calloc(BUFFER_SIZE, sizeof(uint8_t));
cipherBuffer = (uint8_t *)calloc(CIPHER_BUFFER_SIZE, sizeof(uint8_t));
decryptedBuffer = (uint8_t *)calloc(BUFFER_SIZE, sizeof(uint8_t));
strncpy( (char *)plainBuffer, inputString, len);
NSLog(#"init() plainBuffer: %s", plainBuffer);
//NSLog(#"init(): sizeof(plainBuffer): %d", sizeof(plainBuffer));
[self encryptWithPublicKey:(UInt8 *)plainBuffer cipherBuffer:cipherBuffer];
NSLog(#"encrypted data: %s", cipherBuffer);
//NSLog(#"init(): sizeof(cipherBuffer): %d", sizeof(cipherBuffer));
[self decryptWithPrivateKey:cipherBuffer plainBuffer:decryptedBuffer];
NSLog(#"decrypted data: %s", decryptedBuffer);
//NSLog(#"init(): sizeof(decryptedBuffer): %d", sizeof(decryptedBuffer));
NSLog(#"====== /second test =======================================");
free(plainBuffer);
free(cipherBuffer);
free(decryptedBuffer);
}
/* Borrowed from:
* https://developer.apple.com/library/mac/#documentation/security/conceptual/CertKeyTrustProgGuide/iPhone_Tasks/iPhone_Tasks.html
*/
- (void)encryptWithPublicKey:(uint8_t *)plainBuffer cipherBuffer:(uint8_t *)cipherBuffer
{
NSLog(#"== encryptWithPublicKey()");
OSStatus status = noErr;
NSLog(#"** original plain text 0: %s", plainBuffer);
size_t plainBufferSize = strlen((char *)plainBuffer);
size_t cipherBufferSize = CIPHER_BUFFER_SIZE;
NSLog(#"SecKeyGetBlockSize() public = %lu", SecKeyGetBlockSize([self getPublicKeyRef]));
// Error handling
// Encrypt using the public.
status = SecKeyEncrypt([self getPublicKeyRef],
PADDING,
plainBuffer,
plainBufferSize,
&cipherBuffer[0],
&cipherBufferSize
);
NSLog(#"encryption result code: %ld (size: %lu)", status, cipherBufferSize);
NSLog(#"encrypted text: %s", cipherBuffer);
}
- (void)decryptWithPrivateKey:(uint8_t *)cipherBuffer plainBuffer:(uint8_t *)plainBuffer
{
OSStatus status = noErr;
size_t cipherBufferSize = strlen((char *)cipherBuffer);
NSLog(#"decryptWithPrivateKey: length of buffer: %lu", BUFFER_SIZE);
NSLog(#"decryptWithPrivateKey: length of input: %lu", cipherBufferSize);
// DECRYPTION
size_t plainBufferSize = BUFFER_SIZE;
// Error handling
status = SecKeyDecrypt([self getPrivateKeyRef],
PADDING,
&cipherBuffer[0],
cipherBufferSize,
&plainBuffer[0],
&plainBufferSize
);
NSLog(#"decryption result code: %ld (size: %lu)", status, plainBufferSize);
NSLog(#"FINAL decrypted text: %s", plainBuffer);
}
- (SecKeyRef)getPrivateKeyRef {
OSStatus resultCode = noErr;
SecKeyRef privateKeyReference = NULL;
// NSData *privateTag = [NSData dataWithBytes:#"ABCD" length:strlen((const char *)#"ABCD")];
// if(privateKey == NULL) {
[self generateKeyPair:512];
NSMutableDictionary * queryPrivateKey = [[NSMutableDictionary alloc] init];
// Set the private key query dictionary.
[queryPrivateKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
[queryPrivateKey setObject:privateTag forKey:(__bridge id)kSecAttrApplicationTag];
[queryPrivateKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[queryPrivateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
// Get the key.
resultCode = SecItemCopyMatching((__bridge CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKeyReference);
NSLog(#"getPrivateKey: result code: %ld", resultCode);
if(resultCode != noErr)
{
privateKeyReference = NULL;
}
// [queryPrivateKey release];
// } else {
// privateKeyReference = privateKey;
// }
return privateKeyReference;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
- (void)generateKeyPair:(NSUInteger)keySize {
OSStatus sanityCheck = noErr;
publicKey = NULL;
privateKey = NULL;
// LOGGING_FACILITY1( keySize == 512 || keySize == 1024 || keySize == 2048, #"%d is an invalid and unsupported key size.", keySize );
// First delete current keys.
// [self deleteAsymmetricKeys];
// Container dictionaries.
NSMutableDictionary * privateKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary * publicKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary * keyPairAttr = [[NSMutableDictionary alloc] init];
// Set top level dictionary for the keypair.
[keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[keyPairAttr setObject:[NSNumber numberWithUnsignedInteger:keySize] forKey:(__bridge id)kSecAttrKeySizeInBits];
// Set the private key dictionary.
[privateKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
[privateKeyAttr setObject:privateTag forKey:(__bridge id)kSecAttrApplicationTag];
// See SecKey.h to set other flag values.
// Set the public key dictionary.
[publicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
[publicKeyAttr setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
// See SecKey.h to set other flag values.
// Set attributes to top level dictionary.
[keyPairAttr setObject:privateKeyAttr forKey:(__bridge id)kSecPrivateKeyAttrs];
[keyPairAttr setObject:publicKeyAttr forKey:(__bridge id)kSecPublicKeyAttrs];
// SecKeyGeneratePair returns the SecKeyRefs just for educational purposes.
sanityCheck = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr, &publicKey, &privateKey);
// LOGGING_FACILITY( sanityCheck == noErr && publicKey != NULL && privateKey != NULL, #"Something really bad went wrong with generating the key pair." );
if(sanityCheck == noErr && publicKey != NULL && privateKey != NULL)
{
NSLog(#"Successful");
}
// [privateKeyAttr release];
// [publicKeyAttr release];
// [keyPairAttr release];
}
#end

Resources