On Wed, 2018-01-24 at 09:46 +0100, Niels Möller wrote:
So then we'de have something similar to the ccm_*_message functions. Should the nonce length and tag length be variable per message?
The tag is fixed since it is used as the IV. On the branch I'm working on I have the following interface:
struct siv_aes128_cmac_ctx { struct aes128_ctx cipher; uint8_t s2vk[AES128_KEY_SIZE]; };
void siv_aes128_cmac_set_key(struct siv_aes128_cmac_ctx *ctx, const uint8_t *key);
void siv_aes128_cmac_encrypt_message(struct siv_aes128_cmac_ctx *ctx, size_t nlength, const uint8_t *nonce, size_t alength, const uint8_t *adata, size_t tlength, size_t clength, uint8_t *dst, const uint8_t *src);
int siv_aes128_cmac_decrypt_message(struct siv_aes128_cmac_ctx *ctx, size_t nlength, const uint8_t *nonce, size_t alength, const uint8_t *adata, size_t tlength, size_t mlength, uint8_t *dst, const uint8_t *src);
I think this is the right level for most applications. But I'm a bit confused with regards to my questions. Are the tlength and nlength arguments useful (for siv, and and for aead in general)?
The tag length is not. There is an assert in my current code to ensure its value is right. I've keeped this interface compatible with the CCM version (assuming that this will be the generic AEAD interface).
The nlength is variable (0 or more) on SIV so it makes sense to have it there.
Or should at least tag length be considered parameter of the aead algorithm, not something which can vary from message to message?
In CCM removing the tag length will require to introduce a new interface for CCM-8 vs CCM-16. Other modes like GCM can also use shorter auth tags, thus fixing the tag to the interface would require a handful of new functions for each tag length possibility.
For hashes and macs, use of truncated outputs seemed fairly common, which is why the current interfaces includes a digest length argument.
Right, RFC5116's text for AEAD ciphers says about tags: "Each AEAD algorithm MUST provide a description relating the length of the plaintext to that of the ciphertext. This relation MUST NOT depend on external parameters, such as an authentication strength parameter (e.g., authentication tag length). That sort of dependence would complicate the use of the algorithm by creating a situation in which the information from the AEAD registry was not sufficient to ensure interoperability." (from https://tools.ietf.org/html/rfc5116#section-4 )
So I think that when implementing that API, the tag should be indeed implicit per AEAD cipher, meaning that CCM-8 should be treated differently to CCM-16, as well as any GCM variants. The current nettle interface allows more flexibility in that aspect at the cost of another function parameter.
But aeads are a bit different. For SIV, would a shortened tag just reduce the strength of authentication, or would it make it impossible to decrypt the message?
It is not possible in the sense that the IV should be 128-bits and having a shortened tag to be used as IV wouldn't be possible by following the protocol.
I think the expectation is to prepend the tag/IV to the message. As the message interface above doesn't distinguish between tag and ciphertext, I think it quite conveniently fits it.
For authenticated decryption one needs three pieces of data:
The nonce.
The ciphertext.
The tag.
The nonce should most likely be a separate argument, it might not be attached at all to the data on the wire. E.g., it could be derived from an implicit message number.
The current ccm_*_ message functions represents ciphertext and tag as a single blob,
+--------------+-------+ | ciphertext | tag | +--------------+-------+
It seems you're saying that for siv, you put them together in the opposite order,
+-------+--------------+ | tag | ciphertext | +-------+--------------+
Should we treat the encrypted message as a single blob, with any internal structure being an internal detail of the aead? That seems to be the RFC 5116 view.
I think that's reasonable expectation.
In case there are protocols or applications that specify that ciphertext and tag are sent/stored as separately byte strings, we would need to expose that distinction in the api. E.g., say we do in-place block-by-block encryption on disk, and treat nonce and tag for each block as metadata, stored elsewhere.
I'm not sure whether that's a possibility. A protocol which would use an AEAD cipher (e.g., like NTP), would use the formatting required by the AEAD cipher.
A possible interface could be: void siv_aes128_cmac_set_key(struct siv_aes128_cmac_ctx *ctx, const uint8_t *key) void siv_aes128_cmac_s2v(struct siv_aes128_cmac_ctx *ctx, size_t nlength, const uint8_t *nonce, size_t adatalen, size_t *alength, const uint8_t **adata, size_t plength, size_t pdata);
(notice the pointer to pointer for adata)
I think I'd prefer something like
void siv_aes128_cmac_extra_adata(struct siv_aes128_cmac_ctx *ctx, size_t length, const uint8_t *data);
to be called zero or more times between _set_key and the call with the body of the message. (Probably need a separate set_nonce function too, if nonce must be known before processing and associated data).
But then when would generate the actual IV? When data are added gradually, one would have to require order in the calling of functions, to ensure that one would generate the IV to be used by the encryption functions. For example require
siv_aes128_cmac_set_key siv_aes128_cmac_extra_adata siv_aes128_cmac_extra_adata siv_aes_128_cmac_set_nonce (must be last and must be called even if there is no nonce, and will generate and save the IV) siv_aes128_cmac_decrypt (which will use the saved in ctx IV)
or
siv_aes128_cmac_set_key siv_aes128_cmac_extra_adata siv_aes128_cmac_extra _adata siv_aes_128_cmac_set_nonce siv_aes_128_cmac_get_iv siv_aes128_cmac_ decrypt (which will use the provided in param IV)
I'm also not sure how to check the tag? Make siv_aes128_cmac_decrypt() check it and return an int, or provide a digest function which will return the generated IV and let the caller do something with it?
Shouldn't the siv_aes128_cmac_extra_adata be named siv_aes128_cmac_update? (though its semantics would be different from other AEAD ciphers as updating with "ab" is different than two calls with "a" and "b").
Overall, the more I look how a low level API for SIV would look like, the more I think having only a high level one.
regards, Nikos