summaryrefslogtreecommitdiff
path: root/board/cr50/dcrypto/hmacsha2.h
diff options
context:
space:
mode:
authorVadim Sukhomlinov <sukhomlinov@google.com>2021-07-30 08:40:32 -0700
committerCommit Bot <commit-bot@chromium.org>2021-08-12 14:18:48 +0000
commit7ddbd2a9eab0dc54897d6b5bb8ee1d4b3be1fe27 (patch)
tree43356bb71d38ea7f5ea1639855ac3b322d460176 /board/cr50/dcrypto/hmacsha2.h
parent43f6e7be087720507e57cf27e9460aae64c3b69a (diff)
downloadchrome-ec-7ddbd2a9eab0dc54897d6b5bb8ee1d4b3be1fe27.tar.gz
To implement FIPS module we need to bring many crypto functions in the module boundary. Unfortunately, cryptoc is a third-party library used by dcrypto code in cr50. Cryptoc is also not well-maintained and shared with other projects. While just making local copy of cryptoc would solve an issue, it's suboptimal as prevents from many optimizations and improvements. Provided SHA & HMAC implementations from Ti50 project. This provides better performance (500us vs. 670us earlier for HMAC DRBG) and reduce code size. This implementation also enables stack use savings when only specific digest is needed. Earlier SHA512 context was allocated when only SHA256 is needed greatly increasing stack consumption for code using HMAC_DRBG and others. However, it introduce subtle API changes which require handling. As for tests, since core implementation is hardware-independent, make it available for BOARD=host too. Before change (with cryptoc): *** 12368 bytes in flash and 5784 bytes in RAM After: *** 13136 bytes in flash and 5796 bytes in RAM BUG=b:138578318 TEST=make BOARD=cr50 CRYPTO_TEST=1; test/tpm_test/tpmtest.py Signed-off-by: Vadim Sukhomlinov <sukhomlinov@google.com> Change-Id: I2ff5362aee9078ce83dc1f8081943a5101d5f666 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3064201 Reviewed-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Reviewed-by: Andrey Pronin <apronin@chromium.org> Tested-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Auto-Submit: Vadim Sukhomlinov <sukhomlinov@chromium.org> Commit-Queue: Vadim Sukhomlinov <sukhomlinov@chromium.org>
Diffstat (limited to 'board/cr50/dcrypto/hmacsha2.h')
-rw-r--r--board/cr50/dcrypto/hmacsha2.h490
1 files changed, 490 insertions, 0 deletions
diff --git a/board/cr50/dcrypto/hmacsha2.h b/board/cr50/dcrypto/hmacsha2.h
new file mode 100644
index 0000000000..6d9c842c1e
--- /dev/null
+++ b/board/cr50/dcrypto/hmacsha2.h
@@ -0,0 +1,490 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#pragma once
+#include "common.h"
+
+#define SHA1_DIGEST_SIZE 20
+#define SHA_DIGEST_SIZE SHA1_DIGEST_SIZE
+
+#define SHA224_DIGEST_SIZE 28
+#define SHA256_DIGEST_SIZE 32
+#define SHA1_BLOCK_SIZE 64
+#define SHA1_BLOCK_WORDS (SHA1_BLOCK_SIZE / sizeof(uint32_t))
+#define SHA1_BLOCK_DWORDS (SHA1_BLOCK_SIZE / sizeof(uint64_t))
+#define SHA1_DIGEST_WORDS (SHA1_DIGEST_SIZE / sizeof(uint32_t))
+#define SHA224_BLOCK_SIZE 64
+#define SHA224_BLOCK_WORDS (SHA224_BLOCK_SIZE / sizeof(uint32_t))
+#define SHA224_BLOCK_DWORDS (SHA224_BLOCK_SIZE / sizeof(uint64_t))
+#define SHA224_DIGEST_WORDS (SHA224_DIGEST_SIZE / sizeof(uint32_t))
+#define SHA256_BLOCK_SIZE 64
+#define SHA256_BLOCK_WORDS (SHA256_BLOCK_SIZE / sizeof(uint32_t))
+#define SHA256_BLOCK_DWORDS (SHA256_BLOCK_SIZE / sizeof(uint64_t))
+#define SHA256_DIGEST_WORDS (SHA256_DIGEST_SIZE / sizeof(uint32_t))
+
+/**
+ * Hash contexts. Each context starts with pointer to vtable containing
+ * functions to perform implementation specific operations.
+ * It is designed to support both software and hardware implementations.
+ * Contexts for different digest types can overlap, but vtable stores
+ * actual size of context which enables stack-efficient implementation of
+ * HMAC - say HMAC SHA2-256 shouldn't reserve space as for HMAC SHA2-512.
+ */
+union hash_ctx; /* forward declaration of generic hash context type */
+union hmac_ctx; /* forward declaration of generic HMAC context type */
+
+union sha_digests; /* forward declaration of generic digest type */
+
+/* Combined HASH & HMAC vtable to support SW & HW implementations. */
+struct hash_vtable {
+ /* SHA init function, used primarily by SW HMAC implementation. */
+ void (*const init)(union hash_ctx *const);
+ /* Update function for SHA & HMAC, assuming it's the same. */
+ void (*const update)(union hash_ctx *const, const void *, size_t);
+ /* SHA final function, digest specific. */
+ const union sha_digests *(*const final)(union hash_ctx *const);
+
+ /* HW HMAC support may require special ending. */
+ const union sha_digests *(*const hmac_final)(union hmac_ctx *const);
+
+ /* Digest size of in bytes. */
+ size_t digest_size;
+
+ /* Digest block size in bytes. */
+ size_t block_size;
+
+ /* Offset of first byte after context, used for HMAC */
+ size_t context_size;
+};
+
+struct sha256_digest {
+ union {
+ uint8_t b8[SHA256_DIGEST_SIZE];
+ uint32_t b32[SHA256_DIGEST_WORDS];
+ };
+};
+BUILD_ASSERT(sizeof(struct sha256_digest) == SHA256_DIGEST_SIZE);
+
+struct sha224_digest {
+ union {
+ uint8_t b8[SHA224_DIGEST_SIZE];
+ uint32_t b32[SHA224_DIGEST_WORDS];
+ };
+};
+BUILD_ASSERT(sizeof(struct sha224_digest) == SHA224_DIGEST_SIZE);
+
+struct sha1_digest {
+ union {
+ uint8_t b8[SHA1_DIGEST_SIZE];
+ uint32_t b32[SHA1_DIGEST_WORDS];
+ };
+};
+BUILD_ASSERT(sizeof(struct sha1_digest) == SHA1_DIGEST_SIZE);
+
+
+/* SHA256 specific type to allocate just enough memory. */
+struct sha256_ctx {
+ const struct hash_vtable *f; /* metadata & vtable */
+ size_t count; /* number of bytes processed */
+ uint32_t state[SHA256_DIGEST_WORDS]; /* up to SHA2-256 */
+ union {
+ uint8_t b8[SHA256_BLOCK_SIZE];
+ uint32_t b32[SHA256_BLOCK_WORDS];
+ uint64_t b64[SHA256_BLOCK_DWORDS];
+ struct sha256_digest digest;
+ };
+};
+
+#define sha224_ctx sha256_ctx
+
+struct sha1_ctx {
+ const struct hash_vtable *f; /* metadata & vtable. */
+ size_t count; /* number of bytes processed. */
+ uint32_t state[SHA1_DIGEST_WORDS];
+ union {
+ uint8_t b8[SHA1_BLOCK_SIZE];
+ uint32_t b32[SHA1_BLOCK_WORDS];
+ uint64_t b64[SHA1_BLOCK_DWORDS];
+ struct sha1_digest digest;
+ };
+};
+
+#ifdef CONFIG_UPTO_SHA512
+#define SHA384_DIGEST_SIZE 48
+#define SHA512_DIGEST_SIZE 64
+
+#define SHA384_BLOCK_SIZE 128
+#define SHA512_BLOCK_SIZE 128
+
+#define SHA384_BLOCK_WORDS (SHA384_BLOCK_SIZE / sizeof(uint32_t))
+#define SHA384_BLOCK_DWORDS (SHA384_BLOCK_SIZE / sizeof(uint64_t))
+#define SHA384_DIGEST_WORDS (SHA384_DIGEST_SIZE / sizeof(uint32_t))
+#define SHA384_DIGEST_DWORDS (SHA384_DIGEST_SIZE / sizeof(uint64_t))
+
+#define SHA512_BLOCK_WORDS (SHA512_BLOCK_SIZE / sizeof(uint32_t))
+#define SHA512_BLOCK_DWORDS (SHA512_BLOCK_SIZE / sizeof(uint64_t))
+#define SHA512_DIGEST_WORDS (SHA512_DIGEST_SIZE / sizeof(uint32_t))
+#define SHA512_DIGEST_DWORDS (SHA512_DIGEST_SIZE / sizeof(uint64_t))
+
+struct sha384_digest {
+ union {
+ uint8_t b8[SHA384_DIGEST_SIZE];
+ uint32_t b32[SHA384_DIGEST_WORDS];
+ };
+};
+BUILD_ASSERT(sizeof(struct sha384_digest) == SHA384_DIGEST_SIZE);
+
+struct sha512_digest {
+ union {
+ uint8_t b8[SHA512_DIGEST_SIZE];
+ uint32_t b32[SHA512_DIGEST_WORDS];
+ };
+};
+BUILD_ASSERT(sizeof(struct sha512_digest) == SHA512_DIGEST_SIZE);
+
+struct sha512_ctx {
+ const struct hash_vtable *f; /* metadata & vtable. */
+ size_t count; /* number of bytes processed. */
+ uint64_t state[SHA512_DIGEST_DWORDS]; /* up to SHA2-512. */
+ union {
+ uint8_t b8[SHA512_BLOCK_SIZE];
+ uint32_t b32[SHA512_BLOCK_WORDS];
+ uint64_t b64[SHA512_BLOCK_DWORDS];
+ struct sha512_digest digest;
+ };
+};
+
+#define sha384_ctx sha512_ctx
+#endif
+
+/**
+ * Generic hash type, allocating memory for any supported hash context
+ * Each context should have header at known location.
+ */
+union hash_ctx {
+ const struct hash_vtable *f; /* common metadata & vtable */
+ struct sha1_ctx sha1;
+ struct sha256_ctx sha256;
+ struct sha224_ctx sha224;
+#ifdef CONFIG_UPTO_SHA512
+ struct sha384_ctx sha384;
+ struct sha512_ctx sha512;
+#endif
+};
+
+union sha_digests {
+ struct sha1_digest sha1;
+ struct sha224_digest sha224;
+ struct sha256_digest sha256;
+#ifdef CONFIG_UPTO_SHA512
+ struct sha384_digest sha384;
+ struct sha512_digest sha512;
+#endif
+ /* Convenience accessor to bytes. */
+ uint8_t b8[SHA256_DIGEST_SIZE];
+};
+
+/* Header should be at constant offset to safely cast types to smaller size */
+BUILD_ASSERT(offsetof(union hash_ctx, f) == offsetof(struct sha1_ctx, f));
+BUILD_ASSERT(offsetof(union hash_ctx, f) == offsetof(struct sha256_ctx, f));
+BUILD_ASSERT(offsetof(union hash_ctx, f) == offsetof(struct sha224_ctx, f));
+
+#ifdef CONFIG_UPTO_SHA512
+BUILD_ASSERT(offsetof(union hash_ctx, f) == offsetof(struct sha384_ctx, f));
+BUILD_ASSERT(offsetof(union hash_ctx, f) == offsetof(struct sha512_ctx, f));
+#endif
+
+struct hmac_sha1_ctx {
+ struct sha1_ctx hash;
+ uint32_t opad[SHA1_BLOCK_WORDS];
+};
+
+struct hmac_sha224_ctx {
+ struct sha224_ctx hash;
+ uint32_t opad[SHA224_BLOCK_WORDS];
+};
+
+struct hmac_sha256_ctx {
+ struct sha256_ctx hash;
+ uint32_t opad[SHA256_BLOCK_WORDS];
+};
+
+#ifdef CONFIG_UPTO_SHA512
+struct hmac_sha384_ctx {
+ struct sha384_ctx hash;
+ uint32_t opad[SHA384_BLOCK_WORDS];
+};
+
+struct hmac_sha512_ctx {
+ struct sha512_ctx hash;
+ uint32_t opad[SHA512_BLOCK_WORDS];
+};
+#endif
+
+/**
+ * HMAC context reserving memory for any supported hash type.
+ * It's SHA context following storage for ipad/opad
+ */
+union hmac_ctx {
+ const struct hash_vtable *f; /* common metadata & vtable */
+ union hash_ctx hash; /* access as hash */
+ /* hmac contexts */
+ struct hmac_sha1_ctx hmac_sha1;
+ struct hmac_sha256_ctx hmac_sha256;
+ struct hmac_sha224_ctx hmac_sha224;
+#ifdef CONFIG_UPTO_SHA512
+ struct hmac_sha384_ctx hmac_sha384;
+ struct hmac_sha512_ctx hmac_sha512;
+#endif
+};
+
+/* Header should be at constant offset to safely cast types to smaller size */
+BUILD_ASSERT(offsetof(union hmac_ctx, f) == offsetof(struct sha1_ctx, f));
+BUILD_ASSERT(offsetof(union hmac_ctx, f) == offsetof(struct sha256_ctx, f));
+BUILD_ASSERT(offsetof(union hmac_ctx, f) == offsetof(struct sha224_ctx, f));
+
+#ifdef CONFIG_UPTO_SHA512
+BUILD_ASSERT(offsetof(union hmac_ctx, f) == offsetof(struct sha384_ctx, f));
+BUILD_ASSERT(offsetof(union hmac_ctx, f) == offsetof(struct sha512_ctx, f));
+#endif
+
+/**
+ * Reset hash context with the same hash function as configured.
+ * Will crash if previously not configured! Used for HMAC.
+ */
+static inline void HASH_reinit(union hash_ctx *const ctx)
+{
+ ctx->f->init(ctx);
+}
+
+#ifndef CONFIG_DCRYPTO_MOCK
+/**
+ * Add data to message, call configured transform function when block
+ * is full.
+ */
+static inline void HASH_update(union hash_ctx *const ctx, const void *data,
+ size_t len)
+{
+ ctx->f->update(ctx, data, len);
+}
+#else
+void HASH_update(union hash_ctx *const ctx, const void *data, size_t len);
+#endif
+
+static inline void SHA1_update(struct sha1_ctx *const ctx, const void *data,
+ size_t len)
+{
+ ctx->f->update((union hash_ctx *)ctx, data, len);
+}
+
+static inline void SHA256_update(struct sha256_ctx *const ctx, const void *data,
+ size_t len)
+{
+ ctx->f->update((union hash_ctx *)ctx, data, len);
+}
+
+/**
+ * Finalize hash computation by adding padding, message length.
+ * Returns pointer to computed digest stored inside provided context.
+ */
+#ifndef CONFIG_DCRYPTO_MOCK
+static inline const union sha_digests *HASH_final(union hash_ctx *const ctx)
+{
+ return ctx->f->final(ctx);
+}
+#else
+const union sha_digests *HASH_final(union hash_ctx *const ctx);
+#endif
+
+static inline const struct sha1_digest *SHA1_final(struct sha1_ctx *const ctx)
+{
+ return &ctx->f->final((union hash_ctx *)ctx)->sha1;
+}
+
+static inline const struct sha256_digest *
+SHA256_final(struct sha256_ctx *const ctx)
+{
+ return &ctx->f->final((union hash_ctx *)ctx)->sha256;
+}
+
+/**
+ * Returns digest size for configured hash.
+ */
+static inline size_t HASH_size(union hash_ctx *const ctx)
+{
+ return ctx->f->digest_size;
+}
+
+/**
+ * Return block size for configured hash.
+ */
+static inline size_t HASH_block_size(union hash_ctx *const ctx)
+{
+ return ctx->f->block_size;
+}
+
+/* Software implementations of hash functions. */
+void SHA1_sw_init(struct sha1_ctx *const ctx);
+void SHA1_sw_update(struct sha1_ctx *const ctx, const void *data, size_t len);
+const struct sha1_digest *SHA1_sw_final(struct sha1_ctx *const ctx);
+const struct sha1_digest *SHA1_sw_hash(const void *data, size_t len,
+ struct sha1_digest *digest);
+void SHA256_sw_init(struct sha256_ctx *const ctx);
+void SHA256_sw_update(struct sha256_ctx *const ctx, const void *data,
+ size_t len);
+const struct sha256_digest *SHA256_sw_final(struct sha256_ctx *const ctx);
+const struct sha256_digest *SHA256_sw_hash(const void *data, size_t len,
+ struct sha256_digest *digest);
+void SHA224_sw_init(struct sha224_ctx *const ctx);
+void SHA224_sw_update(struct sha224_ctx *const ctx, const void *data,
+ size_t len);
+const struct sha224_digest *SHA224_sw_final(struct sha224_ctx *const ctx);
+const struct sha224_digest *SHA224_sw_hash(const void *data, size_t len,
+ struct sha224_digest *digest);
+
+/**
+ * Initialize HMAC for pre-configured hash.
+ * This is generic function which can initialize HMAC with any supported
+ * hash function.
+ */
+void HMAC_sw_init(union hmac_ctx *const ctx, const void *key, size_t len);
+const union sha_digests *HMAC_sw_final(union hmac_ctx *const ctx);
+
+/* HMAC update is same as SHA update. */
+static inline void HMAC_update(union hmac_ctx *const ctx, const void *data,
+ size_t len)
+{
+ ctx->f->update(&ctx->hash, data, len);
+}
+
+static inline size_t HMAC_size(union hmac_ctx *const ctx)
+{
+ return ctx->f->digest_size;
+}
+
+static inline const union sha_digests *HMAC_final(union hmac_ctx *const ctx)
+{
+ return ctx->f->hmac_final(ctx);
+}
+
+/**
+ * HMAC SHA1 initialization.
+ */
+static inline void HMAC_SHA1_sw_init(struct hmac_sha1_ctx *const ctx,
+ const void *key, size_t len)
+{
+ SHA1_sw_init(&ctx->hash);
+ HMAC_sw_init((union hmac_ctx *)ctx, key, len);
+}
+
+static inline void HMAC_SHA1_update(struct hmac_sha1_ctx *const ctx,
+ const void *data, size_t len)
+{
+ ctx->hash.f->update((union hash_ctx *)&ctx->hash, data, len);
+}
+
+static inline const struct sha1_digest *
+HMAC_SHA1_final(struct hmac_sha1_ctx *const ctx)
+{
+ return &ctx->hash.f->hmac_final((union hmac_ctx *)ctx)->sha1;
+}
+
+/**
+ * HMAC SHA2-224 initialization.
+ */
+static inline void HMAC_SHA224_sw_init(struct hmac_sha224_ctx *const ctx,
+ const void *key, size_t len)
+{
+ SHA224_sw_init(&ctx->hash);
+ HMAC_sw_init((union hmac_ctx *)ctx, key, len);
+}
+
+static inline void HMAC_SHA224_update(struct hmac_sha224_ctx *const ctx,
+ const void *data, size_t len)
+{
+ ctx->hash.f->update((union hash_ctx *)&ctx->hash, data, len);
+}
+
+static inline const struct sha224_digest *
+HMAC_SHA224_final(struct hmac_sha224_ctx *const ctx)
+{
+ return &ctx->hash.f->hmac_final((union hmac_ctx *)ctx)->sha224;
+}
+
+/**
+ * HMAC SHA2-256 initialization.
+ */
+static inline void HMAC_SHA256_sw_init(struct hmac_sha256_ctx *const ctx,
+ const void *key, size_t len)
+{
+ SHA256_sw_init(&ctx->hash);
+ HMAC_sw_init((union hmac_ctx *)ctx, key, len);
+}
+
+static inline void HMAC_SHA256_update(struct hmac_sha256_ctx *const ctx,
+ const void *data, size_t len)
+{
+ ctx->hash.f->update((union hash_ctx *)&ctx->hash, data, len);
+}
+
+static inline const struct sha256_digest *
+HMAC_SHA256_final(struct hmac_sha256_ctx *ctx)
+{
+ return &ctx->hash.f->hmac_final((union hmac_ctx *)ctx)->sha256;
+}
+
+#ifdef CONFIG_UPTO_SHA512
+void SHA384_sw_init(struct sha384_ctx *const ctx);
+void SHA384_sw_update(struct sha384_ctx *const ctx, const void *data,
+ size_t len);
+const struct sha384_digest *SHA384_sw_final(struct sha384_ctx *const ctx);
+const struct sha384_digest *SHA384_sw_hash(const void *data, size_t len,
+ struct sha384_digest *digest);
+void SHA512_sw_init(struct sha512_ctx *const ctx);
+void SHA512_sw_update(struct sha512_ctx *const ctx, const void *data,
+ size_t len);
+const struct sha512_digest *SHA512_sw_final(struct sha512_ctx *ctx);
+const struct sha512_digest *SHA512_sw_hash(const void *data, size_t len,
+ struct sha512_digest *digest);
+
+/**
+ * HMAC SHA2-384 initialization.
+ */
+static inline void HMAC_SHA384_sw_init(struct hmac_sha384_ctx *ctx,
+ const void *key, size_t len)
+{
+ SHA384_sw_init(&ctx->hash);
+ HMAC_sw_init((union hmac_ctx *)ctx, key, len);
+}
+
+static inline void HMAC_SHA384_update(struct hmac_sha384_ctx *ctx,
+ const void *data, size_t len)
+{
+ ctx->hash.f->update((union hash_ctx *)&ctx->hash, data, len);
+}
+static inline const struct sha384_digest *
+HMAC_SHA384_final(struct hmac_sha384_ctx *ctx)
+{
+ return &ctx->hash.f->hmac_final((union hmac_ctx *)ctx)->sha384;
+}
+/**
+ * HMAC SHA2-512 initialization.
+ */
+static inline void HMAC_SHA512_sw_init(struct hmac_sha512_ctx *ctx,
+ const void *key, size_t len)
+{
+ SHA512_sw_init(&ctx->hash);
+ HMAC_sw_init((union hmac_ctx *)ctx, key, len);
+}
+static inline void HMAC_SHA512_update(struct hmac_sha512_ctx *ctx,
+ const void *data, size_t len)
+{
+ ctx->hash.f->update((union hash_ctx *)&ctx->hash, data, len);
+}
+static inline const struct sha512_digest *
+HMAC_SHA512_final(struct hmac_sha512_ctx *ctx)
+{
+ return &ctx->hash.f->hmac_final((union hmac_ctx *)ctx)->sha512;
+}
+#endif