Replying to myself:

>     The context struct and the set_key function is essential to be able
>     to do any optimizations using key-dependant tables.

It actually gets a bit complicated. I think we need several
context/state structs.

First, the key. The only way the key is directly used is for encrypting
things using the underlying block cipher. So it makes sense to represent
the key as

  const void *cipher_ctx;
  nettle_crypt_func *encrypt;

(except that for historical reasons, the first argument for
nettle_crypt_func is not const).

Next, we have tables derived from the key. These are needed for
otpimized implementations of ghash, and should be reused when several
messages are processed using the same key. E.g., this could be done as

  struct gcm128_ctx
  {
    const void *cipher_ctx;
    nettle_crypt_func *encrypt;

    uint8_t H[16]; /* Hash subkey */
    uint8_t M0[16][256]; /* Key-dependent table. */
  };

  void
  gcm128_ctx_init(struct gcm128_ctx *ctx,
                  const void *cipher_ctx,
                  nettle_crypt_func *encrypt);

(It would be more consistent with the rest of nettle to not store those
pointers in gcm128_ctx, since its supposed to be ok to memcpy context
structs around. One could either pass them as arguments to all
functions, or inline an aes_ctx if aes is all we care about. I include
them here, to simplify function prototypes).

Functions to process complete gcm messages can take this ctx as
argument. The main ghash iteration would also take this context struct
as argument,

  /* Set state = (state XOR data) dot H */
  void
  ghash_update(const struct gcm128_ctx *ctx,
               uint8_t *state,
               const uint8_t *data);

For streaming operations, we also need a per-message state struct,
something like

  struct gcm128_msg
  {
    uint8_t Y[16];  /* counter */
    uint8_t J[16];  /* encryption of that */
    uint8_t J0[16]; /* first encrypted counter block to be used for 
constructing the digest. */
    uint8_t hash[16]; /* hashing state */

    unsigned index; /* Index when doing partial blocks */
    uint32_t auth_length;
    uint32_t msg_length;
  };

  void
  gcm128_msg_init(struct gcm128_msg *msg, const struct gcm128_ctx *ctx,
                  uint32_t iv_length, const uint8_t *iv);

  /* Process auxillary auth data */
  void
  gcm128_msg_auth(struct gcm128_msg *msg, const struct gcm128_ctx *ctx,
                  uint32_t length, const uint8_t *data);

  /* Only difference between encrypt and decrypt is if data is hashed
     before or after xoring with the key stream. */
  void
  gcm128_msg_encrypt(struct gcm128_msg *msg, const struct gcm128_ctx *ctx,
                     uint32_t length, uint8_t *dst, const uint8_t *src);

  void
  gcm128_msg_decrypt(struct gcm128_msg *msg, const struct gcm128_ctx *ctx,
                     uint32_t length, uint8_t *dst, const uint8_t *src);

  gcm128_msg_digest(struct gcm128_msg *msg, const struct gcm128_ctx *ctx,
                    uint32_t length, uint8_t *dst);

Comments? It gets more complicated than almost anything currently in
Nettle.

Regards,
/Niels

-- 
Niels Möller. PGP-encrypted email is preferred. Keyid C0B98E26.
Internet email is subject to wholesale government surveillance.
_______________________________________________
nettle-bugs mailing list
[email protected]
http://lists.lysator.liu.se/mailman/listinfo/nettle-bugs

Reply via email to