3 Replies
      Latest reply on May 29, 2020 7:21 PM by Liberty 456
      Liberty 456 Level 1 Level 1 (0 points)

        Hi, I'd like to offer my users the option to save an encrypted backup of their data, from CoreData, to a place of their choosing. Just a textfile with the data in json format. How I envisage it is that they will click the backup button, a popup will ask them to input a password, then they'll save the outputted file somewhere. I don't know how to implement this. I've been playing around with CryptoKit in a playground, but tutorials seem few and far between. What is available isn't geared towards explaining how to do what I want to do. Does anyone know of a resource or tutorial that could help me learn to implement this feature? Any help much appreciated.

        • Re: Encrypted backup
          eskimo Apple Staff Apple Staff (13,905 points)

          The droid you’re looking for here is AES.GCM.SealedBox.  This will take data and encrypt it using AES-GCM, our recommended form of symmetric encryption (critically, it’s authenticated encryption).

          The encryption key is represented by a SymmetricKey value.  Unfortunately there is no easy way to derive this directly from a password.  The standard way to do this, PBKDF2, isn’t supported in Apple CryptoKit (r. 51744434).

          This means you have to use CommonCrypto to do the key derivation.  This is a lot less pleasant than CryptoKit.  To get you started I’ve pasted in a wrapper below.

          IMPORTANT Make sure you supply salt and choose the rounds wisely.  See the Wikipedia article for some advice on that front.

          Also, there are better key derivation algorithms you might use for this problem — things like scrypt — but none of those have APIs in the Apple SDKs.  You might want to look into third-party implementations.

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"


          func pbkdf2SHA256Key(size: Int, from password: String, salt: Data, rounds: Int) throws -> Data {
              precondition(size != 0)         // Otherwise `baseAddress` could be `nil`.
              let rounds32 = UInt32(rounds)   // We trap if you ask for way too many.
              return try password.withCString { passwordPtr in
                  return try salt.withUnsafeBytes { saltBuf in
                      var output = [UInt8](repeating: 0, count: size)
                      let err = CCKeyDerivationPBKDF(
                          CCPBKDFAlgorithm(kCCPBKDF2),
                          passwordPtr, strlen(passwordPtr),
                          saltBuf.baseAddress!.assumingMemoryBound(to: UInt8.self),
                          saltBuf.count,
                          CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256),
                          rounds32,
                          &output, output.count
                      )
                      guard err == 0 else {
                          throw NSError(domain: NSOSStatusErrorDomain, code: Int(err), userInfo: nil)
                      }
                      return Data(output)
                  }
              }
          }
            • Re: Encrypted backup
              Liberty 456 Level 1 Level 1 (0 points)

              Thanks heaps, Eskimo.

              I'll take a look at it all and see if I can nut it out. I'm very much a novice, so I may have some more questions after I've tackled what you've given me.

              Cheers



              • Re: Encrypted backup
                Liberty 456 Level 1 Level 1 (0 points)

                I think I've got the logic of it now. Because I'm a bit slow, could you please correct me if I have this wrong.

                1. A key is derived from a password.
                2. It's used to encrypt the textfile.

                3. It can then be gotten rid of, because when it comes to decryption the same key will be derived from password input again and used to decrypt the file?


                Or perhaps a different key is always generated, in which case 1, 2, and 3 combined would not work?