diff --git a/Makefile.inc b/Makefile.inc index 295414f..aebe6b1 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -1,8 +1,8 @@ LC_SRCS+= aead.c aead_chacha20_poly1305.c LC_SRCS+= auth.c auth_hmac.c auth_poly1305.c LC_SRCS+= cipher.c cipher_chacha20.c -LC_SRCS+= hash.c hash_sha384_sha512.c -LC_SRCS+= impl_chacha20.c impl_poly1305.c impl_sha512.c +LC_SRCS+= hash.c hash_sha224_sha256.c hash_sha384_sha512.c +LC_SRCS+= impl_chacha20.c impl_poly1305.c impl_sha256.c impl_sha512.c LC_SRCS+= ct.c util.c WARNINGS= Yes diff --git a/README b/README index 1dde5c5..38feed5 100644 --- a/README +++ b/README @@ -20,6 +20,8 @@ Utilities Hash ---- +- [x] SHA-224 +- [x] SHA-256 - [x] SHA-384 - [x] SHA-512 (needed for Ed25519) @@ -61,7 +63,6 @@ Utilities Hash ---- -- [ ] SHA-256 & SHA-224 (the latter is a truncated form of the former) - [ ] SHA-512/224 & SHA-512/256 (most of the work done) Authentication diff --git a/auth_hmac.c b/auth_hmac.c index 4c300bd..1c39444 100644 --- a/auth_hmac.c +++ b/auth_hmac.c @@ -21,6 +21,7 @@ #include "hash.h" #include "auth_hmac.h" #include "impl_hmac.h" +#include "impl_sha256.h" #include "impl_sha512.h" #include "util.h" @@ -57,6 +58,16 @@ hmac_common_init(void *arg, const uint8_t *key, size_t keylen) lc_hash_update(ctx->hctx, ikeypad, ctx->blocksz); } +int +hmac_sha224_sha256_init(void *arg, const uint8_t *key, size_t keylen) +{ + struct hmac_ctx *ctx = arg; + + ctx->blocksz = SHA256_CHUNK; + + return hmac_common_init(ctx, key, keylen); +} + int hmac_sha384_sha512_init(void *arg, const uint8_t *key, size_t keylen) { @@ -124,6 +135,18 @@ hmac_common_ctx_new(const struct lc_hash_impl *impl) return ctx; } +static void * +hmac_sha224_ctx_new(void) +{ + return hmac_common_ctx_new(lc_hash_impl_sha224()); +} + +static void * +hmac_sha256_ctx_new(void) +{ + return hmac_common_ctx_new(lc_hash_impl_sha256()); +} + static void * hmac_sha384_ctx_new(void) { @@ -146,6 +169,26 @@ hmac_ctx_free(void *arg) } +static struct lc_auth_impl hmac_sha224_impl = { + .init = &hmac_sha224_sha256_init, + .update = &hmac_update, + .final = &hmac_final, + .auth = NULL, + + .ctx_new = &hmac_sha224_ctx_new, + .ctx_free = &hmac_ctx_free, +}; + +static struct lc_auth_impl hmac_sha256_impl = { + .init = &hmac_sha224_sha256_init, + .update = &hmac_update, + .final = &hmac_final, + .auth = NULL, + + .ctx_new = &hmac_sha256_ctx_new, + .ctx_free = &hmac_ctx_free, +}; + static struct lc_auth_impl hmac_sha384_impl = { .init = &hmac_sha384_sha512_init, .update = &hmac_update, @@ -166,6 +209,18 @@ static struct lc_auth_impl hmac_sha512_impl = { .ctx_free = &hmac_ctx_free, }; +const struct lc_auth_impl * +lc_auth_impl_hmac_sha224(void) +{ + return &hmac_sha224_impl; +} + +const struct lc_auth_impl * +lc_auth_impl_hmac_sha256(void) +{ + return &hmac_sha256_impl; +} + const struct lc_auth_impl * lc_auth_impl_hmac_sha384(void) { diff --git a/auth_hmac.h b/auth_hmac.h index f5424cd..f6707e9 100644 --- a/auth_hmac.h +++ b/auth_hmac.h @@ -18,6 +18,7 @@ #include +int hmac_sha224_sha256_init(void *, const uint8_t *, size_t); int hmac_sha384_sha512_init(void *, const uint8_t *, size_t); int hmac_update(void *, const uint8_t *, size_t); int hmac_final(void *, uint8_t *, size_t *); diff --git a/hash_sha224_sha256.c b/hash_sha224_sha256.c new file mode 100644 index 0000000..c4da1b6 --- /dev/null +++ b/hash_sha224_sha256.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2024 Lucas Gabriel Vuotto + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "lilcrypto.h" +#include "hash.h" +#include "hash_sha224_sha256.h" +#include "impl_sha256.h" + +#include "util.h" + + +/* + * SHA-224 and SHA-256 implementations. + * + * This implementation doesn't support arbitrary amounts of bits, but only full + * bytes sizes. In particular, size is stored in bytes until the length has to + * be appended to the input. This is done to simplify overflow checks for input + * length. + */ + + +#define SHA256_SZ_MAX UINT32_C(0x1fffffff) /* 2^29 - 1 */ + +#define SHA224_H0_0 UINT32_C(0xc1059ed8) +#define SHA224_H0_1 UINT32_C(0x367cd507) +#define SHA224_H0_2 UINT32_C(0x3070dd17) +#define SHA224_H0_3 UINT32_C(0xf70e5939) +#define SHA224_H0_4 UINT32_C(0xffc00b31) +#define SHA224_H0_5 UINT32_C(0x68581511) +#define SHA224_H0_6 UINT32_C(0x64f98fa7) +#define SHA224_H0_7 UINT32_C(0xbefa4fa4) + +#define SHA256_H0_0 UINT32_C(0x6a09e667) +#define SHA256_H0_1 UINT32_C(0xbb67ae85) +#define SHA256_H0_2 UINT32_C(0x3c6ef372) +#define SHA256_H0_3 UINT32_C(0xa54ff53a) +#define SHA256_H0_4 UINT32_C(0x510e527f) +#define SHA256_H0_5 UINT32_C(0x9b05688c) +#define SHA256_H0_6 UINT32_C(0x1f83d9ab) +#define SHA256_H0_7 UINT32_C(0x5be0cd19) + + +int +sha224_init(void *arg) +{ + struct sha256_ctx *ctx = arg; + size_t i; + + ctx->h0 = SHA224_H0_0; + ctx->h1 = SHA224_H0_1; + ctx->h2 = SHA224_H0_2; + ctx->h3 = SHA224_H0_3; + ctx->h4 = SHA224_H0_4; + ctx->h5 = SHA224_H0_5; + ctx->h6 = SHA224_H0_6; + ctx->h7 = SHA224_H0_7; + + ctx->sz = 0; + + ctx->mlen = 0; + for (i = 0; i < SHA256_CHUNK; i++) + ctx->m[i] = 0; + + return 1; +} + +int +sha256_init(void *arg) +{ + struct sha256_ctx *ctx = arg; + size_t i; + + ctx->h0 = SHA256_H0_0; + ctx->h1 = SHA256_H0_1; + ctx->h2 = SHA256_H0_2; + ctx->h3 = SHA256_H0_3; + ctx->h4 = SHA256_H0_4; + ctx->h5 = SHA256_H0_5; + ctx->h6 = SHA256_H0_6; + ctx->h7 = SHA256_H0_7; + + ctx->sz = 0; + + ctx->mlen = 0; + for (i = 0; i < SHA256_CHUNK; i++) + ctx->m[i] = 0; + + return 1; +} + +static int +sha224_sha256_update(void *arg, const uint8_t *in, size_t inlen) +{ + struct sha256_ctx *ctx = arg; + size_t i; + + if (inlen > SHA256_SZ_MAX - ctx->sz) + return 0; + ctx->sz += inlen; + + for (i = 0; i + ctx->mlen < SHA256_CHUNK && i < inlen; i++) + ctx->m[i + ctx->mlen] = in[i]; + ctx->mlen += i; + in += i; + inlen -= i; + + if (ctx->mlen == SHA256_CHUNK) { + sha256_block(ctx); + ctx->mlen = 0; + } + + if (inlen == 0) + return 1; + + while (inlen >= SHA256_CHUNK) { + for (i = 0; i < SHA256_CHUNK; i++) + ctx->m[i] = in[i]; + in += i; + inlen -= i; + + sha256_block(ctx); + } + + for (i = 0; i < inlen; i++) + ctx->m[i] = in[i]; + ctx->mlen = inlen; + + return 1; +} + +int +sha224_update(void *arg, const uint8_t *in, size_t inlen) +{ + return sha224_sha256_update(arg, in, inlen); +} + +int +sha256_update(void *arg, const uint8_t *in, size_t inlen) +{ + return sha224_sha256_update(arg, in, inlen); +} + +static void +sha224_sha256_final(struct sha256_ctx *ctx) +{ + size_t i, mlen; + + mlen = ctx->mlen; + ctx->m[mlen++] = 0x80; + + if (mlen >= SHA256_CHUNK - sizeof(uint64_t)) { + for (i = mlen; i < SHA256_CHUNK; i++) + ctx->m[i] = 0; + sha256_block(ctx); + mlen = 0; + } + + for (i = mlen; i < SHA256_CHUNK - sizeof(uint64_t); i++) + ctx->m[i] = 0; + store64be(&ctx->m[i], ctx->sz << 3); + sha256_block(ctx); +} + +int +sha224_final(void *arg, uint8_t *out, size_t *outlen) +{ + struct sha256_ctx *ctx = arg; + + *outlen = LC_SHA224_HASHLEN; + if (out == NULL) + return 1; + + sha224_sha256_final(ctx); + store32be(out, ctx->h0); + store32be(out + 4, ctx->h1); + store32be(out + 8, ctx->h2); + store32be(out + 12, ctx->h3); + store32be(out + 16, ctx->h4); + store32be(out + 20, ctx->h5); + store32be(out + 24, ctx->h6); + + lc_scrub(ctx, sizeof(*ctx)); + + return 1; +} + +int +sha256_final(void *arg, uint8_t *out, size_t *outlen) +{ + struct sha256_ctx *ctx = arg; + + *outlen = LC_SHA256_HASHLEN; + if (out == NULL) + return 1; + + sha224_sha256_final(ctx); + store32be(out, ctx->h0); + store32be(out + 4, ctx->h1); + store32be(out + 8, ctx->h2); + store32be(out + 12, ctx->h3); + store32be(out + 16, ctx->h4); + store32be(out + 20, ctx->h5); + store32be(out + 24, ctx->h6); + store32be(out + 28, ctx->h7); + + lc_scrub(ctx, sizeof(*ctx)); + + return 1; +} + +static int +sha224_hash(uint8_t *out, size_t *outlen, const uint8_t *in, size_t inlen) +{ + struct sha256_ctx ctx; + + if (out == NULL) { + *outlen = LC_SHA224_HASHLEN; + return 1; + } + + return sha224_init(&ctx) && + sha224_update(&ctx, in, inlen) && + sha224_final(&ctx, out, outlen); +} + +static int +sha256_hash(uint8_t *out, size_t *outlen, const uint8_t *in, size_t inlen) +{ + struct sha256_ctx ctx; + + if (out == NULL) { + *outlen = LC_SHA256_HASHLEN; + return 1; + } + + return sha256_init(&ctx) && + sha256_update(&ctx, in, inlen) && + sha256_final(&ctx, out, outlen); +} + +static void * +sha224_sha256_ctx_new(void) +{ + return malloc(sizeof(struct sha256_ctx)); +} + + +static struct lc_hash_impl sha224_impl = { + .init = &sha224_init, + .update = &sha224_update, + .final = &sha224_final, + .hash = &sha224_hash, + + .ctx_new = &sha224_sha256_ctx_new, + .ctx_free = NULL, +}; + +static struct lc_hash_impl sha256_impl = { + .init = &sha256_init, + .update = &sha256_update, + .final = &sha256_final, + .hash = &sha256_hash, + + .ctx_new = &sha224_sha256_ctx_new, + .ctx_free = NULL, +}; + +const struct lc_hash_impl * +lc_hash_impl_sha224(void) +{ + return &sha224_impl; +} + +const struct lc_hash_impl * +lc_hash_impl_sha256(void) +{ + return &sha256_impl; +} diff --git a/hash_sha224_sha256.h b/hash_sha224_sha256.h new file mode 100644 index 0000000..57ac424 --- /dev/null +++ b/hash_sha224_sha256.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Lucas Gabriel Vuotto + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + + +int sha224_init(void *); +int sha224_update(void *, const uint8_t *, size_t); +int sha224_final(void *, uint8_t *, size_t *); + +int sha256_init(void *); +int sha256_update(void *, const uint8_t *, size_t); +int sha256_final(void *, uint8_t *, size_t *); diff --git a/impl_sha256.c b/impl_sha256.c new file mode 100644 index 0000000..f48bd9a --- /dev/null +++ b/impl_sha256.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024 Lucas Gabriel Vuotto + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include "impl_sha256.h" +#include "util.h" + + +static const uint32_t K[SHA256_ROUNDS] = { + 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, +}; + +#define CH(x, y, z) ((x & y) ^ (~x & z)) +#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) +#define BSIG0(x) (rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22)) +#define BSIG1(x) (rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25)) +#define SSIG0(x) (rotr32(x, 7) ^ rotr32(x, 18) ^ (x >> 3)) +#define SSIG1(x) (rotr32(x, 17) ^ rotr32(x, 19) ^ (x >> 10)) + +void +sha256_block(struct sha256_ctx *ctx) +{ + uint32_t m[SHA256_CHUNK_WORDS], W[SHA256_ROUNDS]; + uint32_t a, b, c, d, e, f, g, h, T1, T2; + size_t i; + + for (i = 0; i < SHA256_CHUNK_WORDS; i++) + W[i] = m[i] = load32be(&ctx->m[i * 4]); + for (; i < SHA256_ROUNDS; i++) + W[i] = SSIG1(W[i - 2]) + W[i - 7] + SSIG0(W[i - 15]) + + W[i - 16]; + + a = ctx->h0; + b = ctx->h1; + c = ctx->h2; + d = ctx->h3; + e = ctx->h4; + f = ctx->h5; + g = ctx->h6; + h = ctx->h7; + + for (i = 0; i < SHA256_ROUNDS; i++) { + T1 = h + BSIG1(e) + CH(e, f, g) + K[i] + W[i]; + T2 = BSIG0(a) + MAJ(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + } + + ctx->h0 += a; + ctx->h1 += b; + ctx->h2 += c; + ctx->h3 += d; + ctx->h4 += e; + ctx->h5 += f; + ctx->h6 += g; + ctx->h7 += h; +} diff --git a/impl_sha256.h b/impl_sha256.h new file mode 100644 index 0000000..d9db590 --- /dev/null +++ b/impl_sha256.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Lucas Gabriel Vuotto + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include "lilcrypto.h" + + +#define SHA256_CHUNK 64 +#define SHA256_CHUNK_WORDS (SHA256_CHUNK / sizeof(uint32_t)) +#define SHA256_ROUNDS 64 + + +struct sha256_ctx { + uint32_t h0, h1, h2, h3, h4, h5, h6, h7; + uint64_t sz; + size_t mlen; + uint8_t m[SHA256_CHUNK]; +}; + + +void sha256_block(struct sha256_ctx *); diff --git a/lilcrypto.h b/lilcrypto.h index 0c81bdd..f0f3268 100644 --- a/lilcrypto.h +++ b/lilcrypto.h @@ -24,6 +24,8 @@ */ /* Hashes. */ +#define LC_SHA224_HASHLEN 28 +#define LC_SHA256_HASHLEN 32 #define LC_SHA384_HASHLEN 48 #define LC_SHA512_HASHLEN 64 @@ -62,6 +64,8 @@ int lc_hash(const struct lc_hash_impl *, uint8_t *, size_t *, struct lc_hash_ctx *lc_hash_ctx_new(const struct lc_hash_impl *); void lc_hash_ctx_free(struct lc_hash_ctx *); +const struct lc_hash_impl *lc_hash_impl_sha224(void); +const struct lc_hash_impl *lc_hash_impl_sha256(void); const struct lc_hash_impl *lc_hash_impl_sha384(void); const struct lc_hash_impl *lc_hash_impl_sha512(void); @@ -84,6 +88,8 @@ struct lc_auth_ctx *lc_auth_ctx_new(const struct lc_auth_impl *); void lc_auth_ctx_free(struct lc_auth_ctx *); const struct lc_auth_impl *lc_auth_impl_poly1305(void); +const struct lc_auth_impl *lc_auth_impl_hmac_sha224(void); +const struct lc_auth_impl *lc_auth_impl_hmac_sha256(void); const struct lc_auth_impl *lc_auth_impl_hmac_sha384(void); const struct lc_auth_impl *lc_auth_impl_hmac_sha512(void); diff --git a/wycheproof/Makefile b/wycheproof/Makefile index d7b3f98..706e95e 100644 --- a/wycheproof/Makefile +++ b/wycheproof/Makefile @@ -33,6 +33,10 @@ tests-mac: .endif .for p in ${MAC} perl ${.CURDIR}/mac.pl ${TESTOPTS} -x ./${p} \ + ${WYCHEPROOF_DIR}/testvectors/hmac_sha224_test.json \ + ${WYCHEPROOF_DIR}/testvectors_v1/hmac_sha224_test.json \ + ${WYCHEPROOF_DIR}/testvectors/hmac_sha256_test.json \ + ${WYCHEPROOF_DIR}/testvectors_v1/hmac_sha256_test.json \ ${WYCHEPROOF_DIR}/testvectors/hmac_sha384_test.json \ ${WYCHEPROOF_DIR}/testvectors_v1/hmac_sha384_test.json \ ${WYCHEPROOF_DIR}/testvectors/hmac_sha512_test.json \ diff --git a/wycheproof_mac.c b/wycheproof_mac.c index d4a0227..f2c006c 100644 --- a/wycheproof_mac.c +++ b/wycheproof_mac.c @@ -79,6 +79,8 @@ kw2impl(const char *s) { /* Needs to be sorted. */ static const struct kwimpl tbl[] = { + { "HMACSHA224", &lc_auth_impl_hmac_sha224 }, + { "HMACSHA256", &lc_auth_impl_hmac_sha256 }, { "HMACSHA384", &lc_auth_impl_hmac_sha384 }, { "HMACSHA512", &lc_auth_impl_hmac_sha512 }, };