Table of Contents

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…

Signing

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

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.

Encrypted Backups

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

Data Recovery

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.

Now GnuPG:

$ 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.

Another more specific example could be the storage of passwords as is done with passwordstore. If an encrypted password was corrupted in some way, the user would very much want access to the results of attempting to decrypt the password. Anything would be better than nothing in that case. Age would deliberately refuse to return anything.

I admit that the previous two examples are contrived. But they are much less contrived than the example of the encrypted tar file. A lesson from application programming is that it is often better to complete the operation and return the error at the end. That seems to be the case for a command line utility that does encryption.

File Substitution

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. 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.

The creator of age has suggested that you can just keep the recipient identity (public key) away from the attacker and prevent them from creating a valid ciphertext to produce a sort of authentication for age6). The fundamental issue with that idea is that it depends on a poorly specified property of the cryptography. Any protection against an attacker being able to derive the public key is merely accidental. The creator of age said in an article:

I am confident the property holds for the X25519 recipients, and that it would hold for a hypothetical Kyber768+X25519 one,…

… but provided no explicit argument to that effect. … and then continued:

…but it's important not to advertise it as an age-wide property.

In practice the recipient identity key will show up on the command line and/or will be kept in an unencrypted file. So age itself treats it as a potentially public value.

If you and the recipient have the ability to share and keep a secret value secret, why use asymmetrical encryption in the first place? Symmetrical encryption is specifically intended to authenticate in that case. Or why not put that secret value in the plaintext as discussed in an article by the creator of age? The reason that there is not more research into the security of secret recipient identities is because there is no practical value in such use.

Conclusion

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.

PGP FAN index

2)
Please note that the single flipped bit here is not a realistic example and that in practice damage tends to encompass one or more media blocks. Such blocks tend to be multiples of 512 bytes. Often the blocks are entirely missing.
3)
The commonly used bzip2 compression utility for example is specifically designed to be recoverable and comes with the bzip2recover command.
5)
GnuPG noticed that I was encrypting text and helpfully compressed it thus eliminating my example. The addition of a --compress-algo none option 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.