[PATCH] Calculate OCB L-tables when setting key instead of when setting nonce
Jussi Kivilinna
jussi.kivilinna at iki.fi
Wed Jan 23 22:20:42 CET 2019
* cipher/cipher-internal.h (gcry_cipher_handle): Mark areas of
u_mode.ocb that are and are not cleared by gcry_cipher_reset.
(_gcry_cipher_ocb_setkey): New.
* cipher/cipher-ocb.c (_gcry_cipher_ocb_set_nonce): Split
L-table generation to ...
(_gcry_cipher_ocb_setkey): ... this new function.
* cipher/cipher.c (cipher_setkey): Add handling for OCB mode.
(cipher_reset): Do not clear L-values for OCB mode.
--
OCB L-tables do not depend on nonce value, but only on cipher key.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
0 files changed
diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h
index 78f05dbb5..79de140dd 100644
--- a/cipher/cipher-internal.h
+++ b/cipher/cipher-internal.h
@@ -316,6 +316,8 @@ struct gcry_cipher_handle
/* Mode specific storage for OCB mode. */
struct {
+ /* --- Following members are not cleared in gcry_cipher_reset --- */
+
/* Helper variables and pre-computed table of L values. */
unsigned char L_star[OCB_BLOCK_LEN];
unsigned char L_dollar[OCB_BLOCK_LEN];
@@ -323,6 +325,8 @@ struct gcry_cipher_handle
unsigned char L0L1L0[OCB_BLOCK_LEN];
unsigned char L[OCB_L_TABLE_SIZE][OCB_BLOCK_LEN];
+ /* --- Following members are cleared in gcry_cipher_reset --- */
+
/* The tag is valid if marks.tag has been set. */
unsigned char tag[OCB_BLOCK_LEN];
@@ -571,6 +575,8 @@ gcry_err_code_t _gcry_cipher_ocb_get_tag
gcry_err_code_t _gcry_cipher_ocb_check_tag
/* */ (gcry_cipher_hd_t c,
const unsigned char *intag, size_t taglen);
+void _gcry_cipher_ocb_setkey
+/* */ (gcry_cipher_hd_t c);
/*-- cipher-xts.c --*/
diff --git a/cipher/cipher-ocb.c b/cipher/cipher-ocb.c
index 58f7be7e6..be6b8dffb 100644
--- a/cipher/cipher-ocb.c
+++ b/cipher/cipher-ocb.c
@@ -123,6 +123,37 @@ ocb_get_L_big (gcry_cipher_hd_t c, u64 n, unsigned char *l_buf)
}
+/* Called after key has been set. Sets up L table. */
+void _gcry_cipher_ocb_setkey (gcry_cipher_hd_t c)
+{
+ unsigned char ktop[OCB_BLOCK_LEN];
+ unsigned int burn = 0;
+ unsigned int nburn;
+ int i;
+
+ /* L_star = E(zero_128) */
+ memset (ktop, 0, OCB_BLOCK_LEN);
+ nburn = c->spec->encrypt (&c->context.c, c->u_mode.ocb.L_star, ktop);
+ burn = nburn > burn ? nburn : burn;
+ /* L_dollar = double(L_star) */
+ double_block_cpy (c->u_mode.ocb.L_dollar, c->u_mode.ocb.L_star);
+ /* L_0 = double(L_dollar), ... */
+ double_block_cpy (c->u_mode.ocb.L[0], c->u_mode.ocb.L_dollar);
+ for (i = 1; i < OCB_L_TABLE_SIZE; i++)
+ double_block_cpy (c->u_mode.ocb.L[i], c->u_mode.ocb.L[i-1]);
+ /* Precalculated offsets L0+L1, L0+L1+L0 */
+ cipher_block_xor (c->u_mode.ocb.L0L1,
+ c->u_mode.ocb.L[0], c->u_mode.ocb.L[1], OCB_BLOCK_LEN);
+ cipher_block_xor (c->u_mode.ocb.L0L1L0,
+ c->u_mode.ocb.L[0], c->u_mode.ocb.L0L1, OCB_BLOCK_LEN);
+
+ /* Cleanup */
+ wipememory (ktop, sizeof ktop);
+ if (burn > 0)
+ _gcry_burn_stack (burn + 4*sizeof(void*));
+}
+
+
/* Set the nonce for OCB. This requires that the key has been set.
Using it again resets start a new encryption cycle using the same
key. */
@@ -133,7 +164,6 @@ _gcry_cipher_ocb_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce,
unsigned char ktop[OCB_BLOCK_LEN];
unsigned char stretch[OCB_BLOCK_LEN + 8];
unsigned int bottom;
- int i;
unsigned int burn = 0;
unsigned int nburn;
@@ -159,23 +189,6 @@ _gcry_cipher_ocb_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce,
if (noncelen > (120/8) || noncelen < (64/8) || noncelen >= OCB_BLOCK_LEN)
return GPG_ERR_INV_LENGTH;
- /* Set up the L table. */
- /* L_star = E(zero_128) */
- memset (ktop, 0, OCB_BLOCK_LEN);
- nburn = c->spec->encrypt (&c->context.c, c->u_mode.ocb.L_star, ktop);
- burn = nburn > burn ? nburn : burn;
- /* L_dollar = double(L_star) */
- double_block_cpy (c->u_mode.ocb.L_dollar, c->u_mode.ocb.L_star);
- /* L_0 = double(L_dollar), ... */
- double_block_cpy (c->u_mode.ocb.L[0], c->u_mode.ocb.L_dollar);
- for (i = 1; i < OCB_L_TABLE_SIZE; i++)
- double_block_cpy (c->u_mode.ocb.L[i], c->u_mode.ocb.L[i-1]);
- /* Precalculated offsets L0+L1, L0+L1+L0 */
- cipher_block_xor (c->u_mode.ocb.L0L1,
- c->u_mode.ocb.L[0], c->u_mode.ocb.L[1], OCB_BLOCK_LEN);
- cipher_block_xor (c->u_mode.ocb.L0L1L0,
- c->u_mode.ocb.L[0], c->u_mode.ocb.L0L1, OCB_BLOCK_LEN);
-
/* Prepare the nonce. */
memset (ktop, 0, (OCB_BLOCK_LEN - noncelen));
buf_cpy (ktop + (OCB_BLOCK_LEN - noncelen), nonce, noncelen);
diff --git a/cipher/cipher.c b/cipher/cipher.c
index 55b991c35..ab3e4240e 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -816,6 +816,10 @@ cipher_setkey (gcry_cipher_hd_t c, byte *key, size_t keylen)
_gcry_cipher_gcm_setkey (c);
break;
+ case GCRY_CIPHER_MODE_OCB:
+ _gcry_cipher_ocb_setkey (c);
+ break;
+
case GCRY_CIPHER_MODE_POLY1305:
_gcry_cipher_poly1305_setkey (c);
break;
@@ -931,9 +935,18 @@ cipher_reset (gcry_cipher_hd_t c)
break;
case GCRY_CIPHER_MODE_OCB:
- memset (&c->u_mode.ocb, 0, sizeof c->u_mode.ocb);
- /* Setup default taglen. */
- c->u_mode.ocb.taglen = 16;
+ /* Do not clear precalculated L-values */
+ {
+ byte *u_mode_head_pos = (void *)&c->u_mode.ocb;
+ byte *u_mode_tail_pos = (void *)&c->u_mode.ocb.tag;
+ size_t u_mode_head_length = u_mode_tail_pos - u_mode_head_pos;
+ size_t u_mode_tail_length = sizeof(c->u_mode.ocb) - u_mode_head_length;
+
+ memset (u_mode_tail_pos, 0, u_mode_tail_length);
+
+ /* Setup default taglen. */
+ c->u_mode.ocb.taglen = 16;
+ }
break;
case GCRY_CIPHER_MODE_XTS:
More information about the Gcrypt-devel
mailing list