Show HN: Age 1.0 – Simple, modern and secure file encryption
github.com
github.com
+ An extremely simple CLI that composes well with UNIX pipes, and that works well as a backend for other programs
+ Small copy-pasteable keys, with optional textual keyrings Support for public/private key pairs and passwords, with multiple recipients
+ The option to encrypt to SSH keys, with built-in GitHub .keys support
+ “Have one joint and keep it well oiled”, no configuration or (much) algorithm agility
+ A good seekable streaming encryption scheme based on modern chunked AEADs, reusable as a general encryption format
Just for fun, I occasionally experiment with proposed "post-quantum" encryption solutions and one in particular called Classic McEliece, from the same author (more or less) as the encryption used in age. Its small and compiles quickly. The interface is elegant and seems impossible to screw up. I have rarely seen anyone outside of the author and his followers use file descriptors in compiled programs in this way. I like it.
Three programs, each only does one thing
usage: cmkeypair 5>publickey 9>secretkey
usage: cmencrypt <message 4<publickey >ciphertext
usage: cmdecrypt <ciphertext 8<secretkey >message
To be fair, I should probably add that McEliece arguably fails the "small, copy-pasteable keys" criteria. :)In practice, I find the syntax needlessly obtuse, and numbered file descriptors are rare enough in the real world that most casual observers will have no idea what's going on.
https://cr.yp.to/proto/ucspi.txt
http://www.catb.org/~esr/writings/taoup/html/ch06s06.html
It’s not built in, just composable in. And to the version in the readme I prefer using command substitution personally: it’s clearer when there are multiple recipients, and the infile tends to be much larger than the keys.
The biggest issues wrt github are that it rejects age files (so you have to rename them) and there is no /keys at the repo level whivh would give you the keys of all maintainers, so you have to hunt them by hand.
Previously: https://news.ycombinator.com/item?id=21897192
STREAM is a well-studied construction for online authenticated encryption. It doesn't just involve an auth tag every few kilobytes (or megabytes, or gigabytes). There's also a byte flag (called a "tag" in some implementations) to indicate whether or not there should be additional blocks or not.
A search for anything like "stream cipher construction" only lands me on the traditional "stream vs block" discussions.
Age: A simple, modern and secure file encryption tool - https://news.ycombinator.com/item?id=21895671 - Dec 2019 (197 comments)
Age - The PGP Replacement (alpha) - https://news.ycombinator.com/item?id=21188517 - Oct 2019 (2 comments)
Alpha release of Age-tool – A small command line encryption utility made in Go - https://news.ycombinator.com/item?id=21177063 - Oct 2019 (1 comment)
https://news.ycombinator.com/item?id=27726982 (July 2021)
https://news.ycombinator.com/item?id=27284079 (May 2021)
https://news.ycombinator.com/item?id=27236708 (May 2021)
https://news.ycombinator.com/item?id=26886074 (April 2021)
https://news.ycombinator.com/item?id=26244468 (Feb 2021)
https://news.ycombinator.com/item?id=26158300 (Feb 2021)
Yes, I used the same tool to find these. Well, not to find them exactly (I use HN Search for that), but to quickly assemble them and follow the links from one comment to the next. One of these years this will all be made available to everyone.
Not having a default keychain location though is a deliberate decision that’s here to stay. age keys are application-specific keys, not universal personal identities. We want to avoid implicit state and make rotation and compartmentalization as easy as possible.
I understand that it is an ugly and imperfect layer of security to secure keys this way, but I still prefer it over nothing. Maybe applications could try implementing OS-level 'secure' keyring storage; that seems marginally better... No idea, though, I'm no expert on security.
Thanks for age regardless. I'm sure I'll be using it a lot in the future.
An early version of the draft spec did include a default keys.txt path, and I implemented it in rage. However, during the beta phase discussions we made the decision Filippo described above, and I removed support for a default path in rage 0.5.0.
----
Not a courtesy you extended to SSH keys, choosing to instead re-use them for an unrelated purpose, with, so far as I can see, still no proof in 1.0 that this is actually safe, just the usual hand-waving.
Couple thoughts that I'll never remember after my 5 minutes of using it but will likely be experienced by a lot of people in their first 5 minutes.
o It's odd that -e (encrypt) can recognize an age-keygen file, but -d (decrypt) errors out with:
age: error: failed to parse recipient file "person.pub": "person.pub": malformed recipient at line 1
I mean, I get it - the recipient should be the key, but you would think that age would be able to recognize its own "# public key: " string and parse it? (Like I said - noticed only in the first 5 minutes of use)
o In the vein of user friendliness/simplicity - why not just default to armored? It doesn't hurt anything to be armored, and if someone really wants a binary output, they could specify it specifically. Given they are both (mostly) equivalent, could as well default to the user friendly version. I get that it's too late to make the change now.
o Not available as a brew install, so I had to armwrestle with MacOS to let me even run it (Security was clever enough to recognize when I was copying something downloaded, had to defeat it with `dd if=age of=age2`)
o I do love `age -e -o out.enc -p somefile.txt`
I'm confused as to how you reached this error message; "age -d" doesn't support recipient files / -R, only identity files (which is what age-keygen produces). It would be helptul to open an issue showing how to reproduce; either there's a bug, or documentation could be improved.
> o Not available as a brew install
While age was in beta, it provided a brew tap. But now that 1.0.0 has been released, it has just (3 hours ago!) been added to homebrew-core: https://github.com/Homebrew/homebrew-core/pull/84805
I assume this is because the author really does not want people to use age to encrypt e-mail because e-mail encryption is hopelessly and unfixably broken. By making armored not be the default, it's an extra little thorn in the side.
1. It sounds like you were passing an identity file to --recipients-file. We do support using identity files with --encrypt, but you need to pass it to --identity. We can make the error message more helpful when we notice this is happening.
2. Armoring has a lot of space overhead, and most applications don't need it. (age is not for encrypting messages and emails!)
3. It's now in Homebrew Core :)
4. :D
I've seen a number of READMEs with this kind of pronunciation note recently--I don't think they really help, because I suspect that most readers aren't familiar enough with the IPA (pronunciation) notation.
I suggest including a link to something like this: http://ipa-reader.xyz/?text=a%C9%A1e̞&voice=Joanna
First, the average user doesn’t actually care that much. Picking algorithms is my job, not theirs. They want to get their task done, so what I need to tell them is what the tool does and what are the security properties, not how it works.
Second, the choice of primitives is a relatively small part of cryptographic design. How you compose them and how it addresses a real use case matters much more. I usually get suspicious when I read “uses AES-256” in marketing copy because, like, it doesn’t tell me _how_ it’s used, and doesn’t seem to think it’s important.
You made a great choice. Thank you. This tool looks awesome. Can't wait to build it.
[0] https://security.stackexchange.com/questions/86305/what-is-t...
Just found a similar tool called hpenc[1], written in C++11 with libsodium yesterday. It uses AES-GCM or ChaCha20 to encrypt files and streams. But this is even better as it's more ergonomic, drop in, I don't have to worry about dependencies and it does much more, like encrypt using ssh or gpg keys.
Some of that seems to be from omitting features, though. Gpg CLI integration allows passing both the cleartext to be encrypted and a passphrase on pipes. Which means things like --passphrase-fd, which age doesn't seem to have. Makes it simpler, but also means you have to have more clear text in files, at least temporarily.
You can use /proc/self/fd/N if the program handles files correctly (particularly, no seek).
* password store (Pass)
* hardware key support
* back up software using Age (as with duplicity)
* integration into operating systems (cross platform)
* integration into apps
* Mobile support
* command line for key management (maybe), to help me organize and rotate keys, and maybe share public keys
* An agent?
* robust positive review or audit (security people need to review the source code independently), or a long history of good security
Mount would be great too!
The way this is set up in the plugin protocol, the age client provides the age header to the plugin, along with any identities the user has asked to decrypt with, and the plugin returns any file keys it is able to decrypt. The process of taking the per-recipient encrypted blobs in the header and extracting file keys, is entirely up to the plugin. This falls nicely out of the way the age format's "one joint" is designed: the file is encrypted with one symmetric key, and that key is encrypted separately to each recipient via whatever mechanism their type requires.
If you squint through the layers upon layers of packet complexity, this is the same way GPG encryption operates [0]: the data is symmetrically encrypted with a random session key, and that session key is asymmetrically encrypted to each recipient. Only the asymmetric decryption part happens on-device for GPG; the symmetric part happens on the computer.
[0] https://datatracker.ietf.org/doc/html/rfc4880#section-2.1
I'm looking especially for end-user ease of installation. minisign seemed promising but `brew install minisign` has tons of dependencies and takes forever. I found a Go port with compiled binaries, but it's not a popular repository.
Is there anything cross-platform and widely trusted that's better than gpg?
I see a libsodium dependency in the sources, anything else?
Don't the binaries at https://github.com/jedisct1/minisign/releases work for you?
I am not any kind of expert in this field, so you are not obligated to listen to me... but I am still right.
https://neilmadden.blog/2019/12/30/a-few-comments-on-age/ Unfortunately, the age spec doesn’t document its threat model or the security goals it is intended to achieve so I’m having to read between the lines to work out what was intended.
$ gpg2 -d backup.tgz.pgp | tar xz
So the modified backup file can do bad things before anyone can stop it because gpg will complete the operation before warning of the modification.It doesn't have integrated signature support so that in most cases an attacker can use the public key to entirely replace the file and avoid the bother of some sort of known text attack in the first place. So I think that the use case is so narrow as to disappear.
The linked article covers this. That is really all there is.
It serves best as a demonstration of what an encryption utility would be like that blows up and errors out on a possible modification, as opposed to completing the operation and returning the error at the end.
https://news.ycombinator.com/item?id=27433186
This is, to put it charitably, an idiosyncratic argument about how data encryption is supposed to work.
I think if we did that, the stupid discussion about GPG and framing its lack of IND-CCA2 as a "recoverability feature" would become moot.
I have looked into this a bit and there doesn't seem to be any reason age could not have a recovery utility. It would involve some minor brute forcing to find the next block and block number. It could even skip any 64k block that failed the integrity check so that only authenticated data was recovered. That would be consistent with the general principle about not releasing unauthenticated data that age was created to enbody.
Error-correction and media block-based encryption is a separate utility than what age provides, and should therefore be a separate tool.
That separate tool can use age for the cryptography. That's fine.
But I will not advocate for more complexity to be shoved into age. It's fine as it is today.
I much look forward to: hardware key support, password store, mount and integration with back up software (and perhaps rclone which is for data movement).
I am pretty happy with GPG, which supports most of these features and more (sometimes via third parties that use it), but also appreciate Age and may play with it, once it’s more useful.
I like that it’s, apparently, easier for applications to interface with it, particularly in the large and growing Go ecosystem.
One complaint: It’s hard to find Age by Google search!
I've been experimenting with a web-based UI [0] for my Rust implementation of age, because I really wanted drag-and-drop but could not figure out how to persuade any Rust GUI libraries to do it ^_^;
if the federal government builds a time machine one day I'm sure the firmware will consist of a little Java 5 servlet running on a Windows XP machine