QUICK HEADS UP 🚨
This section dives into some technical details about algorithms and encryption methods.
In the last part, we built the liboqs
binaries and packed them into an .xcframework
for easy integration into the app. In this part, I'll walk you through the challenges I faced while implementing the encryption and decryption logic for the app.
The Algorithm Dilemma
I began by implementing encryption and decryption using Classic McEliece 8192128f, known for its large public key size (1.3MB). My reasoning was simple: larger key = harder to break.
It worked well on the iOS Simulator (x86_64), but when testing on a real device (an iPhone 16 Pro - arm64), it crashed immediately at the public/private key generation call site with the following error:
Thread 1: EXC_BAD_ACCESS (code=2, address=0x16d017ff8)
The stack trace was completely empty, and the error was the only clue I had.
After digging through liboqs documentation, I found this note:
Note that for algorithms marked with a dagger (†):
liboqs contains at least one implementation that uses a large amount of stack space;
this may cause failures when run in threads or in constrained environments.
That was the missing piece.
If Classic McEliece 8192128f generates a 1.3MB public key, how much stack space does it need? So, I searched for the iOS' stack size limit which turned out to be - 1MB. Naturally, this meant the key generation process was exceeding the stack limit.
After experimenting with other McEliece variants, I switched to Kyber 1024
— which is a NIST-standard algorithm that is more memory-efficient and produces smaller keys.
Simplifying the Encryption Scheme
Next, I had to pick an encryption method. Initially, I tried AES-GCM
, but managing nonces
correctly added unnecessary complexity. While AES
is hardware-optimized on many devices, it isn't the goto one for software-only implementations.
I switched to ChaCha20-Poly1305
because it's more robust against nonce reuse
, offers consistent performance on all devices, and avoids certain side-channel risks.
For key derivation, I needed a solution that made brute-force attacks computationally expensive while still being practical for mobile use. PBKDF2
was built into CommonCrypto
and allows adjustable work factors. While Argon2
is stronger, I kept dependencies minimal for this initial implementation.
With ChaCha20-Poly1305
for encryption and PBKDF2
for key derivation, the app remains efficient and secure against both classical and quantum threats.
Running the app
Here's the final output. Nothing fancy on the front-end, but trust me, the magic is happening in the background -
Maybe someday I’ll actually build that password manager I wanted to in the first place, using these specs!
References
- https://blog.cloudflare.com/post-quantum-key-encapsulation/
- https://github.com/open-quantum-safe/liboqs
- https://en.m.wikipedia.org/wiki/Post-quantum_cryptography
- https://dl.acm.org/doi/pdf/10.1145/3600160.3605038
- https://www.reddit.com/r/cybersecurity/comments/gxso79/chacha20poly1305_vs_aes256gcm/
- https://github.com/krzyzanowskim/OpenSSL