diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2021-10-29 14:35:09 +0900 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2021-11-17 14:29:40 +0900 |
commit | 3bacdac611b9eb3bd5ae8d78156b1110e77e9518 (patch) | |
tree | 1a9f8a33d21bdb80feae818f9df195664f34a027 /random/jitterentropy-sha3.c | |
parent | 5e0187d84fc16d9ff0fbb0ccd4348657fea90d36 (diff) | |
download | libgcrypt-3bacdac611b9eb3bd5ae8d78156b1110e77e9518.tar.gz |
jitterentropy: Merge from jitterentropy-library-3.3.0.
* random/jitterentropy-base.h: New.
* random/jitterentropy-gcd.c: New.
* random/jitterentropy-gcd.h: New.
* random/jitterentropy-health.c: New.
* random/jitterentropy-health.h: New.
* random/jitterentropy-noise.c: New.
* random/jitterentropy-noise.h: New.
* random/jitterentropy-sha3.c: New.
* random/jitterentropy-sha3.h: New.
* random/jitterentropy-timer.c: New.
* random/jitterentropy-timer.h: New.
* random/jitterentropy-base.c: Update.
* random/jitterentropy.h: Update.
* random/jitterentropy-base-user.h: Update, keeping ours mostly.
--
Unicode characters are replaced or removed (quotation mark, minus, and
BOM). Inconsistent Tabs are replaced by spaces.
GnuPG-bug-id: 5523
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
Diffstat (limited to 'random/jitterentropy-sha3.c')
-rw-r--r-- | random/jitterentropy-sha3.c | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/random/jitterentropy-sha3.c b/random/jitterentropy-sha3.c new file mode 100644 index 00000000..59fbb74f --- /dev/null +++ b/random/jitterentropy-sha3.c @@ -0,0 +1,382 @@ +/* Jitter RNG: SHA-3 Implementation + * + * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> + * + * License: see LICENSE file in root directory + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#include "jitterentropy-sha3.h" + +/*************************************************************************** + * Message Digest Implementation + ***************************************************************************/ + +/* + * Conversion of Little-Endian representations in byte streams - the data + * representation in the integer values is the host representation. + */ +static inline uint32_t ptr_to_le32(const uint8_t *p) +{ + return (uint32_t)p[0] | (uint32_t)p[1] << 8 | + (uint32_t)p[2] << 16 | (uint32_t)p[3] << 24; +} + +static inline uint64_t ptr_to_le64(const uint8_t *p) +{ + return (uint64_t)ptr_to_le32(p) | (uint64_t)ptr_to_le32(p + 4) << 32; +} + +static inline void le32_to_ptr(uint8_t *p, const uint32_t value) +{ + p[0] = (uint8_t)(value); + p[1] = (uint8_t)(value >> 8); + p[2] = (uint8_t)(value >> 16); + p[3] = (uint8_t)(value >> 24); +} + +static inline void le64_to_ptr(uint8_t *p, const uint64_t value) +{ + le32_to_ptr(p + 4, (uint32_t)(value >> 32)); + le32_to_ptr(p, (uint32_t)(value)); +} + +/*********************************** Keccak ***********************************/ +/* state[x + y*5] */ +#define A(x, y) (x + 5 * y) + +static inline void keccakp_theta(uint64_t s[25]) +{ + uint64_t C[5], D[5]; + + /* Step 1 */ + C[0] = s[A(0, 0)] ^ s[A(0, 1)] ^ s[A(0, 2)] ^ s[A(0, 3)] ^ s[A(0, 4)]; + C[1] = s[A(1, 0)] ^ s[A(1, 1)] ^ s[A(1, 2)] ^ s[A(1, 3)] ^ s[A(1, 4)]; + C[2] = s[A(2, 0)] ^ s[A(2, 1)] ^ s[A(2, 2)] ^ s[A(2, 3)] ^ s[A(2, 4)]; + C[3] = s[A(3, 0)] ^ s[A(3, 1)] ^ s[A(3, 2)] ^ s[A(3, 3)] ^ s[A(3, 4)]; + C[4] = s[A(4, 0)] ^ s[A(4, 1)] ^ s[A(4, 2)] ^ s[A(4, 3)] ^ s[A(4, 4)]; + + /* Step 2 */ + D[0] = C[4] ^ rol64(C[1], 1); + D[1] = C[0] ^ rol64(C[2], 1); + D[2] = C[1] ^ rol64(C[3], 1); + D[3] = C[2] ^ rol64(C[4], 1); + D[4] = C[3] ^ rol64(C[0], 1); + + /* Step 3 */ + s[A(0, 0)] ^= D[0]; + s[A(1, 0)] ^= D[1]; + s[A(2, 0)] ^= D[2]; + s[A(3, 0)] ^= D[3]; + s[A(4, 0)] ^= D[4]; + + s[A(0, 1)] ^= D[0]; + s[A(1, 1)] ^= D[1]; + s[A(2, 1)] ^= D[2]; + s[A(3, 1)] ^= D[3]; + s[A(4, 1)] ^= D[4]; + + s[A(0, 2)] ^= D[0]; + s[A(1, 2)] ^= D[1]; + s[A(2, 2)] ^= D[2]; + s[A(3, 2)] ^= D[3]; + s[A(4, 2)] ^= D[4]; + + s[A(0, 3)] ^= D[0]; + s[A(1, 3)] ^= D[1]; + s[A(2, 3)] ^= D[2]; + s[A(3, 3)] ^= D[3]; + s[A(4, 3)] ^= D[4]; + + s[A(0, 4)] ^= D[0]; + s[A(1, 4)] ^= D[1]; + s[A(2, 4)] ^= D[2]; + s[A(3, 4)] ^= D[3]; + s[A(4, 4)] ^= D[4]; +} + +static inline void keccakp_rho(uint64_t s[25]) +{ + /* Step 1 */ + /* s[A(0, 0)] = s[A(0, 0)]; */ + +#define RHO_ROL(t) (((t + 1) * (t + 2) / 2) % 64) + /* Step 3 */ + s[A(1, 0)] = rol64(s[A(1, 0)], RHO_ROL(0)); + s[A(0, 2)] = rol64(s[A(0, 2)], RHO_ROL(1)); + s[A(2, 1)] = rol64(s[A(2, 1)], RHO_ROL(2)); + s[A(1, 2)] = rol64(s[A(1, 2)], RHO_ROL(3)); + s[A(2, 3)] = rol64(s[A(2, 3)], RHO_ROL(4)); + s[A(3, 3)] = rol64(s[A(3, 3)], RHO_ROL(5)); + s[A(3, 0)] = rol64(s[A(3, 0)], RHO_ROL(6)); + s[A(0, 1)] = rol64(s[A(0, 1)], RHO_ROL(7)); + s[A(1, 3)] = rol64(s[A(1, 3)], RHO_ROL(8)); + s[A(3, 1)] = rol64(s[A(3, 1)], RHO_ROL(9)); + s[A(1, 4)] = rol64(s[A(1, 4)], RHO_ROL(10)); + s[A(4, 4)] = rol64(s[A(4, 4)], RHO_ROL(11)); + s[A(4, 0)] = rol64(s[A(4, 0)], RHO_ROL(12)); + s[A(0, 3)] = rol64(s[A(0, 3)], RHO_ROL(13)); + s[A(3, 4)] = rol64(s[A(3, 4)], RHO_ROL(14)); + s[A(4, 3)] = rol64(s[A(4, 3)], RHO_ROL(15)); + s[A(3, 2)] = rol64(s[A(3, 2)], RHO_ROL(16)); + s[A(2, 2)] = rol64(s[A(2, 2)], RHO_ROL(17)); + s[A(2, 0)] = rol64(s[A(2, 0)], RHO_ROL(18)); + s[A(0, 4)] = rol64(s[A(0, 4)], RHO_ROL(19)); + s[A(4, 2)] = rol64(s[A(4, 2)], RHO_ROL(20)); + s[A(2, 4)] = rol64(s[A(2, 4)], RHO_ROL(21)); + s[A(4, 1)] = rol64(s[A(4, 1)], RHO_ROL(22)); + s[A(1, 1)] = rol64(s[A(1, 1)], RHO_ROL(23)); +} + +static inline void keccakp_pi(uint64_t s[25]) +{ + uint64_t t = s[A(4, 4)]; + + /* Step 1 */ + /* s[A(0, 0)] = s[A(0, 0)]; */ + s[A(4, 4)] = s[A(1, 4)]; + s[A(1, 4)] = s[A(3, 1)]; + s[A(3, 1)] = s[A(1, 3)]; + s[A(1, 3)] = s[A(0, 1)]; + s[A(0, 1)] = s[A(3, 0)]; + s[A(3, 0)] = s[A(3, 3)]; + s[A(3, 3)] = s[A(2, 3)]; + s[A(2, 3)] = s[A(1, 2)]; + s[A(1, 2)] = s[A(2, 1)]; + s[A(2, 1)] = s[A(0, 2)]; + s[A(0, 2)] = s[A(1, 0)]; + s[A(1, 0)] = s[A(1, 1)]; + s[A(1, 1)] = s[A(4, 1)]; + s[A(4, 1)] = s[A(2, 4)]; + s[A(2, 4)] = s[A(4, 2)]; + s[A(4, 2)] = s[A(0, 4)]; + s[A(0, 4)] = s[A(2, 0)]; + s[A(2, 0)] = s[A(2, 2)]; + s[A(2, 2)] = s[A(3, 2)]; + s[A(3, 2)] = s[A(4, 3)]; + s[A(4, 3)] = s[A(3, 4)]; + s[A(3, 4)] = s[A(0, 3)]; + s[A(0, 3)] = s[A(4, 0)]; + s[A(4, 0)] = t; +} + +static inline void keccakp_chi(uint64_t s[25]) +{ + uint64_t t0[5], t1[5]; + + t0[0] = s[A(0, 0)]; + t0[1] = s[A(0, 1)]; + t0[2] = s[A(0, 2)]; + t0[3] = s[A(0, 3)]; + t0[4] = s[A(0, 4)]; + + t1[0] = s[A(1, 0)]; + t1[1] = s[A(1, 1)]; + t1[2] = s[A(1, 2)]; + t1[3] = s[A(1, 3)]; + t1[4] = s[A(1, 4)]; + + s[A(0, 0)] ^= ~s[A(1, 0)] & s[A(2, 0)]; + s[A(0, 1)] ^= ~s[A(1, 1)] & s[A(2, 1)]; + s[A(0, 2)] ^= ~s[A(1, 2)] & s[A(2, 2)]; + s[A(0, 3)] ^= ~s[A(1, 3)] & s[A(2, 3)]; + s[A(0, 4)] ^= ~s[A(1, 4)] & s[A(2, 4)]; + + s[A(1, 0)] ^= ~s[A(2, 0)] & s[A(3, 0)]; + s[A(1, 1)] ^= ~s[A(2, 1)] & s[A(3, 1)]; + s[A(1, 2)] ^= ~s[A(2, 2)] & s[A(3, 2)]; + s[A(1, 3)] ^= ~s[A(2, 3)] & s[A(3, 3)]; + s[A(1, 4)] ^= ~s[A(2, 4)] & s[A(3, 4)]; + + s[A(2, 0)] ^= ~s[A(3, 0)] & s[A(4, 0)]; + s[A(2, 1)] ^= ~s[A(3, 1)] & s[A(4, 1)]; + s[A(2, 2)] ^= ~s[A(3, 2)] & s[A(4, 2)]; + s[A(2, 3)] ^= ~s[A(3, 3)] & s[A(4, 3)]; + s[A(2, 4)] ^= ~s[A(3, 4)] & s[A(4, 4)]; + + s[A(3, 0)] ^= ~s[A(4, 0)] & t0[0]; + s[A(3, 1)] ^= ~s[A(4, 1)] & t0[1]; + s[A(3, 2)] ^= ~s[A(4, 2)] & t0[2]; + s[A(3, 3)] ^= ~s[A(4, 3)] & t0[3]; + s[A(3, 4)] ^= ~s[A(4, 4)] & t0[4]; + + s[A(4, 0)] ^= ~t0[0] & t1[0]; + s[A(4, 1)] ^= ~t0[1] & t1[1]; + s[A(4, 2)] ^= ~t0[2] & t1[2]; + s[A(4, 3)] ^= ~t0[3] & t1[3]; + s[A(4, 4)] ^= ~t0[4] & t1[4]; +} + +static const uint64_t keccakp_iota_vals[] = { + 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, + 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, + 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, + 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, + 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, + 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, + 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, + 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL +}; + +static inline void keccakp_iota(uint64_t s[25], unsigned int round) +{ + s[0] ^= keccakp_iota_vals[round]; +} + +static inline void keccakp_1600(uint64_t s[25]) +{ + unsigned int round; + + for (round = 0; round < 24; round++) { + keccakp_theta(s); + keccakp_rho(s); + keccakp_pi(s); + keccakp_chi(s); + keccakp_iota(s, round); + } +} + +/*********************************** SHA-3 ************************************/ + +static inline void sha3_init(struct sha_ctx *ctx) +{ + unsigned int i; + + for (i = 0; i < 25; i++) + ctx->state[i] = 0; + ctx->msg_len = 0; +} + +void sha3_256_init(struct sha_ctx *ctx) +{ + sha3_init(ctx); + ctx->r = SHA3_256_SIZE_BLOCK; + ctx->rword = SHA3_256_SIZE_BLOCK / sizeof(uint64_t); + ctx->digestsize = SHA3_256_SIZE_DIGEST; +} + +static inline void sha3_fill_state(struct sha_ctx *ctx, const uint8_t *in) +{ + unsigned int i; + + for (i = 0; i < ctx->rword; i++) { + ctx->state[i] ^= ptr_to_le64(in); + in += 8; + } +} + +void sha3_update(struct sha_ctx *ctx, const uint8_t *in, size_t inlen) +{ + size_t partial = ctx->msg_len % ctx->r; + + ctx->msg_len += inlen; + + /* Sponge absorbing phase */ + + /* Check if we have a partial block stored */ + if (partial) { + size_t todo = ctx->r - partial; + + /* + * If the provided data is small enough to fit in the partial + * buffer, copy it and leave it unprocessed. + */ + if (inlen < todo) { + memcpy(ctx->partial + partial, in, inlen); + return; + } + + /* + * The input data is large enough to fill the entire partial + * block buffer. Thus, we fill it and transform it. + */ + memcpy(ctx->partial + partial, in, todo); + inlen -= todo; + in += todo; + + sha3_fill_state(ctx, ctx->partial); + keccakp_1600(ctx->state); + } + + /* Perform a transformation of full block-size messages */ + for (; inlen >= ctx->r; inlen -= ctx->r, in += ctx->r) { + sha3_fill_state(ctx, in); + keccakp_1600(ctx->state); + } + + /* If we have data left, copy it into the partial block buffer */ + memcpy(ctx->partial, in, inlen); +} + +void sha3_final(struct sha_ctx *ctx, uint8_t *digest) +{ + size_t partial = ctx->msg_len % ctx->r; + unsigned int i; + + /* Final round in sponge absorbing phase */ + + /* Fill the unused part of the partial buffer with zeros */ + memset(ctx->partial + partial, 0, ctx->r - partial); + + /* + * Add the leading and trailing bit as well as the 01 bits for the + * SHA-3 suffix. + */ + ctx->partial[partial] = 0x06; + ctx->partial[ctx->r - 1] |= 0x80; + + /* Final transformation */ + sha3_fill_state(ctx, ctx->partial); + keccakp_1600(ctx->state); + + /* + * Sponge squeeze phase - the digest size is always smaller as the + * state size r which implies we only have one squeeze round. + */ + for (i = 0; i < ctx->digestsize / 8; i++, digest += 8) + le64_to_ptr(digest, ctx->state[i]); + + /* Add remaining 4 bytes if we use SHA3-224 */ + if (ctx->digestsize % 8) + le32_to_ptr(digest, (uint32_t)(ctx->state[i])); + + memset(ctx->partial, 0, ctx->r); + sha3_init(ctx); +} + +int sha3_tester(void) +{ + HASH_CTX_ON_STACK(ctx); + static const uint8_t msg_256[] = { 0x5E, 0x5E, 0xD6 }; + static const uint8_t exp_256[] = { 0xF1, 0x6E, 0x66, 0xC0, 0x43, 0x72, + 0xB4, 0xA3, 0xE1, 0xE3, 0x2E, 0x07, + 0xC4, 0x1C, 0x03, 0x40, 0x8A, 0xD5, + 0x43, 0x86, 0x8C, 0xC4, 0x0E, 0xC5, + 0x5E, 0x00, 0xBB, 0xBB, 0xBD, 0xF5, + 0x91, 0x1E }; + uint8_t act[SHA3_256_SIZE_DIGEST] = { 0 }; + unsigned int i; + + sha3_256_init(&ctx); + sha3_update(&ctx, msg_256, 3); + sha3_final(&ctx, act); + + for (i = 0; i < SHA3_256_SIZE_DIGEST; i++) { + if (exp_256[i] != act[i]) + return 1; + } + + return 0; +} |