summaryrefslogtreecommitdiff
path: root/board/cr50/dcrypto/aes.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/cr50/dcrypto/aes.c')
-rw-r--r--board/cr50/dcrypto/aes.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/board/cr50/dcrypto/aes.c b/board/cr50/dcrypto/aes.c
new file mode 100644
index 0000000000..f5cc0e6d8f
--- /dev/null
+++ b/board/cr50/dcrypto/aes.c
@@ -0,0 +1,160 @@
+/* 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 set_control_register(
+ unsigned mode, unsigned key_size, unsigned encrypt)
+{
+ GWRITE_FIELD(KEYMGR, AES_CTRL, RESET, CTRL_NO_SOFT_RESET);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, KEYSIZE, key_size);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, CIPHER_MODE, mode);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, ENC_MODE, encrypt);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, CTR_ENDIAN, CTRL_CTR_BIG_ENDIAN);
+ GWRITE_FIELD(KEYMGR, AES_CTRL, ENABLE, CTRL_ENABLE);
+
+ /* Turn off random nops (which are enabled by default). */
+ GWRITE_FIELD(KEYMGR, AES_RAND_STALL_CTL, STALL_EN, 0);
+ /* Configure random nop percentage at 25%. */
+ GWRITE_FIELD(KEYMGR, AES_RAND_STALL_CTL, FREQ, 1);
+ /* Now turn on random nops. */
+ GWRITE_FIELD(KEYMGR, AES_RAND_STALL_CTL, STALL_EN, 1);
+}
+
+static int wait_read_data(volatile uint32_t *addr)
+{
+ int empty;
+ int count = 20; /* Wait these many ~cycles. */
+
+ do {
+ empty = REG32(addr);
+ count--;
+ } while (count && empty);
+
+ return empty ? 0 : 1;
+}
+
+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 i;
+ const struct access_helper *p;
+ uint32_t key_mode;
+
+ switch (key_len) {
+ case 128:
+ key_mode = 0;
+ break;
+ case 192:
+ key_mode = 1;
+ break;
+ case 256:
+ key_mode = 2;
+ break;
+ default:
+ /* Invalid key length specified. */
+ return 0;
+ }
+ set_control_register(c_mode, key_mode, e_mode);
+
+ /* Initialize hardware with AES key */
+ p = (struct access_helper *) key;
+ for (i = 0; i < (key_len >> 5); i++)
+ GR_KEYMGR_AES_KEY(i) = p[i].udata;
+ /* Trigger key expansion. */
+ GREG32(KEYMGR, AES_KEY_START) = 1;
+
+ /* Wait for key expansion. */
+ if (!wait_read_data(GREG32_ADDR(KEYMGR, AES_KEY_START))) {
+ /* Should not happen. */
+ return 0;
+ }
+
+ /* Initialize IV for modes that require it. */
+ if (iv) {
+ p = (struct access_helper *) iv;
+ for (i = 0; i < 4; i++)
+ GR_KEYMGR_AES_CTR(i) = p[i].udata;
+ }
+ return 1;
+}
+
+int DCRYPTO_aes_block(const uint8_t *in, uint8_t *out)
+{
+ int i;
+ struct access_helper *outw;
+ const struct access_helper *inw = (struct access_helper *) in;
+
+ /* Write plaintext. */
+ for (i = 0; i < 4; i++)
+ GREG32(KEYMGR, AES_WFIFO_DATA) = inw[i].udata;
+
+ /* Wait for the result. */
+ if (!wait_read_data(GREG32_ADDR(KEYMGR, AES_RFIFO_EMPTY))) {
+ /* Should not happen, ciphertext not ready. */
+ return 0;
+ }
+
+ /* Read ciphertext. */
+ outw = (struct access_helper *) out;
+ for (i = 0; i < 4; i++)
+ outw[i].udata = GREG32(KEYMGR, AES_RFIFO_DATA);
+ return 1;
+}
+
+void DCRYPTO_aes_write_iv(const uint8_t *iv)
+{
+ int i;
+ const struct access_helper *p = (const struct access_helper *) iv;
+
+ for (i = 0; i < 4; i++)
+ GR_KEYMGR_AES_CTR(i) = p[i].udata;
+}
+
+void DCRYPTO_aes_read_iv(uint8_t *iv)
+{
+ int i;
+ struct access_helper *p = (struct access_helper *) iv;
+
+ for (i = 0; i < 4; i++)
+ p[i].udata = GR_KEYMGR_AES_CTR(i);
+}
+
+int DCRYPTO_aes_ctr(uint8_t *out, const uint8_t *key, uint32_t key_bits,
+ const uint8_t *iv, const uint8_t *in, size_t in_len)
+{
+ /* Initialize AES hardware. */
+ if (!DCRYPTO_aes_init(key, key_bits, iv,
+ CIPHER_MODE_CTR, ENCRYPT_MODE))
+ return 0;
+
+ while (in_len > 0) {
+ uint8_t tmpin[16];
+ uint8_t tmpout[16];
+ const uint8_t *inp;
+ uint8_t *outp;
+ const size_t count = MIN(in_len, 16);
+
+ if (count < 16) {
+ memcpy(tmpin, in, count);
+ inp = tmpin;
+ outp = tmpout;
+ } else {
+ inp = in;
+ outp = out;
+ }
+ if (!DCRYPTO_aes_block(inp, outp))
+ return 0;
+ if (outp != out)
+ memcpy(out, outp, count);
+
+ in += count;
+ out += count;
+ in_len -= count;
+ }
+ return 1;
+}