summaryrefslogtreecommitdiff
path: root/chip/g/dcrypto
diff options
context:
space:
mode:
authornagendra modadugu <ngm@google.com>2015-11-19 16:15:35 -0800
committerchrome-bot <chrome-bot@chromium.org>2015-11-25 11:17:13 -0800
commitae89bb6f49f30186e300e0b60c6384b37da8c72f (patch)
treefccdd5ba91b0481f06f68b81a26c7fd33ce1f76b /chip/g/dcrypto
parentf01d71eb5b0ee8f15e2c85e9302c24bc5fe3ebcd (diff)
downloadchrome-ec-ae89bb6f49f30186e300e0b60c6384b37da8c72f.tar.gz
cr50: SHA1 and SHA256 implementation with hardware support
This change includes hardware and software support for SHA1/256 on CR50. When running in the RO image, only hardware sha256 support is included. When running in the RW image, the code auto-selects between the software and hardware implementation. Software implementation path is taken if the hardware is currently in use by some other context. Refactor the CR50 loader to use this abstraction. The existing software implementation for SHA1 and SHA256 is used for the software path. CQ-DEPEND=CL:*239385 BRANCH=none TEST=EC shell boots fine (implies that SHA256 works) BUG=chrome-os-partner:43025 Change-Id: I7bcefc12fcef869dac2e48793bd0cb5ce8e80d5b Signed-off-by: nagendra modadugu <ngm@google.com> Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/313011
Diffstat (limited to 'chip/g/dcrypto')
-rw-r--r--chip/g/dcrypto/dcrypto.h60
-rw-r--r--chip/g/dcrypto/internal.h47
-rw-r--r--chip/g/dcrypto/sha1.c98
-rw-r--r--chip/g/dcrypto/sha256.c216
4 files changed, 410 insertions, 11 deletions
diff --git a/chip/g/dcrypto/dcrypto.h b/chip/g/dcrypto/dcrypto.h
index 1dab319392..7cafb224da 100644
--- a/chip/g/dcrypto/dcrypto.h
+++ b/chip/g/dcrypto/dcrypto.h
@@ -4,15 +4,15 @@
*/
/*
- * Crypto wrapper library for CR50.
+ * Crypto wrapper library for the g chip.
*/
-#ifndef EC_BOARD_CR50_DCRYPTO_DCRYPTO_H_
-#define EC_BOARD_CR50_DCRYPTO_DCRYPTO_H_
+#ifndef __EC_CHIP_G_DCRYPTO_DCRYPTO_H
+#define __EC_CHIP_G_DCRYPTO_DCRYPTO_H
/* TODO(vbendeb) don't forget to disable this for prod builds. */
#define CRYPTO_TEST_SETUP
-#include <inttypes.h>
+#include "internal.h"
enum cipher_mode {
CIPHER_MODE_ECB = 0,
@@ -26,6 +26,36 @@ enum encrypt_mode {
ENCRYPT_MODE = 1
};
+#define SHA1_DIGEST_BYTES 20
+#define SHA256_DIGEST_BYTES 32
+#define SHA384_DIGEST_BYTES 48
+#define SHA512_DIGEST_BYTES 64
+#define SHA_DIGEST_MAX_BYTES SHA512_DIGEST_BYTES
+
+#define SHA1_DIGEST_WORDS (SHA1_DIGEST_BYTES / sizeof(uint32_t))
+#define SHA256_DIGEST_WORDS (SHA256_DIGEST_BYTES / sizeof(uint32_t))
+#define SHA384_DIGEST_WORDS (SHA384_DIGEST_BYTES / sizeof(uint32_t))
+#define SHA512_DIGEST_WORDS (SHA512_DIGEST_BYTES / sizeof(uint32_t))
+
+struct HASH_CTX; /* Forward declaration. */
+
+typedef struct HASH_CTX SHA1_CTX;
+typedef struct HASH_CTX SHA256_CTX;
+
+#define DCRYPTO_HASH_update(ctx, data, len) \
+ ((ctx)->vtab->update((ctx), (data), (len)))
+#define DCRYPTO_HASH_final(ctx) \
+ ((ctx)->vtab->final((ctx)))
+#define DCRYPTO_HASH_size(ctx) \
+ ((ctx)->vtab->size)
+
+#define DCRYPTO_SHA1_update(ctx, data, n) \
+ DCRYPTO_HASH_update((ctx), (data), (n))
+#define DCRYPTO_SHA1_final(ctx) DCRYPTO_HASH_final((ctx))
+
+/*
+ * AES implementation, based on a hardware AES block.
+ */
int DCRYPTO_aes_init(const uint8_t *key, uint32_t key_len, const uint8_t *iv,
enum cipher_mode c_mode, enum encrypt_mode e_mode);
int DCRYPTO_aes_block(const uint8_t *in, uint8_t *out);
@@ -33,4 +63,24 @@ int DCRYPTO_aes_block(const uint8_t *in, uint8_t *out);
void DCRYPTO_aes_write_iv(const uint8_t *iv);
void DCRYPTO_aes_read_iv(uint8_t *iv);
-#endif /* ! EC_BOARD_CR50_DCRYPTO_DCRYPTO_H_ */
+/*
+ * SHA implementation. This abstraction is backed by either a
+ * software or hardware implementation.
+ *
+ * There could be only a single hardware SHA context in progress. The init
+ * functions will try using the HW context, if available, unless 'sw_required'
+ * is TRUE, in which case there will be no attempt to use the hardware for
+ * this particular hashing session.
+ */
+void DCRYPTO_SHA1_init(SHA1_CTX *ctx, uint32_t sw_required);
+void DCRYPTO_SHA256_init(SHA256_CTX *ctx, uint32_t sw_required);
+const uint8_t *DCRYPTO_SHA1_hash(const uint8_t *data, uint32_t n,
+ uint8_t *digest);
+
+#define DCRYPTO_SHA256_update(ctx, data, n) \
+ DCRYPTO_HASH_update((ctx), (data), (n))
+#define DCRYPTO_SHA256_final(ctx) DCRYPTO_HASH_final((ctx))
+const uint8_t *DCRYPTO_SHA256_hash(const uint8_t *data, uint32_t n,
+ uint8_t *digest);
+
+#endif /* ! __EC_CHIP_G_DCRYPTO_DCRYPTO_H */
diff --git a/chip/g/dcrypto/internal.h b/chip/g/dcrypto/internal.h
index 5eb76ecc8a..279b2798e7 100644
--- a/chip/g/dcrypto/internal.h
+++ b/chip/g/dcrypto/internal.h
@@ -3,19 +3,43 @@
* found in the LICENSE file.
*/
-/*
- * Crypto wrapper library for CR50.
- */
-#ifndef EC_BOARD_CR50_DCRYPTO_INTERNAL_H_
-#define EC_BOARD_CR50_DCRYPTO_INTERNAL_H_
+#ifndef __EC_CHIP_G_DCRYPTO_INTERNAL_H
+#define __EC_CHIP_G_DCRYPTO_INTERNAL_H
+
+#include <inttypes.h>
#include "common.h"
+#include "sha1.h"
+#include "sha256.h"
#define CTRL_CTR_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define CTRL_ENABLE 1
#define CTRL_ENCRYPT 1
#define CTRL_NO_SOFT_RESET 0
+struct HASH_CTX; /* Forward declaration. */
+
+struct HASH_VTAB {
+ void (* const update)(struct HASH_CTX *, const uint8_t *, uint32_t);
+ const uint8_t *(* const final)(struct HASH_CTX *);
+ const uint8_t *(* const hash)(const uint8_t *, uint32_t, uint8_t *);
+ uint32_t size;
+};
+
+struct HASH_CTX {
+ const struct HASH_VTAB *vtab;
+ union {
+ uint8_t buf[64];
+ struct sha1_ctx sw_sha1;
+ struct sha256_ctx sw_sha256;
+ } u;
+};
+
+enum sha_mode {
+ SHA1_MODE = 0,
+ SHA256_MODE = 1
+};
+
/*
* Use this structure to avoid alignment problems with input and output
* pointers.
@@ -24,4 +48,15 @@ struct access_helper {
uint32_t udata;
} __packed;
-#endif /* ! EC_BOARD_CR50_DCRYPTO_INTERNAL_H_ */
+#ifndef SECTION_IS_RO
+int dcrypto_grab_sha_hw(void);
+void dcrypto_release_sha_hw(void);
+#endif
+void dcrypto_sha_hash(enum sha_mode mode, const uint8_t *data,
+ uint32_t n, uint8_t *digest);
+void dcrypto_sha_init(enum sha_mode mode);
+void dcrypto_sha_update(struct HASH_CTX *unused,
+ const uint8_t *data, uint32_t n);
+void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest);
+
+#endif /* ! __EC_CHIP_G_DCRYPTO_INTERNAL_H */
diff --git a/chip/g/dcrypto/sha1.c b/chip/g/dcrypto/sha1.c
new file mode 100644
index 0000000000..9721a9c2d9
--- /dev/null
+++ b/chip/g/dcrypto/sha1.c
@@ -0,0 +1,98 @@
+/* Copyright 2015 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.
+ */
+
+#include "dcrypto.h"
+#include "internal.h"
+#include "registers.h"
+
+static void sw_sha1_init(SHA1_CTX *ctx);
+static void sw_sha1_update(SHA1_CTX *ctx, const uint8_t *data, uint32_t len);
+static const uint8_t *sw_sha1_final(SHA1_CTX *ctx);
+static const uint8_t *sha1_hash(const uint8_t *data, uint32_t len,
+ uint8_t *digest);
+static const uint8_t *dcrypto_sha1_final(SHA1_CTX *unused);
+
+/* Software SHA1 implementation. */
+static const struct HASH_VTAB SW_SHA1_VTAB = {
+ sw_sha1_update,
+ sw_sha1_final,
+ sha1_hash,
+ SHA1_DIGEST_BYTES
+};
+
+static void sw_sha1_init(SHA1_CTX *ctx)
+{
+ ctx->vtab = &SW_SHA1_VTAB;
+ sha1_init(&ctx->u.sw_sha1);
+}
+
+static void sw_sha1_update(SHA1_CTX *ctx, const uint8_t *data, uint32_t len)
+{
+ sha1_update(&ctx->u.sw_sha1, data, len);
+}
+
+static const uint8_t *sw_sha1_final(SHA1_CTX *ctx)
+{
+ return sha1_final(&ctx->u.sw_sha1);
+}
+
+static const uint8_t *sha1_hash(const uint8_t *data, uint32_t len,
+ uint8_t *digest)
+{
+ SHA1_CTX ctx;
+
+ sw_sha1_init(&ctx);
+ sw_sha1_update(&ctx, data, len);
+ memcpy(digest, sw_sha1_final(&ctx), SHA1_DIGEST_BYTES);
+ return digest;
+}
+
+
+/*
+ * Hardware SHA implementation.
+ */
+static const struct HASH_VTAB HW_SHA1_VTAB = {
+ dcrypto_sha_update,
+ dcrypto_sha1_final,
+ DCRYPTO_SHA1_hash,
+ SHA1_DIGEST_BYTES
+};
+
+/* Select and initialize either the software or hardware
+ * implementation. If "multi-threaded" behaviour is required, then
+ * callers must set sw_required to 1. This is because SHA1 state
+ * internal to the hardware cannot be extracted, so it is not possible
+ * to suspend and resume a hardware based SHA operation.
+ *
+ * If the caller has no preference as to implementation, then hardware
+ * is preferred based on availability. Hardware is considered to be
+ * in use between init() and finished() calls. */
+void DCRYPTO_SHA1_init(SHA1_CTX *ctx, uint32_t sw_required)
+{
+ if (!sw_required && dcrypto_grab_sha_hw()) {
+ ctx->vtab = &HW_SHA1_VTAB;
+ dcrypto_sha_init(SHA1_MODE);
+ } else {
+ sw_sha1_init(ctx);
+ }
+}
+
+static const uint8_t *dcrypto_sha1_final(SHA1_CTX *ctx)
+{
+ dcrypto_sha_wait(SHA1_MODE, (uint32_t *) ctx->u.buf);
+ return ctx->u.buf;
+}
+
+const uint8_t *DCRYPTO_SHA1_hash(const uint8_t *data, uint32_t n,
+ uint8_t *digest)
+{
+ if (dcrypto_grab_sha_hw())
+ /* dcrypto_sha_wait() will release the hw. */
+ dcrypto_sha_hash(SHA1_MODE, data, n, digest);
+ else
+ sha1_hash(data, n, digest);
+ return digest;
+}
+
diff --git a/chip/g/dcrypto/sha256.c b/chip/g/dcrypto/sha256.c
new file mode 100644
index 0000000000..19025f3503
--- /dev/null
+++ b/chip/g/dcrypto/sha256.c
@@ -0,0 +1,216 @@
+/* Copyright 2015 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.
+ */
+
+#include "dcrypto.h"
+#include "internal.h"
+#include "registers.h"
+#include "util.h"
+
+static const uint8_t *dcrypto_sha256_final(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 void sha256_init(SHA256_CTX *ctx);
+static void sha256_update(SHA256_CTX *ctx, const uint8_t *data, uint32_t len);
+static const uint8_t *sha256_final(SHA256_CTX *ctx);
+static const uint8_t *sha256_hash(const uint8_t *data, uint32_t len,
+ uint8_t *digest);
+
+static const struct HASH_VTAB SW_SHA256_VTAB = {
+ sha256_update,
+ sha256_final,
+ sha256_hash,
+ SHA256_DIGEST_BYTES
+};
+
+static void sha256_init(SHA256_CTX *ctx)
+{
+ ctx->vtab = &SW_SHA256_VTAB;
+ SHA256_init(&ctx->u.sw_sha256);
+}
+
+static void sha256_update(SHA256_CTX *ctx, const uint8_t *data, uint32_t len)
+{
+ SHA256_update(&ctx->u.sw_sha256, data, len);
+}
+
+static const uint8_t *sha256_final(SHA256_CTX *ctx)
+{
+ return SHA256_final(&ctx->u.sw_sha256);
+}
+
+static const uint8_t *sha256_hash(const uint8_t *data, uint32_t len,
+ uint8_t *digest)
+{
+ SHA256_CTX ctx;
+
+ sha256_init(&ctx);
+ sha256_update(&ctx, data, len);
+ sha256_final(&ctx);
+
+ memcpy(digest, ctx.u.sw_sha256.buf, SHA256_DIGEST_WORDS);
+
+ return digest;
+}
+
+static int hw_busy;
+
+int dcrypto_grab_sha_hw(void)
+{
+ int rv = 0;
+
+ mutex_lock(&hw_busy_mutex);
+ if (!hw_busy) {
+ rv = 1;
+ hw_busy = 1;
+ }
+ mutex_unlock(&hw_busy_mutex);
+
+ return rv;
+}
+
+void dcrypto_release_sha_hw(void)
+{
+ mutex_lock(&hw_busy_mutex);
+ hw_busy = 0;
+ mutex_unlock(&hw_busy_mutex);
+}
+
+#endif /* ! SECTION_IS_RO */
+
+void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest)
+{
+ int i;
+ const int digest_len = (mode == SHA1_MODE) ?
+ SHA1_DIGEST_BYTES :
+ SHA256_DIGEST_BYTES;
+
+ /* Stop LIVESTREAM mode. */
+ GWRITE_FIELD(KEYMGR, SHA_TRIG, TRIG_STOP, 1);
+ /* 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();
+}
+
+/* Hardware SHA implementation. */
+static const struct HASH_VTAB HW_SHA256_VTAB = {
+ dcrypto_sha_update,
+ dcrypto_sha256_final,
+ DCRYPTO_SHA256_hash,
+ SHA256_DIGEST_BYTES
+};
+
+void dcrypto_sha_hash(enum sha_mode mode, const uint8_t *data, uint32_t n,
+ uint8_t *digest)
+{
+ dcrypto_sha_init(mode);
+ dcrypto_sha_update(NULL, data, n);
+ dcrypto_sha_wait(mode, (uint32_t *) digest);
+}
+
+void dcrypto_sha_update(struct HASH_CTX *unused,
+ const uint8_t *data, uint32_t n)
+{
+ 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;
+ }
+}
+
+void dcrypto_sha_init(enum sha_mode mode)
+{
+ /* Stop LIVESTREAM mode, in case final() was not called. */
+ GWRITE_FIELD(KEYMGR, SHA_TRIG, TRIG_STOP, 1);
+ /* Clear interrupt status. */
+ GREG32(KEYMGR, SHA_ITOP) = 0;
+ /* SHA1 or SHA256 mode */
+ GWRITE_FIELD(KEYMGR, SHA_CFG_EN, SHA1, mode == SHA1_MODE ? 1 : 0);
+ /* Enable streaming mode. */
+ GWRITE_FIELD(KEYMGR, SHA_CFG_EN, LIVESTREAM, 1);
+ /* Enable the SHA DONE interrupt. */
+ GWRITE_FIELD(KEYMGR, SHA_CFG_EN, INT_EN_DONE, 1);
+ /* Start SHA engine. */
+ GWRITE_FIELD(KEYMGR, SHA_TRIG, TRIG_GO, 1);
+}
+
+void DCRYPTO_SHA256_init(SHA256_CTX *ctx, uint32_t sw_required)
+{
+ if (!sw_required && dcrypto_grab_sha_hw()) {
+ ctx->vtab = &HW_SHA256_VTAB;
+ dcrypto_sha_init(SHA1_MODE);
+ }
+#ifndef SECTION_IS_RO
+ else
+ sha256_init(ctx);
+#endif
+}
+
+static const uint8_t *dcrypto_sha256_final(SHA256_CTX *ctx)
+{
+ dcrypto_sha_wait(SHA256_MODE, (uint32_t *) ctx->u.buf);
+ dcrypto_release_sha_hw();
+ return ctx->u.buf;
+}
+
+const uint8_t *DCRYPTO_SHA256_hash(const uint8_t *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
+ return digest;
+}