The security model.
What protects your files, what the threat model is, and where the boundaries are, stated plainly, because security you can't understand isn't security.
Cryptography
- Encryption: the age protocol. X25519 key agreement, ChaCha20-Poly1305 in the STREAM construction. Implemented to the age v1 spec and verified bit-perfect against the reference CLI.
- Post-quantum encryption: hybrid ML-KEM-768 (FIPS 203) with X25519, the
mlkem768x25519recipient type. Both key encapsulations must be broken to recover the file, so the hybrid is at least as strong as the stronger half. - Passphrase mode: scrypt-stretched keys, with parameters stored in the file stanza so any age implementation can decrypt.
- Signing: SSHSIG (the
ssh-keygen -Y signformat), namespaceagepony, verifiable by stock OpenSSH. - Signing keys: in-app ed25519 / RSA, Secure Enclave (hardware P-256, non-exportable), and external FIDO keys producing
sk-ssh-ed25519orsk-ecdsa-sha2-nistp256.
What post-quantum does and does not buy you
The threat is not a quantum computer reading your screen. It is harvest now, decrypt later: an adversary with storage records ciphertext today, keeps it, and opens it whenever a cryptographically relevant quantum computer arrives. Nothing about that attack requires the machine to exist yet. It only requires the file to still matter when it does.
So the question is not whether quantum computers are imminent, it is how long your file needs to stay secret. A message about lunch does not need this. A source's identity, a key backup, or a medical record might need to hold for decades.
Three limits stated plainly:
- Hybrid, not replacement. ML-KEM is young compared to X25519, and lattice assumptions could yet disappoint. Every post-quantum file is also sealed with X25519, so the hybrid is never weaker than what it replaced.
- Encryption only. ML-KEM is a key encapsulation mechanism, not a signature scheme. Signatures in AgePony remain classical. A quantum adversary in the future could forge one, but they could not retroactively forge a signature you already verified, and they cannot read a post-quantum encrypted file.
- It does not reach backwards. Files already encrypted to a classical key and already copied elsewhere stay exactly as breakable as that key. Re-encrypting your copy helps your copy.
What the ciphertext reveals
An age file's header lists a stanza per recipient. It does not name them, but it does show how many there are and what type each is. A post-quantum stanza is visibly post-quantum. Treat recipient count as public.
Signing changed in 3.0 for exactly this reason. A detached signature beside a file carries the signer's public key in the clear, so anyone who intercepts the pair learns who sent it without decrypting anything. Sign-then-encrypt puts the signature inside the ciphertext, so an interceptor sees only an age file, and the recipient learns the signer only once they can already read the payload.
The verdict on a sealed signature necessarily arrives after the payload has been written out, because the signature is the last thing in the bundle. AgePony shows a failed verification prominently rather than quietly, since the decrypted file exists either way.
Memory and large files
As of 3.1 nothing is held whole. Plaintext, ciphertext, archives and signed bundles all move through fixed 64 KiB buffers, which means the amount of your data resident in memory at any moment is bounded and small no matter how large the file is. Re-encrypting is the one operation that writes plaintext to disk, into the app's temporary storage with the same file protection as every other output, and it is deleted as soon as the operation ends.
Key storage
Identities live in an encrypted vault inside the app sandbox, sealed with a master key held in the platform keystore (iOS Keychain / Android Keystore) and released only after biometric authentication. Secure Enclave signing keys are generated in hardware and never leave the device: AgePony can ask them to sign, but cannot extract them.
Threat model
AgePony defends the confidentiality and integrity of files you encrypt or sign, against an attacker who does not control your unlocked device, including one who stores your ciphertext now and attacks it later with better hardware. It assumes the operating system's keystore, biometric subsystem, and secure hardware behave as documented. It does not defend against malware running on a compromised, unlocked phone, nor against someone who knows a note's passphrase, nor against an attacker who obtains the plaintext from the person you sent it to.
No network surface
There is no AgePony server, so there is no server to breach, no database to leak, and no credentials to steal. The single outbound request, fetching a GitHub user's public keys, is read-only, user-initiated, and carries none of your data. See the privacy policy for the exact detail.
Open to inspection
Both apps and both crypto cores are open source under Apache-2.0, including the from-scratch ML-KEM-768 implementations in Swift and Kotlin. You don't have to take any of the above on faith. Read the code, run the reference test vectors, decrypt an AgePony file with the age CLI, and check the SSHSIG output against OpenSSH yourself.
Reporting a vulnerability
If you find a security issue, email NorseHorse@norsehor.se with details and, ideally, a way to reproduce it. Please give a reasonable window to ship a fix before public disclosure. AgePony is a one-person project, so a clear report gets a faster fix.