Cyber Security is not the first thing that comes to mind when starting development of a new application. However there are cases where it is vital. I think it is important for every developer to be aware of at least the basic concepts, such as asymmetric encryption and digital signing.

In this post I will first introduce the necessary theory and then practical implementations and real life use cases of cryptography. While the theory will be general and applicable to all kinds of applications, practical examples will be shown using the Swift programming language. I will present how to

  • access an application’s local keychain and securely store information in it;
  • generate an asymmetric key-pair of public and private keys both using computer tools and programmatically
  • install a global root certificate on your device

Theory

In this section I will define all the terms that will be used later on. I will assume no prior knowledge of cyber security and cryptography and start with the most basic definitions. I will however skip technical and mathematical details and keep explanations as brief as possible, as to explain basics of cryptography in a single post is not possible. I want you to have a general idea of what is going on and understand the concepts. I will provide sources for those interested in details.

  • Encryption – the process of changing a plaintext message m into an encrypted ciphertext c in such a way, that c is completely unreadable and can be converted back to m only by sender and recipient.
  • Decryption – the process of converting encrypted ciphertext c back into readable plaintext message m. This should only be doable by sender and recipient of message.
  • Key – an object k, usually in a form of a string of bytes, that is used in the process of encryption and decryption
  • Symmetric cryptography – a single secret key k is generated by creator of message m and distributed over a secure channel to all potential recipients. This key is used both to encrypt and decrypt messages
  • Asymmetric cryptography – a pair of keys – public key k_pu and private key k_pr – is generated by anyone who wants to participate in secure communication. k_pu is publicly available, anyone can get access to it. k_pr is secret and known only by its creator. When sending a message m to someone their k_pu is used to encrypt it and when they receive it they use their k_pr to decrypt it.
  • Digital signature – the process of validating the identity of message sender utilising asymmetric cryptography. A sender generates signature s by encrypting m with k_pr and attaches it to m. Then, a recipient can decrypt s with k_pu to check if it was really sent by the original sender. The validity of this process is ensured by the fact, that only the original sender has access to k_pr and it is kept in secret, so no one else could have signed the message.
  • Digital certificate – a piece of information that allows the owner (person, company, organisation etc.) to validate its identity and securely exchange information over the Internet. For a certificate to be valid and trusted it must be digitally signed by another certificate that is already trusted.
  • Root certificate  – a certificate that is universally trusted but not signed by another certificate and is instead signed by itself. It is always at the top of certificate chain. These certificates are usually owned by large and well known companies and are by default built into modern operating systems and Internet browsers.
  • Chain of trust  – a chain of signed certificates that ends in a Root certificate.
  • Certificate Authority (CA) – an entity that issues digital certificates and operates as trusted third party. When requesting a certificate that would validate your identity you must prove, that you are in fact owner of that identity (for example when requesting a digital certificate that would validate Facebook’s identity you must prove that you are owner of Facebook). The existence of CAs ensures, that certificates are valid form of identification.
  • Client certificate – a type of digital certificate used to authenticate communication with a server.

For more detailed descriptions you can refer to these free online sources:

  • Dan Boneh, Victor Shoup A Graduate Course in Applied Cryptography, 17.08.2015, Stanford, link [last accessed 13.03.2019]
  • Laurens van Houtven Crypto 101, 2013, link [last accessed 13.03.2019]

Practical implementation

Now that you understand the most basic concepts of modern cryptography and digital security you can learn how to utilise them in practise. I will show you some basic Swift and iOS techniques and tools that can be used to handle security issues.

Before I begin, one important note. Unless you are an expert in cryptography you should never try to implement cryptography algorithms for your own for real life purposes. There is nothing wrong in implementing them as an exercise, but for serious projects you should always use proven, well tested libraries. The risk that something will go wrong is just too big and you really don’t want to expose your project to security vulnerabilities.

Installing and trusting a custom root certificate

Why would I want to do that?

Most well known root certificates will be trusted by default. However sometimes you may find yourself with a need to install your custom root certificate on a user’s device. This will allow them to securely communicate with your server and do things such as connecting to a secured network that requires a specific certificate.

How do I do it?

Unfortunately this cannot be done in an entirely automatic manner, due to Apple’s approach to security. I will show you steps a user will have to take on his device and you will have to provide him with a proper explanation of what he is doing and why it must be done for your application to work properly.

In this example we will generate the certificate on a personal computer, upload it to online storage and download it to the device. I am assuming you have access to the openSSL tool.

First, generate a private key. Enter following command into a terminal.

openssl genrsa -des3 -out priv_key.key 4096

This will generate a private key in priv_key.key file. By default you will have to set a password for this file. You can avoid this step if you want by removing -des3 parameter. Now we create and sign the root certificate.

openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out root_cert.crt

You will now be asked to provide all the information necessary for certificate generation, such as country name, organisation name, etc. The certificate will be saved in a root_cert.crt file. Note that .crt is a text file extension.

Now host the generated file on the Internet. Let’s assume that our file is hosted on www.examplehosting.com/root_cert.crt.

Start a new Xcode project and add a single button. In its action callback we’re going to redirect the user to Safari to download our hosted certificate file. Here’s code snippet to open a website programmatically.

guard let url: URL? = URL(string: "www.examplehosting.com/root_cert.der") else { 
  return
}
UIApplication.shared.open(url)

That’s the end of programming part. Now the certificate needs to be manually installed. Run this code and when website loads following screen will be shown.

When you press allow you’ll be transferred to Settings app and prompted to install. When that’s done there is still one more thing remaining. In Settings app go to General -> About -> Certificate Trust Settings. There, you will find your certificate name and an unselected switch next to it. After you select it, the certificate will be added to the list of globally trusted certificates on this device.

As you can see this process is quite tedious and may be difficult for regular users. If you need to implement such a system make sure that your users know what they have to do at each step.

Generating and securely storing asymmetric key pair

Why would I want to do that?

Oftentimes when communicating with an API you need some sort of authentication. Usually it is in the form of a token you attach to each request. Sometimes a different approach is chosen and you use a certificate to validate your identity.

In those cases you generally have to create a Certificate Signing Request (CSR). In order to do that you’re going to need an asymmetric key pair, because a public key must be included in the CSR.

How do I do it?

We’re going to make use of SCCSR Objective-C library that will make the process of generating CSR much simpler. Since it’s not Swift, a bridging header must be set up first. After adding ObjC file to a swift project in Xcode, a bridging header file will be generated automatically. Then following lines must be added:

#import <CommonCrypto/CommonCrypto.h>
#import "SCCSR.h"
#import "SMCerts.h"

Now SCCSR can be used. To generate a CSR a pair of private and public keys must be created first. This is achieved by using a built-in Swift framework, Security. The code is as follows:

var pubKey: SecKey?
var privKey: SecKey?

let publicAppTag = <#some arbitrary string#>
let privateAppTag = <#some arbitrary string#>
let publicKeyAttr: [CFString: Any] = [
    kSecAttrIsPermanent: true,
    kSecAttrApplicationTag: publicAppTag.data(using: String.Encoding.utf8) ?? Data()
]
let privateKeyAttr: [CFString: Any] = [
    kSecAttrIsPermanent: true,
    kSecAttrApplicationTag: privateAppTag.data(using: String.Encoding.utf8) ?? Data()
]
let keyPairAttr: [CFString: Any] = [
    kSecAttrKeyType: kSecAttrKeyTypeRSA,
    kSecAttrKeySizeInBits: 2048,
    kSecPublicKeyAttrs: publicKeyAttr,
    kSecPrivateKeyAttrs: privateKeyAttr
]

_ = SecKeyGeneratePair(keyPairAttr as CFDictionary, &pubKey, &privKey)

Variables pubKey and privKey will hold public and private key respectively. Function SecKeyGeneratePair will also automatically save keys in an application’s local Keychain. (Note: if this piece of code will be called multiple times, the kSecAttrApplicationTag parameter should be changed each time, or previous keys should be removed before creating new ones)

Now a CSR can be generated. First public key data must be extracted using the SecKeyCopyExternalRepresentation function. Then a SCCSR object is created, filled with all necessary values and built with public key data and a private key. Finally a string representation is generated using the base64EncodedString method:

let publicKeyData = SecKeyCopyExternalRepresentation(pubKey, nil)
let sccsr: SCCSR = SCCSR()
sccsr.commonName = <#commonName#>
sccsr.organizationName = <#organizationName#>
sccsr.countryName = <#countryName#>
let csr = sccsr.build(publicKeyData, privateKey: privKey)
let csrString = csr?.base64EncodedString(options: [])

Variable csrString now holds the string representation of CSR. Usually that must be sent to a server that will in response send back a certificate which will be from now on used to authenticate requests.