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
 | 
					   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 cipher     The index of the cipher desired
 | 
				
			||||||
   @param key        The secret key to use
 | 
					   @param key        The secret key to use
 | 
				
			||||||
@ -33,8 +33,8 @@
 | 
				
			|||||||
   @param pt         [*1] The plaintext
 | 
					   @param pt         [*1] The plaintext
 | 
				
			||||||
   @param ptlen      The length of the plaintext (octets)
 | 
					   @param ptlen      The length of the plaintext (octets)
 | 
				
			||||||
   @param ct         [*1] The ciphertext
 | 
					   @param ct         [*1] The ciphertext
 | 
				
			||||||
   @param tag        [out] The destination tag
 | 
					   @param tag        [*1] The destination tag
 | 
				
			||||||
   @param taglen     [in/out] The max size and resulting size of the authentication tag
 | 
					   @param taglen     The max size and resulting size of the authentication tag
 | 
				
			||||||
   @param direction  Encrypt or Decrypt direction (0 or 1)
 | 
					   @param direction  Encrypt or Decrypt direction (0 or 1)
 | 
				
			||||||
   @return CRYPT_OK if successful
 | 
					   @return CRYPT_OK if successful
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
@ -48,10 +48,15 @@ int ccm_memory(int cipher,
 | 
				
			|||||||
          unsigned char *tag,    unsigned long *taglen,
 | 
					          unsigned char *tag,    unsigned long *taglen,
 | 
				
			||||||
                    int  direction)
 | 
					                    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;
 | 
					   symmetric_key *skey;
 | 
				
			||||||
   int            err;
 | 
					   int            err;
 | 
				
			||||||
   unsigned long  len, L, x, y, z, CTRlen;
 | 
					   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) {
 | 
					   if (uskey == NULL) {
 | 
				
			||||||
      LTC_ARGCHK(key    != NULL);
 | 
					      LTC_ARGCHK(key    != NULL);
 | 
				
			||||||
@ -65,6 +70,8 @@ int ccm_memory(int cipher,
 | 
				
			|||||||
   LTC_ARGCHK(tag    != NULL);
 | 
					   LTC_ARGCHK(tag    != NULL);
 | 
				
			||||||
   LTC_ARGCHK(taglen != NULL);
 | 
					   LTC_ARGCHK(taglen != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   pt_real = pt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef LTC_FAST
 | 
					#ifdef LTC_FAST
 | 
				
			||||||
   if (16 % sizeof(LTC_FAST_TYPE)) {
 | 
					   if (16 % sizeof(LTC_FAST_TYPE)) {
 | 
				
			||||||
      return CRYPT_INVALID_ARG;
 | 
					      return CRYPT_INVALID_ARG;
 | 
				
			||||||
@ -140,6 +147,15 @@ int ccm_memory(int cipher,
 | 
				
			|||||||
   } else {
 | 
					   } else {
 | 
				
			||||||
      skey = uskey;
 | 
					      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) */
 | 
					   /* form B_0 == flags | Nonce N | l(m) */
 | 
				
			||||||
   x = 0;
 | 
					   x = 0;
 | 
				
			||||||
@ -203,11 +219,9 @@ int ccm_memory(int cipher,
 | 
				
			|||||||
          PAD[x++] ^= header[y];
 | 
					          PAD[x++] ^= header[y];
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      /* remainder? */
 | 
					      /* remainder */
 | 
				
			||||||
      if (x != 0) {
 | 
					      if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
 | 
				
			||||||
         if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
 | 
					         goto error;
 | 
				
			||||||
            goto error;
 | 
					 | 
				
			||||||
         }
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -254,7 +268,7 @@ int ccm_memory(int cipher,
 | 
				
			|||||||
                   goto error;
 | 
					                   goto error;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
             }
 | 
					             }
 | 
				
			||||||
         } else {
 | 
					          } else { /* direction == CCM_DECRYPT */
 | 
				
			||||||
             for (; y < (ptlen & ~15); y += 16) {
 | 
					             for (; y < (ptlen & ~15); y += 16) {
 | 
				
			||||||
                /* increment the ctr? */
 | 
					                /* increment the ctr? */
 | 
				
			||||||
                for (z = 15; z > 15-L; z--) {
 | 
					                for (z = 15; z > 15-L; z--) {
 | 
				
			||||||
@ -328,18 +342,60 @@ int ccm_memory(int cipher,
 | 
				
			|||||||
      cipher_descriptor[cipher].done(skey);
 | 
					      cipher_descriptor[cipher].done(skey);
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   /* store the TAG */
 | 
					   if (direction == CCM_ENCRYPT) {
 | 
				
			||||||
   for (x = 0; x < 16 && x < *taglen; x++) {
 | 
					      /* store the TAG */
 | 
				
			||||||
       tag[x] = PAD[x] ^ CTRPAD[x];
 | 
					      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;
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
   *taglen = x;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef LTC_CLEAN_STACK
 | 
					#ifdef LTC_CLEAN_STACK
 | 
				
			||||||
 | 
					   fastMask = 0;
 | 
				
			||||||
 | 
					   mask = 0;
 | 
				
			||||||
   zeromem(skey,   sizeof(*skey));
 | 
					   zeromem(skey,   sizeof(*skey));
 | 
				
			||||||
   zeromem(PAD,    sizeof(PAD));
 | 
					   zeromem(PAD,    sizeof(PAD));
 | 
				
			||||||
   zeromem(CTRPAD, sizeof(CTRPAD));
 | 
					   zeromem(CTRPAD, sizeof(CTRPAD));
 | 
				
			||||||
 | 
					   if (pt_work != NULL) {
 | 
				
			||||||
 | 
					     zeromem(pt_work, ptlen);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
 | 
					   if (pt_work) {
 | 
				
			||||||
 | 
					      XFREE(pt_work);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
   if (skey != uskey) {
 | 
					   if (skey != uskey) {
 | 
				
			||||||
      XFREE(skey);
 | 
					      XFREE(skey);
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
 | 
				
			|||||||
@ -114,10 +114,12 @@ int ccm_test(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
  unsigned long taglen, x, y;
 | 
					  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;
 | 
					  int           err, idx;
 | 
				
			||||||
  symmetric_key skey;
 | 
					  symmetric_key skey;
 | 
				
			||||||
  ccm_state ccm;
 | 
					  ccm_state ccm;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  zeromem(zero, 64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  idx = find_cipher("aes");
 | 
					  idx = find_cipher("aes");
 | 
				
			||||||
  if (idx == -1) {
 | 
					  if (idx == -1) {
 | 
				
			||||||
@ -166,8 +168,8 @@ int ccm_test(void)
 | 
				
			|||||||
      if (XMEMCMP(buf, tests[x].ct, tests[x].ptlen)) {
 | 
					      if (XMEMCMP(buf, tests[x].ct, tests[x].ptlen)) {
 | 
				
			||||||
#if defined(LTC_TEST_DBG)
 | 
					#if defined(LTC_TEST_DBG)
 | 
				
			||||||
         printf("\n%d: x=%lu y=%lu\n", __LINE__, x, y);
 | 
					         printf("\n%d: x=%lu y=%lu\n", __LINE__, x, y);
 | 
				
			||||||
         print_hex("ct is    ", tag, taglen);
 | 
					         print_hex("ct is    ", buf, tests[x].ptlen);
 | 
				
			||||||
         print_hex("ct should", tests[x].tag, taglen);
 | 
					         print_hex("ct should", tests[x].ct, tests[x].ptlen);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
         return CRYPT_FAIL_TESTVECTOR;
 | 
					         return CRYPT_FAIL_TESTVECTOR;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -188,14 +190,16 @@ int ccm_test(void)
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (y == 0) {
 | 
					      if (y == 0) {
 | 
				
			||||||
         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,
 | 
					                               tests[x].key, 16,
 | 
				
			||||||
                               NULL,
 | 
					                               NULL,
 | 
				
			||||||
                               tests[x].nonce, tests[x].noncelen,
 | 
					                               tests[x].nonce, tests[x].noncelen,
 | 
				
			||||||
                               tests[x].header, tests[x].headerlen,
 | 
					                               tests[x].header, tests[x].headerlen,
 | 
				
			||||||
                               buf2, tests[x].ptlen,
 | 
					                               buf2, tests[x].ptlen,
 | 
				
			||||||
                               buf,
 | 
					                               buf,
 | 
				
			||||||
                               tag2, &taglen, 1   )) != CRYPT_OK) {
 | 
					                               tag3, &taglen, 1   )) != CRYPT_OK) {
 | 
				
			||||||
            return err;
 | 
					            return err;
 | 
				
			||||||
         }
 | 
					         }
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
@ -219,24 +223,56 @@ int ccm_test(void)
 | 
				
			|||||||
      if (XMEMCMP(buf2, tests[x].pt, tests[x].ptlen)) {
 | 
					      if (XMEMCMP(buf2, tests[x].pt, tests[x].ptlen)) {
 | 
				
			||||||
#if defined(LTC_TEST_DBG)
 | 
					#if defined(LTC_TEST_DBG)
 | 
				
			||||||
         printf("\n%d: x=%lu y=%lu\n", __LINE__, x, y);
 | 
					         printf("\n%d: x=%lu y=%lu\n", __LINE__, x, y);
 | 
				
			||||||
         print_hex("pt is    ", tag, taglen);
 | 
					         print_hex("pt is    ", buf2, tests[x].ptlen);
 | 
				
			||||||
         print_hex("pt should", tests[x].tag, taglen);
 | 
					         print_hex("pt should", tests[x].pt, tests[x].ptlen);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
         return CRYPT_FAIL_TESTVECTOR;
 | 
					         return CRYPT_FAIL_TESTVECTOR;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      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)
 | 
					#if defined(LTC_TEST_DBG)
 | 
				
			||||||
         printf("\n%d: x=%lu y=%lu\n", __LINE__, x, y);
 | 
					          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);
 | 
					          print_hex("tag should", tests[x].tag, tests[x].taglen);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
         return CRYPT_FAIL_TESTVECTOR;
 | 
					          return CRYPT_FAIL_TESTVECTOR;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (y == 0) {
 | 
					      if (y == 0) {
 | 
				
			||||||
         cipher_descriptor[idx].done(&skey);
 | 
					         cipher_descriptor[idx].done(&skey);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return CRYPT_OK;
 | 
					  return CRYPT_OK;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user