Asymmetric Encryption macOS

I have a homework in which I need to create an App that encrypts and decrypts some text. It's nothing too fancy, but I do need to use both symetric and asymmetric encryption (for key sharing). I can't find how to do either of them. First I tried to do asymmetric using the Certificate, Key, and Trust Services API, but found that

SecKeyEncrypt
and
SecKeyDecrypt
are not available in OS X.


I tried with the Security Tranforms API, but its documentation says it works only with symmetric encryption. Yet in this other question the person who answered states that it is possible to use asymetric encryption, so I thought I should just pass an RSA key to a

SecKeyEncryptTransform
but that didn't work.


Also according to a WWDC session they have unified SecKey it across iOS and macOS APIs, I thought that means you can now use

SecKeyEncrypt
in macOS but it is not the case, so first I should ask what is the unification about then?


I then tried starting with the symetric part, yet I still can't figure it out, the app just has a an NSTextField and a button that will either encrypt or decrypt the text in it. I do that like this

//Action for encrypt button press
- (IBAction)buttonPress:(NSButton *)sender {
    [[self button] setTitle:[self isEncrytped] ? @"Encrypt" : @"Decrypt"];
    [[self text] setEditable:[self isEncrypted]];

    if (self.isEncrypted) {
        [self encrypt];
    } else {
        [self decrypt];
    }

    self.isEncrypted = ![self isEncrypted];
}
- (void)encrypt {
    CFErrorRef error = NULL;

    NSData* data = [[[self text] stringValue] dataUsingEncoding:NSUTF8StringEncoding];
    SecTransformRef encrypt = SecEncryptTransformCreate([self key], &error);

    if (error) {
        CFShow(error);
    }

    SecTransformSetAttribute(encrypt, kSecTransformInputAttributeName, (__bridge CFTypeRef _Nonnull)(data), NULL);
    if (error) {
        CFShow(error);
    }

    data = SecTransformExecute(encrypt, &error);
    if (error) {
        CFShow(error);
    }
}
- (void)decrypt {
    CFErrorRef error = NULL;

    SecTransformRef decrypt = SecDecryptTransformCreate([self key], &error);
    if (error) {
        CFShow(error);
    }

    SecTransformSetAttribute(decrypt, kSecTransformInputAttributeName, [self data], &error);

    if (error) {
        CFShow(error);
    }

    self.data = SecTransformExecute(decrypt, &error);

    if (error) {
        CFShow(error);
    }
}


It just keeps crashing for some reason, also the errors are useless as they don't even get to execute.


So in short my question is how to do asymmetric encription in OS X, and additionally why doing symmetric encryption crashes?


Update

So I finally got the

CFErrorRef
s to work (not sure how: I just reopened Xcode) and this is what I got:
Error Domain=com.apple.security.transforms.error Code=14
"Can not execute ILEFCMMMU-Decrypt Transform, missing required attributes: INPUT"
UserInfo={NSDescription=Can not execute ILEFCMMMU-Decrypt Transform, missing required attributes: INPUT}

I am not sure why It says

ILEFCMMMU-Decrypt Transform
if I am using an encrypt transform not decrypt (yes I double checked that).

And for decrypting it just crashes.

Update 2

I found out my encrypt and decrypt calls where flipped, so I was trying to encrypt when it was encrypted and decrypt when it was decrypted. That explains the message in update 1, but not it crashes when I try to encrypt. I tracked the error down and found out

SecTransformExecute
is where the crash occurs, it appears that my cast to
NSData
or something is wrong because using
CFStringRef string = (__bridge CFStringRef)([[self texto] stringValue]);
...
SecTransformSetAttribute(encriptar, kSecTransformInputAttributeName, string, NULL);

doesn't crash, but now the Text Field is replaced with an empty string.

Replies

The best place to start here is the CryptoCompatibility sample code. It shows how to do both symmetric encryption (via Common Crypto) and asymmetric encryption (via SecKey on iOS and SecTransform on macOS).

I’m working on an update that uses the new unified crypto API but, alas, it’s not yet on the developer web site. The old APIs still work on the new OS releases so, for the moment, it’s probably best to use them.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for that, it turns out I just needed to encode the data returned by the transformation (because I want to show the replaced string).


As for asymmetric: you just pass the public key and it will do all the work, maybe the documentation should be modified as it makes you believe otherwise.


Either way i'd really like to see how the unified API works, so I hope you can update the sample soon.

Either way i'd really like to see how the unified API works, so I hope you can update the sample soon.

The unified API fits really neatly into the CryptoCompatibility architecture. Pasted in below is the core of my new QCCRSASmallCryptor operation, which has the same structure as the equivalently named operation in the current sample but uses the unified API.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
- (void)runUsingUnified {
    CFErrorRef          errorCF = NULL;    // Security framework seems to be grumpy if errorCF left uninitialised
    SecKeyAlgorithm    algorithm;
    NSData *            resultData;

    // Map our padding constant appropriately.

    switch (self.padding) {
        default:
            assert(NO);
            // fall through
        case QCCRSASmallCryptorPaddingPKCS1: {
            algorithm = kSecKeyAlgorithmRSAEncryptionPKCS1;
        } break;
        case QCCRSASmallCryptorPaddinOAEP: {
            algorithm = kSecKeyAlgorithmRSAEncryptionOAEPSHA1;
        } break;
    }

    // Do the crypto.

    switch (self.op) {
        default:
            assert(NO);
            // fall through
        case QCCRSASmallCryptorOperationEncrypt: {
            resultData = CFBridgingRelease( SecKeyCreateEncryptedData(
                self.key,
                algorithm,
                (__bridge CFDataRef) self.smallInputData,
                &errorCF
            ) );
        } break;
        case QCCRSASmallCryptorOperationDecrypt: {
            resultData = CFBridgingRelease( SecKeyCreateDecryptedData(
                self.key,
                algorithm,
                (__bridge CFDataRef) self.smallInputData,
                &errorCF
            ) );
        } break;
    }

    // Set up the result.

    if (resultData == nil) {
        self.error = CFBridgingRelease( errorCF );
    } else {
        self.smallOutputData = resultData;
    }
}