3 Replies
      Latest reply: Oct 5, 2016 1:40 AM by eskimo RSS
      lsauceda Level 1 Level 1 (0 points)

        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 useSecKeyEncrypt 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 CFErrorRefs 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.

        • Re: Asymmetric Encryption macOS
          eskimo Apple Staff Apple Staff (6,015 points)

          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"

            • Re: Asymmetric Encryption macOS
              lsauceda Level 1 Level 1 (0 points)

              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.

                • Re: Asymmetric Encryption macOS
                  eskimo Apple Staff Apple Staff (6,015 points)

                  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;
                      }
                  }