Interested in unpacking The COSE_Key has new *kty HPKE*, and its JWK cousin.

Comments inline:

On Thu, Nov 17, 2022 at 2:02 PM Ilari Liusvaara <[email protected]>
wrote:

> On Thu, Nov 17, 2022 at 10:05:28AM -0600, Orie Steele wrote:
> > Illari answered a related question here:
> > https://mailarchive.ietf.org/arch/msg/cose/eIxt4u8ox8N35-ZbDk_vsFD9PP4/
> >
> > I have similar questions on how HPKE, PQC KEMs, and COSE Key work
> together
> > in practice.
>
> Here is how I think it will work:
>
> - The COSE_Key has new kty HPKE, containing the algorithm used
>   (expressed using HPKE KEM identifier), public key blob (bstr),
>   possibly some hints and for private keys, private key blob (bstr).
> - When encrypting, the COSE-HPKE just passes the HPKE code the KEM
>   identifier and the public key blob from the key (along with other
>   stuff like the plaintext to encrypt). HPKE code knows what to do
>   with those.
>

Let's look at example in JOSE syntax of how this might work:

Based on https://github.com/dajiaji/hpke-js

       const suite = new CipherSuite({
          kem: TBD, //  Kem.KemKyber1024HkdfSha256 similar to existing
values such as Kem.DhkemP256HkdfSha256
          kdf: Kdf.HkdfSha256,
          aead: Aead.Aes128Gcm
        });

        // instead of generating
        // const rkp = await suite.generateKeyPair();
        // we will import

        const publicKey = await suite.importJwk({
         kty: TBD // HPKE or Kyber
         crv: TBD // not present or Kyber-1024 ... based on previous
discussion on lists
         alg: TBD // not present or HPKE-kem-kdf-aead ... based on previous
discussion on lists
         x: ...
        });

        const sender = await suite.createSenderContext({
          recipientPublicKey: publicKey
        });

         const privateKey = await suite.importJwk({
           kty: TBD // HPKE or Kyber
           crv: TBD // not present or Kyber-1024 ... based on previous
discussion on lists
           alg: TBD // not present or HPKE-kem-kdf-aead ... based on
previous discussion on lists
           x: ...,
           d: ...
        });

        const recipient = await suite.createRecipientContext({
          recipientKey: privateKey,
          enc: sender.enc,
        });

        // encrypt
        const ct = await sender.seal(new TextEncoder().encode("hello
world!"));

        // decrypt
        const pt = await recipient.open(ct);


The thing I was expecting which seems to be different than what others are
expecting is the repeating of the HPKE parameterization

I would have assumed a slightly different interface, that pulled the
parameterization from the key representations, for example:

// encrypt
const sender = HPKE.JOSE.sender.createSenderContext({
  publicKeyJwk: *kty*, ..., x,  *alg: Kem.KemKyber1024HkdfSha256 -
Kdf.HkdfSha256 - Aead.Aes128Gcm* }
})
const ct = await sender.seal(new TextEncoder().encode("hello world!"));

 // decrypt
const recipient = HPKE.JOSE.recipient.createRecipientContext({
  privateKeyJwk: *kty*, ..., x, d, *alg: Kem.KemKyber1024HkdfSha256 -
Kdf.HkdfSha256 - Aead.Aes128Gcm* },
  enc: sender.enc,
})
const pt = await recipient.open(ct);

I would expect that keys generated for use with a specific alg encode this
intention in the alg field... and that the `alg` values in a JWE match
these.
The header would also need to handle the other details Ilari mentions
above, such as "hints".

I understand HPKE design focuses on moving the parameterization outside of
the key representations, and to enable the same public or private key to be
used in many different ways.

I think that's fine for folks who want that, but when designing APIs I
prefer to set this in stone at the time of key generation,
and not invite implementers to use the same key material with many
different parametrization of algorithms.

As I understand it, HPKE can support both design philosophies, but as we
start to register new kty, or alg values, we will be driving consolidation
towards one side or the other when HPKE is used in JOSE or COSE.

- When decrypting, the COSE-HPKE just passes the HPKE code the KEM
>   identifier and the private key blob from the key (along with other
>   stuff like encapsulated key and the ciphertext to decrypt. HPKE code
>   knows what to do with those.
>
> If the KEM is PQC or not is not something COSE-HPKE code needs to
> concern itself with. Currently HPKE does not have any PQC KEMs, but
> that could change at any time.
>
> As for PQC outside HPKE in COSE, that is obviously more complicated
> matter, that turns out to need at least some new alg values, along
> with new (sub)types for the keys. Those things work in way similar to
> ECDH-ES, however reusing the ECDH-ES codepoints is not possible due to
> ECDH-ES requiring ephemeral key, which just does not exist for PQC.
>
>
Yes, agreed, but I think the developer experience should still be
considered.


> > On Thu, Nov 17, 2022 at 9:55 AM Laurence Lundblade <
> [email protected]>
> > wrote:
> >
> > > The details of how HPKE wraps the CEK are needed. The simple answer
> could
> > > be that the CEK is the plain text input to Seal(), but typically we
> want to
> > > use a specialized key wrap protocol when wrapping keys and Seal() may
> not
> > > be that. Maybe it’s OK though, but the crypto experts that know why key
> > > wrap is needed should make that call. Alternatively, we could come up
> with
> > > some way for HPKE to output a KEK.
>
> HPKE Seal() is good enough to wrap keys. It does not have the
> Initialization Vector issues that traditionally drive use of the special
> key wrap algorithms.
>
>
>
> -Ilari
>
> _______________________________________________
> COSE mailing list
> [email protected]
> https://www.ietf.org/mailman/listinfo/cose
>


-- 
*ORIE STEELE*
Chief Technical Officer
www.transmute.industries

<https://www.transmute.industries>
_______________________________________________
COSE mailing list
[email protected]
https://www.ietf.org/mailman/listinfo/cose

Reply via email to