From 09e4b0ec9b46ac4db3fa904658821c54106a1d0e Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Fri, 21 Aug 2015 21:47:43 +0200 Subject: [PATCH] don't reveal plaintext if authentication failed Create two buffers of the same size as the input data. Copy the input data to the first one and work with that version to hold the decrypted data, zeroize the second one. Copy depending on the verification result, either the zero-buffer or the real plaintext to the output buffer. --- src/encauth/ccm/ccm_memory.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/encauth/ccm/ccm_memory.c b/src/encauth/ccm/ccm_memory.c index 166b13c..4b7de92 100644 --- a/src/encauth/ccm/ccm_memory.c +++ b/src/encauth/ccm/ccm_memory.c @@ -48,7 +48,8 @@ int ccm_memory(int cipher, unsigned char *tag, unsigned long *taglen, int direction) { - unsigned char PAD[16], ctr[16], CTRPAD[16], ptTag[16], b; + unsigned char PAD[16], ctr[16], CTRPAD[16], ptTag[16], b, *pt_real; + unsigned char *pt_work[2] = {0}; symmetric_key *skey; int err; unsigned long len, L, x, y, z, CTRlen; @@ -65,6 +66,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; @@ -140,6 +143,17 @@ 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)) { + goto error; + } + + XMEMCPY(pt_work[0], pt, ptlen); + pt = pt_work[0]; + } /* form B_0 == flags | Nonce N | l(m) */ x = 0; @@ -346,13 +360,13 @@ int ccm_memory(int cipher, */ err = XMEM_NEQ(ptTag, PAD, *taglen); - /* TODO: pt should not be revealed when the tag is invalid. However, resetting the - * memory should be done in constant time, which is not the case in the - * (commented) code below. - if (err != CRYPT_OK) { - zeromem(pt, ptlen); - } - */ + /* 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); +#endif } #ifdef LTC_CLEAN_STACK @@ -361,6 +375,12 @@ int ccm_memory(int cipher, zeromem(CTRPAD, sizeof(CTRPAD)); #endif error: + if (pt_work[1]) { + XFREE(pt_work[1]); + } + if (pt_work[0]) { + XFREE(pt_work[0]); + } if (skey != uskey) { XFREE(skey); }