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.
This commit is contained in:
parent
09e4b0ec9b
commit
75b114517a
@ -49,10 +49,14 @@ int ccm_memory(int cipher,
|
|||||||
int direction)
|
int direction)
|
||||||
{
|
{
|
||||||
unsigned char PAD[16], ctr[16], CTRPAD[16], ptTag[16], b, *pt_real;
|
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;
|
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);
|
||||||
@ -143,16 +147,14 @@ int ccm_memory(int cipher,
|
|||||||
} else {
|
} else {
|
||||||
skey = uskey;
|
skey = uskey;
|
||||||
}
|
}
|
||||||
if (direction != CCM_ENCRYPT) {
|
|
||||||
pt_work[0] = XMALLOC(ptlen);
|
/* initialize buffer for pt */
|
||||||
pt_work[1] = XCALLOC(1, ptlen);
|
if (direction == CCM_DECRYPT) {
|
||||||
|
pt_work = XMALLOC(ptlen);
|
||||||
if ((pt_work[0] == NULL) || (pt_work[1] == NULL)) {
|
if (pt_work == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
pt = pt_work;
|
||||||
XMEMCPY(pt_work[0], pt, ptlen);
|
|
||||||
pt = pt_work[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* form B_0 == flags | Nonce N | l(m) */
|
/* form B_0 == flags | Nonce N | l(m) */
|
||||||
@ -360,26 +362,39 @@ int ccm_memory(int cipher,
|
|||||||
*/
|
*/
|
||||||
err = XMEM_NEQ(ptTag, PAD, *taglen);
|
err = XMEM_NEQ(ptTag, PAD, *taglen);
|
||||||
|
|
||||||
/* Here err is 0 or 1, so we just copy either the real plaintext
|
/* Zero the plaintext if the tag was invalid (in constant time) */
|
||||||
* or the zeroized buffer.
|
if (ptlen > 0) {
|
||||||
*/
|
y = 0;
|
||||||
XMEMCPY(pt_real, pt_work[err], ptlen);
|
mask *= 1 - err; /* mask = ( err ? 0 : 0xff ) */
|
||||||
#ifdef LTC_CLEAN_STACK
|
#ifdef LTC_FAST
|
||||||
zeromem(pt_work[0], ptlen);
|
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
|
#endif
|
||||||
|
for (; y < ptlen; y++) {
|
||||||
|
pt_real[y] = pt[y] & mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#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[1]) {
|
if (pt_work) {
|
||||||
XFREE(pt_work[1]);
|
XFREE(pt_work);
|
||||||
}
|
|
||||||
if (pt_work[0]) {
|
|
||||||
XFREE(pt_work[0]);
|
|
||||||
}
|
}
|
||||||
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], tag[16], tag2[16], tag3[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,10 +190,9 @@ int ccm_test(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (y == 0) {
|
if (y == 0) {
|
||||||
|
XMEMCPY(tag3, tests[x].tag, tests[x].taglen);
|
||||||
XMEMCPY(tag3, tests[x].tag, tests[x].taglen);
|
taglen = tests[x].taglen;
|
||||||
taglen = tests[x].taglen;
|
if ((err = ccm_memory(idx,
|
||||||
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,
|
||||||
@ -222,28 +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;
|
||||||
}
|
}
|
||||||
/* Only check the tag if ccm_memory was not called: ccm_memory already
|
if (y == 0) {
|
||||||
validates the tag */
|
/* check if decryption with the wrong tag does not reveal the plaintext */
|
||||||
if (y != 0) {
|
XMEMCPY(tag3, tests[x].tag, tests[x].taglen);
|
||||||
if (XMEMCMP(tag2, tests[x].tag, tests[x].taglen)) {
|
tag3[0] ^= 0xff; /* set the tag to the wrong value */
|
||||||
#if defined(LTC_TEST_DBG)
|
taglen = tests[x].taglen;
|
||||||
printf("\n%d: x=%lu y=%lu\n", __LINE__, x, y);
|
if ((err = ccm_memory(idx,
|
||||||
print_hex("tag is ", tag, tests[x].taglen);
|
tests[x].key, 16,
|
||||||
print_hex("tag should", tests[x].tag, tests[x].taglen);
|
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
|
#endif
|
||||||
return CRYPT_FAIL_TESTVECTOR;
|
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 ", tag2, tests[x].taglen);
|
||||||
|
print_hex("tag should", tests[x].tag, tests[x].taglen);
|
||||||
|
#endif
|
||||||
|
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