---
title: 'Post-Quantum Cryptography (Part 2)'
excerpt: 'Building an iOS POC app for encrypting and decrypting data.'
date: 2025-02-02
categories: ios, security
featureImage: '/images/post-quantum-cryptography.webp'

prev:
  text: 'Post-Quantum Cryptography (Part 1)'
  link: '/blog/post-quantum-cryptography-1'

next:
  text: 'TypeScript & Golang'
  link: '/blog/typescript-and-golang'
---
---

> [!WARNING] 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:

```text
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 -
<BlogPostVideo src="/videos/post-quantum-cryptography-poc-app.mp4" height="500px" width="auto" />

Maybe someday I’ll actually build that password manager I wanted to in the first place, using these specs!

---

### References

1. https://blog.cloudflare.com/post-quantum-key-encapsulation/
2. https://github.com/open-quantum-safe/liboqs
3. https://en.m.wikipedia.org/wiki/Post-quantum_cryptography
4. https://dl.acm.org/doi/pdf/10.1145/3600160.3605038
5. https://www.reddit.com/r/cybersecurity/comments/gxso79/chacha20poly1305_vs_aes256gcm/
6. https://github.com/krzyzanowskim/OpenSSL