FiloSottile / age

A simple, modern and secure encryption tool (and Go library) with small explicit keys, no config options, and UNIX-style composability.
https://age-encryption.org
BSD 3-Clause "New" or "Revised" License
16.67k stars 488 forks source link

Changing recipients of existing encrypted files #136

Open kousu opened 4 years ago

kousu commented 4 years ago

(https://age-encryption.org/v1 has an HSTS error for me right now so I can't read it! sorry!)

Since age supports multiple recipients, I assume it actually encrypts a the file under a symmetric key and then sticks that key encrypted in the header. Is it possible to change the list of recipients, the way a LUKS encrypted disk can have its passphrases changed?

The use case I have in mind is secure data archiving. I want to archive data to three keys at a time, but know that I can efficiently revoke and replace one of them when one of my archivists changes jobs.

I can do this with age by completely decrypting and reencrypting, but for the large-database situation I have in mind it would be a lot better if I didn't have to change that symmetric key.

Thanks. Great project btw!!

str4d commented 4 years ago

Since age supports multiple recipients, I assume it actually encrypts a the file under a symmetric key and then sticks that key encrypted in the header.

That's correct; a FileKey is generated, from which a MAC key (for the header MAC) and a payload key (for encrypting the file) are derived. The FileKey is wrapped either to a single scrypt recipient (for user passphrase encryption), or to one or more arbitrary recipients.

Is it possible to change the list of recipients, the way a LUKS encrypted disk can have its passphrases changed?

Technically, yes. You'd need an identity for one of the existing recipients in order to recover the FileKey, and then you could wrap it to additional recipients and/or drop existing recipients, before recomputing the header MAC.

This isn't however an implemented and supported mechanism in the current implementations. I don't know if @FiloSottile intends this as a usage avenue or not. In particular, if rewriting the header changes its length, then the entire file's contents would need to be moved appropriately. Age does not have a "detached header" mode (that would be another joint, which is more than the one joint intended in the age design).

The use case I have in mind is secure data archiving. I want to archive data to three keys at a time, but know that I can efficiently revoke and replace one of them when one of my archivists changes jobs.

Note that for the same reason that recipients can be swapped in and out, a removed recipient would still be able to decrypt the file if they cached their stanza from the original header before it was rewritten.

kousu commented 4 years ago

Hey! Thanks for picking up on my question so quick :)

This isn't however an implemented and supported mechanism in the current implementations. I don't know if @FiloSottile intends this as a usage avenue or not. In particular, if rewriting the header changes its length, then the entire file's contents would need to be moved appropriately. Age does not have a "detached header" mode (that would be another joint, which is more than the one joint intended in the age design).

Yeah, I don't want a detached header either. I like not having joints ;). But I would also like to be able to change the number of recipients. However stackexchange reminds me that

filesystems don't generally offer true "insertion" in the middle of files.

so I guess that's out, and you might as well re-encrypt the whole thing as you re-write it.

Note that for the same reason that recipients can be swapped in and out, a removed recipient would still be able to decrypt the file if they cached their stanza from the original header before it was rewritten.

Mmm indeed. I think that would be okay. This is a guard against accidental, not malicious, leakage. Anyone with access could make unencrypted copies of everything on secret cloud server, the way you can take screenshots of encrypted emails and send them around, or just gossip their contents to your friends. We can live with that.

str4d commented 4 years ago

One way you could cheat 😈 is to leverage the fact that spec-compliant implementations must ignore unknown stanzas. You could "pre-allocate" sufficient header space when you first encrypt the file, by adding a dummy recipient stanza with a sufficiently-long-for-your-use-case body. Then when you rewrite the header, you replace this dummy stanza with a new one that pads the header with new recipients to the original length. This would enable adding a bounded number of recipients without re-encrypting, and if that limit were exceeded then you could re-encrypt the file with a larger padded header.

str4d commented 4 years ago

@FiloSottile read me the riot act for suggesting the above 😝

The much more standard way to do this is to encrypt the file to an age recipient, and then encrypt that recipient's identity to the desired recipients. Changing recipients would then only require rewriting the (much smaller) encrypted identity file.

kousu commented 4 years ago

Ah that's clever! I like it.

FiloSottile commented 3 years ago

This came up thinking through YubiKey scenarios with @str4d: what do you do with your existing backups encrypted to YubiKey A and YubiKey B when YubiKey A breaks and you want to replace it with YubiKey C?

tv42 commented 2 years ago

I just recently re-encrypted a bunch of files to change recipients from yubikey1+yubikey2+passphrase to yubikey1+yubikey2+different_passphrase (because I lost the previous recovery passphrase). Writing the shell script to loop through them, decrypt | encrypt to temp file && rename to overwrite, was the trivial part. Touching the yubikey for every file was a lot of effort!

FiloSottile commented 2 years ago

Yeah, I recently had to do something similar to migrate from gpg to age!

The issue is that this is a pretty fundamental property of hybrid encryption: to change the recipients you need access to the content, or how else would you delegate that access to a new recipient. If access to the content requires a YubiKey touch, then changing the recipients requires a YubiKey touch.

The most we can save are the cycles involved in symmetric encryption, but that's just CPU, and I'm not sure it's worth it.

ghz-max commented 2 years ago

Hi,

I'm not using a yubikey, however I will definitely need a way to add or change existing password. By example, when a user would share a file with a temporary password that isn't the primary one.

Regards