Building an end-to-end encryption framework in Swift
Intro
Security can be a major concern for companies and developers building applications, especially in the medical field where data breaches are severely penalized. This is where end-to-end encryption comes into play.
A couple of days ago I read this article that inspired me to do a Swift library with utilities around Apple CryptoKit. When the time came to test it against using a real server, I end up adapting the library to an end-to-end (client-server-client) encryption tool.
The article is about my path doing that library, and also how I built client app and web server to test the concept.Before we start, I want to give you a quick intro about how 2 entities can “safely” agree on a (secret) key exchange that will latter be used to encrypt all messages, the Diffie-Helman key exchange algorithm.
I — Diffie-Helman key exchange algorithm.
Before we start, just quick intro about how 2 entities can “safely” agree on a (secret) key exchange that will latter be used to encrypt all messages, the Diffie-Helman key exchange algorithm.
There are 3 concepts to keep in mind:
- Salt : (common paint) is the same and is know only by Alice and Bob, and can be seen as starting “password” between Alice and Bob.
- Public Key : Both Alice and Bob have one and there is no problem if more entities know then.
- Private key : (Secret colours) Both Alice and Bob have one, and only Alice know his Private key and only Bob know his Private key either.
AliceSecret = Salt + Alice.PrivateKey + Bob.PublicKey
BobSecret = Salt + Bob.PrivateKey + Alice.PublicKey
AliceSecret
and BobSecret
should share the same Symmetric key value that will be used to encrypt the messages. used to encrypt the messages.
II — Building
Building the basic operations
- Generate a certificate
static fun newPrivateKeyInstance()
that will contains a Public and Private key. - Extract Public key from certificate.
- Extract Private key from certificate.
- Generate Symmetric key using the Public/Private keys and Salt.
- Encrypt and decrypt a message using the Symmetric key and Salt, or the Salt, a Public key and a Private key.
First tests
- Alice (our sender entity) and Bob (receiver entity), both with Public and Private keys.
- A Salt (common paint).
- A secret message “my secret”.
We can define all (using Swift) and RJSP_Security as follow:
And we can simulate the:
- Symmetric key exchange (line 4 and 8).
- Encryption latter (line 5) by Alice using the common Salt, her Private Key a Bob Public Key.
- Decryption by Bob (line 9) using the common Salt, his Private Key a Alice Public Key.
III — Testing on real App-Server-App use case
Step 1: The app (client) sends its Public key to the server (in the request body). It also sends its userID (in the request header).
The request definition is below:
The request execution is below: (btw, how are your Combine skills?)
Step 2: The server stores the USER_ID and the user’s Public key (for future secure communication) and returns the server Public key to the client app.
Step 3: The client app receives the server Public key, and then with its (client) Private key executes a secure/encrypted request to the server.
The request definition is below:
Step 4: The server receives the encrypted request, and decrypts it using the client Public key (stored on step 1) and its (server) Private key. After decrypting the message, the server just returns it as a “proof” of success.
IV — Materials
- All the code used on this articles, as for the sample client app and server app, can be found at RJSP_Security
- If you are not familiar with Vapor (server app) and you want to learn more, this article will help you for sure.
V — Final notes
- RJSP_Security does more that the ones presented on this article (like Public keys cached storage management for instance).
- RJSP_Security only guarantees Encryption, you’re still are vulnerable to man-in-the-middle attacks.
- If you found any mistakes reach me via twitter at @cricardo_psantos.