Update externals with latest versions.

This commit is contained in:
ben
2025-11-14 23:04:39 +01:00
parent 5db7304983
commit cb4ba1cb3e
7 changed files with 4273 additions and 5120 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -35,8 +35,25 @@
#include <stdlib.h> #include <stdlib.h>
#ifndef ARG_ENABLE_TRACE
#define ARG_ENABLE_TRACE 0 #define ARG_ENABLE_TRACE 0
#endif /* ARG_ENABLE_TRACE */
#ifndef ARG_ENABLE_LOG
#define ARG_ENABLE_LOG 1 #define ARG_ENABLE_LOG 1
#endif /* ARG_ENABLE_LOG */
/* Use the embedded getopt as the system getopt(3) */
#ifndef ARG_REPLACE_GETOPT
#define ARG_REPLACE_GETOPT 1
#endif /* ARG_REPLACE_GETOPT */
/* Size of the buffer pre-allocated for dynamic strings.
* If the length exceeds this size, the buffer will be dynamically allocated.
*/
#ifndef ARG_DSTR_SIZE
#define ARG_DSTR_SIZE 200
#endif /* ARG_DSTR_SIZE */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -81,10 +98,10 @@ typedef void(arg_panicfn)(const char* fmt, ...);
* They can be a problem for the platforms like NuttX, where * They can be a problem for the platforms like NuttX, where
* the namespace is flat for everything including apps and libraries. * the namespace is flat for everything including apps and libraries.
*/ */
#define xmalloc argtable3_xmalloc #define xmalloc malloc
#define xcalloc argtable3_xcalloc #define xcalloc calloc
#define xrealloc argtable3_xrealloc #define xrealloc realloc
#define xfree argtable3_xfree #define xfree free
extern void dbg_printf(const char* fmt, ...); extern void dbg_printf(const char* fmt, ...);
extern void arg_set_panic(arg_panicfn* proc); extern void arg_set_panic(arg_panicfn* proc);

View File

@@ -17,22 +17,17 @@
* DAMAGE. * DAMAGE.
*/ */
#define _GNU_SOURCE
#include <unistd.h> #include <unistd.h>
#include <sys/syscall.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/mman.h> #include <sys/mman.h>
#endif
#include "chacha20_drng.h" #include "chacha20_drng.h"
#include "randombytes.h"
#define MAJVERSION 1 /* API / ABI incompatible changes, #define MAJVERSION 1 /* API / ABI incompatible changes,
* functional changes that require consumer * functional changes that require consumer
@@ -58,9 +53,7 @@
/*********************************** Helper ***********************************/ /*********************************** Helper ***********************************/
#ifndef _WIN32
#define min(x, y) ((x < y) ? x : y) #define min(x, y) ((x < y) ? x : y)
#endif
#define __aligned(x) __attribute__((aligned(x))) #define __aligned(x) __attribute__((aligned(x)))
static inline void memset_secure(void *s, int c, uint32_t n) static inline void memset_secure(void *s, int c, uint32_t n)
@@ -71,23 +64,14 @@ static inline void memset_secure(void *s, int c, uint32_t n)
static inline void get_time(time_t *sec, uint32_t *nsec) static inline void get_time(time_t *sec, uint32_t *nsec)
{ {
#ifdef _WIN32
SYSTEMTIME SystemTime;
GetSystemTime(&SystemTime);
if(sec)
*sec = SystemTime.wSecond;
if(nsec)
*nsec = SystemTime.wMilliseconds;
#else
struct timespec time; struct timespec time;
if (clock_gettime(CLOCK_REALTIME, &time) == 0) { if (clock_gettime(CLOCK_REALTIME, &time) == 0) {
if (sec) if (sec)
*sec = time.tv_sec; *sec = time.tv_sec;
if (nsec) if (nsec)
*nsec = time.tv_nsec; *nsec = time.tv_nsec;
} }
#endif
} }
static inline uint32_t rol32(uint32_t x, int n) static inline uint32_t rol32(uint32_t x, int n)
@@ -95,25 +79,36 @@ static inline uint32_t rol32(uint32_t x, int n)
return ( (x << (n&(32-1))) | (x >> ((32-n)&(32-1))) ); return ( (x << (n&(32-1))) | (x >> ((32-n)&(32-1))) );
} }
/* Endian dependent byte swap operations. */ /* Endian dependent byte swap operations. */
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* Byte swap for 32-bit and 64-bit integers. */ # define le_bswap32(x) _bswap32(x)
static inline uint32_t ror32(uint32_t x, int n) static inline uint32_t ror32(uint32_t x, int n)
{ {
return ( (x >> (n&(32-1))) | (x << ((32-n)&(32-1))) ); return ( (x >> (n&(32-1))) | (x << ((32-n)&(32-1))) );
} }
/* Byte swap for 32-bit and 64-bit integers. */
static inline uint32_t _bswap32(uint32_t x) static inline uint32_t _bswap32(uint32_t x)
{ {
return ((rol32(x, 8) & 0x00ff00ffL) | (ror32(x, 8) & 0xff00ff00L)); return ((rol32(x, 8) & 0x00ff00ffL) | (ror32(x, 8) & 0xff00ff00L));
} }
# define le_bswap32(x) _bswap32(x)
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define le_bswap32(x) ((uint32_t)(x)) # define le_bswap32(x) ((uint32_t)(x))
#else #else
#error "Endianess not defined" #error "Endianess not defined"
#endif #endif
static inline void drng_chacha20_bswap32(uint32_t *ptr, uint32_t words)
{
uint32_t i;
/* Byte-swap data which is an LE representation */
for (i = 0; i < words; i++) {
*ptr = le_bswap32(*ptr);
ptr++;
}
}
/******************************* ChaCha20 Block *******************************/ /******************************* ChaCha20 Block *******************************/
#define CHACHA20_KEY_SIZE 32 #define CHACHA20_KEY_SIZE 32
@@ -203,6 +198,7 @@ static inline int drng_chacha20_selftest_one(struct chacha20_state *state,
uint32_t result[CHACHA20_BLOCK_SIZE_WORDS]; uint32_t result[CHACHA20_BLOCK_SIZE_WORDS];
chacha20_block(&state->constants[0], result); chacha20_block(&state->constants[0], result);
return memcmp(expected, result, CHACHA20_BLOCK_SIZE); return memcmp(expected, result, CHACHA20_BLOCK_SIZE);
} }
@@ -230,24 +226,186 @@ static int drng_chacha20_selftest(void)
expected[12] = 0xd19c12b5; expected[13] = 0xb94e16de; expected[12] = 0xd19c12b5; expected[13] = 0xb94e16de;
expected[14] = 0xe883d0cb; expected[15] = 0x4e3c50a2; expected[14] = 0xe883d0cb; expected[15] = 0x4e3c50a2;
drng_chacha20_bswap32(expected, CHACHA20_BLOCK_SIZE_WORDS);
return drng_chacha20_selftest_one(&chacha20, &expected[0]); return drng_chacha20_selftest_one(&chacha20, &expected[0]);
} }
/********************* getrandom system call seed source *********************/
#ifdef GETRANDOM
#include <limits.h>
static int drng_getrandom_get(uint8_t *buf, uint32_t buflen)
{
uint32_t len = 0;
ssize_t ret;
if (buflen > INT_MAX)
return 0;
do {
ret = syscall(__NR_getrandom, (buf + len), (buflen - len), 0);
if (0 < ret)
len += ret;
} while ((0 < ret || EINTR == errno || ERESTART == errno)
&& buflen > len);
return len;
}
#else
static int drng_getrandom_get(uint8_t *buf, uint32_t buflen)
{
(void)buf;
(void)buflen;
return 0;
}
#endif
/*************************** Jitter RNG seed source ***************************/
#ifdef JENT
#include "jitterentropy.h"
struct jent_noise_source {
struct rand_data *ec;
int initialized;
};
static struct jent_noise_source jent_noise_source = {
NULL,
0,
};
static int drng_jent_alloc()
{
int ret = jent_entropy_init();
if (ret) {
jent_noise_source.initialized = -1;
return -EFAULT;
}
jent_noise_source.ec = jent_entropy_collector_alloc(0, 0);
if (!jent_noise_source.ec)
return -ENOMEM;
return 0;
}
static void drng_jent_dealloc(void)
{
if (jent_noise_source.initialized != 1)
return;
jent_entropy_collector_free(jent_noise_source.ec);
jent_noise_source.ec = NULL;
jent_noise_source.initialized = 0;
}
static int drng_jent_get(uint8_t *buf, uint32_t buflen)
{
if (!jent_noise_source.initialized) {
int ret = drng_jent_alloc();
if (ret)
return ret;
jent_noise_source.initialized = 1;
}
if (jent_noise_source.initialized > 0)
return jent_read_entropy(jent_noise_source.ec,
(char *)buf, buflen);
return 0;
}
#else
static int drng_jent_get(uint8_t *buf, uint32_t buflen)
{
(void)buf;
(void)buflen;
return 0;
}
static void drng_jent_dealloc(void)
{
return;
}
#endif
/************************** /dev/random seed source **************************/
#ifdef DEVRANDOM
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
static int random_fd = -1;
static int drng_random_alloc(void)
{
random_fd = open("/dev/random", O_RDONLY|O_CLOEXEC);
if (0 > random_fd)
return -EBADFD;
return 0;
}
static int drng_random_get(uint8_t *buf, uint32_t buflen) static int drng_random_get(uint8_t *buf, uint32_t buflen)
{ {
int ret = randombytes(buf, buflen); uint32_t len = 0;
if( ret != 0) { ssize_t ret;
if (random_fd == -1) {
int ret = drng_random_alloc();
if (ret)
return ret;
}
if (buflen > INT_MAX)
return 0; return 0;
} else {
return buflen; do {
ret = read(random_fd, (buf + len), (buflen - len));
if (0 < ret)
len += ret;
} while ((0 < ret || EINTR == errno || ERESTART == errno)
&& buflen > len);
return len;
} }
static void drng_random_dealloc(void)
{
if (random_fd < 0)
return;
close(random_fd);
random_fd = -1;
} }
#else
static int drng_random_get(uint8_t *buf, uint32_t buflen)
{
(void)buf;
(void)buflen;
return 0;
}
static void drng_random_dealloc(void)
{
return;
}
#endif
/******************************* ChaCha20 DRNG *******************************/ /******************************* ChaCha20 DRNG *******************************/
struct chacha20_drng { struct chacha20_drng {
@@ -267,22 +425,23 @@ static inline void drng_chacha20_update(struct chacha20_state *chacha20,
{ {
uint32_t i, tmp[CHACHA20_BLOCK_SIZE_WORDS]; uint32_t i, tmp[CHACHA20_BLOCK_SIZE_WORDS];
if (used_words > CHACHA20_KEY_SIZE_WORDS) { if (CHACHA20_BLOCK_SIZE_WORDS - used_words < CHACHA20_KEY_SIZE_WORDS) {
chacha20_block(&chacha20->constants[0], tmp); chacha20_block(&chacha20->constants[0], tmp);
for (i = 0; i < CHACHA20_KEY_SIZE_WORDS; i++) for (i = 0; i < CHACHA20_KEY_SIZE_WORDS; i++)
chacha20->key.u[i] ^= tmp[i]; chacha20->key.u[i] ^= le_bswap32(tmp[i]);
memset_secure(tmp, 0, sizeof(tmp)); memset_secure(tmp, 0, sizeof(tmp));
} else { } else {
for (i = 0; i < CHACHA20_KEY_SIZE_WORDS; i++) for (i = 0; i < CHACHA20_KEY_SIZE_WORDS; i++)
chacha20->key.u[i] ^= buf[i + used_words]; chacha20->key.u[i] ^= le_bswap32(buf[i + used_words]);
} }
/* Deterministic increment of nonce as required in RFC 7539 chapter 4 */ /* Deterministic increment of nonce as required in RFC 7539 chapter 4 */
chacha20->nonce[0]++; chacha20->nonce[0]++;
if (chacha20->nonce[0] == 0) if (chacha20->nonce[0] == 0){
chacha20->nonce[1]++; chacha20->nonce[1]++;
if (chacha20->nonce[1] == 0) if (chacha20->nonce[1] == 0)
chacha20->nonce[2]++; chacha20->nonce[2]++;
}
/* Leave counter untouched as it is start value is undefined in RFC */ /* Leave counter untouched as it is start value is undefined in RFC */
} }
@@ -338,7 +497,7 @@ static int drng_chacha20_generate(struct chacha20_state *chacha20,
int zeroize_buf = 0; int zeroize_buf = 0;
while (outbuflen >= CHACHA20_BLOCK_SIZE) { while (outbuflen >= CHACHA20_BLOCK_SIZE) {
if ((uintptr_t)outbuf & (sizeof(aligned_buf[0]) - 1)) { if ((unsigned long)outbuf & (sizeof(aligned_buf[0]) - 1)) {
chacha20_block(&chacha20->constants[0], aligned_buf); chacha20_block(&chacha20->constants[0], aligned_buf);
memcpy(outbuf, aligned_buf, CHACHA20_BLOCK_SIZE); memcpy(outbuf, aligned_buf, CHACHA20_BLOCK_SIZE);
zeroize_buf = 1; zeroize_buf = 1;
@@ -388,7 +547,7 @@ static int drng_chacha20_rng_selftest(struct chacha20_drng *drng)
* * remaining state is 0 * * remaining state is 0
* and pulling one ChaCha20 DRNG block. * and pulling one ChaCha20 DRNG block.
*/ */
uint8_t expected_block[CHACHA20_KEY_SIZE] = { static const uint8_t expected_block[CHACHA20_KEY_SIZE] = {
0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28, 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
@@ -409,15 +568,15 @@ static int drng_chacha20_rng_selftest(struct chacha20_drng *drng)
* 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f * 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
* and pulling two ChaCha20 DRNG blocks. * and pulling two ChaCha20 DRNG blocks.
*/ */
uint8_t expected_twoblocks[CHACHA20_KEY_SIZE * 2] = { static const uint8_t expected_twoblocks[CHACHA20_KEY_SIZE * 2] = {
0xf5, 0xb4, 0xb6, 0x5a, 0xec, 0xcd, 0x5a, 0x65, 0xe3, 0xb0, 0x8a, 0xcc, 0x34, 0xc3, 0x17, 0x0e,
0x87, 0x56, 0xe3, 0x86, 0x51, 0x54, 0xfc, 0x90, 0xc3, 0xd8, 0xc3, 0x40, 0xe7, 0x73, 0xe9, 0x0d,
0x56, 0xff, 0x5e, 0xae, 0x58, 0xf2, 0x01, 0x88, 0xd1, 0x62, 0xa3, 0x5d, 0x7d, 0xf2, 0xf1, 0x4a,
0xb1, 0x7e, 0xb8, 0x2e, 0x17, 0x9a, 0x27, 0xe6, 0x24, 0x42, 0xb7, 0x1e, 0xb0, 0x05, 0x17, 0x07,
0x86, 0xb3, 0xed, 0x33, 0xf7, 0xb9, 0x06, 0x05, 0xb9, 0x35, 0x10, 0x69, 0x8b, 0x46, 0xfb, 0x51,
0x8a, 0x2d, 0x1a, 0x93, 0xc9, 0x0b, 0x80, 0x04, 0xe9, 0x91, 0x3f, 0x46, 0xf2, 0x4d, 0xea, 0xd0,
0x03, 0xaa, 0x60, 0xaf, 0xd5, 0x36, 0x40, 0x11, 0x81, 0xc1, 0x1b, 0xa9, 0x5d, 0x52, 0x91, 0x5f,
0x67, 0x89, 0xb1, 0x66, 0xd5, 0x88, 0x62, 0x6d }; 0xcd, 0xdc, 0xc6, 0xd6, 0xc3, 0x7c, 0x50, 0x23 };
/* /*
* Expected result when ChaCha20 DRNG state is zero: * Expected result when ChaCha20 DRNG state is zero:
@@ -429,18 +588,22 @@ static int drng_chacha20_rng_selftest(struct chacha20_drng *drng)
* 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, * 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
* 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, * 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
* 0x20 * 0x20
* and pulling one ChaCha20 DRNG block plus one byte. * and pulling one ChaCha20 DRNG block plus four byte.
*/ */
uint8_t expected_block_and_byte[CHACHA20_KEY_SIZE + 1] = { static const uint8_t expected_block_nonaligned[CHACHA20_KEY_SIZE + 4] = {
0x3d, 0x13, 0x47, 0x1e, 0x7f, 0x7c, 0x99, 0x33, 0x9c, 0xfc, 0x5e, 0x31, 0x21, 0x62, 0x11, 0x85,
0xfc, 0x44, 0xa4, 0xdd, 0xf9, 0x3d, 0xe1, 0x9a, 0xd3, 0x77, 0xd3, 0x69, 0x0f, 0xa8, 0x16, 0x55,
0xd4, 0xe8, 0x7a, 0x7d, 0x42, 0xac, 0xd1, 0xcd, 0xb4, 0x4c, 0xf6, 0x52, 0xf3, 0xa8, 0x37, 0x99,
0x10, 0x69, 0xe7, 0xbf, 0xd4, 0xfd, 0x69, 0x4b, 0x38, 0x76, 0xa0, 0x66, 0xec, 0xbb, 0xce, 0xa9,
0xa7 }; 0x9c, 0x95, 0xa1, 0xfd };
drng_chacha20_bswap32((uint32_t *)seed,
sizeof(seed) / sizeof(uint32_t));
/* Generate with zero state */ /* Generate with zero state */
ret = drng_chacha20_generate(&drng->chacha20, outbuf, ret = drng_chacha20_generate(&drng->chacha20, outbuf,
sizeof(expected_block)); sizeof(expected_block));
if (ret) if (ret)
return ret; return ret;
if (memcmp(outbuf, expected_block, sizeof(expected_block))) if (memcmp(outbuf, expected_block, sizeof(expected_block)))
@@ -454,6 +617,7 @@ static int drng_chacha20_rng_selftest(struct chacha20_drng *drng)
sizeof(expected_twoblocks)); sizeof(expected_twoblocks));
if (ret) if (ret)
return ret; return ret;
ret = drng_chacha20_generate(&drng->chacha20, outbuf, ret = drng_chacha20_generate(&drng->chacha20, outbuf,
sizeof(expected_twoblocks)); sizeof(expected_twoblocks));
if (ret) if (ret)
@@ -466,15 +630,15 @@ static int drng_chacha20_rng_selftest(struct chacha20_drng *drng)
/* Reseed with 1 block and one byte */ /* Reseed with 1 block and one byte */
ret = drng_chacha20_seed(&drng->chacha20, seed, ret = drng_chacha20_seed(&drng->chacha20, seed,
sizeof(expected_block_and_byte)); sizeof(expected_block_nonaligned));
if (ret) if (ret)
return ret; return ret;
ret = drng_chacha20_generate(&drng->chacha20, outbuf, ret = drng_chacha20_generate(&drng->chacha20, outbuf,
sizeof(expected_block_and_byte)); sizeof(expected_block_nonaligned));
if (ret) if (ret)
return ret; return ret;
if (memcmp(outbuf, expected_block_and_byte, if (memcmp(outbuf, expected_block_nonaligned,
sizeof(expected_block_and_byte))) sizeof(expected_block_nonaligned)))
return -EFAULT; return -EFAULT;
return 0; return 0;
@@ -499,31 +663,26 @@ static int drng_chacha20_alloc(struct chacha20_drng **out)
return -EFAULT; return -EFAULT;
} }
#ifdef _WIN32 ret = posix_memalign((void *)&drng, CHACHA20_DRNG_ALIGNMENT,
drng = _aligned_malloc(sizeof(*drng), CHACHA20_DRNG_ALIGNMENT); sizeof(*drng));
#endif if (ret) {
return -ret;
#ifndef aligned_alloc
drng = malloc(sizeof(*drng));
#else
drng = aligned_alloc(CHACHA20_DRNG_ALIGNMENT, sizeof(*drng));
#endif
if (drng == NULL) {
return -1;
} }
#ifndef _WIN32
/* prevent paging out of the memory state to swap space */ /* prevent paging out of the memory state to swap space */
ret = mlock(drng, sizeof(*drng)); ret = mlock(drng, sizeof(*drng));
if (ret && errno != EPERM && errno != EAGAIN) { if (ret && errno != EPERM && errno != EAGAIN) {
ret = -errno; ret = -errno;
goto err; goto err;
} }
#endif
memset(drng, 0, sizeof(*drng)); memset(drng, 0, sizeof(*drng));
memcpy(&drng->chacha20.constants[0], "expand 32-byte k", 16); /* String "expand 32-byte k" */
drng->chacha20.constants[0] = 0x61707865;
drng->chacha20.constants[1] = 0x3320646e;
drng->chacha20.constants[2] = 0x79622d32;
drng->chacha20.constants[3] = 0x6b206574;
ret = drng_chacha20_rng_selftest(drng); ret = drng_chacha20_rng_selftest(drng);
if (ret) if (ret)
@@ -559,6 +718,33 @@ int drng_chacha20_reseed(struct chacha20_drng *drng, const uint8_t *inbuf,
int ret; int ret;
uint32_t collected = 0; uint32_t collected = 0;
/* Entropy assumption: 1 data bit delivers one bit of entropy */
ret = drng_getrandom_get(seed, CHACHA20_KEY_SIZE);
if (ret < 0)
return ret;
if (ret) {
collected = ret;
ret = drng_chacha20_seed(&drng->chacha20, seed,
CHACHA20_KEY_SIZE);
if (ret)
return ret;
}
/* Entropy assumption: 2 data bits deliver one bit of entropy */
ret = drng_jent_get(seed, sizeof(seed));
if (ret < 0)
return ret;
if (ret) {
collected += ret;
ret = drng_chacha20_seed(&drng->chacha20, seed, sizeof(seed));
if (ret)
return ret;
}
/* Entropy assumption: 1 data bit delivers one bit of entropy */ /* Entropy assumption: 1 data bit delivers one bit of entropy */
ret = drng_random_get(seed, CHACHA20_KEY_SIZE); ret = drng_random_get(seed, CHACHA20_KEY_SIZE);
if (ret < 0) if (ret < 0)
@@ -591,6 +777,8 @@ int drng_chacha20_reseed(struct chacha20_drng *drng, const uint8_t *inbuf,
DSO_PUBLIC DSO_PUBLIC
void drng_chacha20_destroy(struct chacha20_drng *drng) void drng_chacha20_destroy(struct chacha20_drng *drng)
{ {
drng_jent_dealloc();
drng_random_dealloc();
drng_chacha20_dealloc(drng); drng_chacha20_dealloc(drng);
} }

View File

@@ -1134,4 +1134,3 @@ exit:
return message; return message;
return NULL; return NULL;
} }

View File

@@ -23,22 +23,15 @@
#include "sha3.h" #include "sha3.h"
#define SHA3_ASSERT( x ) #define SHA3_ASSERT( x )
#if defined(_MSC_VER)
#define SHA3_TRACE( format, ...) #define SHA3_TRACE( format, ...)
#define SHA3_TRACE_BUF( format, buf, l, ...) #define SHA3_TRACE_BUF(format, buf, l)
#else
#define SHA3_TRACE(format, args...)
#define SHA3_TRACE_BUF(format, buf, l, args...)
#endif
//#define SHA3_USE_KECCAK
/* /*
* Define SHA3_USE_KECCAK to run "pure" Keccak, as opposed to SHA3. * This flag is used to configure "pure" Keccak, as opposed to NIST SHA3.
* The tests that this macro enables use the input and output from [Keccak]
* (see the reference below). The used test vectors aren't correct for SHA3,
* however, they are helpful to verify the implementation.
* SHA3_USE_KECCAK only changes one line of code in Finalize.
*/ */
#define SHA3_USE_KECCAK_FLAG 0x80000000
#define SHA3_CW(x) ((x) & (~SHA3_USE_KECCAK_FLAG))
#if defined(_MSC_VER) #if defined(_MSC_VER)
#define SHA3_CONST(x) x #define SHA3_CONST(x) x
@@ -123,30 +116,44 @@ keccakf(uint64_t s[25])
/* *************************** Public Inteface ************************ */ /* *************************** Public Inteface ************************ */
/* For Init or Reset call these: */ /* For Init or Reset call these: */
sha3_return_t
sha3_Init(void *priv, unsigned bitSize) {
sha3_context *ctx = (sha3_context *) priv;
if( bitSize != 256 && bitSize != 384 && bitSize != 512 )
return SHA3_RETURN_BAD_PARAMS;
memset(ctx, 0, sizeof(*ctx));
ctx->capacityWords = 2 * bitSize / (8 * sizeof(uint64_t));
return SHA3_RETURN_OK;
}
void void
sha3_Init256(void *priv) sha3_Init256(void *priv)
{ {
sha3_context *ctx = (sha3_context *) priv; sha3_Init(priv, 256);
memset(ctx, 0, sizeof(*ctx));
ctx->capacityWords = 2 * 256 / (8 * sizeof(uint64_t));
} }
void void
sha3_Init384(void *priv) sha3_Init384(void *priv)
{ {
sha3_context *ctx = (sha3_context *) priv; sha3_Init(priv, 384);
memset(ctx, 0, sizeof(*ctx));
ctx->capacityWords = 2 * 384 / (8 * sizeof(uint64_t));
} }
void void
sha3_Init512(void *priv) sha3_Init512(void *priv)
{ {
sha3_context *ctx = (sha3_context *) priv; sha3_Init(priv, 512);
memset(ctx, 0, sizeof(*ctx));
ctx->capacityWords = 2 * 512 / (8 * sizeof(uint64_t));
} }
enum SHA3_FLAGS
sha3_SetFlags(void *priv, enum SHA3_FLAGS flags)
{
sha3_context *ctx = (sha3_context *) priv;
flags &= SHA3_FLAGS_KECCAK;
ctx->capacityWords |= (flags == SHA3_FLAGS_KECCAK ? SHA3_USE_KECCAK_FLAG : 0);
return flags;
}
void void
sha3_Update(void *priv, void const *bufIn, size_t len) sha3_Update(void *priv, void const *bufIn, size_t len)
{ {
@@ -164,7 +171,7 @@ sha3_Update(void *priv, void const *bufIn, size_t len)
SHA3_TRACE_BUF("called to update with:", buf, len); SHA3_TRACE_BUF("called to update with:", buf, len);
SHA3_ASSERT(ctx->byteIndex < 8); SHA3_ASSERT(ctx->byteIndex < 8);
SHA3_ASSERT(ctx->wordIndex < sizeof(ctx->s) / sizeof(ctx->s[0])); SHA3_ASSERT(ctx->wordIndex < sizeof(ctx->u.s) / sizeof(ctx->u.s[0]));
if(len < old_tail) { /* have no complete word or haven't started if(len < old_tail) { /* have no complete word or haven't started
* the word yet */ * the word yet */
@@ -185,13 +192,13 @@ sha3_Update(void *priv, void const *bufIn, size_t len)
ctx->saved |= (uint64_t) (*(buf++)) << ((ctx->byteIndex++) * 8); ctx->saved |= (uint64_t) (*(buf++)) << ((ctx->byteIndex++) * 8);
/* now ready to add saved to the sponge */ /* now ready to add saved to the sponge */
ctx->s[ctx->wordIndex] ^= ctx->saved; ctx->u.s[ctx->wordIndex] ^= ctx->saved;
SHA3_ASSERT(ctx->byteIndex == 8); SHA3_ASSERT(ctx->byteIndex == 8);
ctx->byteIndex = 0; ctx->byteIndex = 0;
ctx->saved = 0; ctx->saved = 0;
if(++ctx->wordIndex == if(++ctx->wordIndex ==
(SHA3_KECCAK_SPONGE_WORDS - ctx->capacityWords)) { (SHA3_KECCAK_SPONGE_WORDS - SHA3_CW(ctx->capacityWords))) {
keccakf(ctx->s); keccakf(ctx->u.s);
ctx->wordIndex = 0; ctx->wordIndex = 0;
} }
} }
@@ -217,10 +224,10 @@ sha3_Update(void *priv, void const *bufIn, size_t len)
#if defined(__x86_64__ ) || defined(__i386__) #if defined(__x86_64__ ) || defined(__i386__)
SHA3_ASSERT(memcmp(&t, buf, 8) == 0); SHA3_ASSERT(memcmp(&t, buf, 8) == 0);
#endif #endif
ctx->s[ctx->wordIndex] ^= t; ctx->u.s[ctx->wordIndex] ^= t;
if(++ctx->wordIndex == if(++ctx->wordIndex ==
(SHA3_KECCAK_SPONGE_WORDS - ctx->capacityWords)) { (SHA3_KECCAK_SPONGE_WORDS - SHA3_CW(ctx->capacityWords))) {
keccakf(ctx->s); keccakf(ctx->u.s);
ctx->wordIndex = 0; ctx->wordIndex = 0;
} }
} }
@@ -253,21 +260,22 @@ sha3_Finalize(void *priv)
* Overall, we feed 0, then 1, and finally 1 to start padding. Without * Overall, we feed 0, then 1, and finally 1 to start padding. Without
* M || 01, we would simply use 1 to start padding. */ * M || 01, we would simply use 1 to start padding. */
#ifndef SHA3_USE_KECCAK uint64_t t;
/* SHA3 version */
ctx->s[ctx->wordIndex] ^=
(ctx->saved ^ ((uint64_t) ((uint64_t) (0x02 | (1 << 2)) <<
((ctx->byteIndex) * 8))));
#else
/* For testing the "pure" Keccak version */
ctx->s[ctx->wordIndex] ^=
(ctx->saved ^ ((uint64_t) ((uint64_t) 1 << (ctx->byteIndex *
8))));
#endif
ctx->s[SHA3_KECCAK_SPONGE_WORDS - ctx->capacityWords - 1] ^= if( ctx->capacityWords & SHA3_USE_KECCAK_FLAG ) {
/* Keccak version */
t = (uint64_t)(((uint64_t) 1) << (ctx->byteIndex * 8));
}
else {
/* SHA3 version */
t = (uint64_t)(((uint64_t)(0x02 | (1 << 2))) << ((ctx->byteIndex) * 8));
}
ctx->u.s[ctx->wordIndex] ^= ctx->saved ^ t;
ctx->u.s[SHA3_KECCAK_SPONGE_WORDS - SHA3_CW(ctx->capacityWords) - 1] ^=
SHA3_CONST(0x8000000000000000UL); SHA3_CONST(0x8000000000000000UL);
keccakf(ctx->s); keccakf(ctx->u.s);
/* Return first bytes of the ctx->s. This conversion is not needed for /* Return first bytes of the ctx->s. This conversion is not needed for
* little-endian platforms e.g. wrap with #if !defined(__BYTE_ORDER__) * little-endian platforms e.g. wrap with #if !defined(__BYTE_ORDER__)
@@ -277,20 +285,39 @@ sha3_Finalize(void *priv)
{ {
unsigned i; unsigned i;
for(i = 0; i < SHA3_KECCAK_SPONGE_WORDS; i++) { for(i = 0; i < SHA3_KECCAK_SPONGE_WORDS; i++) {
const unsigned t1 = (uint32_t) ctx->s[i]; const unsigned t1 = (uint32_t) ctx->u.s[i];
const unsigned t2 = (uint32_t) ((ctx->s[i] >> 16) >> 16); const unsigned t2 = (uint32_t) ((ctx->u.s[i] >> 16) >> 16);
ctx->sb[i * 8 + 0] = (uint8_t) (t1); ctx->u.sb[i * 8 + 0] = (uint8_t) (t1);
ctx->sb[i * 8 + 1] = (uint8_t) (t1 >> 8); ctx->u.sb[i * 8 + 1] = (uint8_t) (t1 >> 8);
ctx->sb[i * 8 + 2] = (uint8_t) (t1 >> 16); ctx->u.sb[i * 8 + 2] = (uint8_t) (t1 >> 16);
ctx->sb[i * 8 + 3] = (uint8_t) (t1 >> 24); ctx->u.sb[i * 8 + 3] = (uint8_t) (t1 >> 24);
ctx->sb[i * 8 + 4] = (uint8_t) (t2); ctx->u.sb[i * 8 + 4] = (uint8_t) (t2);
ctx->sb[i * 8 + 5] = (uint8_t) (t2 >> 8); ctx->u.sb[i * 8 + 5] = (uint8_t) (t2 >> 8);
ctx->sb[i * 8 + 6] = (uint8_t) (t2 >> 16); ctx->u.sb[i * 8 + 6] = (uint8_t) (t2 >> 16);
ctx->sb[i * 8 + 7] = (uint8_t) (t2 >> 24); ctx->u.sb[i * 8 + 7] = (uint8_t) (t2 >> 24);
} }
} }
SHA3_TRACE_BUF("Hash: (first 32 bytes)", ctx->sb, 256 / 8); SHA3_TRACE_BUF("Hash: (first 32 bytes)", ctx->u.sb, 256 / 8);
return (ctx->sb); return (ctx->u.sb);
}
sha3_return_t sha3_HashBuffer( unsigned bitSize, enum SHA3_FLAGS flags, const void *in, unsigned inBytes, void *out, unsigned outBytes ) {
sha3_return_t err;
sha3_context c;
err = sha3_Init(&c, bitSize);
if( err != SHA3_RETURN_OK )
return err;
if( sha3_SetFlags(&c, flags) != flags ) {
return SHA3_RETURN_BAD_PARAMS;
}
sha3_Update(&c, in, inBytes);
const void *h = sha3_Finalize(&c);
if(outBytes > bitSize/8)
outBytes = bitSize/8;
memcpy(out, h, outBytes);
return SHA3_RETURN_OK;
} }

View File

@@ -1,6 +1,8 @@
#ifndef SHA3_H #ifndef SHA3_H
#define SHA3_H #define SHA3_H
#include <stdint.h>
/* ------------------------------------------------------------------------- /* -------------------------------------------------------------------------
* Works when compiled for either 32-bit or 64-bit targets, optimized for * Works when compiled for either 32-bit or 64-bit targets, optimized for
* 64 bit. * 64 bit.
@@ -28,7 +30,7 @@ typedef struct sha3_context_ {
union { /* Keccak's state */ union { /* Keccak's state */
uint64_t s[SHA3_KECCAK_SPONGE_WORDS]; uint64_t s[SHA3_KECCAK_SPONGE_WORDS];
uint8_t sb[SHA3_KECCAK_SPONGE_WORDS * 8]; uint8_t sb[SHA3_KECCAK_SPONGE_WORDS * 8];
}; } u;
unsigned byteIndex; /* 0..7--the next byte after the set one unsigned byteIndex; /* 0..7--the next byte after the set one
* (starts from 0; 0--none are buffered) */ * (starts from 0; 0--none are buffered) */
unsigned wordIndex; /* 0..24--the next word to integrate input unsigned wordIndex; /* 0..24--the next word to integrate input
@@ -37,14 +39,35 @@ typedef struct sha3_context_ {
* words (e.g. 16 for Keccak 512) */ * words (e.g. 16 for Keccak 512) */
} sha3_context; } sha3_context;
enum SHA3_FLAGS {
SHA3_FLAGS_NONE=0,
SHA3_FLAGS_KECCAK=1
};
enum SHA3_RETURN {
SHA3_RETURN_OK=0,
SHA3_RETURN_BAD_PARAMS=1
};
typedef enum SHA3_RETURN sha3_return_t;
/* For Init or Reset call these: */ /* For Init or Reset call these: */
sha3_return_t sha3_Init(void *priv, unsigned bitSize);
void sha3_Init256(void *priv); void sha3_Init256(void *priv);
void sha3_Init384(void *priv); void sha3_Init384(void *priv);
void sha3_Init512(void *priv); void sha3_Init512(void *priv);
enum SHA3_FLAGS sha3_SetFlags(void *priv, enum SHA3_FLAGS);
void sha3_Update(void *priv, void const *bufIn, size_t len); void sha3_Update(void *priv, void const *bufIn, size_t len);
void const *sha3_Finalize(void *priv); void const *sha3_Finalize(void *priv);
/* Single-call hashing */
sha3_return_t sha3_HashBuffer(
unsigned bitSize, /* 256, 384, 512 */
enum SHA3_FLAGS flags, /* SHA3_FLAGS_NONE or SHA3_FLAGS_KECCAK */
const void *in, unsigned inBytes,
void *out, unsigned outBytes ); /* up to bitSize/8; truncation OK */
#endif #endif