Files
cli/vendor/aws-lc-sys/aws-lc/crypto/fipsmodule/sha/sha3.c

521 lines
15 KiB
C

// Copyright 2017-2020 The OpenSSL Project Authors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
#include "internal.h"
#include <string.h>
uint8_t *SHA3_224(const uint8_t *data, size_t len,
uint8_t out[SHA3_224_DIGEST_LENGTH]) {
FIPS_service_indicator_lock_state();
KECCAK1600_CTX ctx;
int ok = (SHA3_Init(&ctx, SHA3_224_DIGEST_BITLENGTH) &&
SHA3_Update(&ctx, data, len) &&
SHA3_Final(out, &ctx));
OPENSSL_cleanse(&ctx, sizeof(ctx));
FIPS_service_indicator_unlock_state();
if (ok == 0) {
return NULL;
}
FIPS_service_indicator_update_state();
return out;
}
uint8_t *SHA3_256(const uint8_t *data, size_t len,
uint8_t out[SHA3_256_DIGEST_LENGTH]) {
FIPS_service_indicator_lock_state();
KECCAK1600_CTX ctx;
int ok = (SHA3_Init(&ctx, SHA3_256_DIGEST_BITLENGTH) &&
SHA3_Update(&ctx, data, len) &&
SHA3_Final(out, &ctx));
OPENSSL_cleanse(&ctx, sizeof(ctx));
FIPS_service_indicator_unlock_state();
if (ok == 0) {
return NULL;
}
FIPS_service_indicator_update_state();
return out;
}
uint8_t *SHA3_384(const uint8_t *data, size_t len,
uint8_t out[SHA3_384_DIGEST_LENGTH]) {
FIPS_service_indicator_lock_state();
KECCAK1600_CTX ctx;
int ok = (SHA3_Init(&ctx, SHA3_384_DIGEST_BITLENGTH) &&
SHA3_Update(&ctx, data, len) &&
SHA3_Final(out, &ctx));
OPENSSL_cleanse(&ctx, sizeof(ctx));
FIPS_service_indicator_unlock_state();
if (ok == 0) {
return NULL;
}
FIPS_service_indicator_update_state();
return out;
}
uint8_t *SHA3_512(const uint8_t *data, size_t len,
uint8_t out[SHA3_512_DIGEST_LENGTH]) {
FIPS_service_indicator_lock_state();
KECCAK1600_CTX ctx;
int ok = (SHA3_Init(&ctx, SHA3_512_DIGEST_BITLENGTH) &&
SHA3_Update(&ctx, data, len) &&
SHA3_Final(out, &ctx));
OPENSSL_cleanse(&ctx, sizeof(ctx));
FIPS_service_indicator_unlock_state();
if (ok == 0) {
return NULL;
}
FIPS_service_indicator_update_state();
return out;
}
uint8_t *SHAKE128(const uint8_t *data, const size_t in_len, uint8_t *out, size_t out_len) {
FIPS_service_indicator_lock_state();
KECCAK1600_CTX ctx;
int ok = (SHAKE_Init(&ctx, SHAKE128_BLOCKSIZE) &&
SHAKE_Absorb(&ctx, data, in_len) &&
SHAKE_Final(out, &ctx, out_len));
OPENSSL_cleanse(&ctx, sizeof(ctx));
FIPS_service_indicator_unlock_state();
if (ok == 0) {
return NULL;
}
FIPS_service_indicator_update_state();
return out;
}
uint8_t *SHAKE256(const uint8_t *data, const size_t in_len, uint8_t *out, size_t out_len) {
FIPS_service_indicator_lock_state();
KECCAK1600_CTX ctx;
int ok = (SHAKE_Init(&ctx, SHAKE256_BLOCKSIZE) &&
SHAKE_Absorb(&ctx, data, in_len) &&
SHAKE_Final(out, &ctx, out_len));
OPENSSL_cleanse(&ctx, sizeof(ctx));
FIPS_service_indicator_unlock_state();
if (ok == 0) {
return NULL;
}
FIPS_service_indicator_update_state();
return out;
}
/*
* FIPS202 APIs manage internal input/output buffer on top of Keccak1600 API layer
*/
// FIPS202_Reset zero's |ctx| fields.
static void FIPS202_Reset(KECCAK1600_CTX *ctx) {
OPENSSL_memset(ctx->A, 0, sizeof(ctx->A));
ctx->buf_load = 0;
ctx->state = KECCAK1600_STATE_ABSORB;
}
// FIPS202_Init checks the correctness of the padding character and size of
// the internal buffer. It initialises the |ctx| fields and returns 1 on
// success and 0 on failure.
static int FIPS202_Init(KECCAK1600_CTX *ctx, uint8_t pad, size_t block_size, size_t bit_len) {
if (pad != SHA3_PAD_CHAR &&
pad != SHAKE_PAD_CHAR) {
return 0;
}
if (block_size <= sizeof(ctx->buf)) {
FIPS202_Reset(ctx);
ctx->block_size = block_size;
ctx->md_size = bit_len / 8;
ctx->pad = pad;
return 1;
}
return 0;
}
// FIPS202_Update checks the state of the |ctx| and processes intermediate buffer from
// previous calls. It processes |data| in blocks through |Keccak1600_Absorb| and places
// the rest in the intermediate buffer. FIPS202_Update fails if called from inappropriate
// |ctx->state| or on |Keccak1600_Absorb| error. Otherwise, it returns 1.
static int FIPS202_Update(KECCAK1600_CTX *ctx, const void *data, size_t len) {
uint8_t *data_ptr_copy = (uint8_t *) data;
size_t block_size = ctx->block_size;
size_t num, rem;
if (ctx->state == KECCAK1600_STATE_SQUEEZE ||
ctx->state == KECCAK1600_STATE_FINAL ) {
return 0;
}
// Case |len| equals 0 is checked in SHA3/SHAKE higher level APIs
// Process intermediate buffer.
num = ctx->buf_load;
if (num != 0) {
rem = block_size - num;
if (len < rem) {
OPENSSL_memcpy(ctx->buf + num, data_ptr_copy, len);
ctx->buf_load += len;
return 1;
}
// There is enough data to fill or overflow the intermediate
// buffer. So we append |rem| bytes and process the block,
// leaving the rest for later processing.
OPENSSL_memcpy(ctx->buf + num, data_ptr_copy, rem);
data_ptr_copy += rem, len -= rem;
if (Keccak1600_Absorb(ctx->A, ctx->buf, block_size, block_size) != 0 ) {
return 0;
}
ctx->buf_load = 0;
// ctx->buf is processed, ctx->buf_load is guaranteed to be zero
}
if (len >= block_size) {
rem = Keccak1600_Absorb(ctx->A, data_ptr_copy, len, block_size);
}
else {
rem = len;
}
if (rem != 0) {
OPENSSL_memcpy(ctx->buf, data_ptr_copy + len - rem, rem);
ctx->buf_load = rem;
}
return 1;
}
// FIPS202_Finalize processes padding and absorb of last input block
// This function should be called once to finalize absorb and initiate
// squeeze phase. FIPS202_Finalize fails if called from inappropriate
// |ctx->state| or on |Keccak1600_Absorb| error. Otherwise, it returns 1.
static int FIPS202_Finalize(uint8_t *md, KECCAK1600_CTX *ctx) {
size_t block_size = ctx->block_size;
size_t num = ctx->buf_load;
if (ctx->state == KECCAK1600_STATE_SQUEEZE ||
ctx->state == KECCAK1600_STATE_FINAL ) {
return 0;
}
// Pad the data with 10*1. Note that |num| can be |block_size - 1|
// in which case both byte operations below are performed on
// the same byte.
OPENSSL_memset(ctx->buf + num, 0, block_size - num);
ctx->buf[num] = ctx->pad;
ctx->buf[block_size - 1] |= 0x80;
if (Keccak1600_Absorb(ctx->A, ctx->buf, block_size, block_size) != 0) {
return 0;
}
// ctx->buf is processed, ctx->buf_load is guaranteed to be zero
ctx->buf_load = 0;
return 1;
}
/*
* SHA3 APIs implement SHA3 functionalities on top of FIPS202 API layer
*/
int SHA3_Init(KECCAK1600_CTX *ctx, size_t bit_len) {
if (ctx == NULL) {
return 0;
}
if (bit_len != SHA3_224_DIGEST_BITLENGTH &&
bit_len != SHA3_256_DIGEST_BITLENGTH &&
bit_len != SHA3_384_DIGEST_BITLENGTH &&
bit_len != SHA3_512_DIGEST_BITLENGTH) {
return 0;
}
// |block_size| depends on the SHA3 |bit_len| output (digest) length
return FIPS202_Init(ctx, SHA3_PAD_CHAR, SHA3_BLOCKSIZE(bit_len), bit_len);
}
int SHA3_Update(KECCAK1600_CTX *ctx, const void *data, size_t len) {
if (ctx == NULL) {
return 0;
}
if (data == NULL && len != 0) {
return 0;
}
if (len == 0) {
return 1;
}
return FIPS202_Update(ctx, data, len);
}
// SHA3_Final should be called once to process final digest value
int SHA3_Final(uint8_t *md, KECCAK1600_CTX *ctx) {
if (md == NULL || ctx == NULL) {
return 0;
}
if (ctx->md_size == 0) {
return 1;
}
if (FIPS202_Finalize(md, ctx) == 0) {
return 0;
}
Keccak1600_Squeeze(ctx->A, md, ctx->md_size, ctx->block_size, ctx->state);
ctx->state = KECCAK1600_STATE_FINAL;
FIPS_service_indicator_update_state();
return 1;
}
int SHA3_224_Init(KECCAK1600_CTX *ctx) {
return SHA3_Init(ctx, SHA3_224_DIGEST_BITLENGTH);
}
int SHA3_224_Update(KECCAK1600_CTX *ctx, const void *data,
size_t len) {
return SHA3_Update(ctx, data, len);
}
int SHA3_224_Final(uint8_t out[SHA3_224_DIGEST_LENGTH],
KECCAK1600_CTX *ctx) {
return SHA3_Final(&out[0], ctx);
}
int SHA3_256_Init(KECCAK1600_CTX *ctx) {
return SHA3_Init(ctx, SHA3_256_DIGEST_BITLENGTH);
}
int SHA3_256_Update(KECCAK1600_CTX *ctx, const void *data,
size_t len) {
return SHA3_Update(ctx, data, len);
}
int SHA3_256_Final(uint8_t out[SHA3_256_DIGEST_LENGTH],
KECCAK1600_CTX *ctx) {
return SHA3_Final(&out[0], ctx);
}
int SHA3_384_Init(KECCAK1600_CTX *ctx) {
return SHA3_Init(ctx, SHA3_384_DIGEST_BITLENGTH);
}
int SHA3_384_Update(KECCAK1600_CTX *ctx, const void *data,
size_t len) {
return SHA3_Update(ctx, data, len);
}
int SHA3_384_Final(uint8_t out[SHA3_384_DIGEST_LENGTH],
KECCAK1600_CTX *ctx) {
return SHA3_Final(&out[0], ctx);
}
int SHA3_512_Init(KECCAK1600_CTX *ctx) {
return SHA3_Init(ctx, SHA3_512_DIGEST_BITLENGTH);
}
int SHA3_512_Update(KECCAK1600_CTX *ctx, const void *data,
size_t len) {
return SHA3_Update(ctx, data, len);
}
int SHA3_512_Final(uint8_t out[SHA3_512_DIGEST_LENGTH],
KECCAK1600_CTX *ctx) {
return SHA3_Final(&out[0], ctx);
}
/*
* SHAKE APIs implement SHAKE functionalities on top of FIPS202 API layer
*/
int SHAKE_Init(KECCAK1600_CTX *ctx, size_t block_size) {
if (ctx == NULL) {
return 0;
}
if (block_size != SHAKE128_BLOCKSIZE &&
block_size != SHAKE256_BLOCKSIZE) {
return 0;
}
// |block_size| depends on the SHAKE security level
// The output length |bit_len| is initialized to 0
return FIPS202_Init(ctx, SHAKE_PAD_CHAR, block_size, 0);
}
int SHAKE_Absorb(KECCAK1600_CTX *ctx, const void *data, size_t len) {
if (ctx == NULL) {
return 0;
}
if (data == NULL && len != 0) {
return 0;
}
if (len == 0) {
return 1;
}
return FIPS202_Update(ctx, data, len);
}
// SHAKE_Final is to be called once to finalize absorb and squeeze phases
// |ctx->state| restricts consecutive calls to |FIPS202_Finalize|.
// Function |SHAKE_Squeeze| should be used for incremental XOF output.
int SHAKE_Final(uint8_t *md, KECCAK1600_CTX *ctx, size_t len) {
if (ctx == NULL || md == NULL) {
return 0;
}
ctx->md_size = len;
if (ctx->md_size == 0) {
return 1;
}
if (FIPS202_Finalize(md, ctx) == 0) {
return 0;
}
Keccak1600_Squeeze(ctx->A, md, ctx->md_size, ctx->block_size, ctx->state);
ctx->state = KECCAK1600_STATE_FINAL;
FIPS_service_indicator_update_state();
return 1;
}
// SHAKE_Squeeze can be called multiple time for incremental XOF output
int SHAKE_Squeeze(uint8_t *md, KECCAK1600_CTX *ctx, size_t len) {
size_t block_bytes;
if (ctx == NULL || md == NULL) {
return 0;
}
ctx->md_size = len;
if (ctx->md_size == 0) {
return 1;
}
if (ctx->state == KECCAK1600_STATE_FINAL) {
return 0;
}
// Skip FIPS202_Finalize if the input has been padded and
// the last block has been processed
if (ctx->state == KECCAK1600_STATE_ABSORB) {
if (FIPS202_Finalize(md, ctx) == 0) {
return 0;
}
}
// Process previous data from output buffer if any
if (ctx->buf_load != 0) {
if (len <= ctx->buf_load) {
OPENSSL_memcpy(md, ctx->buf + ctx->block_size - ctx->buf_load, len);
ctx->buf_load -= len;
return 1;
} else {
OPENSSL_memcpy(md, ctx->buf + ctx->block_size - ctx->buf_load, ctx->buf_load);
md += ctx->buf_load;
len -= ctx->buf_load;
ctx->buf_load = 0;
}
}
// Process all full size output requested blocks
if (len > ctx->block_size) {
block_bytes = ctx->block_size * (len / ctx->block_size);
Keccak1600_Squeeze(ctx->A, md, block_bytes, ctx->block_size, ctx->state);
md += block_bytes;
len -= block_bytes;
ctx->state = KECCAK1600_STATE_SQUEEZE;
}
if (len > 0) {
// Process an additional block if output length is not a multiple of block size.
// Generated output is store in |ctx->buf|. Only requested bytes are transfered
// to the output. The 'unused' output data is kept for processing in a sequenctual
// call to SHAKE_Squeeze (incremental byte-wise SHAKE_Squeeze)
Keccak1600_Squeeze(ctx->A, ctx->buf, ctx->block_size, ctx->block_size, ctx->state);
OPENSSL_memcpy(md, ctx->buf, len);
ctx->buf_load = ctx->block_size - len; // how much there is still in buffer to be consumed
ctx->state = KECCAK1600_STATE_SQUEEZE;
}
//FIPS_service_indicator_update_state();
return 1;
}
/*
* SHAKE batched (x4) APIs implement SHAKE functionalities in batches of four on top of SHAKE API layer
*/
int SHAKE128_Init_x4(KECCAK1600_CTX_x4 *ctx) {
OPENSSL_memset(ctx, 0, sizeof(KECCAK1600_CTX_x4));
return 1;
}
int SHAKE128_Absorb_once_x4(KECCAK1600_CTX_x4 *ctx, const void *data0, const void *data1,
const void *data2, const void *data3, size_t len) {
Keccak1600_Absorb_once_x4(ctx->A, data0, data1, data2, data3, len,
SHAKE128_BLOCKSIZE, SHAKE_PAD_CHAR);
return 1;
}
int SHAKE128_Squeezeblocks_x4(uint8_t *md0, uint8_t *md1, uint8_t *md2, uint8_t *md3,
KECCAK1600_CTX_x4 *ctx, size_t blks) {
Keccak1600_Squeezeblocks_x4(ctx->A, md0, md1, md2, md3, blks, SHAKE128_BLOCKSIZE);
return 1;
}
static int SHAKE256_Absorb_once_x4(KECCAK1600_CTX_x4 *ctx, const void *data0, const void *data1,
const void *data2, const void *data3, size_t len) {
Keccak1600_Absorb_once_x4(ctx->A, data0, data1, data2, data3,
len, SHAKE256_BLOCKSIZE, SHAKE_PAD_CHAR);
return 1;
}
static int SHAKE256_Squeezeblocks_x4(uint8_t *md0, uint8_t *md1, uint8_t *md2, uint8_t *md3,
KECCAK1600_CTX_x4 *ctx, size_t blks) {
Keccak1600_Squeezeblocks_x4(ctx->A, md0, md1, md2, md3, blks, SHAKE256_BLOCKSIZE);
return 1;
}
int SHAKE256_x4(const uint8_t *data0, const uint8_t *data1, const uint8_t *data2,
const uint8_t *data3, const size_t in_len,
uint8_t *out0, uint8_t *out1, uint8_t *out2,
uint8_t *out3, size_t out_len) {
KECCAK1600_CTX_x4 ctx;
OPENSSL_memset(&ctx, 0, sizeof(ctx));
size_t nblocks = out_len / SHAKE256_BLOCKSIZE;
uint8_t tmp0[SHAKE256_BLOCKSIZE];
uint8_t tmp1[SHAKE256_BLOCKSIZE];
uint8_t tmp2[SHAKE256_BLOCKSIZE];
uint8_t tmp3[SHAKE256_BLOCKSIZE];
SHAKE256_Absorb_once_x4(&ctx, data0, data1, data2, data3, in_len);
SHAKE256_Squeezeblocks_x4(out0, out1, out2, out3, &ctx, nblocks);
out0 += nblocks * SHAKE256_BLOCKSIZE;
out1 += nblocks * SHAKE256_BLOCKSIZE;
out2 += nblocks * SHAKE256_BLOCKSIZE;
out3 += nblocks * SHAKE256_BLOCKSIZE;
out_len -= nblocks * SHAKE256_BLOCKSIZE;
if (out_len > 0)
{
SHAKE256_Squeezeblocks_x4(tmp0, tmp1, tmp2, tmp3, &ctx, 1);
OPENSSL_memcpy(out0, tmp0, out_len);
OPENSSL_memcpy(out1, tmp1, out_len);
OPENSSL_memcpy(out2, tmp2, out_len);
OPENSSL_memcpy(out3, tmp3, out_len);
}
OPENSSL_cleanse(tmp0, sizeof(tmp0));
OPENSSL_cleanse(tmp1, sizeof(tmp1));
OPENSSL_cleanse(tmp2, sizeof(tmp2));
OPENSSL_cleanse(tmp3, sizeof(tmp3));
OPENSSL_cleanse(&ctx, sizeof(ctx));
return 1;
}