From: Tomas Mraz Date: Mon, 5 Jan 2026 17:47:23 +0000 (+0100) Subject: base64 encoder: Make ctx->length a constant X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a27b2ca26a8ceb87e6042cc9f0c32f0db8f8fb1d;p=thirdparty%2Fopenssl.git base64 encoder: Make ctx->length a constant It is never changed anywhere. Fixes #29518 Reviewed-by: Saša Nedvědický Reviewed-by: Paul Dale Reviewed-by: Matt Caswell 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 89ccb735c17..1ca46a8357e 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 dd5992d09e6..49b02ed4dd1 100644 --- a/crypto/evp/encode.c +++ b/crypto/evp/encode.c @@ -9,6 +9,7 @@ #include #include +#include #include "internal/cryptlib.h" #include #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 08baae95d88..f8550bdeffe 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 e6026c4f38c..d2d40727893 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; }