From 5adf63fe301e812f5776448f9560af9d6d842554 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 20 Jul 2012 07:37:48 +0200 Subject: lib/crypto: add aes_ccm_128 metze --- lib/crypto/aes_ccm_128.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++ lib/crypto/aes_ccm_128.h | 54 +++++++++++++++ lib/crypto/crypto.h | 1 + lib/crypto/wscript_build | 2 +- 4 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 lib/crypto/aes_ccm_128.c create mode 100644 lib/crypto/aes_ccm_128.h (limited to 'lib/crypto') diff --git a/lib/crypto/aes_ccm_128.c b/lib/crypto/aes_ccm_128.c new file mode 100644 index 0000000000..ac8e01f631 --- /dev/null +++ b/lib/crypto/aes_ccm_128.c @@ -0,0 +1,170 @@ +/* + AES-CCM-128 (rfc 3610) + + Copyright (C) Stefan Metzmacher 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "replace.h" +#include "../lib/crypto/crypto.h" +#include "lib/util/byteorder.h" + +#define M_ ((AES_CCM_128_M - 2) / 2) +#define L_ (AES_CCM_128_L - 1) + +static inline void aes_ccm_128_xor(const uint8_t in1[AES_BLOCK_SIZE], + const uint8_t in2[AES_BLOCK_SIZE], + uint8_t out[AES_BLOCK_SIZE]) +{ + uint8_t i; + + for (i = 0; i < AES_BLOCK_SIZE; i++) { + out[i] = in1[i] ^ in2[i]; + } +} + +void aes_ccm_128_init(struct aes_ccm_128_context *ctx, + const uint8_t K[AES_BLOCK_SIZE], + const uint8_t N[AES_CCM_128_NONCE_SIZE], + size_t a_total, size_t m_total) +{ + uint8_t B_0[AES_BLOCK_SIZE]; + + ZERO_STRUCTP(ctx); + + AES_set_encrypt_key(K, 128, &ctx->aes_key); + memcpy(ctx->nonce, N, AES_CCM_128_NONCE_SIZE); + ctx->a_remain = a_total; + ctx->m_remain = m_total; + + /* + * prepare B_0 + */ + B_0[0] = L_; + B_0[0] += 8 * M_; + if (a_total > 0) { + B_0[0] += 64; + } + memcpy(&B_0[1], ctx->nonce, AES_CCM_128_NONCE_SIZE); + RSIVAL(B_0, (AES_BLOCK_SIZE - AES_CCM_128_L), m_total); + + /* + * prepare X_1 + */ + AES_encrypt(B_0, ctx->X_i, &ctx->aes_key); + + /* + * prepare B_1 + */ + if (a_total >= UINT32_MAX) { + RSSVAL(ctx->B_i, 0, 0xFFFF); + RSBVAL(ctx->B_i, 2, a_total); + ctx->B_i_ofs = 10; + } else if (a_total >= 0xFF00) { + RSSVAL(ctx->B_i, 0, 0xFFFE); + RSIVAL(ctx->B_i, 2, a_total); + ctx->B_i_ofs = 6; + } else if (a_total > 0) { + RSSVAL(ctx->B_i, 0, a_total); + ctx->B_i_ofs = 2; + } + + ctx->S_i_ofs = AES_BLOCK_SIZE; +} + +void aes_ccm_128_update(struct aes_ccm_128_context *ctx, + const uint8_t *v, size_t v_len) +{ + size_t *remain; + + if (ctx->a_remain > 0) { + remain = &ctx->a_remain; + } else { + remain = &ctx->m_remain; + } + + while (v_len > 0) { + size_t n = MIN(AES_BLOCK_SIZE - ctx->B_i_ofs, v_len); + bool more = true; + + memcpy(&ctx->B_i[ctx->B_i_ofs], v, n); + v += n; + v_len -= n; + ctx->B_i_ofs += n; + *remain -= n; + + if (ctx->B_i_ofs == AES_BLOCK_SIZE) { + more = false; + } else if (*remain == 0) { + more = false; + } + + if (more) { + continue; + } + + aes_ccm_128_xor(ctx->X_i, ctx->B_i, ctx->B_i); + AES_encrypt(ctx->B_i, ctx->X_i, &ctx->aes_key); + + ZERO_STRUCT(ctx->B_i); + ctx->B_i_ofs = 0; + } +} + +static void aes_ccm_128_S_i(struct aes_ccm_128_context *ctx, + uint8_t S_i[AES_BLOCK_SIZE], + size_t i) +{ + uint8_t A_i[AES_BLOCK_SIZE]; + + A_i[0] = L_; + memcpy(&A_i[1], ctx->nonce, AES_CCM_128_NONCE_SIZE); + RSIVAL(A_i, (AES_BLOCK_SIZE - AES_CCM_128_L), i); + + AES_encrypt(A_i, S_i, &ctx->aes_key); +} + +void aes_ccm_128_crypt(struct aes_ccm_128_context *ctx, + uint8_t *m, size_t m_len) +{ + while (m_len > 0) { + if (ctx->S_i_ofs == AES_BLOCK_SIZE) { + ctx->S_i_ctr += 1; + aes_ccm_128_S_i(ctx, ctx->S_i, ctx->S_i_ctr); + ctx->S_i_ofs = 0; + } + + m[0] ^= ctx->S_i[ctx->S_i_ofs]; + m += 1; + m_len -= 1; + ctx->S_i_ofs += 1; + } +} + +void aes_ccm_128_digest(struct aes_ccm_128_context *ctx, + uint8_t digest[AES_BLOCK_SIZE]) +{ + uint8_t S_0[AES_BLOCK_SIZE]; + + aes_ccm_128_S_i(ctx, S_0, 0); + + /* + * note X_i is T here + */ + aes_ccm_128_xor(ctx->X_i, S_0, digest); + + ZERO_STRUCT(S_0); + ZERO_STRUCTP(ctx); +} diff --git a/lib/crypto/aes_ccm_128.h b/lib/crypto/aes_ccm_128.h new file mode 100644 index 0000000000..a98c754433 --- /dev/null +++ b/lib/crypto/aes_ccm_128.h @@ -0,0 +1,54 @@ +/* + AES-CCM-128 (rfc 3610) + + Copyright (C) Stefan Metzmacher 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef LIB_CRYPTO_AES_CCM_128_H +#define LIB_CRYPTO_AES_CCM_128_H + +#define AES_CCM_128_M 16 +#define AES_CCM_128_L 4 +#define AES_CCM_128_NONCE_SIZE (15 - AES_CCM_128_L) + +struct aes_ccm_128_context { + AES_KEY aes_key; + uint8_t nonce[AES_CCM_128_NONCE_SIZE]; + + size_t a_remain; + size_t m_remain; + + uint8_t X_i[AES_BLOCK_SIZE]; + uint8_t B_i[AES_BLOCK_SIZE]; + size_t B_i_ofs; + + uint8_t S_i[AES_BLOCK_SIZE]; + size_t S_i_ofs; + size_t S_i_ctr; +}; + +void aes_ccm_128_init(struct aes_ccm_128_context *ctx, + const uint8_t K[AES_BLOCK_SIZE], + const uint8_t N[AES_CCM_128_NONCE_SIZE], + size_t a_total, size_t m_total); +void aes_ccm_128_update(struct aes_ccm_128_context *ctx, + const uint8_t *v, size_t v_len); +void aes_ccm_128_crypt(struct aes_ccm_128_context *ctx, + uint8_t *m, size_t m_len); +void aes_ccm_128_digest(struct aes_ccm_128_context *ctx, + uint8_t digest[AES_BLOCK_SIZE]); + +#endif /* LIB_CRYPTO_AES_CCM_128_H */ diff --git a/lib/crypto/crypto.h b/lib/crypto/crypto.h index c0d85c899e..1f5a1b7e62 100644 --- a/lib/crypto/crypto.h +++ b/lib/crypto/crypto.h @@ -26,4 +26,5 @@ #include "../lib/crypto/arcfour.h" #include "../lib/crypto/aes.h" #include "../lib/crypto/aes_cmac_128.h" +#include "../lib/crypto/aes_ccm_128.h" diff --git a/lib/crypto/wscript_build b/lib/crypto/wscript_build index 849bf1664e..cd7a466a15 100644 --- a/lib/crypto/wscript_build +++ b/lib/crypto/wscript_build @@ -9,7 +9,7 @@ elif not bld.CONFIG_SET('HAVE_COMMONCRYPTO_COMMONDIGEST_H'): bld.SAMBA_SUBSYSTEM('LIBCRYPTO', source='''crc32.c hmacmd5.c md4.c arcfour.c sha256.c hmacsha256.c - aes.c rijndael-alg-fst.c aes_cmac_128.c + aes.c rijndael-alg-fst.c aes_cmac_128.c aes_ccm_128.c ''' + extra_source, deps='talloc' + extra_deps ) -- cgit