Closed ColtonIdle closed 5 months ago
The prefix depends on the key ID, which is chosen at random. (This makes decryption faster, because Tink can find the correct key in the keyset faster.) It is not a good idea to add the prefix yourself to the ciphertext. Instead, you should use a key that doesn't require this prefix, using NO_PREFIX: https://github.com/tink-crypto/tink-java/blob/main/src/main/java/com/google/crypto/tink/hybrid/HpkeParameters.java#L34
This is what I'm doing now. I guess this is bad?
val hpkeParams = com.google.crypto.tink.proto.HpkeParams.newBuilder()
.setKem(com.google.crypto.tink.proto.HpkeKem.DHKEM_X25519_HKDF_SHA256)
.setKdf(com.google.crypto.tink.proto.HpkeKdf.HKDF_SHA256)
.setAead(com.google.crypto.tink.proto.HpkeAead.AES_256_GCM)
.build()
val hpkeKeyFormat = com.google.crypto.tink.proto.HpkeKeyFormat.newBuilder()
.setParams(hpkeParams)
.build()
val a = KeyTemplate.create(
"type.googleapis.com/google.crypto.tink.HpkePrivateKey",
hpkeKeyFormat.toByteArray(),
OutputPrefixType.RAW
)
We do not recommend using protos. They aren't really in the public API (though it's slightly unclear). However, more importantly they do not have an API which we can design since they are tied to the serialization of the key.
Instead, do something like this:
HpkeParameters.Builder params =
HpkeParameters.builder()
.setVariant(HpkeParameters.Variant.NO_PREFIX)
.setKemId(HpkeParameters.KemId.DHKEM_X25519_HKDF_SHA256)
.setKdfId(HpkeParameters.KdfId.HKDF_SHA256)
.setAeadId(HpkeParameters.AeadId.AES_256_GCM).build();
byte[] publicKeyByteArray = ...
Bytes publicKeyBytes = Bytes.copyFrom(publicKeyByteArray);
HpkePublicKey publicKey1 =
HpkePublicKey.create(params, publicKeyBytes, /* idRequirement= */ 123);
By using NO_PREFIX you ensure that Tink doesn't use the 5 byte prefix above.
Thanks for that snippet.
The last line of my snippet should have shown (my apologies that I missed it the first time)
KeysetHandle.generateNew(a)
In your snippet it's creating from an existing publicKeyByteArray. But what if I want to use tink to actually generate a public/private keypair (keyset?) instead of importing? (well I actually want to know how to import into tink and generate with tink, but now I know how to import into tink. thanks to you!) If I use the typical way to generate from tink then it'll give me a prefix, which I would like to opt out of/use OutputPrefixType.RAW)
If you want to create a new one, you can e.g. do
KeysetHandle.generateNew(params)
after you defined params in my snippet.
OutputPrefixType.RAW is a proto thing, I would recommend HpkeParameters.Variant.NO_PREFIX.
Wow! Can't believe I missed that. Thank you @tholenst . This has been insanely helpful!
I'm using hpke with a server that already exists (the server does not use tink). What I'm working on, is a java desktop app that uses tink. Everything is going smoothly except I can't decrypt messages from the server. When the server sends me a message it sends me the key and the message in json format, and i grab the key and message from that.
{ "key" = "OHzZgmNwayS5vyE\/1hj+eTJ1ebrakGg7ZVA2vENMFAQ=", "message="MZxGIq9CZJZ74mf2caSFxHh6Oo+z" }
if I base64 decode those two values then I get a byteArray of size 32 for the key, and size 21 for the message. (This seems to be correct because it's the exact size I generate when I send a message from my desktop app) except that my desktop app uses tink, and so it adds the 5 extra bytes to the start of the data (that makes sense because thats what tink wire format docs state:)
prefix || encapsulated_key || encrypted_data
5 bytes + 32 bytes + 21 bytesso basically everything seems good to go, BUT when I try to decrypt I get a failure
I'm assuming I just can't use 5 empty bytes for the prefix... but any idea how to generate the prefix?