Add the ability to encrypt KeysetHandle with associatedData
Is your feature request related to a problem?:
yes
I'm attempting to write an encrypted key to disk using KeysetHandle.write(KeysetWriter, Aead). I'm noticing in the implementation that this hard codes the associatedData when encrypting to an empty array.
byte[] encryptedKeyset =
masterKey.encrypt(keyset.toByteArray(), /* associatedData= */ new byte[0]);
This is unsuitable for my use case as I'd like to also be able to salt the keyset when it's being encrypted. I don't see a way to be able to do that exposed.
Describe the solution you'd like
Ultimately, I'd like for keyset handles to have an option to include associated data.
public void write(KeysetWriter keysetWriter, Aead masterKey, byte[] associatedData) throws GeneralSecurityException, IOException
Describe alternatives you've considered
I've tried digging around to see if I could manually do this, but since a keyset is private to the KeysetHandle, it'd be impossible to get this data without hacking around with reflection. I'm not aware of any other way to approach this.
If this is something the maintainers are willing to entertain, I would be happy to make a PR. I imagine the change would be pretty simple.
Hi there,
Internally we aim to replace KeysetHandle.write() with a new interface AsyncKeysetAead:
/**
* Interface for Asynchronous Authenticated Encryption with Associated Data (AEAD) for tink {@code
* Keysets}.
*/
public interface AsyncKeysetAead {
/**
* Encrypts {@code Keyset} with {@code associatedData} as associated authenticated data. The
* resulting ciphertext allows for checking authenticity and integrity of associated data ({@code
* associatedData}), but does not guarantee its secrecy.
*
* @param handle the {@code Keyset} to be encrypted. It must be non-null.
* @param associatedData associated data to be authenticated, but not encrypted. For successful
* decryption the same associatedData must be provided along with the ciphertext.
* @return future of the resulting ciphertext
*/
ListenableFuture<ByteString> encryptKeysetAsync(KeysetHandle handle, ByteString associatedData);
/**
* Decrypts {@code ciphertext} with {@code associatedData} as associated authenticated data. The
* decryption verifies the authenticity and integrity of the associated data, but there are no
* guarantees wrt. secrecy of that data.
*
* @param ciphertext to be decrypted. Must be non-null.
* @param associatedData associated data to be authenticated. For successful decryption it must be
* the same as associatedData used during encryption.
* @return future of the resulting {@code Keyset}
*/
ListenableFuture<KeysetHandle> decryptKeysetAsync(
ByteString ciphertext, ByteString associatedData);
}
It is an async interface because usually keyset encryption requires invoking a remote KMS. We'll discuss how to open source this interface and get back to you shortly.
AFAIK this is now fixed. Please reopen this if my understanding is incorrect.