Commit a27b2ca26a for openssl.org
commit a27b2ca26a8ceb87e6042cc9f0c32f0db8f8fb1d
Author: Tomas Mraz <tomas@openssl.org>
Date: Mon Jan 5 18:47:23 2026 +0100
base64 encoder: Make ctx->length a constant
It is never changed anywhere.
Fixes #29518
Reviewed-by: Saša NedvÄ›dický <sashan@openssl.org>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Matt Caswell <matt@openssl.org>
MergeDate: Mon Jan 19 14:20:35 2026
(Merged from https://github.com/openssl/openssl/pull/29550)
diff --git a/crypto/evp/enc_b64_scalar.c b/crypto/evp/enc_b64_scalar.c
index 89ccb735c1..1ca46a8357 100644
--- a/crypto/evp/enc_b64_scalar.c
+++ b/crypto/evp/enc_b64_scalar.c
@@ -134,7 +134,7 @@ int evp_encodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
int srp = (ctx != NULL
&& (ctx->flags & EVP_ENCODE_CTX_USE_SRP_ALPHABET) != 0);
int wrap_cnt_by_input = *wrap_cnt / 4 * 3;
- const int ctx_length = (ctx != NULL) ? ctx->length : 0;
+ const int ctx_length = (ctx != NULL) ? EVP_ENCODE_B64_LENGTH : 0;
if (srp) {
e0 = base64_srp_bin2ascii_0;
@@ -168,11 +168,11 @@ int evp_encodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
int wrap_cnt_nm3 = 0;
while (i + 2 < dlen) {
if (ctx != NULL) {
- if ((wrap_cnt_nm3 < ctx->length
- && (wrap_cnt_nm3 + 3 + wrap_cnt_by_input) > ctx->length)
+ if ((wrap_cnt_nm3 < EVP_ENCODE_B64_LENGTH
+ && (wrap_cnt_nm3 + 3 + wrap_cnt_by_input) > EVP_ENCODE_B64_LENGTH)
&& ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0)) {
- switch (ctx->length % 3) {
+ switch (EVP_ENCODE_B64_LENGTH % 3) {
case 0:
break;
case 1:
@@ -228,7 +228,9 @@ int evp_encodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
ret += 4;
if (ctx != NULL) {
- if ((i + 3 + wrap_cnt_by_input) % ctx->length == 0 && ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0) && ctx->length % 3 == 0) {
+ if ((i + 3 + wrap_cnt_by_input) % EVP_ENCODE_B64_LENGTH == 0
+ && ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0)
+ && EVP_ENCODE_B64_LENGTH % 3 == 0) {
*(t++) = '\n';
ret++;
}
@@ -249,7 +251,9 @@ int evp_encodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
ret += 4;
if (ctx != NULL) {
- if ((i + 1 + wrap_cnt_by_input) % ctx->length == 0 && ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0) && ctx->length % 3 == 0) {
+ if ((i + 1 + wrap_cnt_by_input) % EVP_ENCODE_B64_LENGTH == 0
+ && ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0)
+ && EVP_ENCODE_B64_LENGTH % 3 == 0) {
*(t++) = '\n';
ret++;
}
@@ -266,7 +270,9 @@ int evp_encodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
ret += 4;
if (ctx != NULL) {
- if ((i + 2 + wrap_cnt_by_input) % ctx->length == 0 && ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0) && ctx->length % 3 == 0) {
+ if ((i + 2 + wrap_cnt_by_input) % EVP_ENCODE_B64_LENGTH == 0
+ && ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0)
+ && EVP_ENCODE_B64_LENGTH % 3 == 0) {
*(t++) = '\n';
ret++;
}
diff --git a/crypto/evp/encode.c b/crypto/evp/encode.c
index dd5992d09e..49b02ed4dd 100644
--- a/crypto/evp/encode.c
+++ b/crypto/evp/encode.c
@@ -9,6 +9,7 @@
#include <stdio.h>
#include <limits.h>
+#include <assert.h>
#include "internal/cryptlib.h"
#include <openssl/evp.h>
#include "crypto/evp.h"
@@ -364,7 +365,6 @@ void evp_encode_ctx_set_flags(EVP_ENCODE_CTX *ctx, unsigned int flags)
void EVP_EncodeInit(EVP_ENCODE_CTX *ctx)
{
- ctx->length = 48;
ctx->num = 0;
ctx->line_num = 0;
ctx->flags = 0;
@@ -379,19 +379,19 @@ int EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
*outl = 0;
if (inl <= 0)
return 0;
- OPENSSL_assert(ctx->length <= (int)sizeof(ctx->enc_data));
- if (ctx->length - ctx->num > inl) {
+ assert(EVP_ENCODE_B64_LENGTH <= (int)sizeof(ctx->enc_data));
+ if (EVP_ENCODE_B64_LENGTH - ctx->num > inl) {
memcpy(&(ctx->enc_data[ctx->num]), in, inl);
ctx->num += inl;
return 1;
}
if (ctx->num != 0) {
- i = ctx->length - ctx->num;
+ i = EVP_ENCODE_B64_LENGTH - ctx->num;
memcpy(&(ctx->enc_data[ctx->num]), in, i);
in += i;
inl -= i;
int wrap_cnt = 0;
- j = evp_encodeblock_int(ctx, out, ctx->enc_data, ctx->length,
+ j = evp_encodeblock_int(ctx, out, ctx->enc_data, EVP_ENCODE_B64_LENGTH,
&wrap_cnt);
ctx->num = 0;
out += j;
@@ -399,39 +399,39 @@ int EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
*out = '\0';
}
int wrap_cnt = 0;
- if (ctx->length % 3 != 0) {
- j = evp_encodeblock_int(ctx, out, in, inl - (inl % ctx->length),
+ if (EVP_ENCODE_B64_LENGTH % 3 != 0) {
+ j = evp_encodeblock_int(ctx, out, in, inl - (inl % EVP_ENCODE_B64_LENGTH),
&wrap_cnt);
} else {
#if defined(__AVX2__)
- const int newlines = !(ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) ? ctx->length : 0;
+ const int newlines = !(ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) ? EVP_ENCODE_B64_LENGTH : 0;
j = encode_base64_avx2(ctx,
(unsigned char *)out,
(const unsigned char *)in,
- inl - (inl % ctx->length), newlines, &wrap_cnt);
+ inl - (inl % EVP_ENCODE_B64_LENGTH), newlines, &wrap_cnt);
#elif defined(HAS_IA32CAP_IS_64)
if ((OPENSSL_ia32cap_P[2] & (1u << 5)) != 0) {
- const int newlines = !(ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) ? ctx->length : 0;
+ const int newlines = !(ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) ? EVP_ENCODE_B64_LENGTH : 0;
j = encode_base64_avx2(ctx,
(unsigned char *)out,
(const unsigned char *)in,
- inl - (inl % ctx->length), newlines, &wrap_cnt);
+ inl - (inl % EVP_ENCODE_B64_LENGTH), newlines, &wrap_cnt);
} else {
- j = evp_encodeblock_int(ctx, out, in, inl - (inl % ctx->length),
+ j = evp_encodeblock_int(ctx, out, in, inl - (inl % EVP_ENCODE_B64_LENGTH),
&wrap_cnt);
}
#else
- j = evp_encodeblock_int(ctx, out, in, inl - (inl % ctx->length),
+ j = evp_encodeblock_int(ctx, out, in, inl - (inl % EVP_ENCODE_B64_LENGTH),
&wrap_cnt);
#endif
}
- in += inl - (inl % ctx->length);
- inl -= inl - (inl % ctx->length);
+ in += inl - (inl % EVP_ENCODE_B64_LENGTH);
+ inl -= inl - (inl % EVP_ENCODE_B64_LENGTH);
out += j;
total += j;
- if ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0 && ctx->length % 3 != 0) {
+ if ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0 && EVP_ENCODE_B64_LENGTH % 3 != 0) {
*(out++) = '\n';
total++;
}
@@ -487,7 +487,6 @@ void EVP_DecodeInit(EVP_ENCODE_CTX *ctx)
{
/* Only ctx->num and ctx->flags are used during decoding. */
ctx->num = 0;
- ctx->length = 0;
ctx->line_num = 0;
ctx->flags = 0;
}
diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h
index 08baae95d8..f8550bdeff 100644
--- a/crypto/evp/evp_local.h
+++ b/crypto/evp/evp_local.h
@@ -12,6 +12,12 @@
#define EVP_CTRL_RET_UNSUPPORTED -1
+/*
+ * Length of the BASE64-encoded lines when encoding.
+ * This needs to be divisible by 3 to keep the AVX2 optimized code path.
+ */
+#define EVP_ENCODE_B64_LENGTH 48
+
struct evp_md_ctx_st {
const EVP_MD *reqdigest; /* The original requested digest */
const EVP_MD *digest;
@@ -272,12 +278,6 @@ int PKCS5_v2_PBKDF2_keyivgen_ex(EVP_CIPHER_CTX *ctx, const char *pass,
struct evp_Encode_Ctx_st {
/* number saved in a partial encode/decode */
int num;
- /*
- * The length is either the output line length (in input bytes) or the
- * shortest input line length that is ok. Once decoding begins, the
- * length is adjusted up each time a longer line is decoded
- */
- int length;
/* data to encode */
unsigned char enc_data[80];
/* number read on current line */
diff --git a/test/test_base64_simdutf.c b/test/test_base64_simdutf.c
index e6026c4f38..d2d4072789 100644
--- a/test/test_base64_simdutf.c
+++ b/test/test_base64_simdutf.c
@@ -30,8 +30,7 @@ static void fuzz_fill_encode_ctx(EVP_ENCODE_CTX *ctx, int max_fill)
for (int i = 0; i < num; i++)
ctx->enc_data[i] = (unsigned char)(rand() & 0xFF);
- ctx->length = (rand() % 80) + 1;
- ctx->line_num = rand() % (ctx->length + 1);
+ ctx->line_num = rand() % (EVP_ENCODE_B64_LENGTH + 1);
}
static inline uint32_t next_u32(uint32_t *state)
{
@@ -100,18 +99,18 @@ static int evp_encodeupdate_old(EVP_ENCODE_CTX *ctx, unsigned char *out, int *ou
*outl = 0;
if (inl <= 0)
return 0;
- OPENSSL_assert(ctx->length <= (int)sizeof(ctx->enc_data));
- if (ctx->length - ctx->num > inl) {
+ OPENSSL_assert(EVP_ENCODE_B64_LENGTH <= (int)sizeof(ctx->enc_data));
+ if (EVP_ENCODE_B64_LENGTH - ctx->num > inl) {
memcpy(&(ctx->enc_data[ctx->num]), in, inl);
ctx->num += inl;
return 1;
}
if (ctx->num != 0) {
- i = ctx->length - ctx->num;
+ i = EVP_ENCODE_B64_LENGTH - ctx->num;
memcpy(&(ctx->enc_data[ctx->num]), in, i);
in += i;
inl -= i;
- j = evp_encodeblock_int_old(ctx, out, ctx->enc_data, ctx->length);
+ j = evp_encodeblock_int_old(ctx, out, ctx->enc_data, EVP_ENCODE_B64_LENGTH);
ctx->num = 0;
out += j;
total = j;
@@ -121,10 +120,10 @@ static int evp_encodeupdate_old(EVP_ENCODE_CTX *ctx, unsigned char *out, int *ou
}
*out = '\0';
}
- while (inl >= ctx->length) {
- j = evp_encodeblock_int_old(ctx, out, in, ctx->length);
- in += ctx->length;
- inl -= ctx->length;
+ while (inl >= EVP_ENCODE_B64_LENGTH) {
+ j = evp_encodeblock_int_old(ctx, out, in, EVP_ENCODE_B64_LENGTH);
+ in += EVP_ENCODE_B64_LENGTH;
+ inl -= EVP_ENCODE_B64_LENGTH;
out += j;
total += j;
if ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0) {
@@ -154,7 +153,8 @@ static void evp_encodefinal_old(EVP_ENCODE_CTX *ctx, unsigned char *out, int *ou
}
*outl = ret;
}
-static int test_encode_line_lengths_reinforced(void)
+
+static int test_encode_line_length_reinforced(void)
{
const int trials = 50;
uint32_t seed = 12345;
@@ -175,65 +175,59 @@ static int test_encode_line_lengths_reinforced(void)
for (int partial_ctx_fill = 0; partial_ctx_fill <= 80;
partial_ctx_fill += 1) {
- for (int ctx_len = 1; ctx_len <= 80; ctx_len += 1) {
- ctx_simd = EVP_ENCODE_CTX_new();
- ctx_ref = EVP_ENCODE_CTX_new();
+ ctx_simd = EVP_ENCODE_CTX_new();
+ ctx_ref = EVP_ENCODE_CTX_new();
- if (!ctx_simd || !ctx_ref) {
- TEST_error("Out of memory for contexts");
- goto fail;
- }
+ if (!TEST_ptr(ctx_simd) || !TEST_ptr(ctx_ref))
+ goto fail;
+
+ fuzz_fill_encode_ctx(ctx_simd, partial_ctx_fill);
+
+ memset(out_simd, 0xCC, sizeof(out_simd)); /* poison to catch short writes */
+ memset(out_ref, 0xDD, sizeof(out_ref));
+
+ int outlen_simd = 0, outlen_ref = 0; /* bytes produced by Update */
+ int finlen_simd = 0, finlen_ref = 0; /* bytes produced by Final */
+
+ EVP_EncodeInit(ctx_simd);
+ EVP_EncodeInit(ctx_ref);
- fuzz_fill_encode_ctx(ctx_simd, partial_ctx_fill);
-
- memset(out_simd, 0xCC, sizeof(out_simd)); /* poison to catch short writes */
- memset(out_ref, 0xDD, sizeof(out_ref));
-
- int outlen_simd = 0, outlen_ref = 0; /* bytes produced by Update */
- int finlen_simd = 0, finlen_ref = 0; /* bytes produced by Final */
-
- EVP_EncodeInit(ctx_simd);
- EVP_EncodeInit(ctx_ref);
- ctx_simd->length = ctx_len;
- ctx_ref->length = ctx_len;
-
- for (int i = 0; i < 2; i++) {
- if (i % 2 == 0) {
- /* Turn SRP alphabet OFF */
- ctx_simd->flags &= ~EVP_ENCODE_CTX_USE_SRP_ALPHABET;
- ctx_ref->flags &= ~EVP_ENCODE_CTX_USE_SRP_ALPHABET;
- } else {
- /* Turn SRP alphabet ON */
- ctx_simd->flags |= EVP_ENCODE_CTX_USE_SRP_ALPHABET;
- ctx_ref->flags |= EVP_ENCODE_CTX_USE_SRP_ALPHABET;
- }
-
- int ret_simd = EVP_EncodeUpdate(ctx_simd, out_simd, &outlen_simd,
- input, (int)inl);
- int ret_ref = evp_encodeupdate_old(ctx_ref, out_ref, &outlen_ref,
- input, (int)inl);
-
- if (!TEST_int_eq(ret_simd, ret_ref)
- || !TEST_mem_eq(out_ref, outlen_ref, out_simd, outlen_simd)
- || !TEST_int_eq(outlen_simd, outlen_ref))
- goto fail;
-
- EVP_EncodeFinal(ctx_simd, out_simd + outlen_simd,
- &finlen_simd);
- evp_encodefinal_old(ctx_ref, out_ref + outlen_ref,
- &finlen_ref);
-
- int total_ref = outlen_ref + finlen_ref;
- int total_simd = outlen_simd + finlen_simd;
-
- if (!TEST_int_eq(finlen_simd, finlen_ref)
- || !TEST_mem_eq(out_ref, total_ref, out_simd, total_simd))
- goto fail;
+ for (int i = 0; i < 2; i++) {
+ if (i % 2 == 0) {
+ /* Turn SRP alphabet OFF */
+ ctx_simd->flags &= ~EVP_ENCODE_CTX_USE_SRP_ALPHABET;
+ ctx_ref->flags &= ~EVP_ENCODE_CTX_USE_SRP_ALPHABET;
+ } else {
+ /* Turn SRP alphabet ON */
+ ctx_simd->flags |= EVP_ENCODE_CTX_USE_SRP_ALPHABET;
+ ctx_ref->flags |= EVP_ENCODE_CTX_USE_SRP_ALPHABET;
}
- EVP_ENCODE_CTX_free(ctx_simd);
- EVP_ENCODE_CTX_free(ctx_ref);
+ int ret_simd = EVP_EncodeUpdate(ctx_simd, out_simd, &outlen_simd,
+ input, (int)inl);
+ int ret_ref = evp_encodeupdate_old(ctx_ref, out_ref, &outlen_ref,
+ input, (int)inl);
+
+ if (!TEST_int_eq(ret_simd, ret_ref)
+ || !TEST_mem_eq(out_ref, outlen_ref, out_simd, outlen_simd)
+ || !TEST_int_eq(outlen_simd, outlen_ref))
+ goto fail;
+
+ EVP_EncodeFinal(ctx_simd, out_simd + outlen_simd,
+ &finlen_simd);
+ evp_encodefinal_old(ctx_ref, out_ref + outlen_ref,
+ &finlen_ref);
+
+ int total_ref = outlen_ref + finlen_ref;
+ int total_simd = outlen_simd + finlen_simd;
+
+ if (!TEST_int_eq(finlen_simd, finlen_ref)
+ || !TEST_mem_eq(out_ref, total_ref, out_simd, total_simd))
+ goto fail;
}
+
+ EVP_ENCODE_CTX_free(ctx_simd);
+ EVP_ENCODE_CTX_free(ctx_ref);
}
}
@@ -247,7 +241,7 @@ fail:
int setup_tests(void)
{
- ADD_TEST(test_encode_line_lengths_reinforced);
+ ADD_TEST(test_encode_line_length_reinforced);
return 1;
}