I need to implement encryption / decryption using a X.509 RSA public/private key pair.
So far, I have something which I think will work for encryption, but I have no way
It seems your private key is encrypted (openssl asked you for a password on the command line), yet you do not decrypt it when you try to open it. Besides, private_key.pem is an RSA key, not a certificate, so you should use PEM_read_RSAPrivateKey.
The following decoding code should work:
int pass_cb(char *buf, int size, int rwflag, void* password) {
snprintf(buf, size, "%s", (char*) password);
return strlen(buf);
}
+(void)readTest{
FILE *fp;
RSA *x;
NSString *path =[[NSBundle mainBundle] pathForResource:@"private_key" ofType:@"pem"];
fp=fopen([path UTF8String],"r");
x = PEM_read_RSAPrivateKey(fp,&x,pass_cb,"key password");
if (x == NULL) {
NSLog(@"Cant Read File"); // This ALWAYS fires
}
fclose(fp);
X509_free(x);
}
Alternatively, you could generate a non-encrypted key. Pass -nodes
to openssl when creating the keys and the certificate.
Please note that you might need to make sure OpenSSL is properly initialized with:
SSL_library_init();
OpenSSL_add_all_algorithms();
Besides, OpenSSL generates error messages that could help you through development. You load the error strings with:
SSL_load_error_strings();
And you could call:
ERR_print_errors_fp(stderr);
OpenSSL is not the only solution as Security framework on iOS contains everything you need. I guess you turned to OpenSSL because you did not know how to convert your private key file to valid parameters for SecKeyDecrypt.
The trick is to produce a PKCS#12 file and to call SecPKCS12Import
.
You can produce this file with OpenSSL:
openssl x509 -inform der -outform pem -in public_key.der -out public_key.pem
openssl pkcs12 -export -in public_key.pem -inkey private_key.pem -out private_key.p12
This will ask you for an export password. This password should be passed to SecPKCS12Import ("key password"
below).
NSString *privateKeyPath = [[NSBundle mainBundle] pathForResource:@"private_key" ofType:@"p12"];
NSData *pkcs12key = [NSData dataWithContentsOfFile:privateKeyPath];
NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys: @"key password", kSecImportExportPassphrase, nil];
CFArrayRef importedItems = NULL;
OSStatus returnCode = SecPKCS12Import(
(__bridge CFDataRef) pkcs12key,
(__bridge CFDictionaryRef) options,
&importedItems
);
importedItems
is an array containing all imported PKCS12 items, and basically, the "identity" (private key + certificate).
NSDictionary* item = (NSDictionary*) CFArrayGetValueAtIndex(importedItems, 0);
SecIdentityRef identity = (__bridge SecIdentityRef) [item objectForKey:(__bridge NSString *) kSecImportItemIdentity];
SecKeyRef privateKeyRef;
SecIdentityCopyPrivateKey(identity, &privateKeyRef);
Then you can use privateKeyRef to perform the decryption with SecKeyDecrypt
. To match your encryption routine:
size_t cipherLen = [content length];
void *cipher = malloc(cipherLen);
[content getBytes:cipher length:cipherLen];
size_t plainLen = SecKeyGetBlockSize(privateKeyRef) - 12;
void *plain = malloc(plainLen);
OSStatus decryptReturnCode = SecKeyDecrypt(privateKeyRef, kSecPaddingPKCS1, cipher, cipherLen, plain, &plainLen);