diff options
Diffstat (limited to 'board/cr50/dcrypto/sha256.c')
-rw-r--r-- | board/cr50/dcrypto/sha256.c | 337 |
1 files changed, 175 insertions, 162 deletions
diff --git a/board/cr50/dcrypto/sha256.c b/board/cr50/dcrypto/sha256.c index f127ab445a..2df4514081 100644 --- a/board/cr50/dcrypto/sha256.c +++ b/board/cr50/dcrypto/sha256.c @@ -4,192 +4,205 @@ */ #include "dcrypto.h" +#include "endian.h" #include "internal.h" #include "registers.h" #include "util.h" -#include "cryptoc/sha256.h" - -static void dcrypto_sha256_init(LITE_SHA256_CTX *ctx); -static const uint8_t *dcrypto_sha256_final(LITE_SHA256_CTX *ctx); - -#ifdef SECTION_IS_RO -/* RO is single threaded. */ -#define mutex_lock(x) -#define mutex_unlock(x) -static inline int dcrypto_grab_sha_hw(void) -{ - return 1; -} -static inline void dcrypto_release_sha_hw(void) -{ -} -#else -#include "task.h" -static struct mutex hw_busy_mutex; - -static int hw_busy; - -int dcrypto_grab_sha_hw(void) +static void SHA256_transform(struct sha256_ctx *const ctx) { - int rv = 0; - - mutex_lock(&hw_busy_mutex); - if (!hw_busy) { - rv = 1; - hw_busy = 1; + 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 + }; + uint32_t W[64]; + uint32_t A, B, C, D, E, F, G, H; + size_t t; + + for (t = 0; t < 16; ++t) + W[t] = be32toh(ctx->b32[t]); + for (; t < 64; t++) { + uint32_t s0 = ror(W[t - 15], 7) ^ ror(W[t - 15], 18) ^ + (W[t - 15] >> 3); + uint32_t s1 = ror(W[t - 2], 17) ^ ror(W[t - 2], 19) ^ + (W[t - 2] >> 10); + + W[t] = W[t - 16] + s0 + W[t - 7] + s1; } - mutex_unlock(&hw_busy_mutex); - - return rv; + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + for (t = 0; t < 64; t++) { + uint32_t s0 = ror(A, 2) ^ ror(A, 13) ^ ror(A, 22); + uint32_t maj = (A & B) ^ (A & C) ^ (B & C); + uint32_t t2 = s0 + maj; + uint32_t s1 = ror(E, 6) ^ ror(E, 11) ^ ror(E, 25); + uint32_t ch = (E & F) ^ ((~E) & G); + uint32_t t1 = H + s1 + ch + K[t] + W[t]; + + H = G; + G = F; + F = E; + E = D + t1; + D = C; + C = B; + B = A; + A = t1 + t2; + } + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; } - -void dcrypto_release_sha_hw(void) +/** + * Define aliases taking union type as parameter. This is safe + * as union type has header in same place and is not less than original type. + * Equal to: + * void SHA256_init_as_hash(HASH_CTX *const ctx) {SHA256_init(&ctx.sha256);} + * but save some space for embedded uses. + */ +BUILD_ASSERT(sizeof(union hash_ctx) >= sizeof(struct sha256_ctx)); +BUILD_ASSERT(sizeof(union hash_ctx) >= sizeof(struct sha224_ctx)); + +static void SHA256_init_as_hash(union hash_ctx *const ctx) + __alias(SHA256_sw_init); +static void SHA256_update_as_hash(union hash_ctx *const ctx, const void *data, + size_t len) __alias(SHA256_sw_update); +static const union sha_digests *SHA256_final_as_hash(union hash_ctx *const ctx) + __alias(SHA256_sw_final); +static void SHA224_init_as_hash(union hash_ctx *const ctx) + __alias(SHA224_sw_init); + +void SHA256_sw_init(struct sha256_ctx *const ctx) { - mutex_lock(&hw_busy_mutex); - hw_busy = 0; - mutex_unlock(&hw_busy_mutex); + static const struct hash_vtable sha256_vtable = { + SHA256_init_as_hash, SHA256_update_as_hash, + SHA256_final_as_hash, HMAC_sw_final, + SHA256_DIGEST_SIZE, SHA256_BLOCK_SIZE, + sizeof(struct sha256_ctx) + }; + static const uint32_t sha256_init[SHA256_DIGEST_WORDS] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + }; + + ctx->f = &sha256_vtable; + memcpy(ctx->state, sha256_init, sizeof(ctx->state)); + ctx->count = 0; } -#endif /* ! SECTION_IS_RO */ - -void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest) -{ - int i; - const int digest_len = (mode == SHA1_MODE) ? - SHA_DIGEST_SIZE : - SHA256_DIGEST_SIZE; - - /* Stop LIVESTREAM mode. */ - GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_STOP_MASK; - - /* Wait for SHA DONE interrupt. */ - while (!GREG32(KEYMGR, SHA_ITOP)) - ; - - /* Read out final digest. */ - for (i = 0; i < digest_len / 4; ++i) - *digest++ = GR_KEYMGR_SHA_HASH(i); - dcrypto_release_sha_hw(); -} +/* SHA2-224 and SHA2-256 use same internal context. */ +BUILD_ASSERT(sizeof(struct sha224_ctx) == sizeof(struct sha256_ctx)); +void SHA224_sw_update(struct sha224_ctx *ctx, const void *data, size_t len) + __alias(SHA256_sw_update); -/* Hardware SHA implementation. */ -static const HASH_VTAB HW_SHA256_VTAB = { - dcrypto_sha256_init, - dcrypto_sha_update, - dcrypto_sha256_final, - DCRYPTO_SHA256_hash, - SHA256_DIGEST_SIZE -}; - -void dcrypto_sha_hash(enum sha_mode mode, const uint8_t *data, uint32_t n, - uint8_t *digest) +void SHA256_sw_update(struct sha256_ctx *ctx, const void *data, size_t len) { - dcrypto_sha_init(mode); - dcrypto_sha_update(NULL, data, n); - dcrypto_sha_wait(mode, (uint32_t *) digest); + size_t i = ctx->count & (SHA256_BLOCK_SIZE - 1); + const uint8_t *p = (const uint8_t *)data; + + ctx->count += len; + while (len--) { + ctx->b8[i++] = *p++; + if (i == SHA256_BLOCK_SIZE) { + SHA256_transform(ctx); + i = 0; + } + } } - -void dcrypto_sha_update(struct HASH_CTX *unused, - const void *data, uint32_t n) +const struct sha224_digest *SHA224_sw_final(struct sha224_ctx *const ctx) + __alias(SHA256_sw_final); +const struct sha256_digest *SHA256_sw_final(struct sha256_ctx *const ctx) { - const uint8_t *bp = (const uint8_t *) data; - const uint32_t *wp; - - /* Feed unaligned start bytes. */ - while (n != 0 && ((uint32_t)bp & 3)) { - GREG8(KEYMGR, SHA_INPUT_FIFO) = *bp++; - n -= 1; - } - - /* Feed groups of aligned words. */ - wp = (uint32_t *)bp; - while (n >= 8*4) { - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - n -= 8*4; - } - /* Feed individual aligned words. */ - while (n >= 4) { - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - n -= 4; - } - - /* Feed remaing bytes. */ - bp = (uint8_t *) wp; - while (n != 0) { - GREG8(KEYMGR, SHA_INPUT_FIFO) = *bp++; - n -= 1; + uint64_t cnt = (uint64_t)ctx->count * CHAR_BIT; + size_t i = ctx->count & (SHA256_BLOCK_SIZE - 1); + + /** + * append the bit '1' to the message which would be 0x80 if message + * length is a multiple of 8 bits. + */ + ctx->b8[i++] = 0x80; + /** + * Append 0 ≤ k < 512 bits '0', such that the resulting message length + * in bits is congruent to −64 ≡ 448 (mod 512). + */ + if (i > (SHA256_BLOCK_SIZE - sizeof(cnt))) { + /* Current block won't fit length, so move to next. */ + while (i < SHA256_BLOCK_SIZE) + ctx->b8[i++] = 0; + SHA256_transform(ctx); + i = 0; } + /* Pad rest of zeros. */ + while (i < (SHA256_BLOCK_SIZE - sizeof(cnt))) + ctx->b8[i++] = 0; + + /* Place big-endian 64-bit bit counter at the end of block. */ + ctx->b64[SHA256_BLOCK_DWORDS - 1] = htobe64(cnt); + SHA256_transform(ctx); + for (i = 0; i < 8; i++) + ctx->b32[i] = htobe32(ctx->state[i]); + return &ctx->digest; } -void dcrypto_sha_init(enum sha_mode mode) +void SHA224_sw_init(struct sha224_ctx *const ctx) { - int val; - - /* Stop LIVESTREAM mode, in case final() was not called. */ - GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_STOP_MASK; - /* Clear interrupt status. */ - GREG32(KEYMGR, SHA_ITOP) = 0; - - /* Enable streaming mode. */ - val = GC_KEYMGR_SHA_CFG_EN_LIVESTREAM_MASK; - /* Enable SHA DONE interrupt. */ - val |= GC_KEYMGR_SHA_CFG_EN_INT_EN_DONE_MASK; - /* Select SHA mode. */ - if (mode == SHA1_MODE) - val |= GC_KEYMGR_SHA_CFG_EN_SHA1_MASK; - GREG32(KEYMGR, SHA_CFG_EN) = val; - - /* Turn off random nops (which are enabled by default). */ - GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 0); - /* Configure random nop percentage at 12%. */ - GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, FREQ, 2); - /* Now turn on random nops. */ - GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 1); - - /* Start SHA engine. */ - GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_GO_MASK; + /* SHA2-224 differs from SHA2-256 only in initialization. */ + static const struct hash_vtable sha224_vtable = { + SHA224_init_as_hash, SHA256_update_as_hash, + SHA256_final_as_hash, HMAC_sw_final, + SHA224_DIGEST_SIZE, SHA224_BLOCK_SIZE, + sizeof(struct sha224_ctx) + }; + static const uint32_t sha224_init[SHA256_DIGEST_WORDS] = { + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 + }; + + ctx->f = &sha224_vtable; + memcpy(ctx->state, sha224_init, sizeof(ctx->state)); + ctx->count = 0; } -static void dcrypto_sha256_init(LITE_SHA256_CTX *ctx) +/* One shot hash computation. */ +const struct sha224_digest *SHA224_sw_hash(const void *data, size_t len, + struct sha224_digest *digest) { - ctx->f = &HW_SHA256_VTAB; - dcrypto_sha_init(SHA256_MODE); -} + struct sha224_ctx ctx; -/* Requires dcrypto_grab_sha_hw() to be called first. */ -void DCRYPTO_SHA256_init(LITE_SHA256_CTX *ctx, uint32_t sw_required) -{ - if (!sw_required && dcrypto_grab_sha_hw()) - dcrypto_sha256_init(ctx); -#ifndef SECTION_IS_RO - else - SHA256_init(ctx); -#endif + SHA224_sw_init(&ctx); + SHA224_sw_update(&ctx, data, len); + memcpy(digest->b8, SHA224_sw_final(&ctx), SHA224_DIGEST_SIZE); + return digest; } - -static const uint8_t *dcrypto_sha256_final(LITE_SHA256_CTX *ctx) +/* One shot hash computation */ +const struct sha256_digest *SHA256_sw_hash(const void *data, size_t len, + struct sha256_digest *digest) { - dcrypto_sha_wait(SHA256_MODE, (uint32_t *) ctx->buf); - return ctx->buf; -} + struct sha256_ctx ctx; -const uint8_t *DCRYPTO_SHA256_hash(const void *data, uint32_t n, - uint8_t *digest) -{ - if (dcrypto_grab_sha_hw()) - /* dcrypto_sha_wait() will release the hw. */ - dcrypto_sha_hash(SHA256_MODE, data, n, digest); -#ifndef SECTION_IS_RO - else - SHA256_hash(data, n, digest); -#endif + SHA256_sw_init(&ctx); + SHA256_sw_update(&ctx, data, len); + memcpy(digest->b8, SHA256_sw_final(&ctx)->b8, SHA256_DIGEST_SIZE); return digest; } |