[PATCH 1/5] cipher: keep context copy for reset only for ciphers that need it
Jussi Kivilinna
jussi.kivilinna at iki.fi
Thu Oct 22 19:38:40 CEST 2026
* cipher/arcfour.c (_gcry_cipher_spec_arcfour): Set
'restore_ctx_on_reset' flag.
* cipher/chacha20.c (_gcry_cipher_spec_chacha20): Likewise.
* cipher/gost28147.c (_gcry_cipher_spec_gost28147_mesh): Likewise.
* cipher/salsa20.c (_gcry_cipher_spec_salsa20)
(_gcry_cipher_spec_salsa20r12): Likewise.
* cipher/cipher-internal.h (gcry_cipher_handle): Update comment for
context copy.
* cipher/cipher.c (_gcry_cipher_open_internal): Allocate context copy
only for ciphers with 'restore_ctx_on_reset'.
(cipher_setkey, cipher_reset): Copy and restore context only for
ciphers with 'restore_ctx_on_reset'.
* src/cipher-proto.h (gcry_cipher_spec_t): Add 'restore_ctx_on_reset'
flag.
--
Reset restored full cipher context from copy made at setkey. Only
stream ciphers and GOST28147 with key meshing modify context after
setkey. For other ciphers, restore only discarded lazily prepared
decryption keys (AES, ARIA, IDEA) which then were recomputed after
every reset. Now context copy is kept only for ciphers that need it.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
cipher/arcfour.c | 2 +-
cipher/chacha20.c | 2 +-
cipher/cipher-internal.h | 10 ++++-----
cipher/cipher.c | 48 +++++++++++++++++++++++-----------------
cipher/gost28147.c | 2 +-
cipher/salsa20.c | 4 ++--
src/cipher-proto.h | 1 +
7 files changed, 39 insertions(+), 30 deletions(-)
diff --git a/cipher/arcfour.c b/cipher/arcfour.c
index c8d22c70..294a5a18 100644
--- a/cipher/arcfour.c
+++ b/cipher/arcfour.c
@@ -210,7 +210,7 @@ selftest(void)
gcry_cipher_spec_t _gcry_cipher_spec_arcfour =
{
- GCRY_CIPHER_ARCFOUR, {0, 0},
+ GCRY_CIPHER_ARCFOUR, {0, 0, 1},
"ARCFOUR", NULL, NULL, 1, 128, sizeof (ARCFOUR_context),
arcfour_setkey, NULL, NULL, encrypt_stream, encrypt_stream,
};
diff --git a/cipher/chacha20.c b/cipher/chacha20.c
index 18d7e049..8c15c9a5 100644
--- a/cipher/chacha20.c
+++ b/cipher/chacha20.c
@@ -1549,7 +1549,7 @@ selftest (void)
gcry_cipher_spec_t _gcry_cipher_spec_chacha20 = {
GCRY_CIPHER_CHACHA20,
- {0, 0}, /* flags */
+ {0, 0, 1}, /* flags */
"CHACHA20", /* name */
NULL, /* aliases */
NULL, /* oids */
diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h
index dcae7ee7..e053a765 100644
--- a/cipher/cipher-internal.h
+++ b/cipher/cipher-internal.h
@@ -490,11 +490,11 @@ struct gcry_cipher_handle
} wrap;
} u_mode;
- /* What follows are two contexts of the cipher in use. The first
- one needs to be aligned well enough for the cipher operation
- whereas the second one is a copy created by cipher_setkey and
- used by cipher_reset. That second copy has no need for proper
- aligment because it is only accessed by memcpy. */
+ /* What follows is the context of the cipher in use, aligned well
+ enough for the cipher operation. For ciphers with
+ 'restore_ctx_on_reset' flag, it is followed by a copy created by
+ cipher_setkey and used by cipher_reset. That second copy has no
+ need for proper aligment because it is only accessed by memcpy. */
cipher_context_alignment_t context;
};
diff --git a/cipher/cipher.c b/cipher/cipher.c
index 72227714..ef9df6e1 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -709,8 +709,10 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
if (! err)
{
+ /* Second copy of context is kept for restoring on reset. */
+ size_t nctx = spec->flags.restore_ctx_on_reset ? 2 : 1;
size_t size = (sizeof (*h)
- + 2 * spec->contextsize
+ + nctx * spec->contextsize
- sizeof (cipher_context_alignment_t)
#ifdef NEED_16BYTE_ALIGNED_CONTEXT
+ 15 /* Space for leading alignment gap. */
@@ -723,7 +725,7 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
case GCRY_CIPHER_MODE_XTS:
case GCRY_CIPHER_MODE_SIV:
/* Additional cipher context for tweak. */
- size += 2 * spec->contextsize + 15;
+ size += nctx * spec->contextsize + 15;
break;
default:
@@ -771,13 +773,13 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
break;
case GCRY_CIPHER_MODE_XTS:
- tc = h->context.c + spec->contextsize * 2;
+ tc = h->context.c + spec->contextsize * nctx;
tc += (16 - (uintptr_t)tc % 16) % 16;
h->u_mode.xts.tweak_context = tc;
break;
case GCRY_CIPHER_MODE_SIV:
- tc = h->context.c + spec->contextsize * 2;
+ tc = h->context.c + spec->contextsize * nctx;
tc += (16 - (uintptr_t)tc % 16) % 16;
h->u_mode.siv.ctr_context = tc;
break;
@@ -868,9 +870,10 @@ cipher_setkey (gcry_cipher_hd_t c, byte *key, size_t keylen)
int is_weak_key = (rc == GPG_ERR_WEAK_KEY);
/* Duplicate initial context. */
- memcpy ((void *) ((char *) &c->context.c + c->spec->contextsize),
- (void *) &c->context.c,
- c->spec->contextsize);
+ if (c->spec->flags.restore_ctx_on_reset)
+ memcpy ((void *) ((char *) &c->context.c + c->spec->contextsize),
+ (void *) &c->context.c,
+ c->spec->contextsize);
c->marks.key = 1;
switch (c->mode)
@@ -908,8 +911,9 @@ cipher_setkey (gcry_cipher_hd_t c, byte *key, size_t keylen)
if (!rc || (c->marks.allow_weak_key && rc == GPG_ERR_WEAK_KEY))
{
/* Duplicate initial tweak context. */
- memcpy (c->u_mode.xts.tweak_context + c->spec->contextsize,
- c->u_mode.xts.tweak_context, c->spec->contextsize);
+ if (c->spec->flags.restore_ctx_on_reset)
+ memcpy (c->u_mode.xts.tweak_context + c->spec->contextsize,
+ c->u_mode.xts.tweak_context, c->spec->contextsize);
}
else
c->marks.key = 0;
@@ -921,8 +925,9 @@ cipher_setkey (gcry_cipher_hd_t c, byte *key, size_t keylen)
if (!rc || (c->marks.allow_weak_key && rc == GPG_ERR_WEAK_KEY))
{
/* Duplicate initial CTR context. */
- memcpy (c->u_mode.siv.ctr_context + c->spec->contextsize,
- c->u_mode.siv.ctr_context, c->spec->contextsize);
+ if (c->spec->flags.restore_ctx_on_reset)
+ memcpy (c->u_mode.siv.ctr_context + c->spec->contextsize,
+ c->u_mode.siv.ctr_context, c->spec->contextsize);
}
else
c->marks.key = 0;
@@ -989,9 +994,10 @@ cipher_reset (gcry_cipher_hd_t c)
marks_key = c->marks.key;
marks_allow_weak_key = c->marks.allow_weak_key;
- memcpy (&c->context.c,
- (char *) &c->context.c + c->spec->contextsize,
- c->spec->contextsize);
+ if (c->spec->flags.restore_ctx_on_reset)
+ memcpy (&c->context.c,
+ (char *) &c->context.c + c->spec->contextsize,
+ c->spec->contextsize);
memset (&c->marks, 0, sizeof c->marks);
memset (c->u_iv.iv, 0, c->spec->blocksize);
memset (c->lastiv, 0, c->spec->blocksize);
@@ -1059,9 +1065,10 @@ cipher_reset (gcry_cipher_hd_t c)
break;
case GCRY_CIPHER_MODE_XTS:
- memcpy (c->u_mode.xts.tweak_context,
- c->u_mode.xts.tweak_context + c->spec->contextsize,
- c->spec->contextsize);
+ if (c->spec->flags.restore_ctx_on_reset)
+ memcpy (c->u_mode.xts.tweak_context,
+ c->u_mode.xts.tweak_context + c->spec->contextsize,
+ c->spec->contextsize);
break;
case GCRY_CIPHER_MODE_SIV:
@@ -1073,9 +1080,10 @@ cipher_reset (gcry_cipher_hd_t c)
memset (&c->u_mode, 0, u_mode_head_length);
- memcpy (c->u_mode.siv.ctr_context,
- c->u_mode.siv.ctr_context + c->spec->contextsize,
- c->spec->contextsize);
+ if (c->spec->flags.restore_ctx_on_reset)
+ memcpy (c->u_mode.siv.ctr_context,
+ c->u_mode.siv.ctr_context + c->spec->contextsize,
+ c->spec->contextsize);
memcpy (c->u_mode.siv.s2v_d, c->u_mode.siv.s2v_zero_block,
GCRY_SIV_BLOCK_LEN);
diff --git a/cipher/gost28147.c b/cipher/gost28147.c
index 10383c23..a3ad26f7 100644
--- a/cipher/gost28147.c
+++ b/cipher/gost28147.c
@@ -305,7 +305,7 @@ gcry_cipher_spec_t _gcry_cipher_spec_gost28147 =
* it afterwards would be meaningless. */
gcry_cipher_spec_t _gcry_cipher_spec_gost28147_mesh =
{
- GCRY_CIPHER_GOST28147_MESH, {0, 0},
+ GCRY_CIPHER_GOST28147_MESH, {0, 0, 1},
"GOST28147_MESH", NULL, oids_gost28147_mesh, 8, 256,
sizeof (GOST28147_context),
gost_setkey,
diff --git a/cipher/salsa20.c b/cipher/salsa20.c
index c6707b7a..176542b2 100644
--- a/cipher/salsa20.c
+++ b/cipher/salsa20.c
@@ -562,7 +562,7 @@ selftest (void)
gcry_cipher_spec_t _gcry_cipher_spec_salsa20 =
{
GCRY_CIPHER_SALSA20,
- {0, 0}, /* flags */
+ {0, 0, 1}, /* flags */
"SALSA20", /* name */
NULL, /* aliases */
NULL, /* oids */
@@ -582,7 +582,7 @@ gcry_cipher_spec_t _gcry_cipher_spec_salsa20 =
gcry_cipher_spec_t _gcry_cipher_spec_salsa20r12 =
{
GCRY_CIPHER_SALSA20R12,
- {0, 0}, /* flags */
+ {0, 0, 1}, /* flags */
"SALSA20R12", /* name */
NULL, /* aliases */
NULL, /* oids */
diff --git a/src/cipher-proto.h b/src/cipher-proto.h
index b23eb9ca..e5772d4b 100644
--- a/src/cipher-proto.h
+++ b/src/cipher-proto.h
@@ -178,6 +178,7 @@ typedef struct gcry_cipher_spec
struct {
unsigned int disabled:1;
unsigned int fips:1;
+ unsigned int restore_ctx_on_reset:1;
} flags;
const char *name;
const char **aliases;
--
2.53.0
More information about the Gcrypt-devel
mailing list