Question

Since openssl is deprecated in osx 10.7+, I'd like to switch from openssl to the internal osx keychain and crypto function.

But now I am stuck on asymmetric encryption/decryption.

How can I do encryption/decryption of a randomly generated symmetric key with a asymmetric (RSA) key. With openssl it's quite easy.

In the apple dev docs, they say that CommonCrypto supports asymmetric encryption, but while checking the headers, I can only see support for symmetric stuff.

Any hints?

Was it helpful?

Solution

Take a look at Cryptographic Message Syntax Services and see if that can do what you need.

Also, you're misreading the OpenSSL thing just a bit. The OpenSSL libraries that ship with the OS are deprecated. That doesn't mean you can't continue to use OpenSSL. OpenSSL is Open Source, and there's nothing stopping you from downloading it and using it freely in your application.

Apple's deprecation just means that if you use OpenSSL, you need to include your own copy of the OpenSSL libraries so that you are responsible for keeping your OpenSSL library up-to-date and for fixing any breakage that occurs whenever you do so. :-)

And if not, the iOS asymmetric encryption and decryption functions (SecKeyEncrypt and SecKeyDecrypt) do exist in OS X, and the iOS header even shows that they are available in OS X. I'm not sure why they aren't in the OS X SDK. I filed a bug, and it was marked as a dup.

It probably would not be possible for Apple to remove those functions in the future without breaking the Simulator, but if you're submitting to the app store and they give you grief about using them, here's a roughly compatible replacement for SecKeyEncrypt built using the Security Transforms API:

// Workaround for SecKeyEncrypt not really being public API in OS X
OSStatus OSXSecKeyEncrypt ( SecKeyRef key, SecPadding padding, const uint8_t *plainText, size_t plainTextLen, uint8_t *cipherText, size_t *cipherTextLen )
{
    CFMutableDictionaryRef parameters = CFDictionaryCreateMutable(
                                                                  kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
                                                                  &kCFTypeDictionaryValueCallBacks);
    CFDictionarySetValue(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES);
    CFErrorRef error = NULL;
    SecTransformRef encrypt = SecEncryptTransformCreate(key, &error);

    if (error) {
        AFNSLog(@"Encryption failed: %@\n", (__bridge NSError *)error);
        return (OSStatus)[(__bridge NSError *)error code];
    }

    SecTransformSetAttribute(
                             encrypt,
                             kSecPaddingKey,
                             NULL, // kSecPaddingPKCS1Key (rdar://13661366 : NULL means kSecPaddingPKCS1Key and
                                                                          // kSecPaddingPKCS1Key fails horribly)
                             &error);

    CFDataRef sourceData = CFDataCreate(kCFAllocatorDefault, plainText, plainTextLen);
    SecTransformSetAttribute(encrypt, kSecTransformInputAttributeName,
                             sourceData, &error);

    CFDataRef encryptedData = SecTransformExecute(encrypt, &error);
    if (error) {
        AFNSLog(@"Encryption failed: %@\n", (__bridge NSError *)error);
        return (OSStatus)[(__bridge NSError *)error code];
    }

    if ((unsigned long)CFDataGetLength(encryptedData) > *cipherTextLen) {
        return errSecBufferTooSmall;
    }
    *cipherTextLen = CFDataGetLength(encryptedData);
    CFDataGetBytes(encryptedData, CFRangeMake(0, *cipherTextLen), cipherText);

    return noErr;
}

You should be able to adapt the code for decryption fairly easily; I didn't need it for my purposes, so I didn't write that function.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top