Subject: Re: [COSE] HPKE for COSE

From: John Mattsson <[email-masked]>
Date: Tue, 9 Nov 2021 13:33:48 +0000

Hannes wrote:

I do, however, agree that the cleaner way is to define a new parameter, as you suggested, and then re-use the HPKE registry. By doing this we also make sure that the two registries do not get out of sync. So, unless there is an objection I would go head and make the chance to the draft.

- The current COSE key exchange algorithms comes in pairs such as

ECDH-ES + A128KW (ECDH ES w/ Concat KDF and AES Key Wrap w/ 128-bit key)
ECDH-ES + HKDF-256 (ECDH ES w/ HKDF - generate key directly)

The approaches have different pros and cons. I think it would be good to follow the same architecture with HPKE in COSE (but continue using HPKE Seal() instead of AESKW). The difference between using a CEK and deriving a key directly could easily be signaled with the sign of the ‘hpke-alg' value.

Using (say 'hpke-alg'; label 11) the two approaches could be signaled as

{11 : 17} or {11 : -17}

- I think the current draft and Göran’s ‘hpke-alg' suggestion both lack a definition of the HPKE AEAD used for the Seal operation. I do not think the HPKE AEAD follows from the HPKE KEM ID.

Cheers,
John

---

From: Ilari Liusvaara <[email-masked]>
Date: Tue, 9 Nov 2021 19:52:47 +0200

On Tue, Nov 09, 2021 at 01:33:48PM +0000, John Mattsson wrote:
> Hannes wrote:
> 
> I do, however, agree that the cleaner way is to define a new
> parameter, as you suggested, and then re-use the HPKE registry.
> By doing this we also make sure that the two registries do not get
> out of sync. So, unless there is an objection I would go head and
> make the chance to the draft.
> 
> The approaches have different pros and cons. I think it would be
> good to follow the same architecture with HPKE in COSE (but
> continue using HPKE Seal() instead of AESKW). The difference between
> using a CEK and deriving a key directly could easily be signaled with
> the sign of the ‘hpke-alg' value.
> 
> - I think the current draft and Göran’s ‘hpke-alg' suggestion both
>   lack a definition of the HPKE AEAD used for the Seal operation.
>   I do not think the HPKE AEAD follows from the HPKE KEM ID.

Yes, HPKE actually has three algorithm constants (KEM, KDF and cipher),
and to make things even more confusing, some KDF operations do not use
the KDF, but potentially different KDF dicated by the KEM used.

If one could require that the two KDFs are always the same, then this
would drop the number of distinct algorithms to two, and those two
would map neatly into key and message parts. However, if HPKE ever
gets a KEM that uses KDF it does not know about, then that could not
be used (no such thing exists currently; all current KEMs use
known KDFs). Additionally, I am not sure allowing the KDF to vary
is cryptographically kosher, fixing it in key would take care of
that.

Analyizing how HPKE uses types, most things SealBase/OpenBase deal
with are octet strings, except:

- The public key input for SealBase is abstract.
- The private key input for OpenBase is abstract.
- SealBase returns two octet strings, which go into different
  outputs of OpenBase.

If using NIST curves, the first of the two octet strings returned by
SealBase is uncompressed elliptic curve point. It could be compressed,
but not made compact: The key derivation uses the sign of that point,
even if it does not depend on the sign of the final shared point. This
could be solved by defining HPKE KEMs that are duplicates of NIST curves
with compact encoding.

And the public key being abstract brings its own set of issues, as
different HPKE keys may have different key types:

- NIST curves are EC2.
- Compact NIST curves versions would be OKP?
- CFRG curves are OKP.
- Future PQC KEMs from NISTPQC will be OKP.

And one presumably can not assume that COSE curve will uniquely map to
HPKE KEM. So it looks like one would need to introduce HPKE key type
field.

And HPKE also has mode where it performs direct key generation (which
does not need specified cipher, only KEM and KDF, the latter of which
might be cryptographically unsound anyway). So there could be one
codepoint for HPKE with direct keygen. For key wrap, one would need to
specify the keywrap algorithm too.

-Ilari

---

From: Russ Housley <[email-masked]>
Date: Tue, 9 Nov 2021 16:44:29 -0500

John:

When sending the same content to multiple recipients, you have two choices.  In the first alternative, you encrypt the same random value for each recipient's KEM public key, which results in all of the recipients deriving the same key.  In the second alternative, you encrypt a different random value for each recipient's KEM public key, which results in each of the recipients deriving a different key.

The first approach in the one used in out document.  It is similar to ECDH-ES + A128KW.

   For each recipient:
      Z = randomly generated value.
      WZ = Encrypt Z with the recipient's KEM public key.
      KEK = KDF(Z)

   CEK = randomly generated content-encryption key.
   WCEK = Wrap CEK with KEK.
   C = Encrypt payload with CEK.

   Send SetOf(WZ,WCEK), C.

I think you are suggesting that we should support the second alternative as well, which is similar to ECDH-ES + HKDF-256.

   Z = randomly generated value.

   For each recipient:
      WZ = Encrypt Z with the recipient's KEM public key.

   CEK = KDF(Z)
   C = Encrypt payload with CEK.

   Send SetOf(WZ), C

During the LAMPS session on Monday, it was suggested that the KEM structure optionally allow the inclusion of a UKM as a KDF input.  That would change the above to be:

      key = KDF(Z, [UKM]), where the UKM is optional KDF input.

Russ

> On Nov 9, 2021, at 8:33 AM, John Mattsson <john.mattsson=[email-masked]> wrote:
> 
> Hannes wrote:
>

---

From: John Mattsson <[email-masked]>
Date: Tue, 9 Nov 2021 22:23:51 +0000

Hi Russ,

Sending the same content to multiple recipients is an important use case but not the only one. I think that use case is served well with the first approach. I do not think there is a need to support the second approch for this use case, I do not see any benefits compared to the first approach.

I was thinking about a use case where you send multiple messages to a single recipient. If you have a single recipient, the KEK layer is just overhead and you could use the key from the HPKE KEM directly to encypt the payload.

   WZ, Z = Encaps() with the recipient's KEM public key.
   CEK = KDF(Z)
   C = Encrypt payload with CEK.
   Send WZ, C

In this case the addition of UKM would make it possible to send several messages to the same recipient with a single Encapsulation WZ.

   WZ, Z = Encaps() with the recipient's KEM public key.

   CEK1 = KDF(Z, UKM1)
   C1 = Encrypt payload1 with CEK1.
   Send WZ, C1

   CEK1 = KDF(Z, UKM2)
   C2 = Encrypt payload2 with CEK2.
   Send WZ, C2

   CEK3 = KDF(Z, UKM3)
   C3 = Encrypt payload3 with CEK3.
   Send WZ, C3

My understanding is that HPKE already has User Keying Material (UKM) in the form of salt and info

   *  A Key Derivation Function (KDF):

      -  "Extract(salt, ikm)": Extract a pseudorandom key of fixed
         length "Nh" bytes from input keying material "ikm" and an
         optional byte string "salt".

      -  "Expand(prk, info, L)": Expand a pseudorandom key "prk" using
         optional string "info" into "L" bytes of output keying
         material.

Cheers,
John

From: Russ Housley <[email-masked]>
Date: Tuesday, 9 November 2021 at 22:44
To: John Mattsson <[email-masked]>
Cc: Hannes Tschofenig <[email-masked]>, [email-masked] <[email-masked]>, Brendan Moran <[email-masked]>
Subject: Re: [COSE] HPKE for COSE
John:

   For each recipient:

   Send SetOf(WZ,WCEK), C.

   For each recipient:

   CEK = KDF(Z)

   Send SetOf(WZ), C

Russ

On Nov 9, 2021, at 8:33 AM, John Mattsson <john.mattsson=[email-masked]<mailto:john.mattsson=[email-masked]>> wrote:

Hannes wrote:

{11 : 17} or {11 : -17}

Cheers,
John