nisse@lysator.liu.se (Niels Möller) writes:
Or use struct nettle_buffer for the destination operand, possibly in combination with some macro/function to query the needed space.
I have now tried this approach. For those have haven't used nettle_buffer, it's struct with a data pointer, allocation size, and current size. It can be setup to either use a fix buffer provided by the application, or it can grow as needed, using realloc, xrealloc, or any custom realloc function provided by the application.
A totally untested implementation in the aead-api branch. There actually two interfaces, defined in aead.h.
First question is whether or not this is useful. If it is useful, maybe the interfaces need tweaking. A first test (besides regular test cases) would be to rewrite examples/rsa-encrypt.c and examples/rsa-decrypt.c to use some aead mechanism for the bulk encryption, rather than aes-cbc + hmac-sha1.
First, an interface for processing complete messages. These use the same context as the lower-level algorithm. More or less the same as I have sketched on this list previously.
-----8<---------
/* Interface for processing a complete message at a time. Application must allocate the context and call the set_key function before using this interface. */ size_t aead_encrypt_msg_size (const struct nettle_aead *aead, size_t size); void aead_encrypt_msg (const struct nettle_aead *aead, void *ctx, const uint8_t *nonce, size_t ad_size, const uint8_t *ad, size_t plaintext_size, uint8_t *gibberish, const uint8_t *plaintext);
size_t aead_decrypt_msg_size (const struct nettle_aead *aead, size_t size); int aead_decrypt_msg (const struct nettle_aead *aead, void *ctx, const uint8_t *nonce, size_t ad_size, const uint8_t *ad, size_t gibberish_size, uint8_t *plaintext, const uint8_t *gibberish);
-----8<---------
Second interface is for streaming operation, hiding the block size. Here, the context is the context of the underlying aead algorithm, but with a small extra buffer added at the end (aead->block_size for encryption, and aead->block_size + aead->digest_size for decryption).
-----8<---------
/* Streaming interface, including buffering. Uses a context struct corresponding to the aead algorithm, with additional buffers added at the end. Hence, the context can be passed to algorithm-specific functions. Applications should call set_key and set_nonce before using these functions. */
#define aead_update(aead, ctx, size, data) \ ((aead)->update((ctx), (size), (data)))
size_t aead_encrypt_ctx_size (const struct nettle_aead *aead);
void aead_encrypt_init (const struct nettle_aead *aead, void *ctx, const uint8_t *nonce);
/* Attempts to grow the destination buffer as needed. Returns the amount of plaintext that could be processed. */ size_t aead_encrypt (const struct nettle_aead *aead, void *ctx, struct nettle_buffer *buffer, size_t size, const uint8_t *plaintext);
/* Maximum output size for aead_encrypt_final. */ size_t aead_encrypt_final_size (const struct nettle_aead *aead);
/* Returns 1 on success, 0 if buffer was too small and growing it failed. On failure, some output may still be generated, and the function can be called again with more output space. */ int aead_encrypt_final (const struct nettle_aead *aead, void *ctx, struct nettle_buffer *buffer);
size_t aead_decrypt_ctx_size (const struct nettle_aead *aead);
void aead_decrypt_init (const struct nettle_aead *aead, void *ctx, const uint8_t *nonce);
/* Attempts to grow the destination buffer as needed. Returns the amount of plaintext that could be processed. */ size_t aead_decrypt (const struct nettle_aead *aead, void *ctx, struct nettle_buffer *dst, size_t size, const uint8_t *gibberish);
/* Maximum output size for aead_decrypt_final. */ size_t aead_decrypt_final_size (const struct nettle_aead *aead);
/* Returns 1 on success, 0 if buffer is too small or authentication failed. FIXME: Distinguish between failure cases? */ int aead_decrypt_final (const struct nettle_aead *aead, void *ctx, struct nettle_buffer *dst);
-----8<---------
In particular the decrypt function is quite messy, which makes me think that it's a good idea to implement this at one place, on a level between the application and the implementation of each specific aead mechanism.
Regards, /Niels