Branch
Hash :
a82f1b76
Author :
Date :
2025-09-06T16:38:08
crypto/sha3-buffer, crypto/sha3: Protect against double frees (regr. today). * lib/sha3.c (sha3_free_ctx): Only free the EVP_MD_CTX if it is not NULL, and set it to NULL after freeing. (DEFINE_SHA3_INIT_CTX, sha3_finish_ctx, sha3_process_bytes): Leave freeing memory to the caller. * lib/sha3-stream.c (sha3_xxx_stream): Call sha3_free_ctx on success and if sha3_init_ctx fails. * tests/test-sha3-224-buffer.c (main): Add a test that would otherwise segfault without this patch. * tests/test-sha3-256-buffer.c (main): Likewise. * tests/test-sha3-384-buffer.c (main): Likewise. * tests/test-sha3-512-buffer.c (main): Likewise.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
/* sha3.h - Functions to calculate SHA-3 hashes as specified by FIPS-202.
Copyright (C) 2025 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Collin Funk <collin.funk1@gmail.com>, 2025. */
#ifndef SHA3_H
# define SHA3_H 1
# include <stddef.h>
# include <stdio.h>
# include <stdint.h>
# include "u64.h"
# ifdef __cplusplus
extern "C" {
# endif
/* OpenSSL does not have the Init, Update, Final API for SHA-3. We must use
the EVP API. */
# if HAVE_OPENSSL_SHA3
# include <openssl/evp.h>
# endif
/* Digest sizes in bytes. */
enum { SHA3_224_DIGEST_SIZE = 224 / 8 };
enum { SHA3_256_DIGEST_SIZE = 256 / 8 };
enum { SHA3_384_DIGEST_SIZE = 384 / 8 };
enum { SHA3_512_DIGEST_SIZE = 512 / 8 };
/* Block sizes in bytes. */
enum { SHA3_224_BLOCK_SIZE = 1152 / 8 };
enum { SHA3_256_BLOCK_SIZE = 1088 / 8 };
enum { SHA3_384_BLOCK_SIZE = 832 / 8 };
enum { SHA3_512_BLOCK_SIZE = 576 / 8 };
/* Structure to save state of computation between the single steps. */
struct sha3_ctx
{
# if HAVE_OPENSSL_SHA3
/* EVP_MD_CTX is an incomplete type. It cannot be placed on the stack. */
EVP_MD_CTX *evp_ctx;
# else
u64 state[25];
uint8_t buffer[144]; /* Up to BLOCKLEN in use. */
size_t buflen; /* ≥ 0, ≤ BLOCKLEN */
size_t digestlen; /* One of SHA3_{224,256,384,512}_DIGEST_SIZE. */
size_t blocklen; /* One of SHA3_{224,256,384,512}_BLOCK_SIZE. */
# endif
};
/* Initialize structure containing state of computation. */
extern bool sha3_224_init_ctx (struct sha3_ctx *ctx);
extern bool sha3_256_init_ctx (struct sha3_ctx *ctx);
extern bool sha3_384_init_ctx (struct sha3_ctx *ctx);
extern bool sha3_512_init_ctx (struct sha3_ctx *ctx);
/* Free memory allocated by the init_structure. */
extern void sha3_free_ctx (struct sha3_ctx *ctx);
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is necessary that LEN is a multiple of the BLOCKLEN member of CTX!!!
Return false if an OpenSSL function fails. */
extern bool sha3_process_block (const void *buffer, size_t len,
struct sha3_ctx *ctx);
/* Starting with the result of former calls of this function (or the
initialization function update the context for the next LEN bytes
starting at BUFFER.
It is NOT required that LEN is a multiple of the BLOCKLEN member of CTX.
Return false if an OpenSSL function fails. */
extern bool sha3_process_bytes (const void *buffer, size_t len,
struct sha3_ctx *ctx);
/* Process the remaining bytes in the buffer and put result from CTX in RESBUF.
The result is always in little endian byte order, so that a byte-wise output
yields to the wanted ASCII representation of the message digest.
Return NULL if an OpenSSL function fails. */
extern void *sha3_finish_ctx (struct sha3_ctx *ctx, void *restrict resbuf);
/* Put result from CTX in RESBUF. The result is always in little endian byte
order, so that a byte-wise output yields to the wanted ASCII representation
of the message digest.
Return NULL if an OpenSSL function fails. */
extern void *sha3_read_ctx (const struct sha3_ctx *ctx,
void *restrict resbuf);
/* Compute a SHA-3 message digest for LEN bytes beginning at BUFFER.
The result is always in little endian byte order, so that a byte-wise
output yields to the wanted ASCII representation of the message
digest.
Return NULL if an OpenSSL function fails. */
extern void *sha3_224_buffer (const char *buffer, size_t len,
void *restrict resblock);
extern void *sha3_256_buffer (const char *buffer, size_t len,
void *restrict resblock);
extern void *sha3_384_buffer (const char *buffer, size_t len,
void *restrict resblock);
extern void *sha3_512_buffer (const char *buffer, size_t len,
void *restrict resblock);
/* Compute SHA-3 message digest for bytes read from STREAM. STREAM is an open
file stream. Regular files are handled more efficiently. The contents of
STREAM from its current position to its end will be read. The case that the
last operation on STREAM was an 'ungetc' is not supported. The resulting
message digest number will be written into RESBLOCK. */
extern int sha3_224_stream (FILE *stream, void *resblock);
extern int sha3_256_stream (FILE *stream, void *resblock);
extern int sha3_384_stream (FILE *stream, void *resblock);
extern int sha3_512_stream (FILE *stream, void *resblock);
# ifdef __cplusplus
}
# endif
#endif