Owen Kirby is working on an implementation of the CCM mode. I'm forwarding my comments here (with permission).
Regards, /Niels
nisse@lysator.liu.se (Niels Möller) writes:
Owen Kirby is working on an implementation of the CCM mode. I'm forwarding my comments here (with permission).
Ooops, I got bitten by the bad mailman configuration regarding attachments. New attempt below. /Niels
Owen Kirby osk@exegin.com writes:
I've been looking at trying to add some of the AES-CCM mode cipher suites to GnuTLS. It seemed like the best way to start would be to add support for them to nettle, and this is what I've come up with so far.
Makes sense to me.
These cipher modes are a combination of a CTR encryption with a CBC-MAC, they are technically an AEAD cipher mode, but there are some weird parameters that need to be passed to the nonce function that make it unlikely to work well with the nettle_aead API.
I haven't looked carefully at CCM, I've only read the critique in the eax paper (eax is also CTR-mode + CBC-mac, but in a better way, according to the eax authors).
Let me know if you think these might be suitable for inclusion to nettle, or if there is anything that you think needs to be changed.
I think it looks pretty good. Thanks!
Some initial comments below. I think it would make sense to discuss it on the public nettle mailing list, in particular any interface issues. Feel free to reply on-list. And if you don't object, I'd like to forward this reply to the list.
If you make another revision of these patches, GNU-style ChangeLog entries are also appreciated. And documentation, but it's probably good to wait with that until any interface issues are sorted out.
--- /dev/null +++ b/ccm-aes.c @@ -0,0 +1,65 @@ +/* ccm-aes.c
- Counter with CBC-MAC mode, specified by NIST,
- */
+/* nettle, low-level cryptographics library
- Copyright (C) 2011 Niels Möller
- The nettle library is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or (at your
- option) any later version.
- The nettle library is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- License for more details.
- You should have received a copy of the GNU Lesser General Public License
- along with the nettle library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- MA 02111-1301, USA.
- */
+#if HAVE_CONFIG_H +# include "config.h" +#endif
+#include "ccm.h"
+void +ccm_aes_set_nonce(struct ccm_aes_ctx *ctx,
size_t length, const uint8_t *nonce,
size_t authlen, size_t msglen, size_t taglen)
+{
- CCM_SET_NONCE(ctx, length, nonce, authlen, msglen, taglen);
+}
I don't think the ccm_aes family of functions are needed. ccm_aes128 etc should be sufficient, and since it's a new feature, there's nothing to be backwards compatible with.
--- /dev/null +++ b/ccm.c @@ -0,0 +1,210 @@ +/* ccm.h
- Counter with CBC-MAC mode, specified by NIST,
- */
+/* nettle, low-level cryptographics library
- Copyright (C) 2011 Niels Möller
- Copyright (C) 2011 Katholieke Universiteit Leuven
- Contributed by Owen Kirby
I think we need to be a bit clearer about the copyright. We currently don't do any copyright assignments for Nettle. I take it you wrote the ccm implementation, so you own the copyright. Unless it's owned by your employer or client?
(BTW, I've been very sloppy with copyright headers in the test programs, but it would be good with an accurate header also for ccm-test.c).
+/*
- Because of the encoding of L(a), we have to handle input data that might
- not be a multiple of the block size anyways, as such, we don't have the
- input constraint of most AEAD modes that the intermediate calls to update()
- must be in multiples of the block size.
- */
+void +ccm_update(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f,
size_t length, const uint8_t *data)
In nettle, the update functions usually accept arbitrary size, just like you do. Complete blocks are only required for crypt functions.
+/*
- Because of the underlying CTR mode encryption, when called multiple times
- the data in intermediate calls must be provided in multiples of the block
- size.
- */
+void +ccm_encrypt(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f,
size_t length, uint8_t *dst, const uint8_t *src)
+{
- ccm_pad(ctx, cipher, f);
- ccm_update(ctx, cipher, f, length, src);
- ctr_crypt(cipher, f, CCM_BLOCK_SIZE, ctx->ctr.b, length, dst, src);
+}
+/*
- Because of the underlying CTR mode decryption, when called multiple times
- the data in intermediate calls must be provided in multiples of the block
- size.
- */
+void +ccm_decrypt(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f,
size_t length, uint8_t *dst, const uint8_t *src)
+{
- ctr_crypt(cipher, f, CCM_BLOCK_SIZE, ctx->ctr.b, length, dst, src);
- ccm_pad(ctx, cipher, f);
- ccm_update(ctx, cipher, f, length, dst);
+} +void +ccm_digest(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f,
size_t length, uint8_t *digest)
+{
- int i = CCM_BLOCK_SIZE - CCM_FLAG_GET_L(ctx->ctr.b[CCM_OFFSET_FLAGS]);
- while (i < CCM_BLOCK_SIZE) ctx->ctr.b[i++] = 0;
- ccm_pad(ctx, cipher, f);
- ctr_crypt(cipher, f, CCM_BLOCK_SIZE, ctx->ctr.b, length, digest, ctx->tag.b);
+}
Are there any sanity checks that the lengths match the ones specified with set_nonce?
--- /dev/null +++ b/ccm.h +/* Obnoxiously, CCM mode requires the adata and message lengths when
- building the IV. This prevents any sort of streaming type API to
- the cipher mode. We chose to put all of that cruft in the set_nonce()
- function, so that the update/encrypt/decrypt and digest functions will
- remain compatible with the nettle AEAD API.
- */
+void +ccm_set_nonce(struct ccm_ctx *ctx, size_t noncelen, const uint8_t *nonce,
size_t authlen, size_t msglen, size_t taglen);
Are there any alternative ways to design this interface? E.g., one could specify that for ccm, the update and encrypt/decrypt functions may be called at most once for each message, with no possibility for streaming or incremental processing. But that won't help if one needs *both* lengths before processing either the message data or the associated data.
The general aead interface should include some easy-to-use functions for "all-in-one" processing of messages. It would be nice if ccm could be made to fit into that framework sufficiently well to make such functions work.
--- /dev/null +++ b/testsuite/ccm-test.c
Thanks for including thorough tests.
Regards, /Niels
nisse@lysator.liu.se (Niels Möller) writes:
Owen Kirby osk@exegin.com writes:
--- /dev/null +++ b/ccm.h +/* Obnoxiously, CCM mode requires the adata and message lengths when
- building the IV. This prevents any sort of streaming type API to
- the cipher mode. We chose to put all of that cruft in the set_nonce()
- function, so that the update/encrypt/decrypt and digest functions will
- remain compatible with the nettle AEAD API.
- */
+void +ccm_set_nonce(struct ccm_ctx *ctx, size_t noncelen, const uint8_t *nonce,
size_t authlen, size_t msglen, size_t taglen);
Are there any alternative ways to design this interface? E.g., one could specify that for ccm, the update and encrypt/decrypt functions may be called at most once for each message, with no possibility for streaming or incremental processing. But that won't help if one needs *both* lengths before processing either the message data or the associated data.
It looks like that isn't possible. Reading the code (I haven't read the spec yet), it seems like the message length must be known before processing of the associated data.
However we decide to do the incremental interface for CCM, I think it would be good to also provide an all-in-one function, something like
void ccm_encrypt_message (void *cipher_ctx, nettle_crypt_func *f, size_t nonce_length, const uint8_t *nonce, size_t adata_length, const uint8_t *adata, size_t tag_length, size_t msg_length, uint8_t *dst, const uint8_t *src);
/* Return 1 on success, 0 on authentication failure */ int ccm_decrypt_message (void *cipher_ctx, nettle_crypt_func *f, size_t nonce_length, const uint8_t *nonce, size_t adata_length, const uint8_t *adata, size_t tag_length, size_t msg_length, uint8_t *dst, const uint8_t *src);
(since CCM doesn't quite fit in Nettle's aead framework, it can't easily use any general construction on top of that framework). But there are usecases where incremental processing is desired. E.g, processing a large file (size limited to 16 MB - 1 byte with RFC 5116 parameters for CCM, so maybe not *extremely* large), where you could know the size in advance, e.g., from stat(2), but still might want to do the processing with an i/o buffer in memory limited to, say, 64 KB.
Regards, /Niels
nettle-bugs@lists.lysator.liu.se