Hi, As it is now AEAD ciphers in nettle are supported with their own API. AES-CCM provides: ccm_aes128_set_key ccm_aes128_set_nonce ccm_aes128_update ccm_aes128_encrypt ccm_aes128_decrypt ccm_aes128_digest ccm_aes128_encrypt_message ccm_aes128_decrypt_message
AES-GCM: gcm_aes128_set_key gcm_aes128_update gcm_aes128_set_iv gcm_aes128_encrypt gcm_aes128_decrypt gcm_aes128_digest
chacha-poly1305: chacha_poly1305_set_key chacha_poly1305_set_nonce chacha_poly1305_update chacha_poly1305_encrypt chacha_poly1305_decrypt chacha_poly1305_digest
ccm_aes128_set_nonce takes different parameters from the chacha and gcm equivalent function.
Furthermore the AEAD modes for block ciphers include an abstract layer which can be re-used of other ciphers. For example the GCM mode abstraction is re-used for camellia as well.
So overall there is a kind of "abstract" API followed with the set_key, set_nonce, update, encrypt/decrypt, however these have not always the same parameters as in the CCM case. I'm checking the AES-SIV-CMAC mode which cannot even be put in that abstraction as the MAC in SIV is the IV and thus the MAC-style API doesn't really suit it.
My understanding is that AEAD modes according to RFC5116 need to have 4 inputs: key, nonce, associated data, plaintext so the CCM encrypt and decrypt message seem to be the closer to that API. Would it make sense to standardize on these, and only provide that API for AEAD modes?
The reason I'm asking is because SIV could benefit of a very custom API as well because it can take advantage of multiple associated data, but in the end I believe AEAD is about simplicity. Providing a unique API per AEAD cipher seems to me quite contradictory to that goal.
regards, Nikos
Nikos Mavrogiannopoulos nmav@redhat.com writes:
As it is now AEAD ciphers in nettle are supported with their own API. AES-CCM provides: ccm_aes128_set_key ccm_aes128_set_nonce ccm_aes128_update ccm_aes128_encrypt ccm_aes128_decrypt ccm_aes128_digest ccm_aes128_encrypt_message ccm_aes128_decrypt_message
I've considered ccm odd because it doesn't support a "streaming" mode where the mesage length isn't known up-front.
AES-GCM: gcm_aes128_set_key gcm_aes128_update gcm_aes128_set_iv
And gcm is a bit special because it uses pretty large tables which depend on the key but not the nonce. And it would make sense to rename set_iv to set_nonce, for consitency.
chacha-poly1305: chacha_poly1305_set_key chacha_poly1305_set_nonce chacha_poly1305_update chacha_poly1305_encrypt chacha_poly1305_decrypt chacha_poly1305_digest
These are the methods I'd expect "most" AEADs to have, and it's what the nettle_aead struct is intended to capture. But maybe there are too many exceptions. It's good to have several examples to consider.
I'm checking the AES-SIV-CMAC mode which cannot even be put in that abstraction as the MAC in SIV is the IV and thus the MAC-style API doesn't really suit it.
Does that mean that it processes data twice (first mac, then encryption), so that it can't support "streaming" mode at all, even if lenghts are provided up front?
My understanding is that AEAD modes according to RFC5116 need to have 4 inputs: key, nonce, associated data, plaintext so the CCM encrypt and decrypt message seem to be the closer to that API. Would it make sense to standardize on these, and only provide that API for AEAD modes?
It would make a lot of sense to have some convenience functions to do that, which are consistent between AEADs. However, I think I'd prefer to at least make the set_key method separate, to avoid redoing all of the key setup per message.
So then we'de have something similar to the ccm_*_message functions. Should the nonce length and tag length be variable per message? Would it be useful with a separate area for reading and writing the tag, or should we always attach the tag at the end of the ciphertext, like the current _message functions?
The reason I'm asking is because SIV could benefit of a very custom API as well because it can take advantage of multiple associated data, but in the end I believe AEAD is about simplicity. Providing a unique API per AEAD cipher seems to me quite contradictory to that goal.
I think it's nice to support special features of SIV, but using those functions should be optional.
Regards, /Niels
On Tue, Jan 23, 2018 at 7:34 PM, Niels Möller nisse@lysator.liu.se wrote:
Nikos Mavrogiannopoulos nmav@redhat.com writes:
As it is now AEAD ciphers in nettle are supported with their own API. AES-CCM provides: ccm_aes128_set_key ccm_aes128_set_nonce ccm_aes128_update ccm_aes128_encrypt ccm_aes128_decrypt ccm_aes128_digest ccm_aes128_encrypt_message ccm_aes128_decrypt_message
I've considered ccm odd because it doesn't support a "streaming" mode where the mesage length isn't known up-front.
It seems that the streaming mode is not a feature of AEAD ciphers. The AES-SIV-CMAC is similar in that aspect as the whole plaintext is needed to create the IV.
AES-GCM: gcm_aes128_set_key gcm_aes128_update gcm_aes128_set_iv
And gcm is a bit special because it uses pretty large tables which depend on the key but not the nonce. And it would make sense to rename set_iv to set_nonce, for consitency.
Would be nice.
chacha-poly1305: chacha_poly1305_set_key chacha_poly1305_set_nonce chacha_poly1305_update chacha_poly1305_encrypt chacha_poly1305_decrypt chacha_poly1305_digest
These are the methods I'd expect "most" AEADs to have, and it's what the nettle_aead struct is intended to capture. But maybe there are too many exceptions. It's good to have several examples to consider.
I think that the nettle_aead is too specific to gcm. chacha20-poly1305 fitted in there, but it seems that other AEAD ciphers would not fit.
I'm checking the AES-SIV-CMAC mode which cannot even be put in that abstraction as the MAC in SIV is the IV and thus the MAC-style API doesn't really suit it.
Does that mean that it processes data twice (first mac, then encryption), so that it can't support "streaming" mode at all, even if lenghts are provided up front?
Right. It is tailored towards packet/message encryption.
My understanding is that AEAD modes according to RFC5116 need to have 4 inputs: key, nonce, associated data, plaintext so the CCM encrypt and decrypt message seem to be the closer to that API. Would it make sense to standardize on these, and only provide that API for AEAD modes?
It would make a lot of sense to have some convenience functions to do that, which are consistent between AEADs. However, I think I'd prefer to at least make the set_key method separate, to avoid redoing all of the key setup per message. 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);
Would it be useful with a separate area for reading and writing the tag, or should we always attach the tag at the end of the ciphertext, like the current _message functions?
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.
The reason I'm asking is because SIV could benefit of a very custom API as well because it can take advantage of multiple associated data, but in the end I believe AEAD is about simplicity. Providing a unique API per AEAD cipher seems to me quite contradictory to that goal.
I think it's nice to support special features of SIV, but using those functions should be optional.
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)
The generic non-aes version of it should also contain the pointers to relevant CMAC functions such as: nettle_set_key_func *cmac_set_key, nettle_hash_update_func *cmac_update, nettle_hash_digest_func *cmac_digest and the size of context.
I think with all these parameters, the current API I have could be classified as unbearable even for a low-level one.
regards, Nikos
Nikos Mavrogiannopoulos n.mavrogiannopoulos@gmail.com writes:
On Tue, Jan 23, 2018 at 7:34 PM, Niels Möller nisse@lysator.liu.se wrote:
These are the methods I'd expect "most" AEADs to have, and it's what the nettle_aead struct is intended to capture. But maybe there are too many exceptions. It's good to have several examples to consider.
I think that the nettle_aead is too specific to gcm. chacha20-poly1305 fitted in there, but it seems that other AEAD ciphers would not fit.
I'm afraid you're right. Then we'll either have to change nettle_aead, or introduce a new struct, say nettle_message_aead or so.
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)?
Or should at least tag length be considered parameter of the aead algorithm, not something which can vary from message to message?
For hashes and macs, use of truncated outputs seemed fairly common, which is why the current interfaces includes a digest length argument. 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?
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:
1. The nonce.
2. The ciphertext.
3. 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.
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.
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).
I hope it should be possible to design something reasonable. (And we don't need to expose it in the general aead interface).
Regards, /Niels
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
On Sat, 2018-01-27 at 09:57 +0100, Nikos Mavrogiannopoulos wrote:
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 of having only a high level one.
I've gave up on my attempts for a low-level mode as they were resulting to a very complex to use interface when following nettle conventions, or a very unique interface when trying to capture SIV-CMAC intentions.
Thus, I'm sending an RFC for a high level SIV-CMAC interface with an abstraction function set, which abstract on the cipher. The cipher is then used for both CTR encryption and CMAC. (Initially I tried abstracting over cipher and MAC, which caused a very complex interface, such as functions with 13+ parameters).
That abstraction seems to have a cost on safety as in _siv_s2v() function I simulated the cipher context using an array. Is there a better way to capture that on nettle?
This patch works on top of the proposed CMAC interface.
regards, Nikos
On Fri, Feb 16, 2018 at 10:17:31AM +0100, Nikos Mavrogiannopoulos wrote:
Thus, I'm sending an RFC for a high level SIV-CMAC interface with an abstraction function set, which abstract on the cipher. The cipher is then used for both CTR encryption and CMAC. (Initially I tried abstracting over cipher and MAC, which caused a very complex interface, such as functions with 13+ parameters).
That abstraction seems to have a cost on safety as in _siv_s2v() function I simulated the cipher context using an array. Is there a better way to capture that on nettle?
Is there any feedback on this RFC?
I'd be very interested in the AES-SIV-CMAC support in nettle+gnutls. It will be needed for authenticating NTP packets using the upcoming Network Time Security protocol [1], which I'd like to see supported in the chrony NTP client/server implementation.
[1] https://datatracker.ietf.org/doc/draft-ietf-ntp-using-nts-for-ntp/
nettle-bugs@lists.lysator.liu.se