From 6935ea21e7cbb5e4b2413d41e8cad38440ba4595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikolai=20G=C3=BCtschow?= Date: Tue, 10 Oct 2023 15:19:54 +0200 Subject: [PATCH] sys/hashes: add SHA-512 support --- dist/tools/doccheck/exclude_simple | 7 - makefiles/pseudomodules.inc.mk | 1 + ...icant-add-prefix-wpa_-to-sha512_init.patch | Bin 0 -> 2695 bytes sys/hashes/psa_riot_hashes/Kconfig | 6 + sys/hashes/psa_riot_hashes/sha_512.c | 47 ++ sys/hashes/sha256.c | 2 +- sys/hashes/sha2xx_common.c | 50 ++- sys/hashes/sha512.c | 51 +++ sys/hashes/sha512_common.c | 250 +++++++++++ sys/include/hashes/psa/riot_hashes.h | 6 + sys/include/hashes/sha2xx_common.h | 36 +- sys/include/hashes/sha512.h | 97 +++++ sys/include/hashes/sha512_common.h | 74 ++++ sys/include/psa_crypto/psa/crypto_includes.h | 2 +- sys/psa_crypto/Kconfig.hashes | 4 + sys/psa_crypto/Makefile.dep | 17 +- sys/psa_crypto/Makefile.include | 1 + sys/psa_crypto/doc.txt | 1 + tests/unittests/Makefile.ci | 29 +- .../tests-hashes/tests-hashes-sha256.c | 2 +- .../tests-hashes/tests-hashes-sha512.c | 406 ++++++++++++++++++ tests/unittests/tests-hashes/tests-hashes.c | 1 + tests/unittests/tests-hashes/tests-hashes.h | 7 + 23 files changed, 1024 insertions(+), 73 deletions(-) create mode 100644 pkg/esp32_sdk/patches/0033-wpa_supplicant-add-prefix-wpa_-to-sha512_init.patch create mode 100644 sys/hashes/psa_riot_hashes/sha_512.c create mode 100644 sys/hashes/sha512.c create mode 100644 sys/hashes/sha512_common.c create mode 100644 sys/include/hashes/sha512.h create mode 100644 sys/include/hashes/sha512_common.h create mode 100644 tests/unittests/tests-hashes/tests-hashes-sha512.c diff --git a/dist/tools/doccheck/exclude_simple b/dist/tools/doccheck/exclude_simple index 2a7a1eff3f..362f0057dc 100644 --- a/dist/tools/doccheck/exclude_simple +++ b/dist/tools/doccheck/exclude_simple @@ -4010,7 +4010,6 @@ warning: Member MAG3110_SYSMOD_ACTIVE (macro definition) of file mag3110_reg.h i warning: Member MAG3110_SYSMOD_ACTIVE_RAW (macro definition) of file mag3110_reg.h is not documented. warning: Member MAG3110_SYSMOD_STANDBY (macro definition) of file mag3110_reg.h is not documented. warning: Member MAIPGL_FD (macro definition) of file enc28j60_regs.h is not documented. -warning: Member Maj(x, y, z) (macro definition) of group sys_hashes_sha2xx_common is not documented. warning: Member MASK_MAX_RT (macro definition) of file nrf24l01p_settings.h is not documented. warning: Member MASK_RX_DR (macro definition) of file nrf24l01p_settings.h is not documented. warning: Member MASK_TX_DS (macro definition) of file nrf24l01p_settings.h is not documented. @@ -6025,7 +6024,6 @@ warning: Member rom_setup_set_aon_rtc_sub_sec_inc (macro definition) of file cc2 warning: Member rom_setup_set_cache_mode_according_to_ccfg_setting (macro definition) of file cc26x2_cc13x2_setup.h is not documented. warning: Member rom_setup_step_vddr_trim_to (macro definition) of file cc26x2_cc13x2_setup.h is not documented. warning: Member rotating_hash(const uint8_t *buf, size_t len) (function) of file hashes.h is not documented. -warning: Member ROTR(x, n) (macro definition) of group sys_hashes_sha2xx_common is not documented. warning: Member RR_CLASS_LENGTH (macro definition) of group net_dns is not documented. warning: Member RR_RDLENGTH_LENGTH (macro definition) of group net_dns is not documented. warning: Member RR_TTL_LENGTH (macro definition) of group net_dns is not documented. @@ -6063,14 +6061,10 @@ warning: Member RUN_MIC_PIN (macro definition) of file board.h is not documented warning: Member RX_DR (macro definition) of file nrf24l01p_settings.h is not documented. warning: Member RX_P_NO (macro definition) of file nrf24l01p_settings.h is not documented. warning: Member s0_OFFSET (macro definition) of file context_frame.h is not documented. -warning: Member s0(x) (macro definition) of group sys_hashes_sha2xx_common is not documented. -warning: Member S0(x) (macro definition) of group sys_hashes_sha2xx_common is not documented. warning: Member s10_OFFSET (macro definition) of file context_frame.h is not documented. warning: Member s11_OFFSET (macro definition) of file context_frame.h is not documented. warning: Member S16_F (macro definition) of group pkg_lwip_sys is not documented. warning: Member s1_OFFSET (macro definition) of file context_frame.h is not documented. -warning: Member s1(x) (macro definition) of group sys_hashes_sha2xx_common is not documented. -warning: Member S1(x) (macro definition) of group sys_hashes_sha2xx_common is not documented. warning: Member s2_OFFSET (macro definition) of file context_frame.h is not documented. warning: Member S32_F (macro definition) of group pkg_lwip_sys is not documented. warning: Member s3_OFFSET (macro definition) of file context_frame.h is not documented. @@ -6280,7 +6274,6 @@ warning: Member setup_fpu(void) (function) of group cpu_lm4f120 is not documente warning: Member SGP30_PARAM_I2C_DEV (macro definition) of file sgp30_params.h is not documented. warning: Member SGP30_PARAMS (macro definition) of file sgp30_params.h is not documented. warning: Member SGP30_SAUL_INFO (macro definition) of file sgp30_params.h is not documented. -warning: Member SHR(x, n) (macro definition) of group sys_hashes_sha2xx_common is not documented. warning: Member SHT1X_PARAM_CLK (macro definition) of file board.h is not documented. warning: Member SHT1X_PARAM_DATA (macro definition) of file board.h is not documented. warning: Member SHT2X_PARAM_CRC_MODE (macro definition) of file sht2x_params.h is not documented. diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 986a1c11ca..a58f81e4b0 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -397,6 +397,7 @@ PSEUDOMODULES += psa_riot_hashes_md5 PSEUDOMODULES += psa_riot_hashes_sha_1 PSEUDOMODULES += psa_riot_hashes_sha_224 PSEUDOMODULES += psa_riot_hashes_sha_256 +PSEUDOMODULES += psa_riot_hashes_sha_512 PSEUDOMODULES += psa_riot_hashes_hmac_sha256 PSEUDOMODULES += fortuna_reseed ## @defgroup pseudomodule_random_cmd random_cmd diff --git a/pkg/esp32_sdk/patches/0033-wpa_supplicant-add-prefix-wpa_-to-sha512_init.patch b/pkg/esp32_sdk/patches/0033-wpa_supplicant-add-prefix-wpa_-to-sha512_init.patch new file mode 100644 index 0000000000000000000000000000000000000000..c0ba1dde27a7cb4964d592ba6d55ffec649ffab0 GIT binary patch literal 2695 zcmbVOTW{hx6n;*A#gSH80U;p?Ap|;Gm1U+EON_LXY_YNkTsw1R?ACy?)p0_kscGyEIG(E@6zqRVHA{ zw&3-_b%*)~zUzACDViC=St&>kQ@YA>x{~l=sm3QoJ$3|>$L2>O*$`$WYlG*)gi18v zchTao7YutoSS}hgr{&@gM&%IhZbq~5Idr?7ZucI(ZAn~|+wGcDB5;)?32bwg@&~;H zGJ|48dY&J1!KG>5RBQ7X73WHtB}!(#Cp3q&6jXBDS(d_l=b?5nSK{Pr#uE@^!+>TY zMdz}BZ(Oe6_F^)FO_r2vR=}L*k6W3cACbU(MT!+G=8kFGwuyS1Z6=tIMQ7)s+C!(v zX{S=GUl_V%xgcwY!ry=id8>N0Df@|f0G9P;|GTU>E2yuX|1P9lZIP~sShA!I0dP^U zT&1mOSWPvNur;g3cGENyo~B^iOD=(Q4&43XKt+>_ggrpw1%61Plr8#>(@)c06w$>Z za1nQI7zC;?2ghbwmIVjLcX9%D*l+j2(oY-~GB1$|6%b;D9cb;3G@ctwl$$5BWW5Bu z+X|P3gffEG7xvgT;U^}r0?=u}cyfJuaTZ@(&pzE=k1pfs`KTKO(CVNNPZO5DB!LVv z!JwpIFuwimW;Th>N7M6oba|%qadl|ghOxs7Qmyebl@IoD=~Q#gBhxYrjr9NM_*@1I zW05oR<>-F`Mu$4!mm@mA8ja(tkGed7?&2Mwd#i0NXnc@GV_>~czhtm@oZ6< z;AD+?ue9n2HS6NZXTS{>B~=?s%eARkVC&OpKasD*)-)|G`eS-u6^FktrJKY)re%(4 z(|NCFaJa4B{%`C}EiRyU%n!eKw9MAk0d~R;! literal 0 HcmV?d00001 diff --git a/sys/hashes/psa_riot_hashes/Kconfig b/sys/hashes/psa_riot_hashes/Kconfig index 981d62fe62..cae71f2464 100644 --- a/sys/hashes/psa_riot_hashes/Kconfig +++ b/sys/hashes/psa_riot_hashes/Kconfig @@ -29,6 +29,12 @@ config MODULE_PSA_RIOT_HASHES_SHA_256 select MODULE_PSA_RIOT_HASHES select MODULE_HASHES +config MODULE_PSA_RIOT_HASHES_SHA_512 + bool + depends on MODULE_PSA_CRYPTO + select MODULE_PSA_RIOT_HASHES + select MODULE_HASHES + config MODULE_PSA_RIOT_HASHES_HMAC_SHA256 bool depends on MODULE_PSA_CRYPTO diff --git a/sys/hashes/psa_riot_hashes/sha_512.c b/sys/hashes/psa_riot_hashes/sha_512.c new file mode 100644 index 0000000000..18a11aafc9 --- /dev/null +++ b/sys/hashes/psa_riot_hashes/sha_512.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2023 TU Dresden + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_psa_crypto + * @{ + * + * @brief Glue code translating between PSA Crypto and the RIOT Hash module + * + * @author Mikolai Gütschow + * + * @} + */ + +#include "psa/crypto.h" +#include "hashes/psa/riot_hashes.h" + +psa_status_t psa_hashes_sha512_setup(psa_hashes_sha512_ctx_t *ctx) +{ + sha512_init((sha512_context_t *)ctx); + return PSA_SUCCESS; +} + +psa_status_t psa_hashes_sha512_update(psa_hashes_sha512_ctx_t *ctx, + const uint8_t *input, + size_t input_length) +{ + sha512_update((sha512_context_t *)ctx, input, input_length); + return PSA_SUCCESS; +} + +psa_status_t psa_hashes_sha512_finish(psa_hashes_sha512_ctx_t *ctx, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + sha512_final((sha512_context_t *)ctx, hash); + + (void)hash_size; + (void)hash_length; + return PSA_SUCCESS; +} diff --git a/sys/hashes/sha256.c b/sys/hashes/sha256.c index 124db252ff..a02e34505c 100644 --- a/sys/hashes/sha256.c +++ b/sys/hashes/sha256.c @@ -78,7 +78,7 @@ void *sha256(const void *data, size_t len, void *digest) } sha256_init(&c); - sha2xx_update(&c, data, len); + sha256_update(&c, data, len); sha256_final(&c, digest); return digest; diff --git a/sys/hashes/sha2xx_common.c b/sys/hashes/sha2xx_common.c index ae8b99d443..4931312a15 100644 --- a/sys/hashes/sha2xx_common.c +++ b/sys/hashes/sha2xx_common.c @@ -96,6 +96,40 @@ static void be32enc_vect(void *dst_, const void *src_, size_t len) #endif /* __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__ */ +/** + * @brief Elementary functions used by SHA2XX + * @{ + */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (32 - n))) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) +/** @} */ + +/** @brief SHA-224 and SHA-256 Constants */ +static const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +}; + /* * SHA256 block compression function. The 256-bit state is transformed via * the 512-bit input block to produce a new state. @@ -153,8 +187,8 @@ void sha2xx_pad(sha2xx_context_t *ctx) be32enc_vect(len, ctx->count, 8); /* Add 1--64 bytes so that the resulting length is 56 mod 64 */ - uint32_t r = (ctx->count[1] >> 3) & 0x3f; - uint32_t plen = (r < 56) ? (56 - r) : (120 - r); + uint8_t r = (ctx->count[1] >> 3) & 0x3f; + uint8_t plen = (r < 56) ? (56 - r) : (120 - r); sha2xx_update(ctx, PAD, (size_t) plen); /* Add the terminating bit-count */ @@ -165,7 +199,9 @@ void sha2xx_pad(sha2xx_context_t *ctx) void sha2xx_update(sha2xx_context_t *ctx, const void *data, size_t len) { /* Number of bytes left in the buffer from previous updates */ - uint32_t r = (ctx->count[1] >> 3) & 0x3f; + uint8_t r = (ctx->count[1] >> 3) & 0x3f; + /* Number of bytes free in the buffer from previous updates */ + uint8_t f = 64 - r; /* Convert the length into a number of bits */ uint32_t bitlen1 = ((uint32_t) len) << 3; @@ -179,7 +215,7 @@ void sha2xx_update(sha2xx_context_t *ctx, const void *data, size_t len) ctx->count[0] += bitlen0; /* Handle the case where we don't need to perform any transforms */ - if (len < 64 - r) { + if (len < f) { if (len > 0) { memcpy(&ctx->buf[r], data, len); } @@ -189,10 +225,10 @@ void sha2xx_update(sha2xx_context_t *ctx, const void *data, size_t len) /* Finish the current block */ const unsigned char *src = data; - memcpy(&ctx->buf[r], src, 64 - r); + memcpy(&ctx->buf[r], src, f); sha2xx_transform(ctx->state, ctx->buf); - src += 64 - r; - len -= 64 - r; + src += f; + len -= f; /* Perform complete blocks */ while (len >= 64) { diff --git a/sys/hashes/sha512.c b/sys/hashes/sha512.c new file mode 100644 index 0000000000..a1d44b4e1c --- /dev/null +++ b/sys/hashes/sha512.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023 TU Dresden + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_hashes + * @{ + * + * @file + * @brief SHA-512 hash function implementation + * + * @author Mikolai Gütschow + * + * @} + */ + +#include +#include + +#include "hashes/sha512.h" +#include "hashes/sha512_common.h" + +/* SHA-512 initialization. Begins a SHA-512 operation. */ +void sha512_init(sha512_context_t *ctx) +{ + /* Zero bits processed so far */ + ctx->count[0] = ctx->count[1] = 0; + + /* Magic initialization constants */ + ctx->state[0] = 0x6a09e667f3bcc908; + ctx->state[1] = 0xbb67ae8584caa73b; + ctx->state[2] = 0x3c6ef372fe94f82b; + ctx->state[3] = 0xa54ff53a5f1d36f1; + ctx->state[4] = 0x510e527fade682d1; + ctx->state[5] = 0x9b05688c2b3e6c1f; + ctx->state[6] = 0x1f83d9abfb41bd6b; + ctx->state[7] = 0x5be0cd19137e2179; +} + +void sha512(const void *data, size_t len, void *digest) +{ + sha512_context_t c; + + sha512_init(&c); + sha512_update(&c, data, len); + sha512_final(&c, digest); +} diff --git a/sys/hashes/sha512_common.c b/sys/hashes/sha512_common.c new file mode 100644 index 0000000000..b5480d824c --- /dev/null +++ b/sys/hashes/sha512_common.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2023 TU Dresden + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup sys_hashes_sha512_common SHA-512 common + * @ingroup sys_hashes_unkeyed + * @brief Implementation of common functionality for SHA-512-based hashing functions + * @{ + * + * @file + * @brief Common code for SHA-512-based hash functions + * + * @author Mikolai Gütschow + * + * @} + */ + +#include +#include + +#include "hashes/sha512_common.h" + +#ifdef __BIG_ENDIAN__ +/* Copy a vector of big-endian uint32_t into a vector of bytes */ +#define be64enc_vect memcpy + +/* Copy a vector of bytes into a vector of big-endian uint32_t */ +#define be64dec_vect memcpy +#else /* !__BIG_ENDIAN__ */ + +/* + * Encode a length len/8 vector of (uint64_t) into a length len vector of + * (unsigned char) in big-endian form. Assumes len is a multiple of 8. + */ +static void be64enc_vect(void *dst_, const void *src_, size_t len) +{ + /* Assert if len is not a multiple of 8 */ + assert(!(len & 7)); + + if ((uintptr_t)dst_ % sizeof(uint64_t) == 0 && + (uintptr_t)src_ % sizeof(uint64_t) == 0) { + uint64_t *dst = dst_; + const uint64_t *src = src_; + for (size_t i = 0; i < len / 8; i++) { + dst[i] = __builtin_bswap64(src[i]); + } + } + else { + uint8_t *dst = dst_; + const uint8_t *src = src_; + for (size_t i = 0; i < len; i += 8) { + dst[i] = src[i + 7]; + dst[i + 1] = src[i + 6]; + dst[i + 2] = src[i + 5]; + dst[i + 3] = src[i + 4]; + dst[i + 4] = src[i + 3]; + dst[i + 5] = src[i + 2]; + dst[i + 6] = src[i + 1]; + dst[i + 7] = src[i]; + } + } +} + +/* + * Decode a big-endian length len vector of (unsigned char) into a length + * len/8 vector of (uint64_t). Assumes len is a multiple of 8. + */ +#define be64dec_vect be64enc_vect + +#endif /* __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__ */ + +/** + * @brief Elementary functions used by SHA512 + * @{ + */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (64 - n))) +#define S0(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)) +#define S1(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)) +#define s0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7)) +#define s1(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHR(x, 6)) +/** @} */ + +/** @brief SHA-384, SHA-512, SHA-512/224 and SHA-512/256 Constants */ +static const uint64_t K[80] = { + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, +}; + +/* + * SHA512 block compression function. The 512-bit state is transformed via + * the 1024-bit input block to produce a new state. + */ +static void sha512_transform(uint64_t *state, const unsigned char block[128]) +{ + uint64_t W[80]; + uint64_t S[8]; + + /* 1. Prepare message schedule W. */ + be64dec_vect(W, block, 128); + for (int i = 16; i < 80; i++) { + W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; + } + + /* 2. Initialize working variables. */ + memcpy(S, state, 64); + + /* 3. Mix. */ + for (int i = 0; i < 80; ++i) { + uint64_t e = S[(84 - i) % 8], f = S[(85 - i) % 8]; + uint64_t g = S[(86 - i) % 8], h = S[(87 - i) % 8]; + uint64_t t0 = h + S1(e) + Ch(e, f, g) + W[i] + K[i]; + + uint64_t a = S[(80 - i) % 8], b = S[(81 - i) % 8]; + uint64_t c = S[(82 - i) % 8], d = S[(83 - i) % 8]; + uint64_t t1 = S0(a) + Maj(a, b, c); + + S[(83 - i) % 8] = d + t0; + S[(87 - i) % 8] = t0 + t1; + } + + /* 4. Mix local working variables into global state */ + for (int i = 0; i < 8; i++) { + state[i] += S[i]; + } +} + +static const unsigned char PAD[128] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +/* Add padding and terminating bit-count. */ +void sha512_common_pad(sha512_common_context_t *ctx) +{ + assert(ctx != NULL); + + /* + * Convert length to a vector of bytes -- we do this now rather + * than later because the length will change after we pad. + */ + unsigned char len[16]; + + be64enc_vect(len, ctx->count, 16); + + /* Add 1--128 bytes so that the resulting length is 112 mod 128 */ + uint8_t r = (ctx->count[1] >> 3) & 0x7f; + uint8_t plen = (r < 112) ? (112 - r) : (240 - r); + sha512_common_update(ctx, PAD, (size_t) plen); + + /* Add the terminating bit-count */ + sha512_common_update(ctx, len, 16); +} + +/* Add bytes into the hash */ +void sha512_common_update(sha512_common_context_t *ctx, const void *data, size_t len) +{ + assert(ctx != NULL); + + /* Number of bytes left in the buffer from previous updates */ + uint8_t r = (ctx->count[1] >> 3) & 0x7f; + /* Number of bytes free in the buffer from previous updates */ + uint8_t f = 128 - r; + + /* Convert the length into a number of bits */ + uint64_t bitlen1 = ((uint64_t) len) << 3; + uint64_t bitlen0 = ((uint64_t) len) >> 61; + + /* Update number of bits */ + if ((ctx->count[1] += bitlen1) < bitlen1) { + ctx->count[0]++; + } + + ctx->count[0] += bitlen0; + + /* Handle the case where we don't need to perform any transforms */ + if (len < f) { + if (len > 0) { + memcpy(&ctx->buf[r], data, len); + } + return; + } + + /* Finish the current block */ + const unsigned char *src = data; + + memcpy(&ctx->buf[r], src, f); + sha512_transform(ctx->state, ctx->buf); + src += f; + len -= f; + + /* Perform complete blocks */ + while (len >= 128) { + sha512_transform(ctx->state, src); + src += 128; + len -= 128; + } + + /* Copy left over data into buffer */ + memcpy(ctx->buf, src, len); +} + +/* + * SHA-512 finalization. Pads the input data, exports the hash value, + * and clears the context state. + */ +void sha512_common_final(sha512_common_context_t *ctx, void *dst, size_t dig_len) +{ + assert(ctx != NULL); + + /* Add padding */ + sha512_common_pad(ctx); + + /* Write the hash */ + be64enc_vect(dst, ctx->state, dig_len); + + /* Clear the context state */ + memset(ctx, 0, sizeof(*ctx)); +} diff --git a/sys/include/hashes/psa/riot_hashes.h b/sys/include/hashes/psa/riot_hashes.h index 2638560f05..73de39a854 100644 --- a/sys/include/hashes/psa/riot_hashes.h +++ b/sys/include/hashes/psa/riot_hashes.h @@ -49,6 +49,12 @@ typedef sha224_context_t psa_hashes_sha224_ctx_t; typedef sha256_context_t psa_hashes_sha256_ctx_t; #endif +#if (IS_USED(MODULE_PSA_RIOT_HASHES_SHA_512)) +#include "hashes/sha512.h" + +typedef sha512_context_t psa_hashes_sha512_ctx_t; +#endif + #if (IS_USED(MODULE_PSA_RIOT_HASHES_HMAC_SHA256)) #include "hashes/sha256.h" #endif diff --git a/sys/include/hashes/sha2xx_common.h b/sys/include/hashes/sha2xx_common.h index 1f676dda86..d685809fa5 100644 --- a/sys/include/hashes/sha2xx_common.h +++ b/sys/include/hashes/sha2xx_common.h @@ -62,46 +62,12 @@ extern "C" { typedef struct { /** global state */ uint32_t state[8]; - /** processed bytes counter */ + /** processed bits counter */ uint32_t count[2]; /** data buffer */ unsigned char buf[64]; } sha2xx_context_t; -/** - * @brief Elementary functions used by SHA2XX - * @{ - */ -#define Ch(x, y, z) ((x & (y ^ z)) ^ z) -#define Maj(x, y, z) ((x & (y | z)) | (y & z)) -#define SHR(x, n) (x >> n) -#define ROTR(x, n) ((x >> n) | (x << (32 - n))) -#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) -#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) -#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) -#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) -/** @} */ - -/** @brief SHA-224 and SHA-256 Constants */ -static const uint32_t K[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, -}; - /** * @brief SHA-2XX initialization. Begins a SHA-2XX operation. * diff --git a/sys/include/hashes/sha512.h b/sys/include/hashes/sha512.h new file mode 100644 index 0000000000..0642412b1c --- /dev/null +++ b/sys/include/hashes/sha512.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2023 TU Dresden + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup sys_hashes_sha512 SHA-512 + * @ingroup sys_hashes_unkeyed + * @brief Implementation of the SHA-512 hashing function + * @{ + * + * @file + * @brief Header definitions for the SHA512 hash function + * + * @author Mikolai Gütschow + */ + +#ifndef HASHES_SHA512_H +#define HASHES_SHA512_H + +#include +#include + +#include "hashes/sha512_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Length of SHA512 digests in bytes + */ +#define SHA512_DIGEST_LENGTH (64) + +/** + * @brief 1024 Bit (128 Byte) internally used block size for sha512 + */ +#define SHA512_INTERNAL_BLOCK_SIZE (128) + +/** + * @brief Context for cipher operations based on sha512 + */ +typedef sha512_common_context_t sha512_context_t; + + +/** + * @brief SHA-512 initialization. Begins a SHA-512 operation. + * + * @param ctx sha512_context_t handle to init, must not be NULL + */ +void sha512_init(sha512_context_t *ctx); + +/** + * @brief Add bytes into the hash + * + * @param ctx sha512_context_t handle to use, must not be NULL + * @param[in] data Input data + * @param[in] len Length of @p data + */ +static inline void sha512_update(sha512_context_t *ctx, const void *data, size_t len) +{ + sha512_common_update(ctx, data, len); +} + +/** + * @brief SHA-512 finalization. Pads the input data, exports the hash value, + * and clears the context state. + * + * @param ctx sha512_context_t handle to use, must not be NULL + * @param[out] digest pointer to resulting digest, this is the hash of all the bytes. + * Length must be at least SHA512_DIGEST_LENGTH + */ +static inline void sha512_final(sha512_context_t *ctx, void *digest) +{ + sha512_common_final(ctx, digest, SHA512_DIGEST_LENGTH); +} + +/** + * @brief A wrapper function to simplify the generation of a hash. This is + * useful for generating sha512 for one single buffer in a single step. + * + * @param[in] data pointer to the buffer to generate hash from + * @param[in] len length of the buffer + * @param[out] digest optional pointer to an array for the result, length must + * be SHA512_DIGEST_LENGTH + */ +void sha512(const void *data, size_t len, void *digest); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif /* HASHES_SHA512_H */ diff --git a/sys/include/hashes/sha512_common.h b/sys/include/hashes/sha512_common.h new file mode 100644 index 0000000000..347b6cdfe3 --- /dev/null +++ b/sys/include/hashes/sha512_common.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2023 TU Dresden + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup sys_hashes_sha512_common SHA-512 common + * @ingroup sys_hashes_unkeyed + * @brief Implementation of common functionality for SHA-512 hashing function + * @{ + * + * @file + * @brief Common definitions for the SHA-512 hash function + * + * @author Mikolai Gütschow + */ + +#ifndef HASHES_SHA512_COMMON_H +#define HASHES_SHA512_COMMON_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Structure to hold the SHA-512 context. + */ +typedef struct { + /** global state */ + uint64_t state[8]; + /** processed bits counter */ + uint64_t count[2]; + /** data buffer */ + unsigned char buf[128]; +} sha512_common_context_t; + +/** + * @brief SHA-512 initialization. Begins a SHA-512 operation. + * + * @param ctx sha512_common_context_t handle to init, must not be NULL + */ +void sha512_common_pad(sha512_common_context_t *ctx); + +/** + * @brief Add bytes into the hash + * + * @param ctx sha512_common_context_t handle to use, must not be NULL + * @param[in] data Input data + * @param[in] len Length of @p data + */ +void sha512_common_update(sha512_common_context_t *ctx, const void *data, size_t len); + +/** + * @brief SHA-512 finalization. Pads the input data, exports the hash value, + * and clears the context state. + * + * @param ctx sha512_common_context_t handle to use, must not be NULL + * @param[out] digest resulting digest, this is the hash of all the bytes + * @param[in] dig_len Length of @p digest + */ +void sha512_common_final(sha512_common_context_t *ctx, void *digest, size_t dig_len); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif /* HASHES_SHA512_COMMON_H */ diff --git a/sys/include/psa_crypto/psa/crypto_includes.h b/sys/include/psa_crypto/psa/crypto_includes.h index 128602ea4c..011e41ff12 100644 --- a/sys/include/psa_crypto/psa/crypto_includes.h +++ b/sys/include/psa_crypto/psa/crypto_includes.h @@ -31,7 +31,7 @@ extern "C" { #if IS_USED(MODULE_PSA_RIOT_HASHES_HMAC_SHA256) || IS_USED(MODULE_PSA_RIOT_HASHES_MD5) || \ IS_USED(MODULE_PSA_RIOT_HASHES_SHA_1) || IS_USED(MODULE_PSA_RIOT_HASHES_SHA_224) || \ - IS_USED(MODULE_PSA_RIOT_HASHES_SHA_256) + IS_USED(MODULE_PSA_RIOT_HASHES_SHA_256) || IS_USED(MODULE_PSA_RIOT_HASHES_SHA_512) #include "hashes/psa/riot_hashes.h" #endif diff --git a/sys/psa_crypto/Kconfig.hashes b/sys/psa_crypto/Kconfig.hashes index 6abf34ad9f..b4798a26a9 100644 --- a/sys/psa_crypto/Kconfig.hashes +++ b/sys/psa_crypto/Kconfig.hashes @@ -104,6 +104,10 @@ config MODULE_PSA_HASH_SHA_512_BACKEND_PERIPH depends on HAS_PERIPH_HASH_SHA_512 select MODULE_PERIPH_HASH_SHA_512 +config MODULE_PSA_HASH_SHA_512_BACKEND_RIOT + bool "RIOT hash" + select MODULE_PSA_RIOT_HASHES_SHA_512 + endchoice endif # MODULE_PSA_HASH_SHA_512 diff --git a/sys/psa_crypto/Makefile.dep b/sys/psa_crypto/Makefile.dep index be403cae6a..330c7e2981 100644 --- a/sys/psa_crypto/Makefile.dep +++ b/sys/psa_crypto/Makefile.dep @@ -221,13 +221,28 @@ endif ## SHA-512 ifneq (,$(filter psa_hash_sha_512,$(USEMODULE))) - USEMODULE += psa_hash_sha_512_backend_periph + ifeq (,$(filter psa_hash_sha_512_custom_backend,$(USEMODULE))) + FEATURES_OPTIONAL += periph_hash_sha_512 + include $(RIOTMAKE)/features_check.inc.mk + # HACK: Due to kconfig migration, may cause problems + ifneq (,$(filter periph_hash_sha_512,$(FEATURES_USED))) + USEMODULE += psa_hash_sha_512_backend_periph + else + USEMODULE += psa_hash_sha_512_backend_riot + endif + endif endif ifneq (,$(filter psa_hash_sha_512_backend_periph,$(USEMODULE))) FEATURES_REQUIRED += periph_hash_sha_512 endif +ifneq (,$(filter psa_hash_sha_512_backend_riot,$(USEMODULE))) + USEMODULE += hashes + USEMODULE += psa_riot_hashes + USEMODULE += psa_riot_hashes_sha_512 +endif + # MAC ## HMAC SHA-256 ifneq (,$(filter psa_mac_hmac_sha_256,$(USEMODULE))) diff --git a/sys/psa_crypto/Makefile.include b/sys/psa_crypto/Makefile.include index 9c64f712fd..949c294365 100644 --- a/sys/psa_crypto/Makefile.include +++ b/sys/psa_crypto/Makefile.include @@ -136,6 +136,7 @@ endif PSEUDOMODULES += psa_hash_sha_512 PSEUDOMODULES += psa_hash_sha_512_backend_periph +PSEUDOMODULES += psa_hash_sha_512_backend_riot PSEUDOMODULES += psa_hash_sha_512_custom_backend # check that one and only one backend has been selected diff --git a/sys/psa_crypto/doc.txt b/sys/psa_crypto/doc.txt index 2062405559..a3c4935fe4 100644 --- a/sys/psa_crypto/doc.txt +++ b/sys/psa_crypto/doc.txt @@ -303,6 +303,7 @@ * - psa_hash_sha_512 * - psa_hash_sha_512_backend_periph * - psa_hash_sha_512_custom_backend + * - psa_hash_sha_512_backend_riot * * ### MAC * - Base: psa_mac diff --git a/tests/unittests/Makefile.ci b/tests/unittests/Makefile.ci index ed6ba0ecec..a17c1fe8fd 100644 --- a/tests/unittests/Makefile.ci +++ b/tests/unittests/Makefile.ci @@ -1,23 +1,17 @@ BOARD_INSUFFICIENT_MEMORY := \ airfy-beacon \ - arduino-mkr1000 \ - arduino-mkrfox1200 \ - arduino-mkrwan1300 \ - arduino-mkrzero \ arduino-zero \ - atmega256rfr2-xpro \ avsextrem \ b-l072z-lrwan1 \ blackpill-stm32f103c8 \ - blackpill-stm32f103cb \ bluepill-stm32f030c8 \ bluepill-stm32f103c8 \ - bluepill-stm32f103cb \ calliope-mini \ cc1312-launchpad \ cc1350-launchpad \ cc1352-launchpad \ cc1352p-launchpad \ + cc2538dk \ cc2650-launchpad \ cc2650stk \ e104-bt5010a-tb \ @@ -27,7 +21,7 @@ BOARD_INSUFFICIENT_MEMORY := \ esp8266-esp-12x \ esp8266-olimex-mod \ esp8266-sparkfun-thing \ - feather-m0 \ + firefly \ frdm-kl43z \ hamilton \ hifive1 \ @@ -40,6 +34,7 @@ BOARD_INSUFFICIENT_MEMORY := \ lora-e5-dev \ lsn50 \ maple-mini \ + mbed_lpc1768 \ mcb2388 \ microbit \ msb-430 \ @@ -74,9 +69,14 @@ BOARD_INSUFFICIENT_MEMORY := \ olimex-msp430-h1611 \ olimex-msp430-h2618 \ olimexino-stm32 \ + omote \ opencm904 \ openlabs-kw41z-mini-256kib \ + openmote-b \ + openmote-cc2538 \ pba-d-01-kw2x \ + remote-pa \ + remote-reva \ samd10-xmini \ samd20-xpro \ samd21-xpro \ @@ -86,20 +86,12 @@ BOARD_INSUFFICIENT_MEMORY := \ samr21-xpro \ samr30-xpro \ samr34-xpro \ - seeedstudio-gd32 \ - sensebox_samd21 \ - sipeed-longan-nano \ - sipeed-longan-nano-tft \ + seeeduino_arch-pro \ slstk3400a \ slstk3401a \ sltb001a \ slwstk6000b-slwrb4150a \ slwstk6220a \ - sodaq-autonomo \ - sodaq-explorer \ - sodaq-one \ - sodaq-sara-aff \ - sodaq-sara-sff \ spark-core \ stk3200 \ stk3600 \ @@ -112,9 +104,6 @@ BOARD_INSUFFICIENT_MEMORY := \ stm32mp157c-dk2 \ teensy31 \ telosb \ - weact-f401cc \ - yarm \ yunjia-nrf51822 \ z1 \ - zigduino \ # diff --git a/tests/unittests/tests-hashes/tests-hashes-sha256.c b/tests/unittests/tests-hashes/tests-hashes-sha256.c index cd7cc8aefe..1b8ec53dbd 100644 --- a/tests/unittests/tests-hashes/tests-hashes-sha256.c +++ b/tests/unittests/tests-hashes/tests-hashes-sha256.c @@ -115,7 +115,7 @@ static const unsigned char hempty[] = 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; /** - * @brief expected hash for test failing_compare + * @brief wrong hash for test failing_compare (changed last byte from 3b to 3c) * i.e. c19d3bf8588897076873f1a0a106ba840ca46bd1179d592953acecc4df59593c */ static const unsigned char hfailing_compare[] = diff --git a/tests/unittests/tests-hashes/tests-hashes-sha512.c b/tests/unittests/tests-hashes/tests-hashes-sha512.c new file mode 100644 index 0000000000..122fa1b564 --- /dev/null +++ b/tests/unittests/tests-hashes/tests-hashes-sha512.c @@ -0,0 +1,406 @@ +/* + * Copyright (C) 2023 TU Dresden + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + + /** + * @ingroup unittests + * @{ + * + * @file + * @brief testcases for the sha512 implementation + * + * @author Mikolai Gütschow + * + * @} + */ + +#include +#include +#include +#include + +#include "embUnit/embUnit.h" + +#include "hashes/sha512.h" + +#include "tests-hashes.h" + + +/** + * @brief expected hash for test 01 + * i.e. 0f3e840daba378160173034567d6fa7373056634834c7127399871f6175ff9f5c09cb0d1af35679de6b5893ab7c800a46f121821414f4cf11c27e67630e10e99 + * + * obtained using: + * h=$(echo -n '' | sha512sum - | cut -d ' ' -f1); s=$(echo $h | sed -e 's/../0x&, /g' | sed 's/, $//'); echo $h; echo {$s}; + * + * where is the message to hash, i.e. 1234567890_1 for this test + */ +static const unsigned char h01[] = {0x0f, 0x3e, 0x84, 0x0d, 0xab, 0xa3, 0x78, 0x16, + 0x01, 0x73, 0x03, 0x45, 0x67, 0xd6, 0xfa, 0x73, + 0x73, 0x05, 0x66, 0x34, 0x83, 0x4c, 0x71, 0x27, + 0x39, 0x98, 0x71, 0xf6, 0x17, 0x5f, 0xf9, 0xf5, + 0xc0, 0x9c, 0xb0, 0xd1, 0xaf, 0x35, 0x67, 0x9d, + 0xe6, 0xb5, 0x89, 0x3a, 0xb7, 0xc8, 0x00, 0xa4, + 0x6f, 0x12, 0x18, 0x21, 0x41, 0x4f, 0x4c, 0xf1, + 0x1c, 0x27, 0xe6, 0x76, 0x30, 0xe1, 0x0e, 0x99}; +static const char *s01 = "1234567890_1"; + +/** + * @brief expected hash for test 02 + * i.e. 448e45902091177d01a402e1d31d0852899c48eaa2b331868b91afbec39a2a3413145f565336004055bbc05cfdc862732bf002bf90bc3f941ed7f6bcbc19bdc9 + */ +static const unsigned char h02[] = {0x44, 0x8e, 0x45, 0x90, 0x20, 0x91, 0x17, 0x7d, + 0x01, 0xa4, 0x02, 0xe1, 0xd3, 0x1d, 0x08, 0x52, + 0x89, 0x9c, 0x48, 0xea, 0xa2, 0xb3, 0x31, 0x86, + 0x8b, 0x91, 0xaf, 0xbe, 0xc3, 0x9a, 0x2a, 0x34, + 0x13, 0x14, 0x5f, 0x56, 0x53, 0x36, 0x00, 0x40, + 0x55, 0xbb, 0xc0, 0x5c, 0xfd, 0xc8, 0x62, 0x73, + 0x2b, 0xf0, 0x02, 0xbf, 0x90, 0xbc, 0x3f, 0x94, + 0x1e, 0xd7, 0xf6, 0xbc, 0xbc, 0x19, 0xbd, 0xc9}; +static const char *s02 = "1234567890_2"; + +/** + * @brief expected hash for test 03 + * i.e. bc92bfae4d2b2e40371e543e0b70033ca1d308e01452fcc5678ac7b20b254b09159290166e5c1f4012d5295e2057dc202a4c42bf7d4cb7229f28c5bcf18e655f + */ +static const unsigned char h03[] = {0xbc, 0x92, 0xbf, 0xae, 0x4d, 0x2b, 0x2e, 0x40, + 0x37, 0x1e, 0x54, 0x3e, 0x0b, 0x70, 0x03, 0x3c, + 0xa1, 0xd3, 0x08, 0xe0, 0x14, 0x52, 0xfc, 0xc5, + 0x67, 0x8a, 0xc7, 0xb2, 0x0b, 0x25, 0x4b, 0x09, + 0x15, 0x92, 0x90, 0x16, 0x6e, 0x5c, 0x1f, 0x40, + 0x12, 0xd5, 0x29, 0x5e, 0x20, 0x57, 0xdc, 0x20, + 0x2a, 0x4c, 0x42, 0xbf, 0x7d, 0x4c, 0xb7, 0x22, + 0x9f, 0x28, 0xc5, 0xbc, 0xf1, 0x8e, 0x65, 0x5f}; +static const char *s03 = "1234567890_3"; + +/** + * @brief expected hash for test 04 + * i.e. e9a43cf81972a22e85f1dca0b3be0b71f07ef30778ddf0eb5ae40e6d9ff1927db1d53c717f0cf43f1d99cfe360170a0a5885d2a85ac498be4f12405da4a8c79d + */ +static const unsigned char h04[] = {0xe9, 0xa4, 0x3c, 0xf8, 0x19, 0x72, 0xa2, 0x2e, + 0x85, 0xf1, 0xdc, 0xa0, 0xb3, 0xbe, 0x0b, 0x71, + 0xf0, 0x7e, 0xf3, 0x07, 0x78, 0xdd, 0xf0, 0xeb, + 0x5a, 0xe4, 0x0e, 0x6d, 0x9f, 0xf1, 0x92, 0x7d, + 0xb1, 0xd5, 0x3c, 0x71, 0x7f, 0x0c, 0xf4, 0x3f, + 0x1d, 0x99, 0xcf, 0xe3, 0x60, 0x17, 0x0a, 0x0a, + 0x58, 0x85, 0xd2, 0xa8, 0x5a, 0xc4, 0x98, 0xbe, + 0x4f, 0x12, 0x40, 0x5d, 0xa4, 0xa8, 0xc7, 0x9d}; +static const char *s04 = "1234567890_4"; + +/** + * @brief expected hash for test digits_letters + * i.e. f380afeb63f7d64018d89836c766a18f3cde99047a7fe183326d101ca9d9d4f9a5f03d77b6d542c66bcc9f46c766fe59a6a7dab300237b031a38600f463bb329 + */ +static const unsigned char hdigits_letters[] = + {0xf3, 0x80, 0xaf, 0xeb, 0x63, 0xf7, 0xd6, 0x40, + 0x18, 0xd8, 0x98, 0x36, 0xc7, 0x66, 0xa1, 0x8f, + 0x3c, 0xde, 0x99, 0x04, 0x7a, 0x7f, 0xe1, 0x83, + 0x32, 0x6d, 0x10, 0x1c, 0xa9, 0xd9, 0xd4, 0xf9, + 0xa5, 0xf0, 0x3d, 0x77, 0xb6, 0xd5, 0x42, 0xc6, + 0x6b, 0xcc, 0x9f, 0x46, 0xc7, 0x66, 0xfe, 0x59, + 0xa6, 0xa7, 0xda, 0xb3, 0x00, 0x23, 0x7b, 0x03, + 0x1a, 0x38, 0x60, 0x0f, 0x46, 0x3b, 0xb3, 0x29}; +static const char *sdigits_letters = + "0123456789abcde-0123456789abcde-0123456789abcde-0123456789abcde-"; + +/** + * @brief expected hash for test pangramm + * i.e. af9ed2de700433b803240a552b41b5a472a6ef3fe1431a722b2063c75e9f07451f67a28e37d09cde769424c96aea6f8971389db9e1993d6c565c3c71b855723c + */ +static const unsigned char hpangramm[] = + {0xaf, 0x9e, 0xd2, 0xde, 0x70, 0x04, 0x33, 0xb8, + 0x03, 0x24, 0x0a, 0x55, 0x2b, 0x41, 0xb5, 0xa4, + 0x72, 0xa6, 0xef, 0x3f, 0xe1, 0x43, 0x1a, 0x72, + 0x2b, 0x20, 0x63, 0xc7, 0x5e, 0x9f, 0x07, 0x45, + 0x1f, 0x67, 0xa2, 0x8e, 0x37, 0xd0, 0x9c, 0xde, + 0x76, 0x94, 0x24, 0xc9, 0x6a, 0xea, 0x6f, 0x89, + 0x71, 0x38, 0x9d, 0xb9, 0xe1, 0x99, 0x3d, 0x6c, + 0x56, 0x5c, 0x3c, 0x71, 0xb8, 0x55, 0x72, 0x3c}; +static const char *spangramm = "Franz jagt im komplett verwahrlosten Taxi quer durch Bayern"; + +/** + * @brief expected hash for test pangramm_no_more + * i.e. 90b30ef9902ae4c4c691d2d78c2f8fa0aa785afbc5545286b310f68e91dd2299c84a2484f0419fc5eaa7de598940799e1091c4948926ae1c9488dddae180bb80 + */ +static const unsigned char hpangramm_no_more[] = + {0x90, 0xb3, 0x0e, 0xf9, 0x90, 0x2a, 0xe4, 0xc4, + 0xc6, 0x91, 0xd2, 0xd7, 0x8c, 0x2f, 0x8f, 0xa0, + 0xaa, 0x78, 0x5a, 0xfb, 0xc5, 0x54, 0x52, 0x86, + 0xb3, 0x10, 0xf6, 0x8e, 0x91, 0xdd, 0x22, 0x99, + 0xc8, 0x4a, 0x24, 0x84, 0xf0, 0x41, 0x9f, 0xc5, + 0xea, 0xa7, 0xde, 0x59, 0x89, 0x40, 0x79, 0x9e, + 0x10, 0x91, 0xc4, 0x94, 0x89, 0x26, 0xae, 0x1c, + 0x94, 0x88, 0xdd, 0xda, 0xe1, 0x80, 0xbb, 0x80}; +/* exchanged `z` with `k` of the first word `Fran[z|k]` */ +static const char *spangramm_no_more = "Frank jagt im komplett verwahrlosten Taxi quer durch Bayern"; + +/** + * @brief expected hash for test empty + * i.e. cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e + */ +static const unsigned char hempty[] = + {0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, + 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, + 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, + 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, + 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, + 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, + 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, + 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e}; +static const char *sempty = ""; + +/** + * @brief wrong hash for test failing_compare (changed last byte from a4 to a5) + * i.e. 2dfe3483a0ca0bfb78c0928832bd6854eb0b18963ba24d7d2c9dcd8ec0403bc4d4201f3006d9d235189f657af978b613ea3324bfb7a9d748933980ded86c93a5 + */ +static const unsigned char hfailing_compare[] = + {0x2d, 0xfe, 0x34, 0x83, 0xa0, 0xca, 0x0b, 0xfb, + 0x78, 0xc0, 0x92, 0x88, 0x32, 0xbd, 0x68, 0x54, + 0xeb, 0x0b, 0x18, 0x96, 0x3b, 0xa2, 0x4d, 0x7d, + 0x2c, 0x9d, 0xcd, 0x8e, 0xc0, 0x40, 0x3b, 0xc4, + 0xd4, 0x20, 0x1f, 0x30, 0x06, 0xd9, 0xd2, 0x35, + 0x18, 0x9f, 0x65, 0x7a, 0xf9, 0x78, 0xb6, 0x13, + 0xea, 0x33, 0x24, 0xbf, 0xb7, 0xa9, 0xd7, 0x48, + 0x93, 0x39, 0x80, 0xde, 0xd8, 0x6c, 0x93, 0xa5}; +static const char *sfailing_compare = "This test fails!"; + +/** + * @brief expected hash for test long_sequence + * i.e. 21185dd187d8b7d32d36419260bc65e03294f393aa24c4caf528d664f1cd07a1cc77d63baaa351e156b3f40ca1899121e6dcb0ced8672e1b36c45ec252002a8f + */ +static const unsigned char hlong_sequence[] = + {0x21, 0x18, 0x5d, 0xd1, 0x87, 0xd8, 0xb7, 0xd3, + 0x2d, 0x36, 0x41, 0x92, 0x60, 0xbc, 0x65, 0xe0, + 0x32, 0x94, 0xf3, 0x93, 0xaa, 0x24, 0xc4, 0xca, + 0xf5, 0x28, 0xd6, 0x64, 0xf1, 0xcd, 0x07, 0xa1, + 0xcc, 0x77, 0xd6, 0x3b, 0xaa, 0xa3, 0x51, 0xe1, + 0x56, 0xb3, 0xf4, 0x0c, 0xa1, 0x89, 0x91, 0x21, + 0xe6, 0xdc, 0xb0, 0xce, 0xd8, 0x67, 0x2e, 0x1b, + 0x36, 0xc4, 0x5e, 0xc2, 0x52, 0x00, 0x2a, 0x8f}; +static const char *slong_sequence = + {"RIOT is an open-source microkernel-based operating system, designed" + " to match the requirements of Internet of Things (IoT) devices and" + " other embedded devices. These requirements include a very low memory" + " footprint (on the order of a few kilobytes), high energy efficiency" + ", real-time capabilities, communication stacks for both wireless and" + " wired networks, and support for a wide range of low-power hardware."}; + +/** + * @brief expected hash for "abc" + * (from FIPS 180-2 Appendix C.1) + */ +static const unsigned char h_fips_oneblock[] = + {0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, + 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, + 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, + 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, + 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, + 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, + 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, + 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f}; +static const char *s_fips_oneblock = "abc"; + +/** + * @brief expected hash for "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + * (from FIPS 180-2 Appendix C.2) + */ +static const unsigned char h_fips_multiblock[] = + {0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, + 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f, + 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, + 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, + 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, + 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a, + 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, + 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09}; +static const char *s_fips_multiblock = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklm" + "ghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; + +/** + * @brief expected hash for { 0xC0, 0xFF, 0xEE } + * i.e. d6f3d166b443b394f2505c48a5c6904c682d5a6fbe360d6c337a98f7ea6675f195157b33f599b600e39783c72024f91b4718651b4cfd08afcf6c06b9cdb6508c + * + * obtained using: + * h=$(printf '\xc0\xff\xee' | sha512sum - | cut -d ' ' -f1); s=$(echo $h | sed -e 's/../0x&, /g' | sed 's/, $//'); echo $h; echo {$s}; + */ +static const unsigned char h_coffee[] = + {0xd6, 0xf3, 0xd1, 0x66, 0xb4, 0x43, 0xb3, 0x94, + 0xf2, 0x50, 0x5c, 0x48, 0xa5, 0xc6, 0x90, 0x4c, + 0x68, 0x2d, 0x5a, 0x6f, 0xbe, 0x36, 0x0d, 0x6c, + 0x33, 0x7a, 0x98, 0xf7, 0xea, 0x66, 0x75, 0xf1, + 0x95, 0x15, 0x7b, 0x33, 0xf5, 0x99, 0xb6, 0x00, + 0xe3, 0x97, 0x83, 0xc7, 0x20, 0x24, 0xf9, 0x1b, + 0x47, 0x18, 0x65, 0x1b, 0x4c, 0xfd, 0x08, 0xaf, + 0xcf, 0x6c, 0x06, 0xb9, 0xcd, 0xb6, 0x50, 0x8c}; +static const uint8_t s_coffe[] = { 0xC0, 0xFF, 0xEE }; + +static int calc_and_compare_hash(const char *str, const unsigned char *expected) +{ + static unsigned char hash[SHA512_DIGEST_LENGTH]; + sha512_context_t sha512; + + sha512_init(&sha512); + sha512_update(&sha512, (uint8_t*)str, strlen(str)); + sha512_final(&sha512, hash); + + return (memcmp(expected, hash, SHA512_DIGEST_LENGTH) == 0); +} + +static int calc_and_compare_hash_wrapper(const char *str, const unsigned char *expected) +{ + static unsigned char hash[SHA512_DIGEST_LENGTH]; + + sha512((uint8_t*)str, strlen(str), hash); + + return (memcmp(expected, hash, SHA512_DIGEST_LENGTH) == 0); +} + +static void test_hashes_sha512_hash_sequence_01(void) +{ + TEST_ASSERT(calc_and_compare_hash(s01, h01)); + TEST_ASSERT(calc_and_compare_hash_wrapper(s01, h01)); +} + +static void test_hashes_sha512_hash_sequence_02(void) +{ + TEST_ASSERT(calc_and_compare_hash(s02, h02)); + TEST_ASSERT(calc_and_compare_hash_wrapper(s02, h02)); +} + +static void test_hashes_sha512_hash_sequence_03(void) +{ + TEST_ASSERT(calc_and_compare_hash(s03, h03)); + TEST_ASSERT(calc_and_compare_hash_wrapper(s03, h03)); +} + +static void test_hashes_sha512_hash_sequence_04(void) +{ + TEST_ASSERT(calc_and_compare_hash(s04, h04)); + TEST_ASSERT(calc_and_compare_hash_wrapper(s04, h04)); +} + +static void test_hashes_sha512_hash_sequence_digits_letters(void) +{ + TEST_ASSERT(calc_and_compare_hash(sdigits_letters, hdigits_letters)); + TEST_ASSERT(calc_and_compare_hash_wrapper(sdigits_letters, hdigits_letters)); +} + +static void test_hashes_sha512_hash_sequence_pangramm(void) +{ + TEST_ASSERT(calc_and_compare_hash(spangramm, hpangramm)); + TEST_ASSERT(calc_and_compare_hash_wrapper(spangramm, hpangramm)); +} + +static void test_hashes_sha512_hash_sequence_pangramm_no_more(void) +{ + TEST_ASSERT(calc_and_compare_hash(spangramm_no_more, hpangramm_no_more)); + TEST_ASSERT(calc_and_compare_hash_wrapper(spangramm_no_more, hpangramm_no_more)); +} + +static void test_hashes_sha512_hash_sequence_empty(void) +{ + TEST_ASSERT(calc_and_compare_hash(sempty, hempty)); + TEST_ASSERT(calc_and_compare_hash_wrapper(sempty, hempty)); +} + +static void test_hashes_sha512_hash_sequence_failing_compare(void) +{ + /* failing compare (switched last byte of expected hash from `a4` to `a5`) */ + TEST_ASSERT(!calc_and_compare_hash(sfailing_compare, hfailing_compare)); + TEST_ASSERT(!calc_and_compare_hash_wrapper(sfailing_compare, hfailing_compare)); +} + +static void test_hashes_sha512_hash_long_sequence(void) +{ + TEST_ASSERT(calc_and_compare_hash(slong_sequence, hlong_sequence)); + TEST_ASSERT(calc_and_compare_hash_wrapper(slong_sequence, hlong_sequence)); +} + +static void test_hashes_sha512_hash_sequence_abc(void) +{ + TEST_ASSERT(calc_and_compare_hash(s_fips_oneblock, h_fips_oneblock)); + TEST_ASSERT(calc_and_compare_hash_wrapper(s_fips_oneblock, h_fips_oneblock)); +} + +static void test_hashes_sha512_hash_sequence_abc_long(void) +{ + TEST_ASSERT(calc_and_compare_hash(s_fips_multiblock, h_fips_multiblock)); + TEST_ASSERT(calc_and_compare_hash_wrapper(s_fips_multiblock, h_fips_multiblock)); +} + +static void test_hashes_sha512_hash_sequence_binary(void) +{ + static uint8_t hash[SHA512_DIGEST_LENGTH]; + sha512(s_coffe, sizeof(s_coffe), hash); + TEST_ASSERT(memcmp(h_coffee, hash, SHA512_DIGEST_LENGTH) == 0); +} + +static void test_hashes_sha512_hash_update_twice(void) +{ + static const char *teststring = "abcdef"; + + static uint8_t hash_update_once[SHA512_DIGEST_LENGTH]; + static uint8_t hash_update_twice[SHA512_DIGEST_LENGTH]; + sha512_context_t sha512; + + sha512_init(&sha512); + sha512_update(&sha512, (uint8_t*)teststring, sizeof(teststring)); + sha512_final(&sha512, hash_update_once); + + sha512_init(&sha512); + sha512_update(&sha512, (uint8_t*)teststring, 3); + sha512_update(&sha512, (uint8_t*)&teststring[3], sizeof(teststring)-3); + sha512_final(&sha512, hash_update_twice); + + TEST_ASSERT(memcmp(hash_update_once, hash_update_twice, SHA512_DIGEST_LENGTH) == 0); +} + +static void test_hashes_sha512_hash_clear_ctx(void) +{ + static uint8_t hash[SHA512_DIGEST_LENGTH]; + sha512_context_t sha512; + + sha512_init(&sha512); + sha512_update(&sha512, sempty, strlen(sempty)); + sha512_final(&sha512, hash); + + TEST_ASSERT(memcmp(hempty, hash, SHA512_DIGEST_LENGTH) == 0); + for (size_t i=0; i