Asymmetric Encryption with the iPhone SDK and Security.framework
As a complement to my post on symmetric encryption, here's an example of asymmetric encryption using the RSA algorithm. As before, it's based on the limited sample code I could find, but fleshed out to actually work. Check here for a little more background info. Any and all comments and criticisms are welcome. It's been a long time since I've worked in C (and even then I didn't enjoy it!). So if I could be doing anything better, let me know!
const size_t BUFFER_SIZE = 64;
const size_t CIPHER_BUFFER_SIZE = 1024;
const uint32_t PADDING = kSecPaddingNone;
- (void)testAsymmetricEncryptionAndDecryption {
uint8_t *plainBuffer;
uint8_t *cipherBuffer;
uint8_t *decryptedBuffer;
const char inputString[] = "this is a test. this is only a test. please remain calm.";
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:
* http://developer.apple.com/DOCUMENTATION/Security/Conceptual/CertKeyTrus...
*/
- (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 = %d", SecKeyGetBlockSize([self getPublicKeyRef]));
// Error handling
// Encrypt using the public.
status = SecKeyEncrypt([self getPublicKeyRef],
PADDING,
plainBuffer,
plainBufferSize,
&cipherBuffer[0],
&cipherBufferSize
);
NSLog(@"encryption result code: %d (size: %d)", 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: %d", BUFFER_SIZE);
NSLog(@"decryptWithPrivateKey: length of input: %d", cipherBufferSize);
// DECRYPTION
size_t plainBufferSize = BUFFER_SIZE;
// Error handling
status = SecKeyDecrypt([self getPrivateKeyRef],
PADDING,
&cipherBuffer[0],
cipherBufferSize,
&plainBuffer[0],
&plainBufferSize
);
NSLog(@"decryption result code: %d (size: %d)", status, plainBufferSize);
NSLog(@"FINAL decrypted text: %s", plainBuffer);
}
- (SecKeyRef)getPublicKeyRef {
OSStatus resultCode = noErr;
SecKeyRef publicKeyReference = NULL;
if(publicKey == NULL) {
NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];
// Set the public key query dictionary.
[queryPublicKey setObject:(id)kSecClassKey forKey:(id)kSecClass];
[queryPublicKey setObject:publicTag forKey:(id)kSecAttrApplicationTag];
[queryPublicKey setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef];
// Get the key.
resultCode = SecItemCopyMatching((CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKeyReference);
NSLog(@"getPublicKey: result code: %d", resultCode);
if(resultCode != noErr)
{
publicKeyReference = NULL;
}
[queryPublicKey release];
} else {
publicKeyReference = publicKey;
}
return publicKeyReference;
}
- (SecKeyRef)getPrivateKeyRef {
OSStatus resultCode = noErr;
SecKeyRef privateKeyReference = NULL;
if(privateKey == NULL) {
NSMutableDictionary * queryPrivateKey = [[NSMutableDictionary alloc] init];
// Set the private key query dictionary.
[queryPrivateKey setObject:(id)kSecClassKey forKey:(id)kSecClass];
[queryPrivateKey setObject:privateTag forKey:(id)kSecAttrApplicationTag];
[queryPrivateKey setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
[queryPrivateKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef];
// Get the key.
resultCode = SecItemCopyMatching((CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKeyReference);
NSLog(@"getPrivateKey: result code: %d", resultCode);
if(resultCode != noErr)
{
privateKeyReference = NULL;
}
[queryPrivateKey release];
} else {
privateKeyReference = privateKey;
}
return privateKeyReference;
}













