lib/crypto: optimize aes_ccm_128
authorStefan Metzmacher <metze@samba.org>
Tue, 11 Aug 2015 22:59:58 +0000 (00:59 +0200)
committerJeremy Allison <jra@samba.org>
Thu, 27 Aug 2015 18:23:20 +0000 (20:23 +0200)
- We avoid variables in order to do a lazy cleanup
  in aes_ccm_128_digest() via ZERO_STRUCTP(ctx)
- We use the optimized aes_block_xor() function
- We reuse A_i instead of rebuilding it everything completely.
- Align AES_BLOCK_SIZE arrays to 8 bytes

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11451

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
lib/crypto/aes_ccm_128.c
lib/crypto/aes_ccm_128.h

index 94b980337c1cc0f06d705e501789826fdc5e6037..a821e8d48a8470015bff935eafea2249621d0dfe 100644 (file)
 #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);
@@ -52,22 +39,23 @@ void aes_ccm_128_init(struct aes_ccm_128_context *ctx,
        /*
         * prepare B_0
         */
-       B_0[0]  = L_;
-       B_0[0] += 8 * M_;
+       ctx->B_i[0]  = L_;
+       ctx->B_i[0] += 8 * M_;
        if (a_total > 0) {
-               B_0[0] += 64;
+               ctx->B_i[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);
+       memcpy(&ctx->B_i[1], ctx->nonce, AES_CCM_128_NONCE_SIZE);
+       RSIVAL(ctx->B_i, (AES_BLOCK_SIZE - AES_CCM_128_L), m_total);
 
        /*
         * prepare X_1
         */
-       AES_encrypt(B_0, ctx->X_i, &ctx->aes_key);
+       AES_encrypt(ctx->B_i, ctx->X_i, &ctx->aes_key);
 
        /*
         * prepare B_1
         */
+       ZERO_STRUCT(ctx->B_i);
        if (a_total >= UINT32_MAX) {
                RSSVAL(ctx->B_i, 0, 0xFFFF);
                RSBVAL(ctx->B_i, 2, (uint64_t)a_total);
@@ -81,6 +69,12 @@ void aes_ccm_128_init(struct aes_ccm_128_context *ctx,
                ctx->B_i_ofs = 2;
        }
 
+       /*
+        * prepare A_i
+        */
+       ctx->A_i[0]  = L_;
+       memcpy(&ctx->A_i[1], ctx->nonce, AES_CCM_128_NONCE_SIZE);
+
        ctx->S_i_ofs = AES_BLOCK_SIZE;
 }
 
@@ -89,51 +83,70 @@ void aes_ccm_128_update(struct aes_ccm_128_context *ctx,
 {
        size_t *remain;
 
+       if (v_len == 0) {
+               return;
+       }
+
        if (ctx->a_remain > 0) {
                remain = &ctx->a_remain;
        } else {
                remain = &ctx->m_remain;
        }
 
-       while (v_len > 0) {
+       if (unlikely(v_len > *remain)) {
+               abort();
+       }
+
+       if (ctx->B_i_ofs > 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;
-               }
+       if ((ctx->B_i_ofs == AES_BLOCK_SIZE) || (*remain == 0)) {
+               aes_block_xor(ctx->X_i, ctx->B_i, ctx->B_i);
+               AES_encrypt(ctx->B_i, ctx->X_i, &ctx->aes_key);
+               ctx->B_i_ofs = 0;
+       }
 
-               aes_ccm_128_xor(ctx->X_i, ctx->B_i, ctx->B_i);
+       while (v_len >= AES_BLOCK_SIZE) {
+               aes_block_xor(ctx->X_i, v, ctx->B_i);
                AES_encrypt(ctx->B_i, ctx->X_i, &ctx->aes_key);
+               v += AES_BLOCK_SIZE;
+               v_len -= AES_BLOCK_SIZE;
+               *remain -= AES_BLOCK_SIZE;
+       }
 
+       if (v_len > 0) {
                ZERO_STRUCT(ctx->B_i);
+               memcpy(ctx->B_i, v, v_len);
+               ctx->B_i_ofs += v_len;
+               *remain -= v_len;
+               v = NULL;
+               v_len = 0;
+       }
+
+       if (*remain > 0) {
+               return;
+       }
+
+       if (ctx->B_i_ofs > 0) {
+               aes_block_xor(ctx->X_i, ctx->B_i, ctx->B_i);
+               AES_encrypt(ctx->B_i, ctx->X_i, &ctx->aes_key);
                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)
+static inline 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);
+       RSIVAL(ctx->A_i, (AES_BLOCK_SIZE - AES_CCM_128_L), i);
+       AES_encrypt(ctx->A_i, S_i, &ctx->aes_key);
 }
 
 void aes_ccm_128_crypt(struct aes_ccm_128_context *ctx,
@@ -146,6 +159,15 @@ void aes_ccm_128_crypt(struct aes_ccm_128_context *ctx,
                        ctx->S_i_ofs = 0;
                }
 
+               if (likely(ctx->S_i_ofs == 0 && m_len >= AES_BLOCK_SIZE)) {
+                       aes_block_xor(m, ctx->S_i, m);
+                       m += AES_BLOCK_SIZE;
+                       m_len -= AES_BLOCK_SIZE;
+                       ctx->S_i_ctr += 1;
+                       aes_ccm_128_S_i(ctx, ctx->S_i, ctx->S_i_ctr);
+                       continue;
+               }
+
                m[0] ^= ctx->S_i[ctx->S_i_ofs];
                m += 1;
                m_len -= 1;
@@ -156,15 +178,20 @@ void aes_ccm_128_crypt(struct aes_ccm_128_context *ctx,
 void aes_ccm_128_digest(struct aes_ccm_128_context *ctx,
                        uint8_t digest[AES_BLOCK_SIZE])
 {
-       uint8_t S_0[AES_BLOCK_SIZE];
+       if (unlikely(ctx->a_remain != 0)) {
+               abort();
+       }
+       if (unlikely(ctx->m_remain != 0)) {
+               abort();
+       }
 
-       aes_ccm_128_S_i(ctx, S_0, 0);
+       /* prepare S_0 */
+       aes_ccm_128_S_i(ctx, ctx->S_i, 0);
 
        /*
         * note X_i is T here
         */
-       aes_ccm_128_xor(ctx->X_i, S_0, digest);
+       aes_block_xor(ctx->X_i, ctx->S_i, digest);
 
-       ZERO_STRUCT(S_0);
        ZERO_STRUCTP(ctx);
 }
index a98c75443353b554b2439546b6da567b2edbce90..1382ee704b98aaba5e798ccf79a594625892447f 100644 (file)
 
 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;
 
+       uint64_t __align;
+
        uint8_t X_i[AES_BLOCK_SIZE];
        uint8_t B_i[AES_BLOCK_SIZE];
-       size_t B_i_ofs;
-
+       uint8_t A_i[AES_BLOCK_SIZE];
        uint8_t S_i[AES_BLOCK_SIZE];
+
+       size_t B_i_ofs;
        size_t S_i_ofs;
        size_t S_i_ctr;
 };