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,11 +219,9 @@ int ccm_memory(int cipher, | ||||
|           PAD[x++] ^= header[y]; | ||||
|       } | ||||
| 
 | ||||
|       /* remainder? */ | ||||
|       if (x != 0) { | ||||
|          if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) { | ||||
|             goto error; | ||||
|          } | ||||
|       /* remainder */ | ||||
|       if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) { | ||||
|          goto error; | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
| @ -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); | ||||
|    } | ||||
| 
 | ||||
|    /* store the TAG */ | ||||
|    for (x = 0; x < 16 && x < *taglen; x++) { | ||||
|        tag[x] = PAD[x] ^ CTRPAD[x]; | ||||
|    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; | ||||
|          } | ||||
|       } | ||||
|    } | ||||
|    *taglen = x; | ||||
| 
 | ||||
| #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,14 +190,16 @@ int ccm_test(void) | ||||
|       } | ||||
| 
 | ||||
|       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, | ||||
|                                NULL, | ||||
|                                tests[x].nonce, tests[x].noncelen, | ||||
|                                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 (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 | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user