Print this page
5072963 Need an optimized AES implementation for amd64
6699938 CCM max payload computation is off by one

@@ -21,11 +21,11 @@
 /*
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident   "@(#)aes_cbc_crypt.c    1.9     08/05/09 SMI"
+#pragma ident   "@(#)aes_cbc_crypt.c    1.10    08/06/13 SMI"
 
 
 #include <sys/sysmacros.h>
 #include <sys/systm.h>
 #include <sys/crypto/common.h>

@@ -48,11 +48,11 @@
 aes_ccm_decrypt_contiguous_blocks(aes_ctx_t *ctx, char *data, size_t length,
     crypto_data_t *out);
 
 /*
  * Initialize by setting iov_or_mp to point to the current iovec or mp,
- * and by setting current_offset to an offset within the current iovec or mp .
+ * and by setting current_offset to an offset within the current iovec or mp.
  */
 static void
 aes_init_ptrs(crypto_data_t *out, void **iov_or_mp, offset_t *current_offset)
 {
         offset_t offset;

@@ -251,12 +251,11 @@
                 if (ctx->ac_flags & AES_CBC_MODE) {
                         /*
                          * XOR the previous cipher block or IV with the
                          * current clear block. Check for alignment.
                          */
-                        if (IS_P2ALIGNED(blockp, sizeof (uint32_t)) &&
-                            IS_P2ALIGNED(lastp, sizeof (uint32_t))) {
+                        if (IS_P2ALIGNED2(blockp, lastp, sizeof (uint32_t))) {
                                 /* LINTED: pointer alignment */
                                 *(uint32_t *)&blockp[0] ^=
                                 /* LINTED: pointer alignment */
                                     *(uint32_t *)&lastp[0];
                                 /* LINTED: pointer alignment */

@@ -292,15 +291,31 @@
                         aes_encrypt_block(ctx->ac_keysched, blockp, lastp);
                         aes_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
                             &out_data_1_len, &out_data_2, AES_BLOCK_LEN);
 
                         /* copy block to where it belongs */
+                        if ((out_data_1_len == AES_BLOCK_LEN) &&
+                            (IS_P2ALIGNED2(lastp, out_data_1,
+                            sizeof (uint32_t)))) {
+                                /* LINTED: pointer alignment */
+                                uint32_t *d = (uint32_t *)out_data_1;
+                                /* LINTED: pointer alignment */
+                                d[0] = *(uint32_t *)lastp;
+                                /* LINTED: pointer alignment */
+                                d[1] = *(uint32_t *)&lastp[4];
+                                /* LINTED: pointer alignment */
+                                d[2] = *(uint32_t *)&lastp[8];
+                                /* LINTED: pointer alignment */
+                                d[3] = *(uint32_t *)&lastp[12];
+                        } else {
                         bcopy(lastp, out_data_1, out_data_1_len);
+                        }
                         if (out_data_2 != NULL) {
                                 bcopy(lastp + out_data_1_len, out_data_2,
                                     AES_BLOCK_LEN - out_data_1_len);
                         }
+
                         /* update offset */
                         out->cd_offset += AES_BLOCK_LEN;
                 }
 
                 /* Update pointer to next block of data to be processed. */

@@ -461,12 +476,11 @@
                 if (ctx->ac_flags & AES_CBC_MODE) {
                         /*
                          * XOR the previous cipher block or IV with the
                          * currently decrypted block.  Check for alignment.
                          */
-                        if (IS_P2ALIGNED(blockp, sizeof (uint32_t)) &&
-                            IS_P2ALIGNED(lastp, sizeof (uint32_t))) {
+                        if (IS_P2ALIGNED2(blockp, lastp, sizeof (uint32_t))) {
                                 /* LINTED: pointer alignment */
                                 *(uint32_t *)blockp ^= *(uint32_t *)lastp;
                                 /* LINTED: pointer alignment */
                                 *(uint32_t *)&blockp[4] ^=
                                 /* LINTED: pointer alignment */

@@ -490,11 +504,21 @@
                 if (out != NULL) {
                         aes_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
                             &out_data_1_len, &out_data_2, AES_BLOCK_LEN);
 
                         /* copy temporary block to where it belongs */
+                        if ((out_data_1_len == AES_BLOCK_LEN) &&
+                            (IS_P2ALIGNED(out_data_1, sizeof (uint32_t)))) {
+                                /* LINTED: pointer alignment */
+                                uint32_t *d = (uint32_t *)out_data_1;
+                                d[0] = tmp[0];
+                                d[1] = tmp[1];
+                                d[2] = tmp[2];
+                                d[3] = tmp[3];
+                        } else {
                         bcopy(&tmp, out_data_1, out_data_1_len);
+                        }
                         if (out_data_2 != NULL) {
                                 bcopy((uint8_t *)&tmp + out_data_1_len,
                                     out_data_2, AES_BLOCK_LEN - out_data_1_len);
                         }
 

@@ -692,12 +716,11 @@
                          * do CBC MAC
                          *
                          * XOR the previous cipher block current clear block.
                          * mac_buf always contain previous cipher block.
                          */
-                        if (IS_P2ALIGNED(blockp, sizeof (uint32_t)) &&
-                            IS_P2ALIGNED(mac_buf, sizeof (uint32_t))) {
+                        if (IS_P2ALIGNED2(blockp, mac_buf, sizeof (uint32_t))) {
                                 /* LINTED: pointer alignment */
                                 *(uint32_t *)&mac_buf[0] ^=
                                 /* LINTED: pointer alignment */
                                     *(uint32_t *)&blockp[0];
                                 /* LINTED: pointer alignment */

@@ -758,12 +781,11 @@
 
                 /*
                  * XOR the previous cipher block or IV with the
                  * current clear block. Check for alignment.
                  */
-                if (IS_P2ALIGNED(blockp, sizeof (uint32_t)) &&
-                    IS_P2ALIGNED(lastp, sizeof (uint32_t))) {
+                if (IS_P2ALIGNED2(blockp, lastp, sizeof (uint32_t))) {
                         /* LINTED: pointer alignment */
                         *(uint32_t *)&blockp[0] ^=
                         /* LINTED: pointer alignment */
                             *(uint32_t *)&lastp[0];
                         /* LINTED: pointer alignment */

@@ -798,15 +820,31 @@
                 } else {
                         aes_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
                             &out_data_1_len, &out_data_2, AES_BLOCK_LEN);
 
                         /* copy block to where it belongs */
+                        if ((out_data_1_len == AES_BLOCK_LEN) &&
+                            (IS_P2ALIGNED2(lastp, out_data_1,
+                            sizeof (uint32_t)))) {
+                                /* LINTED: pointer alignment */
+                                uint32_t *d = (uint32_t *)out_data_1;
+                                /* LINTED: pointer alignment */
+                                d[0] = *(uint32_t *)lastp;
+                                /* LINTED: pointer alignment */
+                                d[1] = *(uint32_t *)&lastp[4];
+                                /* LINTED: pointer alignment */
+                                d[2] = *(uint32_t *)&lastp[8];
+                                /* LINTED: pointer alignment */
+                                d[3] = *(uint32_t *)&lastp[12];
+                        } else {
                         bcopy(lastp, out_data_1, out_data_1_len);
+                        }
                         if (out_data_2 != NULL) {
                                 bcopy(lastp + out_data_1_len, out_data_2,
                                     AES_BLOCK_LEN - out_data_1_len);
                         }
+
                         /* update offset */
                         out->cd_offset += AES_BLOCK_LEN;
                 }
 
                 /* Update pointer to next block of data to be processed. */

@@ -866,12 +904,11 @@
 
         /* The IV for CBC MAC for AES CCM mode is always zero */
         bzero(iv, AES_BLOCK_LEN);
         ivp = (uint8_t *)iv;
 
-        if (IS_P2ALIGNED(ivp, sizeof (uint32_t)) &&
-            IS_P2ALIGNED(mac_buf, sizeof (uint32_t))) {
+        if (IS_P2ALIGNED2(ivp, mac_buf, sizeof (uint32_t))) {
                 /* LINTED: pointer alignment */
                 *(uint32_t *)&mac_buf[0] ^= *(uint32_t *)&ivp[0];
                 /* LINTED: pointer alignment */
                 *(uint32_t *)&mac_buf[4] ^= *(uint32_t *)&ivp[4];
                 /* LINTED: pointer alignment */

@@ -903,12 +940,11 @@
                 /* in case auth_data is very small */
                 processed = auth_data_len;
         }
         bcopy(auth_data, authp+encoded_a_len, processed);
         /* xor with previous buffer */
-        if (IS_P2ALIGNED(authp, sizeof (uint32_t)) &&
-            IS_P2ALIGNED(mac_buf, sizeof (uint32_t))) {
+        if (IS_P2ALIGNED2(authp, mac_buf, sizeof (uint32_t))) {
                 /* LINTED: pointer alignment */
                 *(uint32_t *)&mac_buf[0] ^= *(uint32_t *)&authp[0];
                 /* LINTED: pointer alignment */
                 *(uint32_t *)&mac_buf[4] ^= *(uint32_t *)&authp[4];
                 /* LINTED: pointer alignment */

@@ -940,12 +976,11 @@
                         processed += AES_BLOCK_LEN;
                         remainder -= AES_BLOCK_LEN;
                 }
 
                 /* xor with previous buffer */
-                if (IS_P2ALIGNED(datap, sizeof (uint32_t)) &&
-                    IS_P2ALIGNED(mac_buf, sizeof (uint32_t))) {
+                if (IS_P2ALIGNED2(datap, mac_buf, sizeof (uint32_t))) {
                         /* LINTED: pointer alignment */
                         *(uint32_t *)&mac_buf[0] ^= *(uint32_t *)&datap[0];
                         /* LINTED: pointer alignment */
                         *(uint32_t *)&mac_buf[4] ^= *(uint32_t *)&datap[4];
                         /* LINTED: pointer alignment */

@@ -1032,12 +1067,11 @@
 
                 /* copy remainder to temporary buffer */
                 bcopy(ctx->ac_remainder, macp, ctx->ac_remainder_len);
 
                 /* calculate the CBC MAC */
-                if (IS_P2ALIGNED(macp, sizeof (uint32_t)) &&
-                    IS_P2ALIGNED(mac_buf, sizeof (uint32_t))) {
+                if (IS_P2ALIGNED2(macp, mac_buf, sizeof (uint32_t))) {
                         /* LINTED: pointer alignment */
                         *(uint32_t *)&mac_buf[0] ^= *(uint32_t *)&macp[0];
                         /* LINTED: pointer alignment */
                         *(uint32_t *)&mac_buf[4] ^= *(uint32_t *)&macp[4];
                         /* LINTED: pointer alignment */

@@ -1145,24 +1179,25 @@
         size_t macSize, nonceSize;
         uint8_t q;
         uint64_t maxValue;
 
         /*
-         * Check the length of the MAC.  Only valid length
+         * Check the byte length of the MAC.  The only valid
          * lengths for the MAC are: 4, 6, 8, 10, 12, 14, 16
          */
         macSize = ccm_param->ulMACSize;
         if ((macSize < 4) || (macSize > 16) || ((macSize % 2) != 0)) {
                 return (CRYPTO_MECHANISM_PARAM_INVALID);
         }
 
-        /* Check the nonce value.  Valid values are 7, 8, 9, 10, 11, 12, 13 */
+        /* Check the nonce length.  Valid values are 7, 8, 9, 10, 11, 12, 13 */
         nonceSize = ccm_param->ulNonceSize;
         if ((nonceSize < 7) || (nonceSize > 13)) {
                 return (CRYPTO_MECHANISM_PARAM_INVALID);
         }
 
+        /* q is the length of the field storing the length, in bytes */
         q = (uint8_t)((15 - nonceSize) & 0xFF);
 
 
         /*
          * If it is decrypt, need to make sure size of ciphertext is at least

@@ -1175,11 +1210,11 @@
         /*
          * Check to make sure the length of the payload is within the
          * range of values allowed by q
          */
         if (q < 8) {
-                maxValue = 1ULL << (q * 8);
+                maxValue = (1ULL << (q * 8)) - 1;
         } else {
                 maxValue = ULONG_MAX;
         }
 
         if (ccm_param->ulDataSize > maxValue) {

@@ -1190,11 +1225,11 @@
         return (0);
 }
 
 /*
  * Format the first block used in CBC-MAC (B0) and the initial counter
- * block based on formating functions and counter generation functions
+ * block based on formatting functions and counter generation functions
  * specified in RFC 3610 and NIST publication 800-38C, appendix A
  *
  * b0 is the first block used in CBC-MAC
  * cb0 is the first counter block
  *

@@ -1217,11 +1252,11 @@
 #endif  /* _LITTLE_ENDIAN */
 
         q = (uint8_t)((15 - nonceSize) & 0xFF);
         t = (uint8_t)((aes_ctx->ac_ccm_mac_len) & 0xFF);
 
-        /* Construct the first octect of b0 */
+        /* Construct the first octet of b0 */
         if (authDataSize > 0) {
                 have_adata = 1;
         }
         b0[0] = (have_adata << 6) | (((t - 2)  / 2) << 3) | (q - 1);
 

@@ -1270,11 +1305,11 @@
 
         /*
          * During calculation, we start using counter block 1, we will
          * set it up right here.
          * We can just set the last byte to have the value 1, because
-         * even with the bigest nonce of 13, the last byte of the
+         * even with the biggest nonce of 13, the last byte of the
          * counter block will be used for the counter value.
          */
         cb[15] = 0x01;
 
 /* EXPORT DELETE END */

@@ -1523,12 +1558,11 @@
                 counter &= ctx->ac_counter_mask;
                 ctx->ac_cb[1] =
                     (ctx->ac_cb[1] & ~(ctx->ac_counter_mask)) | counter;
 
                 /* XOR with the ciphertext */
-                if (IS_P2ALIGNED(blockp, sizeof (uint32_t)) &&
-                    IS_P2ALIGNED(cbp, sizeof (uint32_t))) {
+                if (IS_P2ALIGNED2(blockp, cbp, sizeof (uint32_t))) {
                         /* LINTED: pointer alignment */
                         *(uint32_t *)&blockp[0] ^= *(uint32_t *)&cbp[0];
                         /* LINTED: pointer alignment */
                         *(uint32_t *)&blockp[4] ^= *(uint32_t *)&cbp[4];
                         /* LINTED: pointer alignment */

@@ -1540,12 +1574,11 @@
                 }
 
                 /* Copy the plaintext to the "holding buffer" */
                 resultp = (uint8_t *)ctx->ac_ccm_pt_buf +
                     ctx->ac_ccm_processed_data_len;
-                if (IS_P2ALIGNED(blockp, sizeof (uint32_t)) &&
-                    IS_P2ALIGNED(resultp, sizeof (uint32_t))) {
+                if (IS_P2ALIGNED2(blockp, resultp, sizeof (uint32_t))) {
                         /* LINTED: pointer alignment */
                         *(uint32_t *)&resultp[0] = *(uint32_t *)blockp;
                         /* LINTED: pointer alignment */
                         *(uint32_t *)&resultp[4] = *(uint32_t *)&blockp[4];
                         /* LINTED: pointer alignment */

@@ -1627,12 +1660,11 @@
                 if (mac_remain < AES_BLOCK_LEN) {
                         bzero(tmp, AES_BLOCK_LEN);
                         bcopy(pt, tmp, mac_remain);
                         mac_remain = 0;
                 } else {
-                        if (IS_P2ALIGNED(pt, sizeof (uint32_t)) &&
-                            IS_P2ALIGNED(macp, sizeof (uint32_t))) {
+                        if (IS_P2ALIGNED2(pt, macp, sizeof (uint32_t))) {
                                 /* LINTED: pointer alignment */
                                 *(uint32_t *)&macp[0] = *(uint32_t *)pt;
                                 /* LINTED: pointer alignment */
                                 *(uint32_t *)&macp[4] = *(uint32_t *)&pt[4];
                                 /* LINTED: pointer alignment */

@@ -1645,12 +1677,11 @@
                         mac_remain -= AES_BLOCK_LEN;
                         pt += AES_BLOCK_LEN;
                 }
 
                 /* calculate the CBC MAC */
-                if (IS_P2ALIGNED(macp, sizeof (uint32_t)) &&
-                    IS_P2ALIGNED(mac_buf, sizeof (uint32_t))) {
+                if (IS_P2ALIGNED2(macp, mac_buf, sizeof (uint32_t))) {
                         /* LINTED: pointer alignment */
                         *(uint32_t *)&mac_buf[0] ^= *(uint32_t *)&macp[0];
                         /* LINTED: pointer alignment */
                         *(uint32_t *)&mac_buf[4] ^= *(uint32_t *)&macp[4];
                         /* LINTED: pointer alignment */