Introducing CryptoKit | raywenderlich.com

Cryptography is key to protecting your users’ data. This tutorial shows you how to use Apple’s new CryptoKit API to authenticate or encrypt your app’s data.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/10846296-introducing-cryptokit

Hey Audrey, I am wondering how this site (https://codebeautify.org/hmac-generator) generate HMAC?

hi James! it lets you choose from a long list of coding algorithms and you have to provide a key. You can look up many of those algorithms on wikipedia if you want to know more details.

Great article Audrey! Thank you.
Do you know if there is any agreement on what level of security is typically considered compliant with HIPAA in the US? Does CryptoKit meet those standards?

hi Kurt! if you’re making an app that collects health data, you should probably check with a lawyer. Apple has some requirements around HealthKit too.

For data encryption, I can’t see how you can go wrong if you use the NSA stuff, which is all covered in CryptoKit, and is the only private key you can create in Secure Enclave.

You should also make sure to secure any servers as much as possible, to keep the backend data safe.

Hi Audrey, thank you very much for the great article.
Do I need to use “Curve25519” symmetric key for encryption if I’m already using “ChaChaPoly” ?
“ChaChaPoly”+combined seems to be producing different encryption values every time I build the project. How can I test with the other endpoint(which is the API) ?

Hi Onur! ChaChaPoly generates an initialisation value / nonce every time you use it, so the encrypted value will be different each time.

If you don’t have a way to send/receive the secret key you use for ChaChaPoly, you would create a symmetric key from your private key and the API’s public key, and use that for encryption.

The API should have some response codes that indicate whether it could open your sealed box.

Hi Audrey,
Thank you very much for the great article.
I tried to launch the app on my phone but I get the following error:
Error Domain=NSCocoaErrorDomain Code=260 "The file “Secrets.enc” couldn’t be opened because there is no such file."

I tried to find out what is happening but it seems that there is no such file, also I don’t see it in your article. Is it an issue on my side or how can I fix it?
Greetings,
Dakata

hi Dakata! There’s actually a secrets.enc file in the starter project but I think that shouldn’t be there. In ContentView.swift, there’s this modifier:

.onAppear {
  self.initHorcruxes()
  self.readFile()
  self.writeFile(items: self.horcruxes)
}

Comment out the readFile() line the first time you run this. Then it will write the secrets file. Now comment out initHorcruxes() and uncomment readFile() and run it on your phone.

The app doesn’t do anything except show off the artwork. You could add the baby image as Harry, for completeness :wink:

Thank you very much for the clarification.
I have one more question. In the " Creating a Symmetric Key for Encryption" section, you show how to create the public/private key pair with these 2 lines:

let harryPrivateKey = Curve25519.KeyAgreement.PrivateKey()
let harryPublicKeyData = harryPrivateKey.publicKey.rawRepresentation

In the very next paragraph you have another constant which generates Harry’s Public key:

let harryPublicKey = try! Curve25519.KeyAgreement.PublicKey(
  rawRepresentation: harryPublicKeyData)

My question is, what is the difference between let harryPublicKeyDat and let harryPublicKey. They should contain the same value, right? Is it necessary to write the (try! Curve25519.KeyAgreement.PublicKey) or you are using it in order to catch an error if the key is a nil?

hi Dakata! this is just the procedure you have to follow to get the symmetric key. The PublicKey initializer needs the rawRepresentation form. It throws an error if it can’t create a public key.

If you think there really might be an error, you would use do { ... try ... } catch. You use try! when you’re pretty sure there won’t be an error to catch.

Hi again Audrey and happy new year!
I wanted to ask you, which cryptokit feature should I use when I have to secure messages between 2 or more devices. I want to establish multi-party key agreement by exchanging the public keys of the participants, but I am realising now that this works only for 2 people, like in your example. If I want to include 3 or more people, I can’t create a shared symmetric key. So how can I create a secure environment between more than 2 people?

1 Like

Thank you for the awesome article Audrey! One question I had was whether the “sealedBox” api is appropriate for encrypting data at rest, or if it’s just for encrypting data in transit?

hi Scott, for data at rest, you can use the Data Protection API, see the section Protecting Users’ Data

sealed box is needed when you’ve got two participants who need shared knowledge of the key

1 Like

hi Dakota! the central user can use public key to transmit the symmetric key to new users. Or any user can transmit the symmetric key to a new user they invite.

Hi Audrey, generating a SymmetricKey object is a simple one-liner. But how to store this key for later use? There must be a way to convert the SymmetricKey to Data so it can be stored in a keychain or a private file. Then later I would need to recreate the SymmetricKey from this stored data.

hi Mike, there’s something in Apple’s documentation Apple Developer Documentation

extension SymmetricKey: GenericPasswordConvertible creates a rawRepresentation.

Found the answer. For anyone interested, here is a code gist that shows how to encrypt/decrypt with a symmetric key which is saved and restored.

// Encrypt
let key256 = SymmetricKey (size: .bits256 )
let msg = "here is a test message"
let data = msg.data(using: .ascii)!
let sealedBoxData = try! ChaChaPoly .seal (data, using: key256).combined

// Save the key
let savedKey = key256.withUnsafeBytes {Data (Array ($0)).base64EncodedString ()}

// Restore the key from storage
let keyData = Data(base64Encoded: savedKey)!
let retrievedKey = SymmetricKey(data: keyData)

// Decrypt
let sealedBox = try! ChaChaPoly.SealedBox(combined: sealedBoxData)
let decryptedData = try! ChaChaPoly.open(sealedBox, using: retrievedKey)
let msg2 = String(data: decryptedData, encoding: .ascii)

1 Like

Hi Audrey!

Thanks for the detailed article.
I’m following this for my project. But I need to export the public key in PEM format. The base 64 of the data representation doesn’t seem to look like a PEM encoding. Can you please tell how do I create the PEM for a Curve25519 public key? Thanks in advance!

hi Anna! I found an Apple forum discussion from 3 years ago, pre-CryptoKit

Quinn “The Eskimo!” confirms the OP’s statement:

I’m lead to beleive that simply base64 encoding to a string the output of SecKeyCopyExternalRepresentation is all that is required to export the public key in PEM format (without

BEGIN RSA PUBLIC KEY

and

END RSA PUBLIC KEY

)

also scroll down to a follow-up from eskimo, with a link to some old cryptography code:

ps If you haven’t already looked at the CryptoCompatibility sample code, you should. It shows how to do various crypto transforms such the results exactly match other crypto toolkits, including OpenSSL.