1

I'm creating an iPhone Objective-C app that uses secure communication between a server and a client. The protocol I want to follow goes like this:

  1. The client is compiled and distributed with the Server's Public RSA key (hardcoded). Let's call this Kspub. (For Key Server Public)

  2. The client generates an random AES key. Let's call this key Kcaes (for Key Client AES)

  3. The client encrypts Kcaes using Kspub, and produces the encrypted text: Kspub(Kcaes)

  4. The client sends Kspub(Kcaes) to the server.

  5. The server decrypts Kspub(Kcaes) using the server's private key, Kspri. This recovers Kcaes. Now the client and the server both share a common AES key, Kcaes.

  6. To verify this, the server encrypts Kcaes USING Kcaes. This produces encrypted text Kcaes(Kcaes).

  7. The server sends Kcaes(Kcaes) to the client.

  8. The client decrypts Kcaes(Kcaes) using the Kcaes key. This produces Kcaes. If this matches the original Kcaes, then the client knows it has established a secure connection.

  9. The client and server can now securely exchange information using symmetrical key Kcaes.

I have already implemented server-side and client-side key generation, encryption, and decryption methods. Currently, keypairs generated on the iPhone are being stored in it's keychain. Here's the issue:

I cannot seem to find a method in Apple's Keychain or Security API to import a Public RSA key from a text file. How can I import a key through a text file and store it in a SecKeyRef object?

Thanks!

Thor Correia
  • 1,528
  • 3
  • 23
  • 30

2 Answers2

0

You do this via SecItemAdd, passing:

A dictionary containing an item class key-value pair (Keychain Item Class Keys and Values) and optional attribute key-value pairs (Attribute Item Keys and Values) specifying the item's attribute values.

OSStatus err = SecItemAdd((CFDictionaryRef)
    [NSDictionary dictionaryWithObjectsAndKeys:
     (id)kSecClassKey,         kSecClass,
     kSecAttrKeyTypeRSA,       kSecAttrKeyType,
     keyTagUTF8,               kSecAttrApplicationTag,
     kSecAttrKeyClassPrivate,  kSecAttrKeyClass, 
     keyData,                  kSecValueData,
     nil],
 NULL);

Ensure that the attributes to store and retrieve match exactly.

SwiftArchitect
  • 47,376
  • 28
  • 140
  • 179
  • I suppose kSecValueData would be an NSData object representing the public key (after converting from Base64 and stripping the header)? – Thor Correia Jul 15 '15 at 07:44
  • Clarification: the data (keyData) shall be in DER-encoded ASN.1. I suspect that `encoding:NSUTF8StringEncoding` may work as well. Not verified. – SwiftArchitect Jul 15 '15 at 08:05
0

SecKeyCreateWithData will accept RSA data in PKCS#1 as well as the x509 public key format.

Because the question mentions a text as opposed to binary file I'll assume the public key is in the standard PEM format. First you'd strip the PEM headers and new lines:

NSMutableString *pemString = [textFileString mutableCopy];
[pemString replaceOccurrencesOfString:@"-----BEGIN PUBLIC KEY-----" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [pemString length])];
[pemString replaceOccurrencesOfString:@"-----END PUBLIC KEY-----" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [pemString length])];
[pemString replaceOccurrencesOfString:@"\n" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [pemString length])];

Now you're left with a Base64 string which you can decode into binary data. I want to point out that Apple's native Base64 methods are not tolerant of padding issues and other standards.

CFDataRef data = (__bridge CFDataRef) [NSData dataWithBase64EncodedString... // Your preferred base64 method here

Now you can get the SecKeyRef via SecKeyCreateWithData.

if (data)
{
    CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    if (dictionary)
    {
        CFDictionarySetValue(dictionary, kSecAttrKeyClass, kSecAttrKeyClassPublic);
        CFDictionarySetValue(dictionary, kSecAttrIsPermanent, kCFBooleanFalse);
        CFDictionarySetValue(dictionary, kSecAttrKeyType, kSecAttrKeyTypeRSA);
        CFErrorRef error = NULL;
        SecKeyRef publicKey = SecKeyCreateWithData(data, dictionary, &error);
        if (publicKey)
        {
            if (error)
            {
                CFShow(error);
                CFRelease(error);
            }
            //...
            CFRelease(publicKey);
        }
        CFRelease(dictionary);
    }
}

From here you can either keep the reference around, or decide to save it in the keychain via SecItemAdd etc.

NSDestr0yer
  • 1,419
  • 16
  • 20