Add SHA-3 support to secure-hash

* admin/merge-gnulib (GNULIB_MODULES): Add crypto/sha3-buffer.
* lib/sha3.c: New file, imported by running admin/merge-gnulib.
* lib/sha3.h: Likewise.
* m4/sha3.m4: Likewise.
* lib/gnulib.mk.in: Updated by admin/merge-gnulib.
* m4/gnulib-comp.m4: Likewise.
* src/fns.c: Include sha3.h
(Fsecure_hash_algorithms): Add Qsha3_224, Qsha3_256, Qsha3_384, and
Qsha3_512.
(secure_hash): Likewise.
(Fsecure_hash): List the SHA-3 algorithms in the docstring.
(syms_of_fns): Define Qsha3_224, Qsha3_256, Qsha3_384, and Qsha3_512.
* test/lisp/net/gnutls-tests.el (gnutls-tests-internal-macs-upcased):
Filter out the new SHA-3 algorithms since they are currently not
implemented in gnutls.
* test/src/fns-tests.el (test-secure-hash): Add test cases for the new
algorithms.
* doc/lispref/text.texi (Checksum/Hash): List the SHA-3 algorithms.
Mention that they are considered secure.
* etc/NEWS: Mention the new feature.
This commit is contained in:
Collin Funk
2026-02-23 00:20:46 -08:00
committed by Paul Eggert
parent ccaa4a07f0
commit 29440eedac
11 changed files with 701 additions and 26 deletions

View File

@@ -35,6 +35,7 @@ GNULIB_MODULES='
careadlinkat close-stream copy-file-range
crypto/md5 crypto/md5-buffer
crypto/sha1-buffer crypto/sha256-buffer crypto/sha512-buffer
crypto/sha3-buffer
d-type diffseq double-slash-root dtoastr dtotimespec dup2
environ execinfo faccessat
fchmodat fcntl fcntl-h fdopendir file-has-acl

View File

@@ -4983,15 +4983,15 @@ that you have an unaltered copy of that data.
@cindex message digest
Emacs supports several common cryptographic hash algorithms: MD5,
SHA-1, SHA-2, SHA-224, SHA-256, SHA-384 and SHA-512. MD5 is the
oldest of these algorithms, and is commonly used in @dfn{message
digests} to check the integrity of messages transmitted over a
network. MD5 and SHA-1 are not collision resistant (i.e., it is
possible to deliberately design different pieces of data which have
the same MD5 or SHA-1 hash), so you should not use them for anything
security-related. For security-related applications you should use
the other hash types, such as SHA-2 (e.g., @code{sha256} or
@code{sha512}).
SHA-1, SHA-2, SHA-224, SHA-256, SHA-384, SHA-512, SHA3-224, SHA3-256,
SHA3-384, and SHA3-512. MD5 is the oldest of these algorithms, and is
commonly used in @dfn{message digests} to check the integrity of
messages transmitted over a network. MD5 and SHA-1 are not collision
resistant (i.e., it is possible to deliberately design different pieces
of data which have the same MD5 or SHA-1 hash), so you should not use
them for anything security-related. For security-related applications
you should use the other hash types, such as SHA-2 (e.g., @code{sha256}
or @code{sha512}) or SHA-3 (e.g., @code{sha3-256} or @code{sha3-512}).
@defun secure-hash-algorithms
This function returns a list of symbols representing algorithms that
@@ -5001,8 +5001,9 @@ This function returns a list of symbols representing algorithms that
@defun secure-hash algorithm object &optional start end binary
This function returns a hash for @var{object}. The argument
@var{algorithm} is a symbol stating which hash to compute: one of
@code{md5}, @code{sha1}, @code{sha224}, @code{sha256}, @code{sha384}
or @code{sha512}. The argument @var{object} should be a buffer or a
@code{md5}, @code{sha1}, @code{sha224}, @code{sha256}, @code{sha384},
@code{sha512}, @code{sha3-224}, @code{sha3-256}, @code{sha3-384}, or
@code{sha3-512}. The argument @var{object} should be a buffer or a
string.
The optional arguments @var{start} and @var{end} are character
@@ -5035,6 +5036,18 @@ non-@code{nil}).
@item
For @code{sha512}: 128 characters (64 bytes if @var{binary} is
non-@code{nil}).
@item
For @code{sha3-224}: 56 characters (28 bytes if @var{binary} is
non-@code{nil}).
@item
For @code{sha3-256}: 64 characters (32 bytes if @var{binary} is
non-@code{nil}).
@item
For @code{sha3-384}: 96 characters (48 bytes if @var{binary} is
non-@code{nil}).
@item
For @code{sha3-512}: 128 characters (64 bytes if @var{binary} is
non-@code{nil}).
@end itemize
This function does not compute the hash directly from the internal

View File

@@ -3955,6 +3955,13 @@ that will provide an Xref backend when used.
* Lisp Changes in Emacs 31.1
+++
** 'secure-hash' now supports generating SHA-3 message digests.
The list returned by 'secure-hash-algorithms' now contains the symbols
'sha3-224', 'sha3-256', 'sha3-384', and 'sha3-512'. These symbols can
be used as the ALGORITHM argument of 'secure-hash' to generate SHA-3
hashes.
+++
** New function 'garbage-collect-heapsize'.
Same as 'garbage-collect' but just returns the info from the last GC

View File

@@ -99,6 +99,7 @@
# crypto/md5-buffer \
# crypto/sha1-buffer \
# crypto/sha256-buffer \
# crypto/sha3-buffer \
# crypto/sha512-buffer \
# d-type \
# diffseq \
@@ -1853,6 +1854,16 @@ EXTRA_DIST += gl_openssl.h sha256.h
endif
## end gnulib module crypto/sha256-buffer
## begin gnulib module crypto/sha3-buffer
ifeq (,$(OMIT_GNULIB_MODULE_crypto/sha3-buffer))
libgnu_a_SOURCES += sha3.c
EXTRA_DIST += sha3.h
endif
## end gnulib module crypto/sha3-buffer
## begin gnulib module crypto/sha512-buffer
ifeq (,$(OMIT_GNULIB_MODULE_crypto/sha512-buffer))

442
lib/sha3.c Normal file
View File

@@ -0,0 +1,442 @@
/* sha3.c - Functions to calculate SHA-3 hashes as specified by FIPS-202.
Copyright (C) 2025-2026 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. */
#include <config.h>
/* Specification. */
#include "sha3.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <byteswap.h>
#ifdef WORDS_BIGENDIAN
# define SWAP(n) u64bswap (n)
#else
# define SWAP(n) (n)
#endif
#if ! HAVE_OPENSSL_SHA3
static const u64 rc[] = {
u64init (0x00000000, 0x00000001), u64init (0x00000000, 0x00008082),
u64init (0x80000000, 0x0000808A), u64init (0x80000000, 0x80008000),
u64init (0x00000000, 0x0000808B), u64init (0x00000000, 0x80000001),
u64init (0x80000000, 0x80008081), u64init (0x80000000, 0x00008009),
u64init (0x00000000, 0x0000008A), u64init (0x00000000, 0x00000088),
u64init (0x00000000, 0x80008009), u64init (0x00000000, 0x8000000A),
u64init (0x00000000, 0x8000808B), u64init (0x80000000, 0x0000008B),
u64init (0x80000000, 0x00008089), u64init (0x80000000, 0x00008003),
u64init (0x80000000, 0x00008002), u64init (0x80000000, 0x00000080),
u64init (0x00000000, 0x0000800A), u64init (0x80000000, 0x8000000A),
u64init (0x80000000, 0x80008081), u64init (0x80000000, 0x00008080),
u64init (0x00000000, 0x80000001), u64init (0x80000000, 0x80008008)
};
#define DEFINE_SHA3_INIT_CTX(SIZE) \
bool \
sha3_##SIZE##_init_ctx (struct sha3_ctx *ctx) \
{ \
memset (&ctx->state, '\0', sizeof ctx->state); \
ctx->buflen = 0; \
ctx->digestlen = SHA3_##SIZE##_DIGEST_SIZE; \
ctx->blocklen = SHA3_##SIZE##_BLOCK_SIZE; \
return true; \
}
DEFINE_SHA3_INIT_CTX (224)
DEFINE_SHA3_INIT_CTX (256)
DEFINE_SHA3_INIT_CTX (384)
DEFINE_SHA3_INIT_CTX (512)
void
sha3_free_ctx (_GL_UNUSED struct sha3_ctx *ctx)
{
/* Do nothing. */
}
/* Copy the value from V into the memory location pointed to by *CP,
If your architecture allows unaligned access, this is equivalent to
* (__typeof__ (v) *) cp = v */
static void
set_uint64 (char *cp, u64 v)
{
memcpy (cp, &v, sizeof v);
}
void *
sha3_read_ctx (struct sha3_ctx const *restrict ctx, void *restrict resbuf)
{
char *r = resbuf;
size_t words = ctx->digestlen / sizeof *ctx->state;
size_t bytes = ctx->digestlen % sizeof *ctx->state;
int i;
for (i = 0; i < words; ++i, r += sizeof *ctx->state)
set_uint64 (r, SWAP (ctx->state[i]));
if (bytes)
{
u64 word = ctx->state[i];
do
{
*r++ = u64getlo (word) & 0xFF;
word = u64shr (word, 8);
}
while (--bytes);
}
return resbuf;
}
static void
sha3_conclude_ctx (struct sha3_ctx *ctx)
{
ctx->buffer[ctx->buflen++] = 0x06;
memset (ctx->buffer + ctx->buflen, '\0', ctx->blocklen - ctx->buflen);
ctx->buffer[ctx->blocklen - 1] |= 0x80;
sha3_process_block (ctx->buffer, ctx->blocklen, ctx);
}
void *
sha3_finish_ctx (struct sha3_ctx *restrict ctx, void *restrict resbuf)
{
sha3_conclude_ctx (ctx);
return sha3_read_ctx (ctx, resbuf);
}
#define DEFINE_SHA3_BUFFER(SIZE) \
void * \
sha3_##SIZE##_buffer (char const *restrict buffer, size_t len, \
void *restrict resblock) \
{ \
struct sha3_ctx ctx; \
sha3_##SIZE##_init_ctx (&ctx); \
sha3_process_bytes (buffer, len, &ctx); \
return sha3_finish_ctx (&ctx, resblock); \
}
DEFINE_SHA3_BUFFER (224)
DEFINE_SHA3_BUFFER (256)
DEFINE_SHA3_BUFFER (384)
DEFINE_SHA3_BUFFER (512)
bool
sha3_process_bytes (void const *restrict buffer, size_t len,
struct sha3_ctx *restrict ctx)
{
char const *buf = buffer;
if (0 < ctx->buflen)
{
size_t left = ctx->blocklen - ctx->buflen;
if (len < left)
{
/* Not enough to fill a full block. */
memcpy (ctx->buffer + ctx->buflen, buf, len);
ctx->buflen += len;
return true;
}
/* Process the block that already had bytes buffered. */
memcpy (ctx->buffer + ctx->buflen, buf, left);
buf += left;
len -= left;
sha3_process_block (ctx->buffer, ctx->blocklen, ctx);
}
/* Process as many complete blocks as possible. */
size_t full_len = len - len % ctx->blocklen;
sha3_process_block (buf, full_len, ctx);
buf += full_len;
len -= full_len;
memcpy (ctx->buffer, buf, len);
ctx->buflen = len;
return true;
}
bool
sha3_process_block (void const *restrict buffer, size_t len,
struct sha3_ctx *restrict ctx)
{
u64 *a = ctx->state;
const u64 *words = buffer;
size_t nwords = len / sizeof *words;
const u64 *endp = words + nwords;
while (words < endp)
{
for (size_t i = 0; i < ctx->blocklen / sizeof *ctx->state; ++i, ++words)
ctx->state[i] = u64xor (ctx->state[i], SWAP (*words));
for (int i = 0; i < 24; ++i)
{
u64 c[5];
u64 d[5];
u64 t1;
u64 t2;
/* Theta step 1. */
c[0] = u64xor (u64xor (u64xor (u64xor (a[0], a[5]), a[10]),
a[15]), a[20]);
c[1] = u64xor (u64xor (u64xor (u64xor (a[1], a[6]), a[11]),
a[16]), a[21]);
c[2] = u64xor (u64xor (u64xor (u64xor (a[2], a[7]), a[12]),
a[17]), a[22]);
c[3] = u64xor (u64xor (u64xor (u64xor (a[3], a[8]), a[13]),
a[18]), a[23]);
c[4] = u64xor (u64xor (u64xor (u64xor (a[4], a[9]), a[14]),
a[19]), a[24]);
/* Theta step 2. */
d[0] = u64xor (c[4], u64rol (c[1], 1));
d[1] = u64xor (c[0], u64rol (c[2], 1));
d[2] = u64xor (c[1], u64rol (c[3], 1));
d[3] = u64xor (c[2], u64rol (c[4], 1));
d[4] = u64xor (c[3], u64rol (c[0], 1));
/* Theta step 3. */
a[0] = u64xor (a[0], d[0]);
a[5] = u64xor (a[5], d[0]);
a[10] = u64xor (a[10], d[0]);
a[15] = u64xor (a[15], d[0]);
a[20] = u64xor (a[20], d[0]);
a[1] = u64xor (a[1], d[1]);
a[6] = u64xor (a[6], d[1]);
a[11] = u64xor (a[11], d[1]);
a[16] = u64xor (a[16], d[1]);
a[21] = u64xor (a[21], d[1]);
a[2] = u64xor (a[2], d[2]);
a[7] = u64xor (a[7], d[2]);
a[12] = u64xor (a[12], d[2]);
a[17] = u64xor (a[17], d[2]);
a[22] = u64xor (a[22], d[2]);
a[3] = u64xor (a[3], d[3]);
a[8] = u64xor (a[8], d[3]);
a[13] = u64xor (a[13], d[3]);
a[18] = u64xor (a[18], d[3]);
a[23] = u64xor (a[23], d[3]);
a[4] = u64xor (a[4], d[4]);
a[9] = u64xor (a[9], d[4]);
a[14] = u64xor (a[14], d[4]);
a[19] = u64xor (a[19], d[4]);
a[24] = u64xor (a[24], d[4]);
/* Rho and Pi. */
t1 = a[1];
t2 = u64rol (t1, 1);
t1 = a[10];
a[10] = t2;
t2 = u64rol (t1, 3);
t1 = a[7];
a[7] = t2;
t2 = u64rol (t1, 6);
t1 = a[11];
a[11] = t2;
t2 = u64rol (t1, 10);
t1 = a[17];
a[17] = t2;
t2 = u64rol (t1, 15);
t1 = a[18];
a[18] = t2;
t2 = u64rol (t1, 21);
t1 = a[3];
a[3] = t2;
t2 = u64rol (t1, 28);
t1 = a[5];
a[5] = t2;
t2 = u64rol (t1, 36);
t1 = a[16];
a[16] = t2;
t2 = u64rol (t1, 45);
t1 = a[8];
a[8] = t2;
t2 = u64rol (t1, 55);
t1 = a[21];
a[21] = t2;
t2 = u64rol (t1, 2);
t1 = a[24];
a[24] = t2;
t2 = u64rol (t1, 14);
t1 = a[4];
a[4] = t2;
t2 = u64rol (t1, 27);
t1 = a[15];
a[15] = t2;
t2 = u64rol (t1, 41);
t1 = a[23];
a[23] = t2;
t2 = u64rol (t1, 56);
t1 = a[19];
a[19] = t2;
t2 = u64rol (t1, 8);
t1 = a[13];
a[13] = t2;
t2 = u64rol (t1, 25);
t1 = a[12];
a[12] = t2;
t2 = u64rol (t1, 43);
t1 = a[2];
a[2] = t2;
t2 = u64rol (t1, 62);
t1 = a[20];
a[20] = t2;
t2 = u64rol (t1, 18);
t1 = a[14];
a[14] = t2;
t2 = u64rol (t1, 39);
t1 = a[22];
a[22] = t2;
t2 = u64rol (t1, 61);
t1 = a[9];
a[9] = t2;
t2 = u64rol (t1, 20);
t1 = a[6];
a[6] = t2;
t2 = u64rol (t1, 44);
t1 = a[1];
a[1] = t2;
/* Chi. */
for (int j = 0; j < 25; j += 5)
{
t1 = a[j];
t2 = a[j + 1];
a[j] = u64xor (a[j], u64and (u64not (a[j + 1]), a[j + 2]));
a[j + 1] = u64xor (a[j + 1], u64and (u64not (a[j + 2]),
a[j + 3]));
a[j + 2] = u64xor (a[j + 2], u64and (u64not (a[j + 3]),
a[j + 4]));
a[j + 3] = u64xor (a[j + 3], u64and (u64not (a[j + 4]), t1));
a[j + 4] = u64xor (a[j + 4], u64and (u64not (t1), t2));
}
/* Iota. */
a[0] = u64xor (a[0], rc[i]);
}
}
return true;
}
#else /* OpenSSL implementation. */
/* We avoid using all of EVP error strings. Just guess a reasonable errno. */
#include <errno.h>
#define DEFINE_SHA3_INIT_CTX(SIZE) \
bool \
sha3_##SIZE##_init_ctx (struct sha3_ctx *ctx) \
{ \
EVP_MD_CTX *evp_ctx = EVP_MD_CTX_new (); \
if (evp_ctx && ! EVP_DigestInit_ex (evp_ctx, EVP_sha3_##SIZE (), NULL)) \
{ \
EVP_MD_CTX_free (evp_ctx); \
evp_ctx = NULL; \
} \
ctx->evp_ctx = evp_ctx; \
errno = ENOMEM; /* OK to set errno even if successful. */ \
return !!evp_ctx; \
}
DEFINE_SHA3_INIT_CTX (224)
DEFINE_SHA3_INIT_CTX (256)
DEFINE_SHA3_INIT_CTX (384)
DEFINE_SHA3_INIT_CTX (512)
void
sha3_free_ctx (struct sha3_ctx *ctx)
{
if (ctx->evp_ctx != NULL)
{
int saved_errno = errno;
EVP_MD_CTX_free (ctx->evp_ctx);
ctx->evp_ctx = NULL;
errno = saved_errno;
}
}
void *
sha3_read_ctx (struct sha3_ctx const *restrict ctx, void *restrict resbuf)
{
void *result = NULL;
int err = ENOMEM;
EVP_MD_CTX *evp_ctx = EVP_MD_CTX_new ();
if (evp_ctx)
{
if (EVP_MD_CTX_copy_ex (evp_ctx, ctx->evp_ctx))
{
if (EVP_DigestFinal_ex (evp_ctx, resbuf, 0))
result = resbuf;
err = EINVAL;
}
EVP_MD_CTX_free (evp_ctx);
}
errno = err; /* OK to set errno even if successful. */
return result;
}
void *
sha3_finish_ctx (struct sha3_ctx *restrict ctx, void *restrict resbuf)
{
int result = EVP_DigestFinal_ex (ctx->evp_ctx, resbuf, NULL);
if (result == 0)
{
errno = EINVAL;
return NULL;
}
return resbuf;
}
#define DEFINE_SHA3_BUFFER(SIZE) \
void * \
sha3_##SIZE##_buffer (char const *restrict buffer, size_t len, \
void *restrict resblock) \
{ \
struct sha3_ctx ctx; \
void *result = ((sha3_##SIZE##_init_ctx (&ctx) \
&& sha3_process_bytes (buffer, len, &ctx)) \
? sha3_finish_ctx (&ctx, resblock) \
: NULL); \
sha3_free_ctx (&ctx); \
return result; \
}
DEFINE_SHA3_BUFFER (224)
DEFINE_SHA3_BUFFER (256)
DEFINE_SHA3_BUFFER (384)
DEFINE_SHA3_BUFFER (512)
bool
sha3_process_bytes (void const *restrict buffer, size_t len,
struct sha3_ctx *restrict ctx)
{
int result = EVP_DigestUpdate (ctx->evp_ctx, buffer, len);
if (result == 0)
{
errno = EINVAL;
return false;
}
return true;
}
bool
sha3_process_block (void const *restrict buffer, size_t len,
struct sha3_ctx *restrict ctx)
{
return sha3_process_bytes (buffer, len, ctx);
}
#endif

132
lib/sha3.h Normal file
View File

@@ -0,0 +1,132 @@
/* sha3.h - Functions to calculate SHA-3 hashes as specified by FIPS-202.
Copyright (C) 2025-2026 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 (void const *restrict buffer, size_t len,
struct sha3_ctx *restrict 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 (void const *restrict buffer, size_t len,
struct sha3_ctx *restrict 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 *restrict 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 (struct sha3_ctx const *restrict 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 (char const *restrict buffer, size_t len,
void *restrict resblock);
extern void *sha3_256_buffer (char const *restrict buffer, size_t len,
void *restrict resblock);
extern void *sha3_384_buffer (char const *restrict buffer, size_t len,
void *restrict resblock);
extern void *sha3_512_buffer (char const *restrict 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 *restrict stream, void *restrict resblock);
extern int sha3_256_stream (FILE *restrict stream, void *restrict resblock);
extern int sha3_384_stream (FILE *restrict stream, void *restrict resblock);
extern int sha3_512_stream (FILE *restrict stream, void *restrict resblock);
# ifdef __cplusplus
}
# endif
#endif

View File

@@ -70,6 +70,7 @@ AC_DEFUN([gl_EARLY],
# Code from module crypto/md5-buffer:
# Code from module crypto/sha1-buffer:
# Code from module crypto/sha256-buffer:
# Code from module crypto/sha3-buffer:
# Code from module crypto/sha512-buffer:
# Code from module d-type:
# Code from module diffseq:
@@ -286,6 +287,8 @@ AC_DEFUN([gl_INIT],
AC_REQUIRE([AC_C_RESTRICT])
gl_SHA256
AC_REQUIRE([AC_C_RESTRICT])
gl_SHA3
AC_REQUIRE([AC_C_RESTRICT])
gl_SHA512
gl_CHECK_TYPE_STRUCT_DIRENT_D_TYPE
gl_DIRENT_H
@@ -1445,6 +1448,8 @@ AC_DEFUN([gl_FILE_LIST], [
lib/sha1.h
lib/sha256.c
lib/sha256.h
lib/sha3.c
lib/sha3.h
lib/sha512.c
lib/sha512.h
lib/sig2str.c
@@ -1609,6 +1614,7 @@ AC_DEFUN([gl_FILE_LIST], [
m4/selinux-selinux-h.m4
m4/sha1.m4
m4/sha256.m4
m4/sha3.m4
m4/sha512.m4
m4/sig2str.m4
m4/sigdescr_np.m4

16
m4/sha3.m4 Normal file
View File

@@ -0,0 +1,16 @@
# sha3.m4
# serial 1
dnl Copyright (C) 2025-2026 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl This file is offered as-is, without any warranty.
AC_DEFUN([gl_SHA3],
[
dnl Prerequisites of lib/sha3.c.
AC_REQUIRE([gl_BIGENDIAN])
dnl Determine HAVE_OPENSSL_SHA3 and LIB_CRYPTO
gl_CRYPTO_CHECK([SHA3])
])

View File

@@ -6014,13 +6014,14 @@ DEFUN ("internal--hash-table-index-size",
/************************************************************************
MD5, SHA-1, and SHA-2
MD5, SHA-1, SHA-2, and SHA-3
************************************************************************/
#include "md5.h"
#include "sha1.h"
#include "sha256.h"
#include "sha512.h"
#include "sha3.h"
/* Store into HEXBUF an unterminated hexadecimal character string
representing DIGEST, which is binary data of size DIGEST_SIZE bytes.
@@ -6051,7 +6052,8 @@ DEFUN ("secure-hash-algorithms", Fsecure_hash_algorithms,
doc: /* Return a list of all the supported `secure-hash' algorithms. */)
(void)
{
return list (Qmd5, Qsha1, Qsha224, Qsha256, Qsha384, Qsha512);
return list (Qmd5, Qsha1, Qsha224, Qsha256, Qsha384, Qsha512,
Qsha3_224, Qsha3_256, Qsha3_384, Qsha3_512);
}
/* Extract data from a string or a buffer. SPEC is a list of
@@ -6290,6 +6292,26 @@ secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start,
digest_size = SHA512_DIGEST_SIZE;
hash_func = sha512_buffer;
}
else if (EQ (algorithm, Qsha3_224))
{
digest_size = SHA3_224_DIGEST_SIZE;
hash_func = sha3_224_buffer;
}
else if (EQ (algorithm, Qsha3_256))
{
digest_size = SHA3_256_DIGEST_SIZE;
hash_func = sha3_256_buffer;
}
else if (EQ (algorithm, Qsha3_384))
{
digest_size = SHA3_384_DIGEST_SIZE;
hash_func = sha3_384_buffer;
}
else if (EQ (algorithm, Qsha3_512))
{
digest_size = SHA3_512_DIGEST_SIZE;
hash_func = sha3_512_buffer;
}
else
error ("Invalid algorithm arg: %s", SDATA (Fsymbol_name (algorithm)));
@@ -6351,12 +6373,16 @@ anything security-related. See `secure-hash' for alternatives. */)
DEFUN ("secure-hash", Fsecure_hash, Ssecure_hash, 2, 5, 0,
doc: /* Return the secure hash of OBJECT, a buffer or string.
ALGORITHM is a symbol specifying the hash to use:
- md5 corresponds to MD5, produces a 32-character signature
- sha1 corresponds to SHA-1, produces a 40-character signature
- sha224 corresponds to SHA-2 (SHA-224), produces a 56-character signature
- sha256 corresponds to SHA-2 (SHA-256), produces a 64-character signature
- sha384 corresponds to SHA-2 (SHA-384), produces a 96-character signature
- sha512 corresponds to SHA-2 (SHA-512), produces a 128-character signature
- md5 corresponds to MD5, produces a 32-character signature
- sha1 corresponds to SHA-1, produces a 40-character signature
- sha224 corresponds to SHA-2 (SHA-224), produces a 56-character signature
- sha256 corresponds to SHA-2 (SHA-256), produces a 64-character signature
- sha384 corresponds to SHA-2 (SHA-384), produces a 96-character signature
- sha512 corresponds to SHA-2 (SHA-512), produces a 128-character signature
- sha3-224 corresponds to SHA-3 (SHA3-224), produces a 56-character signature
- sha3-256 corresponds to SHA-3 (SHA3-256), produces a 64-character signature
- sha3-384 corresponds to SHA-3 (SHA3-384), produces a 96-character signature
- sha3-512 corresponds to SHA-3 (SHA3-512), produces a 128-character signature
The two optional arguments START and END are positions specifying for
which part of OBJECT to compute the hash. If nil or omitted, uses the
@@ -6718,12 +6744,16 @@ syms_of_fns (void)
/* Crypto and hashing stuff. */
DEFSYM (Qiv_auto, "iv-auto");
DEFSYM (Qmd5, "md5");
DEFSYM (Qsha1, "sha1");
DEFSYM (Qsha224, "sha224");
DEFSYM (Qsha256, "sha256");
DEFSYM (Qsha384, "sha384");
DEFSYM (Qsha512, "sha512");
DEFSYM (Qmd5, "md5");
DEFSYM (Qsha1, "sha1");
DEFSYM (Qsha224, "sha224");
DEFSYM (Qsha256, "sha256");
DEFSYM (Qsha384, "sha384");
DEFSYM (Qsha512, "sha512");
DEFSYM (Qsha3_224, "sha3-224");
DEFSYM (Qsha3_256, "sha3-256");
DEFSYM (Qsha3_384, "sha3-384");
DEFSYM (Qsha3_512, "sha3-512");
/* Miscellaneous stuff. */

View File

@@ -50,7 +50,12 @@
(defvar gnutls-tests-internal-macs-upcased
(mapcar (lambda (sym) (cons sym (intern (upcase (symbol-name sym)))))
(secure-hash-algorithms)))
;; Remove the SHA-3 algorithms. Currently, the GNUTLS_MAC_SHA3_*
;; macros are reserved, but unimplemented. See:
;; <https://www.gnutls.org/manual/html_node/Hash-and-MAC-functions.html>.
(seq-remove (lambda (sym)
(string-prefix-p "sha3-" (symbol-name sym)))
(secure-hash-algorithms))))
(defvar gnutls-tests-tested-macs
(when (gnutls-available-p)

View File

@@ -1402,6 +1402,18 @@
(concat "0a50261ebd1a390fed2bf326f2673c145582a6342d5"
"23204973d0219337f81616a8069b012587cf5635f69"
"25f1b56c360230c19b273500ee013e030601bf2425")))
(should (equal (secure-hash 'sha3-224 "foobar")
"1ad852ba147a715fe5a3df39a741fad08186c303c7d21cefb7be763b"))
(should (equal (secure-hash 'sha3-256 "foobar")
(concat "09234807e4af85f17c66b48ee3bca89d"
"ffd1f1233659f9f940a2b17b0b8c6bc5")))
(should (equal (secure-hash 'sha3-384 "foobar")
(concat "0fa8abfbdaf924ad307b74dd2ed183b9a4a398891a2f6bac"
"8fd2db7041b77f068580f9c6c66f699b496c2da1cbcc7ed8")))
(should (equal (secure-hash 'sha3-512 "foobar")
(concat "ff32a30c3af5012ea395827a3e99a13073c3a8d8410"
"a708568ff7e6eb85968fccfebaea039bc21411e9d43"
"fdb9a851b529b9960ffea8679199781b8f45ca85e2")))
;; Test that a call to getrandom returns the right format.
;; This does not test randomness; it's merely a format check.
(should (string-match "\\`[0-9a-f]\\{128\\}\\'"