iOS Security Tutorial — Part 1

Fady Derias
5 min readOct 24, 2019

--

Thanks to drawkit.io for the nice illustration

On March 25th 2019, Apple announced its new consumer U.S. credit card issued by Goldman Sachs “Apple Card”. They pointed out that for every Apple Card, there’s a unique per device card number that is created and stored safely in the device’s secure element & that every purchase is authenticated with Touch ID or Face ID.

The purpose of this tutorial is to further elaborate what is the iOS device’s secure element Apple pointed out during their new Card announcement and how developers can utilize it for purposes that have to do with their applications.

First, let’s go through some base concepts to establish the purpose of this tutorial.

Symmetric and Asymmetric Encryption

Generally, encryption is some way to conceal messages between two parties to prevent unauthorized access to these messages. In other words, consider you’re sending a message to a friend and you don’t want an outsider to read that message, so you scramble it in some way that only both of you and your friend know how to read/decipher it.

One way to conceal that message is for the sender to add a password to it and provide the receiver with that password. This happens to be of certain threat because there’s a high chance that whatever method the sender uses to send the password to the receiver, it’s going to be compromised. This method is called Symmetric Encryption and proved to be inefficient and for that Asymmetric Encryption was introduced.

Asymmetric encryption mainly relies on cryptographic keys. “In cryptography, a key is a string of characters used within an encryption algorithm for altering data so that it appears random. Like a physical key, it locks (encrypts) data so that only someone with the right key can unlock (decrypt) it.”

In Asymmetric Encryption, both the sender and the receiver, have a key pair. That is a public key and a private key. Both parties share their public keys to one another and keep the private key only a secret to themselves. Whenever the sender (A) wants to send a message to the receiver (B), (A) encrypts the message using (B)’s public key, and for (B) to read the message, they have to decrypt the message using their very own secret private key.

A key pair can be generated using numerous cryptography algorithms (RSA algorithm, ECC algorithm .. etc). As a result, both generated keys are linked together but still can’t be derived from each other.

Asymmetric Encryption in Swift

For asymmetric encryption in iOS, here are the requires steps :

  1. Create an attributes dictionary that would define the specifications of the asymmetric key pair to be generated. Specifications like the keys’ size in bits and the algorithm used to generate the pair. These specifications are defined via dedicated iOS Security “Key generation attributes”.
  2. Passing the attributes dictionary to a dedicated Swift API to generate both the public and private keys.
  3. Encrypting a message using the public key.
  4. Decrypting the message using the private key.

Let’s get ourselves coding.

Attributes Dictionary

The attributes dictionary define properties for both the public and private keys. It’s done over two steps.

The first step is to create a Dictionary object that will act as a sub-dictionary in the main attributes dictionary. It defines the specifications of the private key.

let privateKeyTag = “com.security.tutorial”.data(using: .utf8)!let privateKeyParams: [String: Any] = [kSecAttrCanDecrypt as String: true,kSecAttrIsPermanent as String: true,kSecAttrApplicationTag as String: privateKeyTag]
  • kSecAttrCanDecrypt: A key whose value indicates that the cryptographic private key can be used for decryption.
  • kSecAttrIsPermanent: A key whose value is a boolean. If true, it indicates that the cryptographic key should be stored in the default keychain at creation time.
  • kSecAttrApplicationTag: A key whose value is an attribute with a unique NSData value so that you can find and retrieve the private key later on from the key chain. It’s constructed from a string and preferable to be in reverse DNS notation.

The second step is to create the main attributes dictionary object.

let attributes = 
[kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits as String: 256,kSecPrivateKeyAttrs as String:privateKeyParams] as CFDictionary
  • kSecAttrKeyType: A key whose value indicates the type of cryptography algorithm used to produce the key pair (public and private keys). Set to elliptic curve algorithm (ECC).
  • kSecAttrKeySizeInBits: A key whose value indicates the size of the generated key pair. Set to 256 bits.
  • kSecPrivateKeyAttrs: A key whose value is set to the created sub-dictionary that does contain the specifications of the private key.

2. Key Pair Generation

The first thing to do is to create two variable objects of type “SecKey” to hold references to the generated key pair (public key and private key).

//Variables to store both the public and private keys.
var publicKeySec, privateKeySec: SecKey?
Second thing is to call the SecKeyGeneratePair API to generate the public and private keys using the created attributes dictionary.//Generating both the public and private keys via the SecGeneratePair APIs.SecKeyGeneratePair(attributes, &publicKeySec, &privateKeySec)

3. Encryption

Let’s assume the message to be encrypted is a credit card number string.

let message = “4043 1710 2843 4577” //1guard let messageData = message.data(using: String.Encoding.utf8) else {print(“Bad message to encrypt”)} //2guard let encryptData = SecKeyCreateEncryptedData(publicKey,SecKeyAlgorithm.eciesEncryptionStandardX963SHA256AESGCM,messageData as CFData,nil) else {print(“Encryption Error”)}

The steps for generating an encrypted string are as follows:-

  1. Set/Get the message to be encrypted.
  2. Set the message to be of type Data.
  3. Utilize the SecKeyCreateEncryptedData security API to encrypt the message data. You pass public key and the encryption algorithm (SecKeyAlgorithm) for it to be utilized.

4. Decryption

guard let messageData = Data(base64Encoded: encryptedString, options: []) else {
print(“Bad message to decrypt”)
return nil} //1guard let decryptData = SecKeyCreateDecryptedData(privateKey,SecKeyAlgorithm.eciesEncryptionStandardX963SHA256AESGCM,messageData as CFData,nil) else {print(“Decryption Error”)return nil} //2let decryptedData = decryptData as Dataguardlet decryptedString = String(data: decryptedData, encoding: String.Encoding.utf8) else {print(“Error retrieving string”)}

The steps for decrypting an encrypted string are as follows:

  1. Get the encrypted message string & transform the encrypted message to be of type Data.
  2. Utilize the SecKeyCreateDecryptedData security API to decrypt the encrypted message data. You pass to it the created private key and the encryption algorithm (SecKeyAlgorithm) used before for encryption
  3. You can transform the data back to a string and print it

Where to go?

Check out the second and final part of this tutorial to learn about Digital signature and verification and how to achieve it through the ios devices’ secure enclave.

--

--