diff options
author | Andy Polyakov <appro@openssl.org> | 2017-07-16 23:40:14 +0200 |
---|---|---|
committer | Andy Polyakov <appro@openssl.org> | 2017-07-25 21:40:23 +0200 |
commit | 91ce87c0d5675329614dd5b56ce67670a6aaa387 (patch) | |
tree | f11552b82a03d9ee345356088a443e647943840a /crypto/evp | |
parent | c363ce55f2a04124519e504bbe1706f858260805 (diff) |
Add evp/m_sha3.c.
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3943)
Diffstat (limited to 'crypto/evp')
-rw-r--r-- | crypto/evp/build.info | 2 | ||||
-rw-r--r-- | crypto/evp/m_sha3.c | 168 |
2 files changed, 169 insertions, 1 deletions
diff --git a/crypto/evp/build.info b/crypto/evp/build.info index c0df858ae0..a3e4fc8273 100644 --- a/crypto/evp/build.info +++ b/crypto/evp/build.info @@ -5,7 +5,7 @@ SOURCE[../../libcrypto]=\ e_rc4.c e_aes.c names.c e_seed.c e_aria.c \ e_xcbc_d.c e_rc2.c e_cast.c e_rc5.c \ m_null.c m_md2.c m_md4.c m_md5.c m_sha1.c m_wp.c \ - m_md5_sha1.c m_mdc2.c m_ripemd.c \ + m_md5_sha1.c m_mdc2.c m_ripemd.c m_sha3.c \ p_open.c p_seal.c p_sign.c p_verify.c p_lib.c p_enc.c p_dec.c \ bio_md.c bio_b64.c bio_enc.c evp_err.c e_null.c \ c_allc.c c_alld.c evp_lib.c bio_ok.c \ diff --git a/crypto/evp/m_sha3.c b/crypto/evp/m_sha3.c new file mode 100644 index 0000000000..3fe2b07a05 --- /dev/null +++ b/crypto/evp/m_sha3.c @@ -0,0 +1,168 @@ +/* + * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <string.h> + +#include <openssl/evp.h> +#include <openssl/objects.h> +#include "internal/evp_int.h" +#include "evp_locl.h" + +size_t SHA3_absorb(uint64_t A[5][5], const unsigned char *inp, size_t len, + size_t r); +void SHA3_squeeze(uint64_t A[5][5], unsigned char *out, size_t len, size_t r); + +#define KECCAK1600_WIDTH 1600 + +typedef struct { + uint64_t A[5][5]; + size_t block_size; /* cached ctx->digest->block_size */ + size_t md_size; /* output length, variable in XOF */ + size_t num; /* used bytes in below buffer */ + unsigned char buf[KECCAK1600_WIDTH / 8 - 32]; + unsigned char pad; +} KECCAK1600_CTX; + +static int init(EVP_MD_CTX *evp_ctx, unsigned char pad) +{ + KECCAK1600_CTX *ctx = evp_ctx->md_data; + size_t bsz = evp_ctx->digest->block_size; + + if (bsz <= sizeof(ctx->buf)) { + memset(ctx->A, 0, sizeof(ctx->A)); + + ctx->num = 0; + ctx->block_size = bsz; + ctx->md_size = evp_ctx->digest->md_size; + ctx->pad = pad; + + return 1; + } + + return 0; +} + +static int sha3_init(EVP_MD_CTX *evp_ctx) +{ + return init(evp_ctx, '\x06'); +} + +static int shake_init(EVP_MD_CTX *evp_ctx) +{ + return init(evp_ctx, '\x1f'); +} + +static int sha3_update(EVP_MD_CTX *evp_ctx, const void *_inp, size_t len) +{ + KECCAK1600_CTX *ctx = evp_ctx->md_data; + const unsigned char *inp = _inp; + size_t bsz = ctx->block_size; + size_t num, rem; + + if ((num = ctx->num) != 0) { /* process intermediate buffer? */ + rem = bsz - num; + + if (len < rem) { + memcpy(ctx->buf + num, inp, len); + ctx->num += len; + return 1; + } + /* + * We have enough data to fill or overflow the intermediate + * buffer. So we append |rem| bytes and process the block, + * leaving the rest for later processing... + */ + memcpy(ctx->buf + num, inp, rem); + inp += rem, len -= rem; + (void)SHA3_absorb(ctx->A, ctx->buf, bsz, bsz); + ctx->num = 0; + /* ctx->buf is processed, ctx->num is guaranteed to be zero */ + } + + if (len >= bsz) + rem = SHA3_absorb(ctx->A, inp, len, bsz); + else + rem = len; + + if (rem) { + memcpy(ctx->buf, inp + len - rem, rem); + ctx->num = rem; + } + + return 1; +} + +static int sha3_final(EVP_MD_CTX *evp_ctx, unsigned char *md) +{ + KECCAK1600_CTX *ctx = evp_ctx->md_data; + size_t bsz = ctx->block_size; + size_t num = ctx->num; + + /* + * Pad the data with 10*1. Note that |num| can be |bsz - 1| + * in which case both byte operations below are performed on + * same byte... + */ + memset(ctx->buf + num, 0, bsz - num); + ctx->buf[num] = ctx->pad; + ctx->buf[bsz - 1] |= 0x80; + + (void)SHA3_absorb(ctx->A, ctx->buf, bsz, bsz); + + SHA3_squeeze(ctx->A, md, ctx->md_size, bsz); + + return 1; +} + +#define EVP_MD_SHA3(bitlen) \ +const EVP_MD *EVP_sha3_##bitlen(void) \ +{ \ + static const EVP_MD sha3_##bitlen##_md = { \ + NID_sha3_##bitlen, \ + 0, \ + bitlen / 8, \ + 0, \ + sha3_init, \ + sha3_update, \ + sha3_final, \ + NULL, \ + NULL, \ + (KECCAK1600_WIDTH - bitlen * 2) / 8, \ + sizeof(KECCAK1600_CTX), \ + }; \ + return &sha3_##bitlen##_md; \ +} + +EVP_MD_SHA3(224) +EVP_MD_SHA3(256) +EVP_MD_SHA3(384) +EVP_MD_SHA3(512) + +#define EVP_MD_SHAKE(bitlen) \ +const EVP_MD *EVP_shake##bitlen(void) \ +{ \ + static const EVP_MD shake##bitlen##_md = { \ + NID_shake##bitlen, \ + 0, \ + 512, \ + 0, \ + shake_init, \ + sha3_update, \ + sha3_final, \ + NULL, \ + NULL, \ + (KECCAK1600_WIDTH - bitlen * 2) / 8, \ + sizeof(KECCAK1600_CTX), \ + }; \ + return &shake##bitlen##_md; \ +} + +EVP_MD_SHAKE(128) +EVP_MD_SHAKE(256) |