Merge branch 'fix/ccm_constant_time' into develop
This closes #73 and closes #76
This commit is contained in:
		
						commit
						eb26b7efd4
					
				@ -20,7 +20,7 @@
 | 
			
		||||
/**
 | 
			
		||||
   CCM encrypt/decrypt and produce an authentication tag
 | 
			
		||||
 | 
			
		||||
     *1 'pt' and 'ct' can both be 'in' or 'out', depending on 'direction'
 | 
			
		||||
     *1 'pt', 'ct' and 'tag' can both be 'in' or 'out', depending on 'direction'
 | 
			
		||||
 | 
			
		||||
   @param cipher     The index of the cipher desired
 | 
			
		||||
   @param key        The secret key to use
 | 
			
		||||
@ -33,8 +33,8 @@
 | 
			
		||||
   @param pt         [*1] The plaintext
 | 
			
		||||
   @param ptlen      The length of the plaintext (octets)
 | 
			
		||||
   @param ct         [*1] The ciphertext
 | 
			
		||||
   @param tag        [out] The destination tag
 | 
			
		||||
   @param taglen     [in/out] The max size and resulting size of the authentication tag
 | 
			
		||||
   @param tag        [*1] The destination tag
 | 
			
		||||
   @param taglen     The max size and resulting size of the authentication tag
 | 
			
		||||
   @param direction  Encrypt or Decrypt direction (0 or 1)
 | 
			
		||||
   @return CRYPT_OK if successful
 | 
			
		||||
*/
 | 
			
		||||
@ -48,10 +48,15 @@ int ccm_memory(int cipher,
 | 
			
		||||
          unsigned char *tag,    unsigned long *taglen,
 | 
			
		||||
                    int  direction)
 | 
			
		||||
{
 | 
			
		||||
   unsigned char  PAD[16], ctr[16], CTRPAD[16], b;
 | 
			
		||||
   unsigned char  PAD[16], ctr[16], CTRPAD[16], ptTag[16], b, *pt_real;
 | 
			
		||||
   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);
 | 
			
		||||
@ -65,6 +70,8 @@ int ccm_memory(int cipher,
 | 
			
		||||
   LTC_ARGCHK(tag    != NULL);
 | 
			
		||||
   LTC_ARGCHK(taglen != NULL);
 | 
			
		||||
 | 
			
		||||
   pt_real = pt;
 | 
			
		||||
 | 
			
		||||
#ifdef LTC_FAST
 | 
			
		||||
   if (16 % sizeof(LTC_FAST_TYPE)) {
 | 
			
		||||
      return CRYPT_INVALID_ARG;
 | 
			
		||||
@ -141,6 +148,15 @@ int ccm_memory(int cipher,
 | 
			
		||||
      skey = uskey;
 | 
			
		||||
   }
 | 
			
		||||
   
 | 
			
		||||
   /* initialize buffer for pt */
 | 
			
		||||
   if (direction == CCM_DECRYPT) {
 | 
			
		||||
      pt_work = XMALLOC(ptlen);
 | 
			
		||||
      if (pt_work == NULL) {
 | 
			
		||||
         goto error;
 | 
			
		||||
      }
 | 
			
		||||
      pt = pt_work;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   /* form B_0 == flags | Nonce N | l(m) */
 | 
			
		||||
   x = 0;
 | 
			
		||||
   PAD[x++] = (unsigned char)(((headerlen > 0) ? (1<<6) : 0) |
 | 
			
		||||
@ -203,13 +219,11 @@ int ccm_memory(int cipher,
 | 
			
		||||
          PAD[x++] ^= header[y];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      /* remainder? */
 | 
			
		||||
      if (x != 0) {
 | 
			
		||||
      /* remainder */
 | 
			
		||||
      if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
 | 
			
		||||
         goto error;
 | 
			
		||||
      }
 | 
			
		||||
   }
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   /* setup the ctr counter */
 | 
			
		||||
   x = 0;
 | 
			
		||||
@ -254,7 +268,7 @@ int ccm_memory(int cipher,
 | 
			
		||||
                   goto error;
 | 
			
		||||
                }
 | 
			
		||||
             }
 | 
			
		||||
         } else {
 | 
			
		||||
          } else { /* direction == CCM_DECRYPT */
 | 
			
		||||
             for (; y < (ptlen & ~15); y += 16) {
 | 
			
		||||
                /* increment the ctr? */
 | 
			
		||||
                for (z = 15; z > 15-L; z--) {
 | 
			
		||||
@ -328,18 +342,60 @@ int ccm_memory(int cipher,
 | 
			
		||||
      cipher_descriptor[cipher].done(skey);
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   if (direction == CCM_ENCRYPT) {
 | 
			
		||||
      /* store the TAG */
 | 
			
		||||
      for (x = 0; x < 16 && x < *taglen; x++) {
 | 
			
		||||
          tag[x] = PAD[x] ^ CTRPAD[x];
 | 
			
		||||
      }
 | 
			
		||||
      *taglen = x;
 | 
			
		||||
   } else { /* direction == CCM_DECRYPT */
 | 
			
		||||
      /* decrypt the tag */
 | 
			
		||||
      for (x = 0; x < 16 && x < *taglen; x++) {
 | 
			
		||||
         ptTag[x] = tag[x] ^ CTRPAD[x];
 | 
			
		||||
      }
 | 
			
		||||
      *taglen = x;
 | 
			
		||||
 | 
			
		||||
      /* check validity of the decrypted tag against the computed PAD (in constant time) */
 | 
			
		||||
      /* HACK: the boolean value of XMEM_NEQ becomes either 0 (CRYPT_OK) or 1 (CRYPT_ERR).
 | 
			
		||||
       *       there should be a better way of setting the correct error code in constant
 | 
			
		||||
       *       time.
 | 
			
		||||
       */
 | 
			
		||||
      err = XMEM_NEQ(ptTag, PAD, *taglen);
 | 
			
		||||
 | 
			
		||||
      /* 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) {
 | 
			
		||||
      XFREE(pt_work);
 | 
			
		||||
   }
 | 
			
		||||
   if (skey != uskey) {
 | 
			
		||||
      XFREE(skey);
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
@ -114,11 +114,13 @@ int ccm_test(void)
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
  unsigned long taglen, x, y;
 | 
			
		||||
  unsigned char buf[64], buf2[64], tag2[16], tag[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) {
 | 
			
		||||
     idx = find_cipher("rijndael");
 | 
			
		||||
@ -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,6 +190,8 @@ int ccm_test(void)
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (y == 0) {
 | 
			
		||||
          XMEMCPY(tag3, tests[x].tag, tests[x].taglen);
 | 
			
		||||
          taglen = tests[x].taglen;
 | 
			
		||||
          if ((err = ccm_memory(idx,
 | 
			
		||||
                               tests[x].key, 16,
 | 
			
		||||
                               NULL,
 | 
			
		||||
@ -195,7 +199,7 @@ int ccm_test(void)
 | 
			
		||||
                               tests[x].header, tests[x].headerlen,
 | 
			
		||||
                               buf2, tests[x].ptlen,
 | 
			
		||||
                               buf,
 | 
			
		||||
                               tag2, &taglen, 1   )) != CRYPT_OK) {
 | 
			
		||||
                               tag3, &taglen, 1   )) != CRYPT_OK) {
 | 
			
		||||
            return err;
 | 
			
		||||
         }
 | 
			
		||||
      } else {
 | 
			
		||||
@ -219,24 +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;
 | 
			
		||||
      }
 | 
			
		||||
      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 is    ", tag2, tests[x].taglen);
 | 
			
		||||
          print_hex("tag should", tests[x].tag, tests[x].taglen);
 | 
			
		||||
#endif
 | 
			
		||||
          return CRYPT_FAIL_TESTVECTOR;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (y == 0) {
 | 
			
		||||
         cipher_descriptor[idx].done(&skey);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return CRYPT_OK;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user