Could Age Replace OpenPGP?
Age is a utility and library to do public key and symmetrical encryption/decryption in a simple and straightforward way1). The idea that age could replace OpenPGP comes up from time to time.
OpenPGP based systems are used for multiple purposes…
In terms of actual use, this is probably the most important function of OpenPGP. The value here is mostly the well supported and standardized signature standard provided by OpenPGP. Age does not do signing at all.
Age is obviously not intended for this purpose.
Messaging is all about identities. Age provides no identity management at all. Again, it doesn't even do signatures.
Age is obviously not intended for this purpose either.
Email already has two working and widely implemented encryption standards (OpenPGP and S/MIME). Messaging is mostly about standards. Even if someone were to build out age to do messaging it would be irresponsible to promote it as a third standard for email.
This (and encrypted long term storage in general) is where age has purpose. Let's say you use GnuPG as an OpenPGP implementation to encrypt a backup, that backup becomes corrupt and then you use this command line to decrypt it and unarchive it all in one go:
$ gpg2 -d backup.tgz.pgp | tar xz
GnuPG then dumps the unencrypted file, corruption and all, to tar. When it hits the end it does an integrity check which would fail with this message:
gpg: WARNING: encrypted message has been manipulated!
Then GnuPG would return an error.
The issue here is that tar might of had to deal with garbage for input. A potentially more serious issue would be if a malicious entity had enough knowledge of the unencrypted backup to allow them to modify files and/or file locations in a purposeful way. This might be a concern if you store your backups on a server that is not under your control.
Age does an integrity check every 64KB along the encrypted stream. If the integrity check fails then it does not release the bad 64KB chunk and errors out thus truncating the output. This allows an attacker to terminate your process at any point they choose. The assumption here is that no data or partial data is better than bad data.
The solution to the GnuPG bad data and the age truncated data is the same. Check the integrity of the input file before attempting to do anything with it. I would think this step would be mandatory in a case where there is a possibility that someone might attempt to modify your encrypted file(s). A manual integrity check could be as simple as running GnuPG and dumping the output to see if an error message shows up:
$ gpg2 -d backup.tgz.pgp >/dev/null
To be clear, “recovery” here is the sifting of good data from bad. Neither age or GnuPG can regenerate good data from redundant bad data.
Here is what this would look like in practice using the example of a single flipped bit2) near the start of the encrypted file. First age:
$ age -d -i key.txt -o totc_out.txt totc.txt.age Error: chacha20poly1305: message authentication failed [ Did age not do what you expected? Could an error be more useful? Tell us: https://filippo.io/age/report ]
$ ls -l totc_out.txt -rw-r--r-- 1 operator operator 0 Dec 25 12:53 totc_out.txt
Age has returned a zero length file. Those that have spent time maintaining backups for others might be suffering some vicarious anxiety at this point. A single bit error has nerfed the entire backup. There is no recovery mode or utility available for age which makes the recovery capability provided by your compression utility3) worthless.
The published standard for age 4) is incomplete. I was not able to determine if a recovery utility was even possible as the standard does not provide a description of how the 64KB chunks relate to one another. Creating a recovery utility would be harder due to this lack of documentation.
It is quite common for media problems to result in the loss of one or more media blocks. Since the 64k chunk used by age is likely going to be larger, an age recovery process would require a search for the start of the next chunk.
$ gpg2 -d totc.txt.pgp >totc_out.txt gpg: encrypted with 2048-bit RSA key, ID B456C3BB5A48A0EA, created 2020-06-01 "BACKUP <backup@store>" gpg: WARNING: encrypted message has been manipulated!
$ ls -l totc_out.txt -rw-r--r-- 1 operator operator 807615 Dec 25 15:26 totc_out.txt
Here is the damage to the text:
... which passed within his view, at a distance of some fifty or sixty yards. It is likely enough that, rooted in the woods of France and Norway, there were growing trees, wheo <CC>tR<EF>ZQ^Z^\'s^Q<E1>.3ACs put to death, already marked by the Woodman, Fate, to come down and be sawn into boards, to make a certain movable framework with a sack and a knife in ...
So we have lost 5 words out of 800KB of text5). This is an example of a somewhat unknown and under appreciated feature of the type of encryption used in OpenPGP. It is self-synchronizing in the face of corruption. The “chunk” in this case is only going to be something like 16 bytes which is going to be shorter than the media block so there is no search required to find the next good “chunk”. As a result, no recovery mode or utility is required for GnuPG in almost all cases. Recovery is automatic with a provided warning and returned error.
At this point you might want to consider how often longer term backups end up with bad sections. Then consider how many attackers exist with sufficient skill, combined with sufficient knowledge of the organization and content of your backups to do reliable changes. Attackers that are willing to have their efforts revealed after the first attempt. This would seem to be where OpenPGP is superior to age.
The ultimate point here is that “blowing up with an error” might not be the best way to handle this sort of situation in a command line utility. A lesson from application programming is that it is often better to complete the operation and return the error at the end.
Public key encryption has a generic consideration that is quite relevant here. Anyone with access to the public key can easily create a file that will pass any file modification tests … because after all that file has not been modified after creation. You can try to keep the public key secret but a public key design does not guarantee that the public key can not be derived from the encrypted material. That guarantee only applies to the secret key. So an attacker can skip the bother of attempting to overcome the authentication and just replace the file with whatever they want.
The traditional fix for this weakness is to cryptographically sign the file … and, once again, age does not do signatures. An age user would need to go through the process of finding a separate signing utility and would have to apply it correctly while using a separate signature file. A GnuPG user would only have to add a
-s option while encrypting and would have an integrated signature protected by the encryption. No further effort would be required on the part of the GnuPG user. A good signature message would appear automatically after decryption.
Age should be considered where a simple encryption utility is needed that will not under any circumstances release unauthenticated data. Where that behaviour is undesirable, such as for encrypted backups, something based on OpenPGP would be preferred.
--compress-algo noneoption at encrypt time was required. Almost all backups are separately compressed. GnuPG will not recompress input. So GnuPG still gets credit for good recoverablity for the backup case using default options.