浏览代码

make sure no cache-based timing attack is possible

instead of two different buffers, there is just one buffer. Based upon the verification result, a mask is applied to the buffer before it is written to the output buffer.
Sebastian Verschoor 10 年之前
父节点
当前提交
75b114517a
共有 2 个文件被更改,包括 82 次插入38 次删除
  1. 35 20
      src/encauth/ccm/ccm_memory.c
  2. 47 18
      src/encauth/ccm/ccm_test.c

+ 35 - 20
src/encauth/ccm/ccm_memory.c

@@ -49,10 +49,14 @@ int ccm_memory(int cipher,
                     int  direction)
 {
    unsigned char  PAD[16], ctr[16], CTRPAD[16], ptTag[16], b, *pt_real;
-   unsigned char  *pt_work[2] = {0};
+   unsigned char *pt_work = NULL;
    symmetric_key *skey;
    int            err;
    unsigned long  len, L, x, y, z, CTRlen;
+#ifdef LTC_FAST
+   LTC_FAST_TYPE fastMask = -1; /* initialize fastMask at all zeroes */
+#endif
+   unsigned char mask = 0xff; /* initialize mask at all zeroes */
 
    if (uskey == NULL) {
       LTC_ARGCHK(key    != NULL);
@@ -143,16 +147,14 @@ int ccm_memory(int cipher,
    } else {
       skey = uskey;
    }
-   if (direction != CCM_ENCRYPT) {
-      pt_work[0] = XMALLOC(ptlen);
-      pt_work[1] = XCALLOC(1, ptlen);
-
-      if ((pt_work[0] == NULL) || (pt_work[1] == NULL)) {
+   
+   /* initialize buffer for pt */
+   if (direction == CCM_DECRYPT) {
+      pt_work = XMALLOC(ptlen);
+      if (pt_work == NULL) {
          goto error;
       }
-
-      XMEMCPY(pt_work[0], pt, ptlen);
-      pt = pt_work[0];
+      pt = pt_work;
    }
 
    /* form B_0 == flags | Nonce N | l(m) */
@@ -360,26 +362,39 @@ int ccm_memory(int cipher,
        */
       err = XMEM_NEQ(ptTag, PAD, *taglen);
 
-      /* Here err is 0 or 1, so we just copy either the real plaintext
-       * or the zeroized buffer.
-       */
-      XMEMCPY(pt_real, pt_work[err], ptlen);
-#ifdef LTC_CLEAN_STACK
-      zeromem(pt_work[0], ptlen);
+      /* Zero the plaintext if the tag was invalid (in constant time) */
+      if (ptlen > 0) {
+         y = 0;
+         mask *= 1 - err; /* mask = ( err ? 0 : 0xff ) */
+#ifdef LTC_FAST
+         fastMask *= 1 - err;
+         if (ptlen & ~15) {
+            for (; y < (ptlen & ~15); y += 16) {
+              for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
+                *((LTC_FAST_TYPE*)(&pt_real[y+z])) = *((LTC_FAST_TYPE*)(&pt[y+z])) & fastMask;
+              }
+            }
+         }
 #endif
+         for (; y < ptlen; y++) {
+            pt_real[y] = pt[y] & mask;
+         }
+      }
    }
 
 #ifdef LTC_CLEAN_STACK
+   fastMask = 0;
+   mask = 0;
    zeromem(skey,   sizeof(*skey));
    zeromem(PAD,    sizeof(PAD));
    zeromem(CTRPAD, sizeof(CTRPAD));
+   if (pt_work != NULL) {
+     zeromem(pt_work, ptlen);
+   }
 #endif
 error:
-   if (pt_work[1]) {
-      XFREE(pt_work[1]);
-   }
-   if (pt_work[0]) {
-      XFREE(pt_work[0]);
+   if (pt_work) {
+      XFREE(pt_work);
    }
    if (skey != uskey) {
       XFREE(skey);

+ 47 - 18
src/encauth/ccm/ccm_test.c

@@ -114,10 +114,12 @@ int ccm_test(void)
 
 };
   unsigned long taglen, x, y;
-  unsigned char buf[64], buf2[64], tag[16], tag2[16], tag3[16];
+  unsigned char buf[64], buf2[64], tag[16], tag2[16], tag3[16], zero[64];
   int           err, idx;
   symmetric_key skey;
   ccm_state ccm;
+  
+  zeromem(zero, 64);
 
   idx = find_cipher("aes");
   if (idx == -1) {
@@ -166,8 +168,8 @@ int ccm_test(void)
       if (XMEMCMP(buf, tests[x].ct, tests[x].ptlen)) {
 #if defined(LTC_TEST_DBG)
          printf("\n%d: x=%lu y=%lu\n", __LINE__, x, y);
-         print_hex("ct is    ", tag, taglen);
-         print_hex("ct should", tests[x].tag, taglen);
+         print_hex("ct is    ", buf, tests[x].ptlen);
+         print_hex("ct should", tests[x].ct, tests[x].ptlen);
 #endif
          return CRYPT_FAIL_TESTVECTOR;
       }
@@ -188,10 +190,9 @@ int ccm_test(void)
       }
 
       if (y == 0) {
-
-         XMEMCPY(tag3, tests[x].tag, tests[x].taglen);
-         taglen = tests[x].taglen;
-         if ((err = ccm_memory(idx,
+          XMEMCPY(tag3, tests[x].tag, tests[x].taglen);
+          taglen = tests[x].taglen;
+          if ((err = ccm_memory(idx,
                                tests[x].key, 16,
                                NULL,
                                tests[x].nonce, tests[x].noncelen,
@@ -222,28 +223,56 @@ int ccm_test(void)
       if (XMEMCMP(buf2, tests[x].pt, tests[x].ptlen)) {
 #if defined(LTC_TEST_DBG)
          printf("\n%d: x=%lu y=%lu\n", __LINE__, x, y);
-         print_hex("pt is    ", tag, taglen);
-         print_hex("pt should", tests[x].tag, taglen);
+         print_hex("pt is    ", buf2, tests[x].ptlen);
+         print_hex("pt should", tests[x].pt, tests[x].ptlen);
 #endif
          return CRYPT_FAIL_TESTVECTOR;
       }
-      /* Only check the tag if ccm_memory was not called: ccm_memory already
-         validates the tag */
-      if (y != 0) {
-         if (XMEMCMP(tag2, tests[x].tag, tests[x].taglen)) {
+      if (y == 0) {
+        /* check if decryption with the wrong tag does not reveal the plaintext */
+        XMEMCPY(tag3, tests[x].tag, tests[x].taglen);
+        tag3[0] ^= 0xff; /* set the tag to the wrong value */
+        taglen = tests[x].taglen;
+        if ((err = ccm_memory(idx,
+                              tests[x].key, 16,
+                              NULL,
+                              tests[x].nonce, tests[x].noncelen,
+                              tests[x].header, tests[x].headerlen,
+                              buf2, tests[x].ptlen,
+                              buf,
+                              tag3, &taglen, 1   )) != CRYPT_ERROR) {
+          return CRYPT_FAIL_TESTVECTOR;
+        }
+        if (XMEMCMP(buf2, zero, tests[x].ptlen)) {
+#if defined(LTC_CCM_TEST_DBG)
+          printf("\n%d: x=%lu y=%lu\n", __LINE__, x, y);
+          print_hex("pt is    ", buf2, tests[x].ptlen);
+          print_hex("pt should", zero, tests[x].ptlen);
+#endif
+          return CRYPT_FAIL_TESTVECTOR;
+        }
+      } else {
+        /* FIXME: Only check the tag if ccm_memory was not called: ccm_memory already
+           validates the tag. ccm_process and ccm_done should somehow do the same,
+           although with current setup it is impossible to keep the plaintext hidden
+           if the tag is incorrect.
+        */
+        if (XMEMCMP(tag2, tests[x].tag, tests[x].taglen)) {
 #if defined(LTC_TEST_DBG)
-            printf("\n%d: x=%lu y=%lu\n", __LINE__, x, y);
-            print_hex("tag is    ", tag, tests[x].taglen);
-            print_hex("tag should", tests[x].tag, tests[x].taglen);
+          printf("\n%d: x=%lu y=%lu\n", __LINE__, x, y);
+          print_hex("tag is    ", tag2, tests[x].taglen);
+          print_hex("tag should", tests[x].tag, tests[x].taglen);
 #endif
-            return CRYPT_FAIL_TESTVECTOR;
-         }
+          return CRYPT_FAIL_TESTVECTOR;
+        }
       }
+
       if (y == 0) {
          cipher_descriptor[idx].done(&skey);
       }
     }
   }
+
   return CRYPT_OK;
 #endif
 }