Norbert Pocs <np...@redhat.com> writes:

> My idea about the API was: set up a context, do encryption with the created
> context;
> as mentioned in the standard [2].
> The documentation was updated to cover all the functions listed in hpke.h
> In short:
> - hpke_setup_* sets up the encryption context for sender or receiver
> in the given mode
> - hpke_seal: encryption
> - hpke_open: decryption
> - export_secret: derives a secret from the internal secret

I've read the spec now, and I think I've have a better understanding of
what it's doing, although I don't yet grasp all the details.

Let me sketch how I think an api for it could look like.

* We need an object responsible for the symmetric encryption/decryption,
  similar to the Context type in the spec. It's not clear to me if we
  need separate types for sender and receiver (as suggested in the spec)
  or if we can use the same type.

  This one needs to hold a context for an AEAD algorithm initialized
  with a secret key, function pointers for doing the actual
  encrypt/decrypt (possibly a const struct nettle_aead*), and the
  message sequence number (could perhaps be an uin64_t, regardless of
  algorithm).

  As far as I see, it doesn't need to know what KDF or KEM was used when
  the context was created.

  The context should have associated functions like
  encrypt_msg/decrypt_message, maybe "streaming" functions like update,
  encrypt/decrypt/digest, and perhaps some way to access the "export
  secret" feature.

  From the docs:

   : @deftypefun int hpke_seal (struct hpke_ctx @var{ctx}, uint8_t *@var{aad}, 
size_t @var{aad_len}, uint8_t *@var{pt}, size_t @var{pt_len}, uint8_t 
**@var{ct}, size_t *@var{ct_len})
   : Encrypts a plaintext using an hpke context and an
   : optional additional authenticated data into ciphertext.
   : @end deftypefun

  I take it hpke_ctx argument should be a pointer, right? Is it
  non-const because it needs to update the sequence number? The aad and
  pt arguments should be const, I think. pt_len will be known by the
  caller, but how can it query for the size of the corresponding cipher
  text? For other aead modes, nettle use a single length argument, and
  it's the lenght of the destination (ct for encrypto, pt for decrypt),
  see https://www.lysator.liu.se/~nisse/nettle/nettle.html#Conventions.

* Then we need some way(s) way to create/initialize such a context, for
  sender and receiver.

  One way would be to have general function, which gets kdf, kem and
  aead to use as arguments. Or would could take out some or all of that
  parameterization and have one function for each configuration.

  E.g., we could have something like

    hpke_init_curve25519_send(struct hpke_context *ctx, 
                              const uint8_t *receiver_pubkey,
                              const struct hkpe_kdf *kdf,
                              const struct nettle_aead *aead);

  to initialize the sender's context for sending to a receiver with a
  curve25519 public key. Now there are a few things missing: I think it
  needs to know the hpke id for the aead, and we should also pass in
  some parameters to specify how to get randomness for the ephemeral keys.

  If possible, it's also nice if allocation can be left to the caller,
  e.g., something like

    hpke_init_curve25519_send(struct hpke_context *ctx,
                              const struct nettle_aead *aead,
                              void *aead_ctx,
                              const uint8_t *receiver_pubkey,
                              const struct hkpe_kdf *kdf);

* It may make sense to have one object that is responsible for a hpke
  configuration (mainly, which algorithms and which mode to use, maybe
  randomness source), and have functions which takes such a (const)
  objects + relevant keys and initializes a context like above.

> To narrow the scope of the review I suggest to start with the base mode
> and for the algorithms perhaps with one of the FIPS 140-3 approved ones, but
> otherwise I have not much preference in the algorithms.

I'm afraid I don't know what is or isn't approved in FIPS 140-3. I think
point validation might be simpler with curve25519 than with the secp
curves. I'd prefer initial algorithm based on what you think is most
useful for applications.

Starting with base mode only makes sense to me. 

> I am a bit confused on the external structs. How I understood was that the
> users can use it for the context creation - which algorithms they prefer to
> use. Therefore it should be public so they can pass it to `hpke_ctx_init`
> or do I understand it wrong?

I think they should be public in that sense. However, there are some
subtle details. Either they are completely public: You declare the types
in the public hpke.h, and declare (as const extern struct ...)
instances, details becomes part of the nettle ABI. This is like, e.g.,
const struct nettle_hash nettle_sha256.

Or you only forward declare the type in hpke.h, like

  struct hpke_kem;

which actual contents in the private hpke-internal.h.

In that case, you cannot publicly declare constants (because in some
caes that can result in copy relocations making the size of the struct
leak into the abi, even though contents of the struct was intended to be
private). Instead, you have to declare accessors, like

  const struct hpke_kem *hpke_get_curve25519(void);

This is like struct ecc_curve is handled.

> Is there a function which can clear memory space after a private key?
> I see `gmp_free`, but no comments to it.

I think you have to just use memset.

>> * There's quite a lot in struct hpke_ctx. I think it would be good to
>>   think about what parts are (i) algorithm parameterization, (ii)
>>   related to key schedule, (iii) per message state? Can some parts be
>>   moved from the state to inputs or outputs of relevant functions?
> I didn't want to have enormous function parameters everywhere, that's
> why I moved the variables there. If you are okay with bulkier function
> arguments I'll rework this.

Not sure what's the right way. But a context with lots of setter methods
is rather different from most other things in Nettle. 

I often find that it makes things clearer to have separation between the
separate stages/layers, e.g.: First do algorithm parameterization,
resulting in a struct representing an instantiation of hpke mode. Then
use a (const) struct like that + keys to create a session with the
result of the key schedule. And then use that to process one or more
messages, with another struct representing per-message state. (Not a
perfect fit for hpke, but I hope you get the idea. In this case the
"session" thing would correspond to the "context" in the spec, and if it
is responsible for the message sequence number, it has to be mutable).

Regards,
/Niels

-- 
Niels Möller. PGP key CB4962D070D77D7FCB8BA36271D8F1FF368C6677.
Internet email is subject to wholesale government surveillance.
_______________________________________________
nettle-bugs mailing list -- nettle-bugs@lists.lysator.liu.se
To unsubscribe send an email to nettle-bugs-le...@lists.lysator.liu.se

Reply via email to