mirror of
https://github.com/jedisct1/libsodium.git
synced 2026-08-25 08:37:13 +09:00
sha3: make post-final misuse safe and deterministic
This commit is contained in:
@@ -37,6 +37,14 @@ sha3_update(sha3_state_internal *state, const unsigned char *in, size_t inlen)
|
||||
{
|
||||
size_t consumed = 0;
|
||||
size_t chunk_size;
|
||||
int ret = 0;
|
||||
|
||||
if (state->phase != SHA3_PHASE_ABSORBING) {
|
||||
crypto_core_keccak1600_permute_24(&state->state);
|
||||
state->phase = SHA3_PHASE_ABSORBING;
|
||||
state->offset = 0;
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
while (consumed < inlen) {
|
||||
if (state->offset == state->rate) {
|
||||
@@ -52,36 +60,42 @@ sha3_update(sha3_state_internal *state, const unsigned char *in, size_t inlen)
|
||||
consumed += chunk_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
sha3_final(sha3_state_internal *state, unsigned char *out)
|
||||
{
|
||||
unsigned char pad;
|
||||
int ret = 0;
|
||||
|
||||
if (state->offset == state->rate) {
|
||||
if (state->phase != SHA3_PHASE_ABSORBING) {
|
||||
crypto_core_keccak1600_permute_24(&state->state);
|
||||
state->offset = 0;
|
||||
}
|
||||
|
||||
if (state->offset == state->rate - 1) {
|
||||
pad = (unsigned char) (SHA3_DOMAIN ^ 0x80);
|
||||
crypto_core_keccak1600_xor_bytes(&state->state, &pad, state->offset, 1);
|
||||
ret = -1;
|
||||
} else {
|
||||
pad = SHA3_DOMAIN;
|
||||
crypto_core_keccak1600_xor_bytes(&state->state, &pad, state->offset, 1);
|
||||
pad = 0x80;
|
||||
crypto_core_keccak1600_xor_bytes(&state->state, &pad, state->rate - 1, 1);
|
||||
}
|
||||
if (state->offset == state->rate) {
|
||||
crypto_core_keccak1600_permute_24(&state->state);
|
||||
state->offset = 0;
|
||||
}
|
||||
|
||||
crypto_core_keccak1600_permute_24(&state->state);
|
||||
if (state->offset == state->rate - 1) {
|
||||
pad = (unsigned char) (SHA3_DOMAIN ^ 0x80);
|
||||
crypto_core_keccak1600_xor_bytes(&state->state, &pad, state->offset, 1);
|
||||
} else {
|
||||
pad = SHA3_DOMAIN;
|
||||
crypto_core_keccak1600_xor_bytes(&state->state, &pad, state->offset, 1);
|
||||
pad = 0x80;
|
||||
crypto_core_keccak1600_xor_bytes(&state->state, &pad, state->rate - 1, 1);
|
||||
}
|
||||
|
||||
crypto_core_keccak1600_permute_24(&state->state);
|
||||
}
|
||||
|
||||
crypto_core_keccak1600_extract_bytes(&state->state, out, 0, state->outlen);
|
||||
state->offset = 0;
|
||||
state->phase = SHA3_PHASE_FINALIZED;
|
||||
|
||||
sodium_memzero(state, sizeof *state);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t
|
||||
@@ -125,6 +139,7 @@ crypto_hash_sha3256(unsigned char *out, const unsigned char *in, unsigned long l
|
||||
crypto_hash_sha3256_init(&state);
|
||||
crypto_hash_sha3256_update(&state, in, inlen);
|
||||
crypto_hash_sha3256_final(&state, out);
|
||||
sodium_memzero(&state, sizeof state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -170,6 +185,7 @@ crypto_hash_sha3512(unsigned char *out, const unsigned char *in, unsigned long l
|
||||
crypto_hash_sha3512_init(&state);
|
||||
crypto_hash_sha3512_update(&state, in, inlen);
|
||||
crypto_hash_sha3512_final(&state, out);
|
||||
sodium_memzero(&state, sizeof state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#define TEST_NAME "hash_sha3256"
|
||||
#include "cmptest.h"
|
||||
|
||||
#define TEST_SHA3_256_BYTES 32U
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
@@ -125,6 +127,77 @@ main(void)
|
||||
printf("Rate-1 boundary test passed\n");
|
||||
}
|
||||
|
||||
{
|
||||
static const unsigned char resumed_msg[] = { 0x78, 0x79 };
|
||||
static const unsigned char resumed_msg_other[] = { 0x78, 0x7a };
|
||||
unsigned char resumed_out1[TEST_SHA3_256_BYTES];
|
||||
unsigned char resumed_out2[TEST_SHA3_256_BYTES];
|
||||
unsigned char resumed_out3[TEST_SHA3_256_BYTES];
|
||||
crypto_hash_sha3256_state state2;
|
||||
crypto_hash_sha3256_state state3;
|
||||
int ret;
|
||||
|
||||
crypto_hash_sha3256_init(&state);
|
||||
crypto_hash_sha3256_init(&state2);
|
||||
crypto_hash_sha3256_init(&state3);
|
||||
crypto_hash_sha3256_update(&state, msg_abc, 3);
|
||||
crypto_hash_sha3256_update(&state2, msg_abc, 3);
|
||||
crypto_hash_sha3256_update(&state3, msg_abc, 3);
|
||||
crypto_hash_sha3256_final(&state, out);
|
||||
crypto_hash_sha3256_final(&state2, resumed_out2);
|
||||
crypto_hash_sha3256_final(&state3, resumed_out3);
|
||||
assert(memcmp(out, out_abc, 32) == 0);
|
||||
assert(memcmp(resumed_out2, out_abc, 32) == 0);
|
||||
assert(memcmp(resumed_out3, out_abc, 32) == 0);
|
||||
|
||||
ret = crypto_hash_sha3256_update(&state, resumed_msg, sizeof resumed_msg);
|
||||
assert(ret == -1);
|
||||
ret = crypto_hash_sha3256_update(&state2, resumed_msg, sizeof resumed_msg);
|
||||
assert(ret == -1);
|
||||
ret = crypto_hash_sha3256_update(&state3, resumed_msg_other, sizeof resumed_msg_other);
|
||||
assert(ret == -1);
|
||||
|
||||
ret = crypto_hash_sha3256_final(&state, resumed_out1);
|
||||
assert(ret == 0);
|
||||
ret = crypto_hash_sha3256_final(&state2, resumed_out2);
|
||||
assert(ret == 0);
|
||||
ret = crypto_hash_sha3256_final(&state3, resumed_out3);
|
||||
assert(ret == 0);
|
||||
|
||||
assert(memcmp(resumed_out1, resumed_out2, TEST_SHA3_256_BYTES) == 0);
|
||||
assert(memcmp(resumed_out1, resumed_out3, TEST_SHA3_256_BYTES) != 0);
|
||||
printf("Update-after-final recovery test passed\n");
|
||||
}
|
||||
|
||||
{
|
||||
unsigned char repeated_out1[TEST_SHA3_256_BYTES];
|
||||
unsigned char repeated_out2[TEST_SHA3_256_BYTES];
|
||||
crypto_hash_sha3256_state state2;
|
||||
int ret;
|
||||
|
||||
memset(repeated_out1, 0xAA, sizeof repeated_out1);
|
||||
memset(repeated_out2, 0xAA, sizeof repeated_out2);
|
||||
|
||||
crypto_hash_sha3256_init(&state);
|
||||
crypto_hash_sha3256_init(&state2);
|
||||
crypto_hash_sha3256_update(&state, msg_abc, 3);
|
||||
crypto_hash_sha3256_update(&state2, msg_abc, 3);
|
||||
ret = crypto_hash_sha3256_final(&state, out);
|
||||
assert(ret == 0);
|
||||
ret = crypto_hash_sha3256_final(&state2, out);
|
||||
assert(ret == 0);
|
||||
|
||||
ret = crypto_hash_sha3256_final(&state, repeated_out1);
|
||||
assert(ret == -1);
|
||||
ret = crypto_hash_sha3256_final(&state2, repeated_out2);
|
||||
assert(ret == -1);
|
||||
|
||||
assert(memcmp(repeated_out1, repeated_out2, TEST_SHA3_256_BYTES) == 0);
|
||||
assert(memcmp(repeated_out1, out, TEST_SHA3_256_BYTES) != 0);
|
||||
assert(repeated_out1[0] != 0xAA);
|
||||
printf("Final-after-final test passed\n");
|
||||
}
|
||||
|
||||
printf("OK\n");
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -6,4 +6,6 @@ Chunked update test passed
|
||||
Rate boundary test passed
|
||||
Rate+1 boundary test passed
|
||||
Rate-1 boundary test passed
|
||||
Update-after-final recovery test passed
|
||||
Final-after-final test passed
|
||||
OK
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#define TEST_NAME "hash_sha3512"
|
||||
#include "cmptest.h"
|
||||
|
||||
#define TEST_SHA3_512_BYTES 64U
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
@@ -134,6 +136,77 @@ main(void)
|
||||
printf("Rate-1 boundary test passed\n");
|
||||
}
|
||||
|
||||
{
|
||||
static const unsigned char resumed_msg[] = { 0x78, 0x79 };
|
||||
static const unsigned char resumed_msg_other[] = { 0x78, 0x7a };
|
||||
unsigned char resumed_out1[TEST_SHA3_512_BYTES];
|
||||
unsigned char resumed_out2[TEST_SHA3_512_BYTES];
|
||||
unsigned char resumed_out3[TEST_SHA3_512_BYTES];
|
||||
crypto_hash_sha3512_state state2;
|
||||
crypto_hash_sha3512_state state3;
|
||||
int ret;
|
||||
|
||||
crypto_hash_sha3512_init(&state);
|
||||
crypto_hash_sha3512_init(&state2);
|
||||
crypto_hash_sha3512_init(&state3);
|
||||
crypto_hash_sha3512_update(&state, msg_abc, 3);
|
||||
crypto_hash_sha3512_update(&state2, msg_abc, 3);
|
||||
crypto_hash_sha3512_update(&state3, msg_abc, 3);
|
||||
crypto_hash_sha3512_final(&state, out);
|
||||
crypto_hash_sha3512_final(&state2, resumed_out2);
|
||||
crypto_hash_sha3512_final(&state3, resumed_out3);
|
||||
assert(memcmp(out, out_abc, 64) == 0);
|
||||
assert(memcmp(resumed_out2, out_abc, 64) == 0);
|
||||
assert(memcmp(resumed_out3, out_abc, 64) == 0);
|
||||
|
||||
ret = crypto_hash_sha3512_update(&state, resumed_msg, sizeof resumed_msg);
|
||||
assert(ret == -1);
|
||||
ret = crypto_hash_sha3512_update(&state2, resumed_msg, sizeof resumed_msg);
|
||||
assert(ret == -1);
|
||||
ret = crypto_hash_sha3512_update(&state3, resumed_msg_other, sizeof resumed_msg_other);
|
||||
assert(ret == -1);
|
||||
|
||||
ret = crypto_hash_sha3512_final(&state, resumed_out1);
|
||||
assert(ret == 0);
|
||||
ret = crypto_hash_sha3512_final(&state2, resumed_out2);
|
||||
assert(ret == 0);
|
||||
ret = crypto_hash_sha3512_final(&state3, resumed_out3);
|
||||
assert(ret == 0);
|
||||
|
||||
assert(memcmp(resumed_out1, resumed_out2, TEST_SHA3_512_BYTES) == 0);
|
||||
assert(memcmp(resumed_out1, resumed_out3, TEST_SHA3_512_BYTES) != 0);
|
||||
printf("Update-after-final recovery test passed\n");
|
||||
}
|
||||
|
||||
{
|
||||
unsigned char repeated_out1[TEST_SHA3_512_BYTES];
|
||||
unsigned char repeated_out2[TEST_SHA3_512_BYTES];
|
||||
crypto_hash_sha3512_state state2;
|
||||
int ret;
|
||||
|
||||
memset(repeated_out1, 0xAA, sizeof repeated_out1);
|
||||
memset(repeated_out2, 0xAA, sizeof repeated_out2);
|
||||
|
||||
crypto_hash_sha3512_init(&state);
|
||||
crypto_hash_sha3512_init(&state2);
|
||||
crypto_hash_sha3512_update(&state, msg_abc, 3);
|
||||
crypto_hash_sha3512_update(&state2, msg_abc, 3);
|
||||
ret = crypto_hash_sha3512_final(&state, out);
|
||||
assert(ret == 0);
|
||||
ret = crypto_hash_sha3512_final(&state2, out);
|
||||
assert(ret == 0);
|
||||
|
||||
ret = crypto_hash_sha3512_final(&state, repeated_out1);
|
||||
assert(ret == -1);
|
||||
ret = crypto_hash_sha3512_final(&state2, repeated_out2);
|
||||
assert(ret == -1);
|
||||
|
||||
assert(memcmp(repeated_out1, repeated_out2, TEST_SHA3_512_BYTES) == 0);
|
||||
assert(memcmp(repeated_out1, out, TEST_SHA3_512_BYTES) != 0);
|
||||
assert(repeated_out1[0] != 0xAA);
|
||||
printf("Final-after-final test passed\n");
|
||||
}
|
||||
|
||||
printf("OK\n");
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -6,4 +6,6 @@ Chunked update test passed
|
||||
Rate boundary test passed
|
||||
Rate+1 boundary test passed
|
||||
Rate-1 boundary test passed
|
||||
Update-after-final recovery test passed
|
||||
Final-after-final test passed
|
||||
OK
|
||||
|
||||
Reference in New Issue
Block a user