Age is great and all but it has a huge footgun. It encourages the user to encrypt material with a public key in a way that is entirely unauthenticated. So an attacker with access to that public key can simply overwrite the file with whatever they want. If ensuring that you end up with the same stuff as you encrypted is important than that can be a big problem. Fixing this involves the use of a separate signing utility and thus introduces an entirely different set of keys for the user to manually manage.
By doing the key management for the user, GPG actually ends up being a lot more usable...
I'm not sure I understand this comment: age doesn't have authenticated encryption, but neither does PGP. The closest thing in PGP is the "Modification Detection Code," which is hilariously broken[1].
Edit: On top of that, every PGP implementation that I've ever worked with happily streams unauthenticated, decrypted plaintext before completing MDC verification.
I think the GP was complaining about lack of key management not lack of authenticated encryption.
In any case i clicked on the github link for AGE and it said ChaCha20-Poly1305, which is an authenticated encryption (AEAD) algorithm, so im very confused by your comment. Am i missing something?
In age with X25519 identities, ChaCha20-Poly1305 ensures the authenticity of data modulo the public key. It doesn't ensure the authenticity of the data itself, since anybody can encrypt to the public key.
In other words: it establishes that the data was encrypted to the expected key (and is not just random data being transformed by the cryptosystem), but not that a particular entity encrypted to that key.
(age does provide de-facto authenticated encryption when you use it with a passphrase, since the passphrase effectively forms a proof of identity. But not with asymmetric keypairs.)
This entire conversation is confusing because people are mixing up authenticated encryption with key management/signing, but those are separate things.
Its possible that i am mistaken (not a crypto expert), but usually the term "authenticated encryption" means the ciphertext is verified to not have been modified by an attacker (to for example do a padding oracle attack, although that wouldnt apply to a stream cipher of course). It has nothing to do with authenticating the source of the message or verifying the entire message has not been replaced by a different valid ciphertext - that's a totally different thing.
So Age provides authenticated encryption. It does not prevent an attacker who knows the public key from substituting in a different ciphertext, because that has nothing to do with authenticated encryption.
The terminology here is very confusing, because "authenticity" means different things in different schemes: it might mean authenticity of the ciphertext (which age does provide), or it might mean authenticity of the plaintext (which age does not provide with X25519 identities).
With an X25519 identity, age will guarantee that, if you can decrypt, then you are decrypting a message that was encrypted to a public key that you have the private half of. This is an improvement over some schemes, where decryption is potentially malleable (with a small enough message and enough tries, an attacker can make you decrypt something that looks valid but wasn't actually encrypted correctly). But it can't guarantee that you should trust everything that's encrypted against your public key.
It turns out that "The PGP Problem" was simply wrong about the MDC being broken (among other incorrect and misleading arguments)[1].
Note that since PGP addresses offline non-connected media it is simpler to directly authenticate the material. So the sort of thing that is being described here as "authenticated encryption" is not usually relevant[2].
>On top of that, every PGP implementation that I've ever worked with happily streams unauthenticated, decrypted plaintext before completing MDC verification.
For offline non-connected media, that is a completely reasonable approach. Not everything works like TLS.
This post doesn't adequately explain how MDC isn't broken: if my PGP implementation gives me unauthenticated data, then I am not doing authenticated encryption no matter what might be smashed onto the end of my ciphertext. Folding authentication into the correctness decryption phase is the only secure and misuse-resistant way to do authenticated encryption; PGP fails to provide either.
We can nitpick about the factuality of the "16 bit" claim or the truncation attack (which I believe GPG has since fixed), but neither directly contradicts the above.
> Note that since PGP addresses offline non-connected media it is simpler to directly authenticate the material. So the sort of thing that is being described here as "authenticated encryption" is not usually relevant[2].
Okay, but you just pointed to this property as a "huge footgun" in age. Why is it a footgun there, and not in PGP?
Besides, this is entirely ignoring actual use patterns: age is intended for offline file encryption, while PGP is used in all kinds of online channels and directly advertises itself as a "toolbox" for any purpose.
>Folding authentication into the correctness decryption phase is the only secure and misuse-resistant way to do authenticated encryption...
Again, PGP does not do things the same way TLS does. I do not see how you can possibly prove that other approaches can not be secure.
>We can nitpick about the factuality of the "16 bit" claim or the truncation attack (which I believe GPG has since fixed), but neither directly contradicts the above.
There is no nitpicking involved here. The claim is straight up wrong. The author of The PGP Principle either misread the email thread or deliberately misrepresented it. GPG could not fix that which was not broken.
>Okay, but you just pointed to this property as a "huge footgun" in age. Why is it a footgun there, and not in PGP?
Please read this article to understand how PGP does things:
The MDC is as much "authenticated encryption" as the proposed pointless and harmful "AEAD" modes[1]. The confusion here comes from the fact that a non-connection oriented protocol like PGP does that authentication directly on the plaintext[2]. There is no authentication to maintain over the life of a connection to maintain in the way that, say, TLS requires.
Wow, I just looked at the issues in the repo, and the position of the developers is indeed that there will be no signing - so you can verify the recipient, but never the sender.
So if I have your public key, I can just replace all your backups for example - and age cannot help you detect that. (for the particular use-case of encrypt-to-self, one could use the authenticated symmetric encryption, rather than public key - and assume the pass phrase is kept secret). But then your backup client can both "read and write" your backups - rather than just encrypt (to your public key) and sign (with backup instance private key).
So you get.. 30% of the benefits of public key encryption, for 90% of the complexity?
One of the things I like most about Age is that it made the very deliberate choice to __not__ become a general tool like GPG, and focuses only on one thing: secure encryption. You can read some of the reasoning about specifically not supporting signing as well here [0], but TL;DR -- it's a hard problem and age isn't really designed for communication and doesn't want to become a "a worse version of signal".
I'm familiar with GnuPG and I'm trying to understand how I can actually use age in practice. There doesn't seem to be a good explanation beyond the command line usage. My current understanding based on various pieces across the internet is the following:
1. age has only a single use-case: Encrypting files using public key cryptography or alternatively password-based encryption.
2. It is technically possible to encrypt e-mails with age, but it is not encouraged because the author considers e-mail to be fundamentally broken
3. age should be considered as a part of a wider cryptographic ecosystem. For example, if you need to sign files (or messages), you would reach for a different tool like minisign. I wonder if there is another tool/service that one can use for public key distribution
4. There is currently no tool that tries to combine different modern crypto tools into one big suite. I have no information about what age's author would think about such a tool.
5. age is intended to be minimalistic and therefore less bug-prone/misuse-prone.
6. The author of age talks a lot about forward secrecy. But there is no good explanation on how to manage key pairs over time.
I was going to agree completely but I think there's a use-case where age can work sensibly; distribute separate public keys to each semi-trusted host to perform its own automated backups. Rotate the keys frequently. There's still a significant advantage over symmetric encryption; the backups themselves will never be readable by an attacker who compromises a semi-trusted host.
The reason this scenario makes sense is that even if backups were encrypted and signed with gpg an attacker gaining root access to the semi-trusted host would also have access to its signing key and be able to impersonate it anyway. By only accepting backups from particular hosts based on its currently-valid public key we can avoid the risk of an attacker overwriting arbitrary backups.
You're going to be rotating either a gpg signing key or an age public key frequently regardless to reduce the time window when a potential attacker can impersonate a host, so age makes things slightly simpler by avoiding signatures entirely.
Mind describing (to a layman?) how checksums can help Age prevent switcharoo?
I ask because i've been writing a datastore of sorts that's immutable. Ie all content addressed. I plan to add some basic encryption for cloud storage primarily, however if Age could let someone swap file contents then i can't use Age.
I know someone's thinking "if it's content addressed how can someone tamper with the file contents?" - they can't, of course, but that only works if you know the HEAD's to point to. If you don't, say you're doing a full recovery, you slurp in all the content IDs and now have to determine which one is the HEAD. This is where tampering could take place, hypothetically, as they could not just swap the file contents but _also_ change the hashes/content IDs.
In a content addressed system signing the HEAD is really the only thing needed, since everything else can be validated via checksum. However i think it still needs signing, no?
Sidenote, i know next to nothing about crypto practices. I desperately need to find a class which teaches necessary knowledge to use crypto correctly in your own programs.
I think basically - if you already know the file is the correct version, then it must be the correct version, so no need to check again. Which sounds much less impressive when put that way.
One way to do this is to hash the file and store that hash somewhere you trust, which i think is what the person is suggesting. This approach has somewhat limited applicability, because if you already have a trusted channel, why are you using cryptography? (Yes there are lots of exceptions to that where crrypto still makes sense, but in general the point stands)
> Sidenote, i know next to nothing about crypto practices. I desperately need to find a class which teaches necessary knowledge to use crypto correctly in your own programs.
If you like hands on stuff, https://cryptopals.com/ has a lot of challenges to help learn stuff. Other than that maybe look into books. When i was trying to learn about this stuff, I liked "Cryptography Engineering" by Ferguson, but that was a while ago no idea if its dated now (also i am definitely an amartur in this so take everything i say with a grain of salt)
> One way to do this is to hash the file and store that hash somewhere you trust, which i think is what the person is suggesting. This approach has somewhat limited applicability, because if you already have a trusted channel, why are you using cryptography? (Yes there are lots of exceptions to that where crrypto still makes sense, but in general the point stands)
Yup. In my case my system is content addressed, so everything is a hash. So one one hand, sign-less encryption will work fine if i know the HEAD hash, as you mentioned. However i also want these backups to work from no local store. Ie i don't know the HEAD, and in that case someone could tamper with my pointer.
Kinda surprising that Age doesn't have a way to handle this. Shame, but good to learn.
Cryptopals is interesting, appreciate the link! I'll also look into that book, thank you! Did you find the book a bit deep? I have no intention of writing my own crypto, i just want to use it reliably and correctly.
> Kinda surprising that Age doesn't have a way to handle this. Shame, but good to learn.
The big problem is there are no really good ways to deal with this problem fully.
If you use digital signatures, you have to have a trusted method of distributing the verification keys.
If you have a secure method of distributing keys, you could also just distribute the encrypted file (or its hash) via that secure method.
Digital signatures usually work best when you previously had a secure channel but dont anymore (which is actually fairly common). But once you start doing that, often you start to want doing complex key management (e.g. PKI, tofu etc. Who manages the trust store), and how most appropriately to do that can be application specific (lots of tradeoffs and all options suck in different ways). So i kind of get why the author wants people to use a separate tool for that (even if it is a bit of a cop out).
> Did you find the book a bit deep? I have no intention of writing my own crypto, i just want to use it reliably and correctly.
Its been a while since i read it, but it was mostly about how to use different crypto primitives properly. It was not about how to design a block cipher or anything like that.
> If you have a secure method of distributing keys, you could also just distribute the encrypted file (or its hash) via that secure method.
Well in my case the central thing is mutable, changing. Ie it's a pointer to the HEAD, in git terms.
So yes, i have to distribute keys but the keys are immutable and can be distributed. The HEAD however can't, or at least can't with assurances that it's trusted.
Which is kinda the root issue i suppose. To answer the question of "the file on S3 is mutable, did i actually write it?". I have to be able to answer that
> Its been a while since i read it, but it was mostly about how to use different crypto primitives properly. It was not about how to design a block cipher or anything like that.
That actually sounds great. Definitely interested, thank you!
Right, I am just as much of a n00b at crypto as next guy/gal, but here's my understanding.
GP mentioned that detecting switcheroo is not possible because both original and new secret will be encrypted by the same public key. Until the decrypted secret is actually used, we will not realise it.
But, if we track all the changes in git, and have more than one copy (you have them, right?) then it becomes quite easy to detect this. Goes more if git commit access is gated by SSH key or another secret/auth layer. And this, makes detecting and or rolling back a switcheroo possible.
> By doing the key management for the user, GPG actually ends up being a lot more usable...
Isn’t that because GPG is a vertically integrated product while age is only trying to provide the foundation for products like gpg? Couldn’t another project accomplish key management so that age is focused on doing one thing very well?
The public key is generally not considered a secret and is therefore "less guarded". Anybody with access to the public key is able to encrypt and create legitimate looking files that are indistinguishable from the original files. You can still only decrypt them using the private key, but you can no longer trust the contents of the file as your own.
A solution would be to encrypt with the public key, and then _also_ sign with the private key. When reading, you work in reverse order. You verify the signature using the public key, and then decrypt the file using the private key.
But then if you're just using both, why not use fast and robust symmetric encryption instead? Not only will decryption be garbage if the file has been tampered with, but you can also create a signature to detect it (HMAC).
I think I understand what you are saying. For example, if you are using age to send an encrypted email, it is easy to encrypt the body/attachments to multiple recipients with their public keys (maybe published over DNS TXT records). But age doesn't give you a clear way for the recipients to read the message, fetch your private key, and authenticate the message was actually from you.
The thing that age is missing: A description of how to use it properly. I've looked into age several times and it is supposed to be a GnuPG killer for file encryption. But there is afaik no document or talk that describes how to use age in practice. Afaik there is absolutely no information about how to manage your public keys and what the best practices are for rotating and distributing them. Part of me really wants to use age, but when it comes to crypto, you need to know how use it properly.
I'm in the same boat. The people who understand Age assume everyone can use man pages. I can work my way through them, but I could really use a few explanatory articles with examples.
I'm eagerly awaiting the Kotlin implementation of age[0] because once that's finished, Android Password Store[1] will be able to offer age encryption next to/ instead of gpg.
Ooh, nice! Having a Kotlin-native implementation will be a significant UX improvement over e.g. using my Rust age implementation via FFI / JNI behind a wrapper.
It also reminds me (again) of the cross-language plugin question. The CLI apps interact with plugins using an IPC protocol over stdin/stdout. The idea was that the plugin side of the IPC could be placed in front of a regular Recipient or Identity library interface, so plugin authors could offer both a plugin binary for any CLI app, and a plugin library that can be compiled into other apps of the same language. Libraries in other languages sit somewhere in the middle ^_^;; It's probable that e.g. my age-plugin-yubikey Rust code could also be wrapped via JNI and used directly as a library, but there's maybe an IPC-over-FFI approach that could work as well. It would definitely be nice if only the main age client needed to be ported to target languages (though it should be similarly possible for language ports of plugins to work).
Next to is fine, but instead of would be a huge loss. Although GPG gets a lot of unwarranted hate, it is still a very powerful tool that I won't be replacing anytime soon.
The availability of age as a Go library means that it's easy to embed age into other tools. For example chezmoi supports age encryption for your sensitive dotfiles, and you don't even have to install age on your machine to use it.
Also, I would like to point out a major foot-gun with Age. I was using age in the symmetric mode, glad that I am getting a cleanly written ChaCha20-Poly1305 symmetric cipher. This is supposed to be 256-bits symmetric encryption, and quantum-resistance.
But if I recall, it seems that the age key file itself is 128 bits! Thus in the symmetric mode, Age provides only 128 bits of security. This is substandard, and in particular secure only until 2035 or so.
Worse, Age creates by default a 10-word password from BIP-39 list. That’s actually 110 bits, in default configuration. Again, a good deal weakening the security.
I reverted back to GPG AES-256. AES-GCM appears in 2.3.
Correct me if I’m wrong.
————-
Update: Here are the links for the security level of 128 bits in Age:
> But if I recall, it seems that the age key file itself is 128 bits! Thus in the symmetric mode, Age provides only 128 bits of security. This is substandard, and in particular secure only until 2035 or so.
This is not the case. To meet NIST's Category 1 requirements, post-quantum cryptography "must require computational resources comparable to or greater than those required for key search on a block cipher with a 128-bit key (e.g. AES128)" [0]. It is therefore completely appropriate to pair any Category 1 post-quantum KEMs with 128-bit symmetric keys. See [1] for more details about post-quantum age. Symmetric passphrase age similarly is fine because it's the same as the post-quantum KEM case but without the KEM.
A symmetric key of length 128 bits has only 64 bits of security with quantum computers. The age developer mentioned this in a GitHub issue (although I think the fact that the security level is only 128 bits is very important and shouldn’t have been tucked away in the GitHub issues brought about by someone else; it should have been highlighted in the documentation, which doesn’t mention the security guarantees).
Here is part of the code, considering that the file key is 128 bits.
salt = ephemeral share || recipient
info = "age-encryption.org/v1/X25519"
The author "filosottile" has built some amazing tools. My favorite is the "mkcert" tool. What a breeze to setup https/ssl on localhost within minutes. I guess I should go through his repo. in detail.
scrypt is solely passphrase-based; age has "identities". Identities, in turn, can be the private half of an asymmetric keypair, a passphrase (which then uses scrypt under the hood), or a handful of "extension" types, like SSH keys (for the reference implementation).
In other words: if you're using age with passphrases, it's very similar to scrypt's CLI. But you can also use it to encrypt to public recipients, similar to how you'd encrypt using someone's public GPG key.
The selling points of these tools is usability and misuse-resistance, not breadth of functionality. OpenSSL broadly fails on both of those metrics (although certainly not on breadth).
By doing the key management for the user, GPG actually ends up being a lot more usable...