From 00b712db867e533a12df0f2c7e3c6e6d49fdeac6 Mon Sep 17 00:00:00 2001 From: Josip Sokcevic Date: Thu, 17 Jun 2021 14:12:54 -0700 Subject: Move copy chip/g/dcrypto to boards/cr50/dcrypto Signed-off-by: Josip Sokcevic --- board/cr50/dcrypto/aes.c | 160 ++++ board/cr50/dcrypto/aes_cmac.c | 346 ++++++++ board/cr50/dcrypto/app_cipher.c | 451 ++++++++++ board/cr50/dcrypto/app_key.c | 87 ++ board/cr50/dcrypto/bn.c | 1244 ++++++++++++++++++++++++++++ board/cr50/dcrypto/compare.c | 20 + board/cr50/dcrypto/dcrypto.h | 445 ++++++++++ board/cr50/dcrypto/dcrypto_bn.c | 1496 ++++++++++++++++++++++++++++++++++ board/cr50/dcrypto/dcrypto_p256.c | 1018 +++++++++++++++++++++++ board/cr50/dcrypto/dcrypto_runtime.c | 480 +++++++++++ board/cr50/dcrypto/dcrypto_sha512.c | 772 ++++++++++++++++++ board/cr50/dcrypto/gcm.c | 345 ++++++++ board/cr50/dcrypto/hkdf.c | 83 ++ board/cr50/dcrypto/hmac.c | 63 ++ board/cr50/dcrypto/hmac_drbg.c | 478 +++++++++++ board/cr50/dcrypto/internal.h | 219 +++++ board/cr50/dcrypto/key_ladder.c | 300 +++++++ board/cr50/dcrypto/p256.c | 30 + board/cr50/dcrypto/p256_ec.c | 39 + board/cr50/dcrypto/p256_ecies.c | 175 ++++ board/cr50/dcrypto/proofs_p256.md | 28 + board/cr50/dcrypto/rsa.c | 743 +++++++++++++++++ board/cr50/dcrypto/sha1.c | 65 ++ board/cr50/dcrypto/sha256.c | 195 +++++ board/cr50/dcrypto/sha384.c | 20 + board/cr50/dcrypto/sha512.c | 20 + board/cr50/dcrypto/trng.c | 236 ++++++ board/cr50/dcrypto/x509.c | 545 +++++++++++++ chip/g/dcrypto/aes.c | 160 ---- chip/g/dcrypto/aes_cmac.c | 346 -------- chip/g/dcrypto/app_cipher.c | 451 ---------- chip/g/dcrypto/app_key.c | 87 -- chip/g/dcrypto/bn.c | 1244 ---------------------------- chip/g/dcrypto/compare.c | 20 - chip/g/dcrypto/dcrypto.h | 445 ---------- chip/g/dcrypto/dcrypto_bn.c | 1496 ---------------------------------- chip/g/dcrypto/dcrypto_p256.c | 1018 ----------------------- chip/g/dcrypto/dcrypto_runtime.c | 480 ----------- chip/g/dcrypto/dcrypto_sha512.c | 772 ------------------ chip/g/dcrypto/gcm.c | 345 -------- chip/g/dcrypto/hkdf.c | 83 -- chip/g/dcrypto/hmac.c | 63 -- chip/g/dcrypto/hmac_drbg.c | 478 ----------- chip/g/dcrypto/internal.h | 219 ----- chip/g/dcrypto/key_ladder.c | 300 ------- chip/g/dcrypto/p256.c | 30 - chip/g/dcrypto/p256_ec.c | 39 - chip/g/dcrypto/p256_ecies.c | 175 ---- chip/g/dcrypto/proofs_p256.md | 28 - chip/g/dcrypto/rsa.c | 743 ----------------- chip/g/dcrypto/sha1.c | 65 -- chip/g/dcrypto/sha256.c | 195 ----- chip/g/dcrypto/sha384.c | 20 - chip/g/dcrypto/sha512.c | 20 - chip/g/dcrypto/x509.c | 545 ------------- chip/g/trng.c | 236 ------ 56 files changed, 10103 insertions(+), 10103 deletions(-) create mode 100644 board/cr50/dcrypto/aes.c create mode 100644 board/cr50/dcrypto/aes_cmac.c create mode 100644 board/cr50/dcrypto/app_cipher.c create mode 100644 board/cr50/dcrypto/app_key.c create mode 100644 board/cr50/dcrypto/bn.c create mode 100644 board/cr50/dcrypto/compare.c create mode 100644 board/cr50/dcrypto/dcrypto.h create mode 100644 board/cr50/dcrypto/dcrypto_bn.c create mode 100644 board/cr50/dcrypto/dcrypto_p256.c create mode 100644 board/cr50/dcrypto/dcrypto_runtime.c create mode 100644 board/cr50/dcrypto/dcrypto_sha512.c create mode 100644 board/cr50/dcrypto/gcm.c create mode 100644 board/cr50/dcrypto/hkdf.c create mode 100644 board/cr50/dcrypto/hmac.c create mode 100644 board/cr50/dcrypto/hmac_drbg.c create mode 100644 board/cr50/dcrypto/internal.h create mode 100644 board/cr50/dcrypto/key_ladder.c create mode 100644 board/cr50/dcrypto/p256.c create mode 100644 board/cr50/dcrypto/p256_ec.c create mode 100644 board/cr50/dcrypto/p256_ecies.c create mode 100644 board/cr50/dcrypto/proofs_p256.md create mode 100644 board/cr50/dcrypto/rsa.c create mode 100644 board/cr50/dcrypto/sha1.c create mode 100644 board/cr50/dcrypto/sha256.c create mode 100644 board/cr50/dcrypto/sha384.c create mode 100644 board/cr50/dcrypto/sha512.c create mode 100644 board/cr50/dcrypto/trng.c create mode 100644 board/cr50/dcrypto/x509.c delete mode 100644 chip/g/dcrypto/aes.c delete mode 100644 chip/g/dcrypto/aes_cmac.c delete mode 100644 chip/g/dcrypto/app_cipher.c delete mode 100644 chip/g/dcrypto/app_key.c delete mode 100644 chip/g/dcrypto/bn.c delete mode 100644 chip/g/dcrypto/compare.c delete mode 100644 chip/g/dcrypto/dcrypto.h delete mode 100644 chip/g/dcrypto/dcrypto_bn.c delete mode 100644 chip/g/dcrypto/dcrypto_p256.c delete mode 100644 chip/g/dcrypto/dcrypto_runtime.c delete mode 100644 chip/g/dcrypto/dcrypto_sha512.c delete mode 100644 chip/g/dcrypto/gcm.c delete mode 100644 chip/g/dcrypto/hkdf.c delete mode 100644 chip/g/dcrypto/hmac.c delete mode 100644 chip/g/dcrypto/hmac_drbg.c delete mode 100644 chip/g/dcrypto/internal.h delete mode 100644 chip/g/dcrypto/key_ladder.c delete mode 100644 chip/g/dcrypto/p256.c delete mode 100644 chip/g/dcrypto/p256_ec.c delete mode 100644 chip/g/dcrypto/p256_ecies.c delete mode 100644 chip/g/dcrypto/proofs_p256.md delete mode 100644 chip/g/dcrypto/rsa.c delete mode 100644 chip/g/dcrypto/sha1.c delete mode 100644 chip/g/dcrypto/sha256.c delete mode 100644 chip/g/dcrypto/sha384.c delete mode 100644 chip/g/dcrypto/sha512.c delete mode 100644 chip/g/dcrypto/x509.c delete mode 100644 chip/g/trng.c 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; +} diff --git a/board/cr50/dcrypto/aes_cmac.c b/board/cr50/dcrypto/aes_cmac.c new file mode 100644 index 0000000000..4f996f42b6 --- /dev/null +++ b/board/cr50/dcrypto/aes_cmac.c @@ -0,0 +1,346 @@ +/* Copyright 2018 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. + */ + +/* AES-CMAC-128 implementation according to NIST SP 800-38B, RFC4493 */ +#include "console.h" +#include "dcrypto.h" + +#define BSIZE 16 /* 16 bytes per 128-bit block */ + +/* Given a 128-bit number in 32-bit chunks, shift to the left by one */ +static void shiftl_1(const uint8_t *in, uint8_t *out) +{ + int i; + uint8_t carry = 0; + + for (i = 15; i >= 0; i--) { + out[i] = in[i] << 1; + out[i] |= carry; + carry = (in[i] & 0x80) ? 1 : 0; + } +} + +static void xor128(const uint32_t in1[4], const uint32_t in2[4], + uint32_t out[4]) +{ + int i; + + for (i = 0; i < 4; i++) + out[i] = in1[i] ^ in2[i]; +} + +static void get_and_xor(const uint8_t *arr, const uint32_t nBytes, int i, + const uint8_t *xor_term, uint8_t *out) +{ + int j; + int k; + + for (j = 0; j < 16; j++) { + k = i*16 + j; /* index in arr */ + if (k < nBytes) + out[j] = arr[k]; + else if (k == nBytes) + out[j] = 0x80; + else + out[j] = 0; + out[j] = out[j] ^ xor_term[j]; + } +} + +/* Wrapper for initializing and calling AES-128 */ +static int aes128(const uint8_t *K, const uint32_t in[4], uint32_t out[4]) +{ + const uint32_t zero[4] = {0, 0, 0, 0}; + + if (!DCRYPTO_aes_init((const uint8_t *)K, 128, (const uint8_t *) zero, + CIPHER_MODE_ECB, ENCRYPT_MODE)) + return 0; + if (!DCRYPTO_aes_block((const uint8_t *) in, (uint8_t *) out)) + return 0; + return 1; +} + +static int gen_subkey(const uint8_t *K, uint32_t k1[4], uint32_t k2[4]) +{ + uint32_t L[4]; + uint32_t tmp[4]; + const uint32_t *xor_term; + static const uint32_t zero[4] = {0, 0, 0, 0}; + static const uint32_t Rb[4] = {0, 0, 0, 0x87000000}; + + if (!aes128(K, zero, L)) + return 0; + + xor_term = (L[0] & 0x00000080) ? Rb : zero; + shiftl_1((const uint8_t *)L, (uint8_t *)tmp); + xor128(tmp, xor_term, k1); + + xor_term = (k1[0] & 0x00000080) ? Rb : zero; + shiftl_1((const uint8_t *) k1, (uint8_t *) tmp); + xor128(tmp, xor_term, k2); + + return 1; +} + +int DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, const uint32_t len, + uint32_t T[4]) +{ + uint32_t n; + int i; + int flag; + uint32_t k1[4]; + uint32_t k2[4]; + uint32_t M_last[4]; + uint32_t Y[4]; + uint32_t X[4] = {0, 0, 0, 0}; + + /* Generate the subkeys K1 and K2 */ + if (!gen_subkey(K, k1, k2)) + return 0; + + /* Set n and flag. + * flag = 1 if the last block has a full 128 bits; 0 otherwise + * n = number of 128-bit blocks in input = ceil (len / BSIZE) + * + * Special case: if len = 0, then n = 1 and flag = 0. + */ + flag = (len % BSIZE == 0) ? 1 : 0; + n = len / BSIZE + (flag ? 0 : 1); // ceil (len / BSIZE) + if (len == 0) { + n = 1; + flag = 0; + } + + /* M_last = padded(last 128-bit block of M) ^ (flag ? k1 : k2) */ + get_and_xor(M, len, n-1, (uint8_t *) (flag ? k1 : k2), + (uint8_t *) M_last); + + for (i = 0; i < n - 1; i++) { + /* Y = padded(nth 128-bit block of M) ^ (flag ? k1 : k2) */ + get_and_xor(M, len, i, (uint8_t *)X, (uint8_t *)Y); + if (!aes128(K, Y, X)) + return 0; + } + + /* TODO: This block is separate from the main loop in the RFC. However, + * if we set M[n-1] = M_last, then it is equivalent to running the loop + * for one more step, which might be a nicer way to write it. + */ + xor128(X, M_last, Y); + if (!aes128(K, Y, T)) + return 0; + return 1; +} + +int DCRYPTO_aes_cmac_verify(const uint8_t *key, const uint8_t *M, const int len, + const uint32_t T[4]) +{ + int i; + uint32_t T2[4]; + int match = 1; + + if (!DCRYPTO_aes_cmac(key, M, len, T2)) + return -EC_ERROR_UNKNOWN; + + for (i = 0; i < 4; i++) { + if (T[i] != T2[i]) + match = 0; + } + return match; +} + +#ifdef CRYPTO_TEST_SETUP +static int check_answer(const uint32_t expected[4], uint32_t actual[4]) +{ + int i; + int success = 1; + + for (i = 0; i < 4; i++) { + if (actual[i] != expected[i]) + success = 0; + } + if (success) { + ccprintf("SUCCESS\n"); + } else { + ccprintf("FAILURE:\n"); + ccprintf("actual = 0x%08x 0x%08x 0x%08x 0x%08x\n", actual[0], + actual[1], actual[2], actual[3]); + ccprintf("expected = 0x%08x 0x%08x 0x%08x 0x%08x\n", + expected[0], expected[1], expected[2], expected[3]); + } + return success; +} + +static int command_test_aes_block(int argc, char **argv) +{ + uint32_t actual[4]; + const uint32_t zero[4] = {0, 0, 0, 0}; + const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09}; + const uint32_t expected[4] = {0x0c6bf77d, 0xb399b81a, 0x47f0423e, + 0x6f541bb9}; + + aes128((const uint8_t *) K, zero, actual); + check_answer(expected, actual); + + return 0; +} + +DECLARE_SAFE_CONSOLE_COMMAND(test_aesbk, command_test_aes_block, NULL, + "Test AES block in AES-CMAC subkey generation"); + +static int command_test_subkey_gen(int argc, char **argv) +{ + uint32_t k1[4]; + uint32_t k2[4]; + /* K: 2b7e1516 28aed2a6 abf71588 09cf4f3c + * k1: fbeed618 35713366 7c85e08f 7236a8de + * k2: f7ddac30 6ae266cc f90bc11e e46d513b + */ + const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09}; + const uint32_t k1e[4] = {0x18d6eefb, 0x66337135, 0x8fe0857c, + 0xdea83672}; + const uint32_t k2e[4] = {0x30acddf7, 0xcc66e26a, 0x1ec10bf9, + 0x3b516de4}; + + gen_subkey((const uint8_t *) K, k1, k2); + + ccprintf("Checking K1: "); + check_answer(k1e, k1); + + ccprintf("Checking K2: "); + check_answer(k2e, k2); + + return 0; +} + +DECLARE_SAFE_CONSOLE_COMMAND(test_skgen, command_test_subkey_gen, NULL, + "Test AES-CMAC subkey generation"); + +struct cmac_test_param { + uint32_t len; + uint8_t *M; + uint32_t Te[4]; +}; + +/* N.B. The order of bytes in each 32-bit block is reversed from the form in + * which they are written in the RFC. + */ +const struct cmac_test_param rfctests[4] = { + /* -------------------------------------------------- + * Example 1: len = 0 + * M + * AES-CMAC bb1d6929 e9593728 7fa37d12 9b756746 + * -------------------------------------------------- + */ + { .len = 0, + .M = (uint8_t *) "", + .Te = {0x29691dbb, 0x283759e9, 0x127da37f, 0x4667759b}, + }, + /* -------------------------------------------------- + * Example 2: len = 16 + * M 6bc1bee2 2e409f96 e93d7e11 7393172a + * AES-CMAC 070a16b4 6b4d4144 f79bdd9d d04a287c + * -------------------------------------------------- + */ + { .len = 16, + .M = (uint8_t *) (uint32_t[]) { + 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373 + }, + .Te = {0xb4160a07, 0x44414d6b, 0x9ddd9bf7, 0x7c284ad0}, + }, + /* -------------------------------------------------- + * Example 3: len = 40 + * M 6bc1bee2 2e409f96 e93d7e11 7393172a + * ae2d8a57 1e03ac9c 9eb76fac 45af8e51 + * 30c81c46 a35ce411 + * AES-CMAC dfa66747 de9ae630 30ca3261 1497c827 + * -------------------------------------------------- + */ + { .len = 40, + .M = (uint8_t *) (uint32_t[]) { + 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373, + 0x578a2dae, 0x9cac031e, 0xac6fb79e, 0x518eaf45, + 0x461cc830, 0x11e45ca3 + }, + .Te = {0x4767a6df, 0x30e69ade, 0x6132ca30, 0x27c89714}, + }, + /* -------------------------------------------------- + * Example 4: len = 64 + * M 6bc1bee2 2e409f96 e93d7e11 7393172a + * ae2d8a57 1e03ac9c 9eb76fac 45af8e51 + * 30c81c46 a35ce411 e5fbc119 1a0a52ef + * f69f2445 df4f9b17 ad2b417b e66c3710 + * AES-CMAC 51f0bebf 7e3b9d92 fc497417 79363cfe + * -------------------------------------------------- + */ + { .len = 64, + .M = (uint8_t *) (uint32_t[]) { + 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373, + 0x578a2dae, 0x9cac031e, 0xac6fb79e, 0x518eaf45, + 0x461cc830, 0x11e45ca3, 0x19c1fbe5, 0xef520a1a, + 0x45249ff6, 0x179b4fdf, 0x7b412bad, 0x10376ce6 + }, + .Te = {0xbfbef051, 0x929d3b7e, 0x177449fc, 0xfe3c3679}, + }, +}; + +static int command_test_aes_cmac(int argc, char **argv) +{ + int i; + uint32_t T[4]; + int testN; + struct cmac_test_param param; + const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09}; + + for (i = 1; i < argc; i++) { + testN = strtoi(argv[i], NULL, 10); + param = rfctests[testN - 1]; + + ccprintf("Testing RFC Example #%d (%d-byte message)...", testN, + param.len); + + DCRYPTO_aes_cmac((const uint8_t *)K, param.M, param.len, T); + check_answer(param.Te, T); + } + + return 0; +} + +DECLARE_SAFE_CONSOLE_COMMAND(test_cmac, command_test_aes_cmac, + "[test cases (1-4)]", + "Test AES-CMAC with RFC examples"); + +static int command_test_verify(int argc, char **argv) +{ + int i; + int testN; + int result; + struct cmac_test_param param; + const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09}; + + for (i = 1; i < argc; i++) { + testN = strtoi(argv[i], NULL, 10); + param = rfctests[testN-1]; + + ccprintf("Testing RFC Example #%d (%d-byte message)...", testN, + param.len); + + result = DCRYPTO_aes_cmac_verify((const uint8_t *)K, param.M, + param.len, param.Te); + if (result == 1) + ccprintf("SUCCESS\n"); + else if (result == 0) + ccprintf("FAILURE: verify returned INVALID\n"); + else if (result == -EC_ERROR_UNKNOWN) + ccprintf("FAILURE: verify returned ERROR\n"); + } + + return 0; +} + +DECLARE_SAFE_CONSOLE_COMMAND(test_cmac_ver, command_test_verify, + "[test cases (1-4)]", + "Test AES-CMAC-verify with RFC examples"); +#endif /* CRYPTO_TEST_SETUP */ diff --git a/board/cr50/dcrypto/app_cipher.c b/board/cr50/dcrypto/app_cipher.c new file mode 100644 index 0000000000..125b443ee6 --- /dev/null +++ b/board/cr50/dcrypto/app_cipher.c @@ -0,0 +1,451 @@ +/* + * Copyright 2017 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 "registers.h" + +/* The default build options compile for size (-Os); instruct the + * compiler to optimize for speed here. Incidentally -O produces + * faster code than -O2! + */ +static int __attribute__((optimize("O"))) +inner_loop(uint32_t **out, const uint32_t **in, size_t len) +{ + uint32_t *outw = *out; + const uint32_t *inw = *in; + + while (len >= 16) { + uint32_t w0, w1, w2, w3; + + w0 = inw[0]; + w1 = inw[1]; + w2 = inw[2]; + w3 = inw[3]; + GREG32(KEYMGR, AES_WFIFO_DATA) = w0; + GREG32(KEYMGR, AES_WFIFO_DATA) = w1; + GREG32(KEYMGR, AES_WFIFO_DATA) = w2; + GREG32(KEYMGR, AES_WFIFO_DATA) = w3; + + while (GREG32(KEYMGR, AES_RFIFO_EMPTY)) + ; + + w0 = GREG32(KEYMGR, AES_RFIFO_DATA); + w1 = GREG32(KEYMGR, AES_RFIFO_DATA); + w2 = GREG32(KEYMGR, AES_RFIFO_DATA); + w3 = GREG32(KEYMGR, AES_RFIFO_DATA); + outw[0] = w0; + outw[1] = w1; + outw[2] = w2; + outw[3] = w3; + + inw += 4; + outw += 4; + len -= 16; + } + + *in = inw; + *out = outw; + return len; +} + +static int outer_loop(uint32_t **out, const uint32_t **in, size_t len) +{ + uint32_t *outw = *out; + const uint32_t *inw = *in; + + if (len >= 16) { + GREG32(KEYMGR, AES_WFIFO_DATA) = inw[0]; + GREG32(KEYMGR, AES_WFIFO_DATA) = inw[1]; + GREG32(KEYMGR, AES_WFIFO_DATA) = inw[2]; + GREG32(KEYMGR, AES_WFIFO_DATA) = inw[3]; + inw += 4; + len -= 16; + + len = inner_loop(&outw, &inw, len); + + while (GREG32(KEYMGR, AES_RFIFO_EMPTY)) + ; + + outw[0] = GREG32(KEYMGR, AES_RFIFO_DATA); + outw[1] = GREG32(KEYMGR, AES_RFIFO_DATA); + outw[2] = GREG32(KEYMGR, AES_RFIFO_DATA); + outw[3] = GREG32(KEYMGR, AES_RFIFO_DATA); + outw += 4; + } + + *in = inw; + *out = outw; + return len; +} + +static int aes_init(struct APPKEY_CTX *ctx, enum dcrypto_appid appid, + const uint32_t iv[4]) +{ + /* Setup USR-based application key. */ + if (!DCRYPTO_appkey_init(appid, ctx)) + return 0; + + /* Configure AES engine. */ + GWRITE_FIELD(KEYMGR, AES_CTRL, RESET, CTRL_NO_SOFT_RESET); + GWRITE_FIELD(KEYMGR, AES_CTRL, KEYSIZE, 2 /* AES-256 */); + GWRITE_FIELD(KEYMGR, AES_CTRL, CIPHER_MODE, CIPHER_MODE_CTR); + GWRITE_FIELD(KEYMGR, AES_CTRL, ENC_MODE, ENCRYPT_MODE); + GWRITE_FIELD(KEYMGR, AES_CTRL, CTR_ENDIAN, CTRL_CTR_BIG_ENDIAN); + + /* + * For fixed-key, bulk ciphering, turn off random nops (which + * are enabled by default). + */ + GWRITE_FIELD(KEYMGR, AES_RAND_STALL_CTL, STALL_EN, 0); + + /* Enable hidden key usage, each appid gets its own + * USR, with USR0 starting at 0x2a0. + */ + GWRITE_FIELD(KEYMGR, AES_USE_HIDDEN_KEY, INDEX, + 0x2a0 + (appid * 2)); + GWRITE_FIELD(KEYMGR, AES_USE_HIDDEN_KEY, ENABLE, 1); + GWRITE_FIELD(KEYMGR, AES_CTRL, ENABLE, CTRL_ENABLE); + + /* Wait for key-expansion. */ + GREG32(KEYMGR, AES_KEY_START) = 1; + while (GREG32(KEYMGR, AES_KEY_START)) + ; + + /* Check for errors (e.g. USR not correctly setup. */ + if (GREG32(KEYMGR, HKEY_ERR_FLAGS)) + return 0; + + /* Set IV. */ + GR_KEYMGR_AES_CTR(0) = iv[0]; + GR_KEYMGR_AES_CTR(1) = iv[1]; + GR_KEYMGR_AES_CTR(2) = iv[2]; + GR_KEYMGR_AES_CTR(3) = iv[3]; + + return 1; +} + +int DCRYPTO_app_cipher(enum dcrypto_appid appid, const void *salt, + void *out, const void *in, size_t len) +{ + struct APPKEY_CTX ctx; + const uint32_t *inw = in; + uint32_t *outw = out; + + /* Test pointers for word alignment. */ + if (((uintptr_t) in & 0x03) || ((uintptr_t) out & 0x03)) + return 0; + + { + /* Initialize key, and AES engine. */ + uint32_t iv[4]; + + memcpy(iv, salt, sizeof(iv)); + if (!aes_init(&ctx, appid, iv)) + return 0; + } + + len = outer_loop(&outw, &inw, len); + + if (len) { + /* Cipher the final partial block */ + uint32_t tmpin[4]; + uint32_t tmpout[4]; + const uint32_t *tmpinw; + uint32_t *tmpoutw; + + tmpinw = tmpin; + tmpoutw = tmpout; + + memcpy(tmpin, inw, len); + outer_loop(&tmpoutw, &tmpinw, 16); + memcpy(outw, tmpout, len); + } + + DCRYPTO_appkey_finish(&ctx); + return 1; +} + +#ifdef CRYPTO_TEST_SETUP + +#include "common.h" +#include "console.h" +#include "hooks.h" +#include "shared_mem.h" +#include "task.h" +#include "timer.h" +#include "watchdog.h" + +#define HEAP_HEAD_ROOM 0x400 +static uint32_t number_of_iterations; +static uint8_t result; + +/* Staticstics for ecrypt and decryp passes. */ +struct ciph_stats { + uint16_t min_time; + uint16_t max_time; + uint32_t total_time; +} __packed; /* Just in case. */ + +/* A common structure to contain information about the test run. */ +struct test_info { + size_t test_blob_size; + struct ciph_stats enc_stats; + struct ciph_stats dec_stats; + char *p; /* Pointer to an allcoated buffer of test_blob_size bytes. */ +}; + +static void init_stats(struct ciph_stats *stats) +{ + stats->min_time = ~0; + stats->max_time = 0; + stats->total_time = 0; +} + +static void update_stats(struct ciph_stats *stats, uint32_t time) +{ + if (time < stats->min_time) + stats->min_time = time; + + if (time > stats->max_time) + stats->max_time = time; + + stats->total_time += time; +} + +static void report_stats(const char *direction, struct ciph_stats *stats) +{ + ccprintf("%s results: min %d us, max %d us, average %d us\n", + direction, stats->min_time, stats->max_time, + stats->total_time / number_of_iterations); +} + +/* + * Prepare to run the test: allocate memory, initialize stats structures. + * + * Returns EC_SUCCESS if everything is fine, EC_ERROR_OVERFLOW on malloc + * failures. + */ +static int prepare_running(struct test_info *pinfo) +{ + memset(pinfo, 0, sizeof(*pinfo)); + + + pinfo->test_blob_size = shared_mem_size(); + /* + * Leave some room for crypto functions if they need to allocate + * something, just in case. 0x20 extra bytes are needed to be able to + * modify size alignment of the allocated buffer. + */ + if (pinfo->test_blob_size < (HEAP_HEAD_ROOM + 0x20)) { + ccprintf("Not enough memory to run the test\n"); + return EC_ERROR_OVERFLOW; + } + pinfo->test_blob_size = (pinfo->test_blob_size - HEAP_HEAD_ROOM); + + if (shared_mem_acquire(pinfo->test_blob_size, + (char **)&(pinfo->p)) != EC_SUCCESS) { + ccprintf("Failed to allocate %d bytes\n", + pinfo->test_blob_size); + return EC_ERROR_OVERFLOW; + } + + /* + * Use odd block size to make sure unaligned length blocks are handled + * properly. This leaves room in the end of the buffer to check if the + * decryption routine scratches it. + */ + pinfo->test_blob_size &= ~0x1f; + pinfo->test_blob_size |= 7; + + ccprintf("running %d iterations\n", number_of_iterations); + ccprintf("blob size %d at %pP\n", pinfo->test_blob_size, pinfo->p); + + init_stats(&(pinfo->enc_stats)); + init_stats(&(pinfo->dec_stats)); + + return EC_SUCCESS; +} + +/* + * Let's split the buffer in two equal halves, encrypt the lower half into the + * upper half and compare them word by word. There should be no repetitions. + * + * The side effect of this is starting the test with random clear text data. + * + * The first 16 bytes of the allocated buffer are used as the encryption IV. + */ +static int basic_check(struct test_info *pinfo) +{ + size_t half; + int i; + uint32_t *p; + + ccprintf("original data %ph\n", HEX_BUF(pinfo->p, 16)); + + half = (pinfo->test_blob_size/2) & ~3; + if (!DCRYPTO_app_cipher(NVMEM, pinfo->p, pinfo->p, + pinfo->p + half, half)) { + ccprintf("first ecnryption run failed\n"); + return EC_ERROR_UNKNOWN; + } + + p = (uint32_t *)pinfo->p; + half /= sizeof(*p); + + for (i = 0; i < half; i++) + if (p[i] == p[i + half]) { + ccprintf("repeating 32 bit word detected" + " at offset 0x%x!\n", i * 4); + return EC_ERROR_UNKNOWN; + } + + ccprintf("hashed data %ph\n", HEX_BUF(pinfo->p, 16)); + + return EC_SUCCESS; +} + +/* + * Main iteration of the console command, runs ecnryption/decryption cycles, + * vefifying that decrypted text's hash matches the original, and accumulating + * timing statistics. + */ +static int command_loop(struct test_info *pinfo) +{ + uint8_t sha[SHA_DIGEST_SIZE]; + uint8_t sha_after[SHA_DIGEST_SIZE]; + uint32_t iteration; + uint8_t *p_last_byte; + int rv; + + /* + * Prepare the hash of the original data to be able to verify + * results. + */ + DCRYPTO_SHA1_hash(pinfo->p, pinfo->test_blob_size, sha); + + /* Use the hash as an IV for the cipher. */ + memcpy(sha_after, sha, sizeof(sha_after)); + + iteration = number_of_iterations; + p_last_byte = pinfo->p + pinfo->test_blob_size; + + while (iteration--) { + char last_byte = (char) iteration; + uint32_t tstamp; + + *p_last_byte = last_byte; + + if (!(iteration % 500)) + watchdog_reload(); + + tstamp = get_time().val; + rv = DCRYPTO_app_cipher(NVMEM, sha_after, pinfo->p, + pinfo->p, pinfo->test_blob_size); + tstamp = get_time().val - tstamp; + + if (!rv) { + ccprintf("encryption failed\n"); + return EC_ERROR_UNKNOWN; + } + if (*p_last_byte != last_byte) { + ccprintf("encryption overflowed\n"); + return EC_ERROR_UNKNOWN; + } + update_stats(&pinfo->enc_stats, tstamp); + + tstamp = get_time().val; + rv = DCRYPTO_app_cipher(NVMEM, sha_after, pinfo->p, + pinfo->p, pinfo->test_blob_size); + tstamp = get_time().val - tstamp; + + if (!rv) { + ccprintf("decryption failed\n"); + return EC_ERROR_UNKNOWN; + } + if (*p_last_byte != last_byte) { + ccprintf("decryption overflowed\n"); + return EC_ERROR_UNKNOWN; + } + + DCRYPTO_SHA1_hash(pinfo->p, pinfo->test_blob_size, sha_after); + if (memcmp(sha, sha_after, sizeof(sha))) { + ccprintf("\n" + "sha1 before and after mismatch, %d to go!\n", + iteration); + return EC_ERROR_UNKNOWN; + } + + update_stats(&pinfo->dec_stats, tstamp); + + /* get a new IV */ + DCRYPTO_SHA1_hash(sha_after, sizeof(sha), sha_after); + } + + return EC_SUCCESS; +} + +/* + * Run cipher command on the hooks task context, as dcrypto's stack + * requirements exceed console tasks' allowance. + */ +static void run_cipher_cmd(void) +{ + struct test_info info; + + result = prepare_running(&info); + + if (result == EC_SUCCESS) + result = basic_check(&info); + + if (result == EC_SUCCESS) + result = command_loop(&info); + + if (result == EC_SUCCESS) { + report_stats("Encryption", &info.enc_stats); + report_stats("Decryption", &info.dec_stats); + } else if (info.p) { + ccprintf("current data %ph\n", HEX_BUF(info.p, 16)); + } + + if (info.p) + shared_mem_release(info.p); + + task_set_event(TASK_ID_CONSOLE, TASK_EVENT_CUSTOM_BIT(0), 0); +} +DECLARE_DEFERRED(run_cipher_cmd); + +static int cmd_cipher(int argc, char **argv) +{ + uint32_t events; + uint32_t max_time; + + /* Ignore potential input errors, let the user handle them. */ + if (argc > 1) + number_of_iterations = strtoi(argv[1], NULL, 0); + else + number_of_iterations = 1000; + + if (!number_of_iterations) { + ccprintf("not running zero iterations\n"); + return EC_ERROR_PARAM1; + } + + hook_call_deferred(&run_cipher_cmd_data, 0); + + /* Roughly, .5 us per byte should be more than enough. */ + max_time = number_of_iterations * shared_mem_size() / 2; + + ccprintf("Will wait up to %d ms\n", (max_time + 500)/1000); + + events = task_wait_event_mask(TASK_EVENT_CUSTOM_BIT(0), max_time); + if (!(events & TASK_EVENT_CUSTOM_BIT(0))) { + ccprintf("Timed out, you might want to reboot...\n"); + return EC_ERROR_TIMEOUT; + } + + return result; +} +DECLARE_SAFE_CONSOLE_COMMAND(cipher, cmd_cipher, NULL, NULL); +#endif diff --git a/board/cr50/dcrypto/app_key.c b/board/cr50/dcrypto/app_key.c new file mode 100644 index 0000000000..1fafab9d2e --- /dev/null +++ b/board/cr50/dcrypto/app_key.c @@ -0,0 +1,87 @@ +/* Copyright 2016 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 "endian.h" +#include "registers.h" + +#include "cryptoc/util.h" + +#include "console.h" + +const char *const dcrypto_app_names[] = { + "RESERVED", + "NVMEM", + "U2F_ATTEST", + "U2F_ORIGIN", + "U2F_WRAP", + /* This key signs data from H1's configured by mn50/scribe. */ + "PERSO_AUTH", + "PINWEAVER", +}; + +static void name_hash(enum dcrypto_appid appid, + uint32_t digest[SHA256_DIGEST_WORDS]) +{ + LITE_SHA256_CTX ctx; + const char *name = dcrypto_app_names[appid]; + size_t x; + + /* The PERSO_AUTH digest was improperly defined, so now this exception + * exists to prevent data loss. + */ + if (appid == PERSO_AUTH) { + digest[0] = 0x2019da34; + digest[1] = 0xf1a01a13; + digest[2] = 0x0fb9f73f; + digest[3] = 0xf2e85f76; + digest[4] = 0x5ecb7690; + digest[5] = 0x09f732c9; + digest[6] = 0xe540bf14; + digest[7] = 0xcc46799a; + return; + } + + DCRYPTO_SHA256_init(&ctx, 0); + HASH_update(&ctx, name, strlen(name)); + memcpy(digest, HASH_final(&ctx), SHA256_DIGEST_SIZE); + + /* The digests were originally endian swapped because xxd was used to + * print them so this operation is needed to keep the derived keys the + * same. Any changes to they key derivation process must result in the + * same keys being produced given the same inputs, or devices will + * effectively be reset and user data will be lost by the key change. + */ + for (x = 0; x < SHA256_DIGEST_WORDS; ++x) + digest[x] = __builtin_bswap32(digest[x]); +} + +int DCRYPTO_appkey_init(enum dcrypto_appid appid, struct APPKEY_CTX *ctx) +{ + uint32_t digest[SHA256_DIGEST_WORDS]; + + memset(ctx, 0, sizeof(*ctx)); + name_hash(appid, digest); + + if (!dcrypto_ladder_compute_usr(appid, digest)) + return 0; + + return 1; +} + +void DCRYPTO_appkey_finish(struct APPKEY_CTX *ctx) +{ + always_memset(ctx, 0, sizeof(struct APPKEY_CTX)); + GREG32(KEYMGR, AES_WIPE_SECRETS) = 1; +} + +int DCRYPTO_appkey_derive(enum dcrypto_appid appid, const uint32_t input[8], + uint32_t output[8]) +{ + uint32_t digest[SHA256_DIGEST_WORDS]; + + name_hash(appid, digest); + return !!dcrypto_ladder_derive(appid, digest, input, output); +} diff --git a/board/cr50/dcrypto/bn.c b/board/cr50/dcrypto/bn.c new file mode 100644 index 0000000000..94aafa1799 --- /dev/null +++ b/board/cr50/dcrypto/bn.c @@ -0,0 +1,1244 @@ +/* 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. + */ + +#ifdef PRINT_PRIMES +#include "console.h" +#endif + +#include "dcrypto.h" +#include "internal.h" + +#include "trng.h" + +#include "cryptoc/util.h" + +#include + +#ifdef CONFIG_WATCHDOG +extern void watchdog_reload(void); +#else +static inline void watchdog_reload(void) { } +#endif + +void bn_init(struct LITE_BIGNUM *b, void *buf, size_t len) +{ + DCRYPTO_bn_wrap(b, buf, len); + always_memset(buf, 0x00, len); +} + +void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len) +{ + /* Only word-multiple sized buffers accepted. */ + assert((len & 0x3) == 0); + b->dmax = len / LITE_BN_BYTES; + b->d = (struct access_helper *) buf; +} + +int bn_eq(const struct LITE_BIGNUM *a, const struct LITE_BIGNUM *b) +{ + int i; + uint32_t top = 0; + + for (i = a->dmax - 1; i > b->dmax - 1; --i) + top |= BN_DIGIT(a, i); + if (top) + return 0; + + for (i = b->dmax - 1; i > a->dmax - 1; --i) + top |= BN_DIGIT(b, i); + if (top) + return 0; + + for (i = MIN(a->dmax, b->dmax) - 1; i >= 0; --i) + if (BN_DIGIT(a, i) != BN_DIGIT(b, i)) + return 0; + + return 1; +} + +static void bn_copy(struct LITE_BIGNUM *dst, const struct LITE_BIGNUM *src) +{ + dst->dmax = src->dmax; + memcpy(dst->d, src->d, bn_size(dst)); +} + +int bn_check_topbit(const struct LITE_BIGNUM *N) +{ + return BN_DIGIT(N, N->dmax - 1) >> 31; +} + +/* a[n]. */ +int bn_is_bit_set(const struct LITE_BIGNUM *a, int n) +{ + int i, j; + + if (n < 0) + return 0; + + i = n / LITE_BN_BITS2; + j = n % LITE_BN_BITS2; + if (a->dmax <= i) + return 0; + + return (BN_DIGIT(a, i) >> j) & 1; +} + +static int bn_set_bit(const struct LITE_BIGNUM *a, int n) +{ + int i, j; + + if (n < 0) + return 0; + + i = n / LITE_BN_BITS2; + j = n % LITE_BN_BITS2; + if (a->dmax <= i) + return 0; + + BN_DIGIT(a, i) |= 1 << j; + return 1; +} + +/* a[] >= b[]. */ +/* TODO(ngm): constant time. */ +static int bn_gte(const struct LITE_BIGNUM *a, const struct LITE_BIGNUM *b) +{ + int i; + uint32_t top = 0; + + for (i = a->dmax - 1; i > b->dmax - 1; --i) + top |= BN_DIGIT(a, i); + if (top) + return 1; + + for (i = b->dmax - 1; i > a->dmax - 1; --i) + top |= BN_DIGIT(b, i); + if (top) + return 0; + + for (i = MIN(a->dmax, b->dmax) - 1; + BN_DIGIT(a, i) == BN_DIGIT(b, i) && i > 0; --i) + ; + return BN_DIGIT(a, i) >= BN_DIGIT(b, i); +} + +/* c[] = c[] - a[], assumes c > a. */ +uint32_t bn_sub(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a) +{ + int64_t A = 0; + int i; + + for (i = 0; i < a->dmax; i++) { + A += (uint64_t) BN_DIGIT(c, i) - BN_DIGIT(a, i); + BN_DIGIT(c, i) = (uint32_t) A; + A >>= 32; + } + + for (; A && i < c->dmax; i++) { + A += (uint64_t) BN_DIGIT(c, i); + BN_DIGIT(c, i) = (uint32_t) A; + A >>= 32; + } + + return (uint32_t) A; /* 0 or -1. */ +} + +/* c[] = c[] - a[], negative numbers in 2's complement representation. */ +/* Returns borrow bit. */ +static uint32_t bn_signed_sub(struct LITE_BIGNUM *c, int *c_neg, + const struct LITE_BIGNUM *a, int a_neg) +{ + uint32_t carry = 0; + uint64_t A = 1; + int i; + + for (i = 0; i < a->dmax; ++i) { + A += (uint64_t) BN_DIGIT(c, i) + ~BN_DIGIT(a, i); + BN_DIGIT(c, i) = (uint32_t) A; + A >>= 32; + } + + for (; i < c->dmax; ++i) { + A += (uint64_t) BN_DIGIT(c, i) + 0xFFFFFFFF; + BN_DIGIT(c, i) = (uint32_t) A; + A >>= 32; + } + + A &= 0x01; + carry = (!*c_neg && a_neg && A) || (*c_neg && !a_neg && !A); + *c_neg = carry ? *c_neg : (*c_neg + !a_neg + A) & 0x01; + return carry; +} + +/* c[] = c[] + a[]. */ +uint32_t bn_add(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a) +{ + uint64_t A = 0; + int i; + + for (i = 0; i < a->dmax; ++i) { + A += (uint64_t) BN_DIGIT(c, i) + BN_DIGIT(a, i); + BN_DIGIT(c, i) = (uint32_t) A; + A >>= 32; + } + + for (; A && i < c->dmax; ++i) { + A += (uint64_t) BN_DIGIT(c, i); + BN_DIGIT(c, i) = (uint32_t) A; + A >>= 32; + } + + return (uint32_t) A; /* 0 or 1. */ +} + +/* c[] = c[] + a[], negative numbers in 2's complement representation. */ +/* Returns carry bit. */ +static uint32_t bn_signed_add(struct LITE_BIGNUM *c, int *c_neg, + const struct LITE_BIGNUM *a, int a_neg) +{ + uint32_t A = bn_add(c, a); + uint32_t carry; + + carry = (!*c_neg && !a_neg && A) || (*c_neg && a_neg && !A); + *c_neg = carry ? *c_neg : (*c_neg + a_neg + A) & 0x01; + return carry; +} + +/* r[] <<= 1. */ +static uint32_t bn_lshift(struct LITE_BIGNUM *r) +{ + int i; + uint32_t w; + uint32_t carry = 0; + + for (i = 0; i < r->dmax; i++) { + w = (BN_DIGIT(r, i) << 1) | carry; + carry = BN_DIGIT(r, i) >> 31; + BN_DIGIT(r, i) = w; + } + return carry; +} + +/* r[] >>= 1. Handles 2's complement negative numbers. */ +static void bn_rshift(struct LITE_BIGNUM *r, uint32_t carry, uint32_t neg) +{ + int i; + uint32_t ones = ~0; + uint32_t highbit = (!carry && neg) || (carry && !neg); + + for (i = 0; i < r->dmax - 1; ++i) { + uint32_t accu; + + ones &= BN_DIGIT(r, i); + accu = (BN_DIGIT(r, i) >> 1); + accu |= (BN_DIGIT(r, i + 1) << (LITE_BN_BITS2 - 1)); + BN_DIGIT(r, i) = accu; + } + ones &= BN_DIGIT(r, i); + BN_DIGIT(r, i) = (BN_DIGIT(r, i) >> 1) | + (highbit << (LITE_BN_BITS2 - 1)); + + if (ones == ~0 && highbit && neg) + memset(r->d, 0x00, bn_size(r)); /* -1 >> 1 = 0. */ +} + +/* Montgomery c[] += a * b[] / R % N. */ +/* TODO(ngm): constant time. */ +static void bn_mont_mul_add(struct LITE_BIGNUM *c, const uint32_t a, + const struct LITE_BIGNUM *b, const uint32_t nprime, + const struct LITE_BIGNUM *N) +{ + uint32_t A, B, d0; + int i; + + { + register uint64_t tmp; + + tmp = BN_DIGIT(c, 0) + (uint64_t) a * BN_DIGIT(b, 0); + A = tmp >> 32; + d0 = (uint32_t) tmp * (uint32_t) nprime; + tmp = (uint32_t)tmp + (uint64_t) d0 * BN_DIGIT(N, 0); + B = tmp >> 32; + } + + for (i = 0; i < N->dmax - 1;) { + register uint64_t tmp; + + tmp = A + (uint64_t) a * BN_DIGIT(b, i + 1) + + BN_DIGIT(c, i + 1); + A = tmp >> 32; + tmp = B + (uint64_t) d0 * BN_DIGIT(N, i + 1) + (uint32_t) tmp; + BN_DIGIT(c, i) = (uint32_t) tmp; + B = tmp >> 32; + ++i; + } + + { + uint64_t tmp = (uint64_t) A + B; + + BN_DIGIT(c, i) = (uint32_t) tmp; + A = tmp >> 32; /* 0 or 1. */ + if (A) + bn_sub(c, N); + } +} + +/* Montgomery c[] = a[] * b[] / R % N. */ +static void bn_mont_mul(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a, + const struct LITE_BIGNUM *b, const uint32_t nprime, + const struct LITE_BIGNUM *N) +{ + int i; + + for (i = 0; i < N->dmax; i++) + BN_DIGIT(c, i) = 0; + + bn_mont_mul_add(c, a ? BN_DIGIT(a, 0) : 1, b, nprime, N); + for (i = 1; i < N->dmax; i++) + bn_mont_mul_add(c, a ? BN_DIGIT(a, i) : 0, b, nprime, N); +} + +/* Mongomery R * R % N, R = 1 << (1 + log2N). */ +/* TODO(ngm): constant time. */ +static void bn_compute_RR(struct LITE_BIGNUM *RR, const struct LITE_BIGNUM *N) +{ + int i; + + bn_sub(RR, N); /* R - N = R % N since R < 2N */ + + /* Repeat 2 * R % N, log2(R) times. */ + for (i = 0; i < N->dmax * LITE_BN_BITS2; i++) { + if (bn_lshift(RR)) + assert(bn_sub(RR, N) == -1); + if (bn_gte(RR, N)) + bn_sub(RR, N); + } +} + +/* Montgomery nprime = -1 / n0 % (2 ^ 32). */ +static uint32_t bn_compute_nprime(const uint32_t n0) +{ + int i; + uint32_t ninv = 1; + + /* Repeated Hensel lifting. */ + for (i = 0; i < 5; i++) + ninv *= 2 - (n0 * ninv); + + return ~ninv + 1; /* Two's complement. */ +} + +/* TODO(ngm): this implementation not timing or side-channel safe by + * any measure. */ +static void bn_modexp_internal(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, + const struct LITE_BIGNUM *N) +{ + int i; + uint32_t nprime; + uint32_t RR_buf[RSA_MAX_WORDS]; + uint32_t acc_buf[RSA_MAX_WORDS]; + uint32_t aR_buf[RSA_MAX_WORDS]; + + struct LITE_BIGNUM RR; + struct LITE_BIGNUM acc; + struct LITE_BIGNUM aR; + + bn_init(&RR, RR_buf, bn_size(N)); + bn_init(&acc, acc_buf, bn_size(N)); + bn_init(&aR, aR_buf, bn_size(N)); + + nprime = bn_compute_nprime(BN_DIGIT(N, 0)); + bn_compute_RR(&RR, N); + bn_mont_mul(&acc, NULL, &RR, nprime, N); /* R = 1 * RR / R % N */ + bn_mont_mul(&aR, input, &RR, nprime, N); /* aR = a * RR / R % N */ + + /* TODO(ngm): burn stack space and use windowing. */ + for (i = exp->dmax * LITE_BN_BITS2 - 1; i >= 0; i--) { + bn_mont_mul(output, &acc, &acc, nprime, N); + if (bn_is_bit_set(exp, i)) { + bn_mont_mul(&acc, output, &aR, nprime, N); + } else { + struct LITE_BIGNUM tmp = *output; + + *output = acc; + acc = tmp; + } + /* Poke the watchdog. + * TODO(ngm): may be unnecessary with + * a faster implementation. + */ + watchdog_reload(); + } + + bn_mont_mul(output, NULL, &acc, nprime, N); /* Convert out. */ + /* Copy to output buffer if necessary. */ + if (acc.d != (struct access_helper *) acc_buf) { + memcpy(acc.d, acc_buf, bn_size(output)); + *output = acc; + } + + /* TODO(ngm): constant time. */ + if (bn_sub(output, N)) + bn_add(output, N); /* Final reduce. */ + output->dmax = N->dmax; + + always_memset(RR_buf, 0, sizeof(RR_buf)); + always_memset(acc_buf, 0, sizeof(acc_buf)); + always_memset(aR_buf, 0, sizeof(aR_buf)); +} + +/* output = input ^ exp % N */ +int bn_modexp(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, const struct LITE_BIGNUM *N) +{ +#ifndef CR50_NO_BN_ASM + if ((bn_bits(N) & 255) == 0) { + /* Use hardware support for standard key sizes. */ + return dcrypto_modexp(output, input, exp, N); + } +#endif + bn_modexp_internal(output, input, exp, N); + return 1; +} + +/* output = input ^ exp % N */ +int bn_modexp_word(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, + uint32_t exp, const struct LITE_BIGNUM *N) +{ +#ifndef CR50_NO_BN_ASM + if ((bn_bits(N) & 255) == 0) { + /* Use hardware support for standard key sizes. */ + return dcrypto_modexp_word(output, input, exp, N); + } +#endif + { + struct LITE_BIGNUM pubexp; + + DCRYPTO_bn_wrap(&pubexp, &exp, sizeof(exp)); + bn_modexp_internal(output, input, &pubexp, N); + return 1; + } +} + +/* output = input ^ exp % N */ +int bn_modexp_blinded(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, + const struct LITE_BIGNUM *N, + uint32_t pubexp) +{ +#ifndef CR50_NO_BN_ASM + if ((bn_bits(N) & 255) == 0) { + /* Use hardware support for standard key sizes. */ + return dcrypto_modexp_blinded(output, input, exp, N, pubexp); + } +#endif + bn_modexp_internal(output, input, exp, N); + return 1; +} + +/* c[] += a * b[] */ +static uint32_t bn_mul_add(struct LITE_BIGNUM *c, uint32_t a, + const struct LITE_BIGNUM *b, uint32_t offset) +{ + int i; + uint64_t carry = 0; + + for (i = 0; i < b->dmax; i++) { + carry += BN_DIGIT(c, offset + i) + + (uint64_t) BN_DIGIT(b, i) * a; + BN_DIGIT(c, offset + i) = (uint32_t) carry; + carry >>= 32; + } + + return carry; +} + +/* c[] = a[] * b[] */ +void DCRYPTO_bn_mul(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a, + const struct LITE_BIGNUM *b) +{ + int i; + uint32_t carry = 0; + + memset(c->d, 0, bn_size(c)); + for (i = 0; i < a->dmax; i++) { + BN_DIGIT(c, i + b->dmax - 1) = carry; + carry = bn_mul_add(c, BN_DIGIT(a, i), b, i); + } + + BN_DIGIT(c, i + b->dmax - 1) = carry; +} + +/* c[] = a[] * b[] */ +static void bn_mul_ex(struct LITE_BIGNUM *c, + const struct LITE_BIGNUM *a, int a_len, + const struct LITE_BIGNUM *b) +{ + int i; + uint32_t carry = 0; + + memset(c->d, 0, bn_size(c)); + for (i = 0; i < a_len; i++) { + BN_DIGIT(c, i + b->dmax - 1) = carry; + carry = bn_mul_add(c, BN_DIGIT(a, i), b, i); + } + + BN_DIGIT(c, i + b->dmax - 1) = carry; +} + +static int bn_div_word_ex(struct LITE_BIGNUM *q, + struct LITE_BIGNUM *r, + const struct LITE_BIGNUM *u, int m, + uint32_t div) +{ + uint32_t rem = 0; + int i; + + for (i = m - 1; i >= 0; --i) { + uint64_t tmp = ((uint64_t)rem << 32) + BN_DIGIT(u, i); + uint32_t qd = tmp / div; + + BN_DIGIT(q, i) = qd; + rem = tmp - (uint64_t)qd * div; + } + + if (r != NULL) + BN_DIGIT(r, 0) = rem; + + return 1; +} + +/* + * Knuth's long division. + * + * Returns 0 on error. + * |u| >= |v| + * v[n-1] must not be 0 + * r gets |v| digits written to. + * q gets |u| - |v| + 1 digits written to. + */ +static int bn_div_ex(struct LITE_BIGNUM *q, + struct LITE_BIGNUM *r, + const struct LITE_BIGNUM *u, int m, + const struct LITE_BIGNUM *v, int n) +{ + uint32_t vtop; + int s, i, j; + uint32_t vn[RSA_MAX_WORDS]; /* Normalized v */ + uint32_t un[RSA_MAX_WORDS + 1]; /* Normalized u */ + + if (m < n || n <= 0) + return 0; + + vtop = BN_DIGIT(v, n - 1); + + if (vtop == 0) + return 0; + + if (n == 1) + return bn_div_word_ex(q, r, u, m, vtop); + + /* Compute shift factor to make v have high bit set */ + s = 0; + while ((vtop & 0x80000000) == 0) { + s = s + 1; + vtop = vtop << 1; + } + + /* Normalize u and v into un and vn. + * Note un always gains a leading digit + */ + if (s != 0) { + for (i = n - 1; i > 0; i--) + vn[i] = (BN_DIGIT(v, i) << s) | + (BN_DIGIT(v, i - 1) >> (32 - s)); + vn[0] = BN_DIGIT(v, 0) << s; + + un[m] = BN_DIGIT(u, m - 1) >> (32 - s); + for (i = m - 1; i > 0; i--) + un[i] = (BN_DIGIT(u, i) << s) | + (BN_DIGIT(u, i - 1) >> (32 - s)); + un[0] = BN_DIGIT(u, 0) << s; + } else { + for (i = 0; i < n; ++i) + vn[i] = BN_DIGIT(v, i); + for (i = 0; i < m; ++i) + un[i] = BN_DIGIT(u, i); + un[m] = 0; + } + + /* Main loop, reducing un digit by digit */ + for (j = m - n; j >= 0; j--) { + uint32_t qd; + int64_t t, k; + + /* Estimate quotient digit */ + if (un[j + n] == vn[n - 1]) { + /* Maxed out */ + qd = 0xFFFFFFFF; + } else { + /* Fine tune estimate */ + uint64_t rhat = ((uint64_t)un[j + n] << 32) + + un[j + n - 1]; + + qd = rhat / vn[n - 1]; + rhat = rhat - (uint64_t)qd * vn[n - 1]; + while ((rhat >> 32) == 0 && + (uint64_t)qd * vn[n - 2] > + (rhat << 32) + un[j + n - 2]) { + qd = qd - 1; + rhat = rhat + vn[n - 1]; + } + } + + /* Multiply and subtract */ + k = 0; + for (i = 0; i < n; i++) { + uint64_t p = (uint64_t)qd * vn[i]; + + t = un[i + j] - k - (p & 0xFFFFFFFF); + un[i + j] = t; + k = (p >> 32) - (t >> 32); + } + t = un[j + n] - k; + un[j + n] = t; + + /* If borrowed, add one back and adjust estimate */ + if (t < 0) { + k = 0; + qd = qd - 1; + for (i = 0; i < n; i++) { + t = (uint64_t)un[i + j] + vn[i] + k; + un[i + j] = t; + k = t >> 32; + } + un[j + n] = un[j + n] + k; + } + + BN_DIGIT(q, j) = qd; + } + + if (r != NULL) { + /* Denormalize un into r */ + if (s != 0) { + for (i = 0; i < n - 1; i++) + BN_DIGIT(r, i) = (un[i] >> s) | + (un[i + 1] << (32 - s)); + BN_DIGIT(r, n - 1) = un[n - 1] >> s; + } else { + for (i = 0; i < n; i++) + BN_DIGIT(r, i) = un[i]; + } + } + + return 1; +} + +static void bn_set_bn(struct LITE_BIGNUM *d, const struct LITE_BIGNUM *src, + size_t n) +{ + size_t i = 0; + + for (; i < n && i < d->dmax; ++i) + BN_DIGIT(d, i) = BN_DIGIT(src, i); + for (; i < d->dmax; ++i) + BN_DIGIT(d, i) = 0; +} + +static size_t bn_digits(const struct LITE_BIGNUM *a) +{ + size_t n = a->dmax - 1; + + while (BN_DIGIT(a, n) == 0 && n) + --n; + return n + 1; +} + +int DCRYPTO_bn_div(struct LITE_BIGNUM *quotient, + struct LITE_BIGNUM *remainder, + const struct LITE_BIGNUM *src, + const struct LITE_BIGNUM *divisor) +{ + int src_len = bn_digits(src); + int div_len = bn_digits(divisor); + int i, result; + + if (src_len < div_len) + return 0; + + result = bn_div_ex(quotient, remainder, + src, src_len, + divisor, div_len); + + if (!result) + return 0; + + /* 0-pad the destinations. */ + for (i = src_len - div_len + 1; i < quotient->dmax; ++i) + BN_DIGIT(quotient, i) = 0; + if (remainder) { + for (i = div_len; i < remainder->dmax; ++i) + BN_DIGIT(remainder, i) = 0; + } + + return result; +} + +/* + * Extended Euclid modular inverse. + * + * https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm + * #Computing_multiplicative_inverses_in_modular_structures: + + * function inverse(a, n) + * t := 0; newt := 1; + * r := n; newr := a; + * while newr ≠ 0 + * quotient := r div newr + * (t, newt) := (newt, t - quotient * newt) + * (r, newr) := (newr, r - quotient * newr) + * if r > 1 then return "a is not invertible" + * if t < 0 then t := t + n + * return t + */ +int bn_modinv_vartime(struct LITE_BIGNUM *dst, const struct LITE_BIGNUM *src, + const struct LITE_BIGNUM *mod) +{ + uint32_t R_buf[RSA_MAX_WORDS]; + uint32_t nR_buf[RSA_MAX_WORDS]; + uint32_t Q_buf[RSA_MAX_WORDS]; + + uint32_t nT_buf[RSA_MAX_WORDS + 1]; /* Can go negative, hence +1 */ + uint32_t T_buf[RSA_MAX_WORDS + 1]; /* Can go negative */ + uint32_t tmp_buf[2 * RSA_MAX_WORDS + 1]; /* needs to hold Q*nT */ + + struct LITE_BIGNUM R; + struct LITE_BIGNUM nR; + struct LITE_BIGNUM Q; + struct LITE_BIGNUM T; + struct LITE_BIGNUM nT; + struct LITE_BIGNUM tmp; + + struct LITE_BIGNUM *pT = &T; + struct LITE_BIGNUM *pnT = &nT; + struct LITE_BIGNUM *pR = &R; + struct LITE_BIGNUM *pnR = &nR; + struct LITE_BIGNUM *bnswap; + + int t_neg = 0; + int nt_neg = 0; + int iswap; + + size_t r_len, nr_len; + + bn_init(&R, R_buf, bn_size(mod)); + bn_init(&nR, nR_buf, bn_size(mod)); + bn_init(&Q, Q_buf, bn_size(mod)); + bn_init(&T, T_buf, bn_size(mod) + sizeof(uint32_t)); + bn_init(&nT, nT_buf, bn_size(mod) + sizeof(uint32_t)); + bn_init(&tmp, tmp_buf, bn_size(mod) + sizeof(uint32_t)); + + r_len = bn_digits(mod); + nr_len = bn_digits(src); + + BN_DIGIT(&nT, 0) = 1; /* T = 0, nT = 1 */ + bn_set_bn(&R, mod, r_len); /* R = n */ + bn_set_bn(&nR, src, nr_len); /* nR = input */ + + /* Trim nR */ + while (nr_len && BN_DIGIT(&nR, nr_len - 1) == 0) + --nr_len; + + while (nr_len) { + size_t q_len = r_len - nr_len + 1; + + /* (r, nr) = (nr, r % nr), q = r / nr */ + if (!bn_div_ex(&Q, pR, pR, r_len, pnR, nr_len)) + return 0; + + /* swap R and nR */ + r_len = nr_len; + bnswap = pR; pR = pnR; pnR = bnswap; + + /* trim nR and Q */ + while (nr_len && BN_DIGIT(pnR, nr_len - 1) == 0) + --nr_len; + while (q_len && BN_DIGIT(&Q, q_len - 1) == 0) + --q_len; + + Q.dmax = q_len; + + /* compute t - q*nt */ + if (q_len == 1 && BN_DIGIT(&Q, 0) <= 2) { + /* Doing few direct subs is faster than mul + sub */ + uint32_t n = BN_DIGIT(&Q, 0); + + while (n--) + bn_signed_sub(pT, &t_neg, pnT, nt_neg); + } else { + /* Call bn_mul_ex with smallest operand first */ + if (nt_neg) { + /* Negative numbers use all digits, + * thus pnT is large + */ + bn_mul_ex(&tmp, &Q, q_len, pnT); + } else { + int nt_len = bn_digits(pnT); + + if (q_len < nt_len) + bn_mul_ex(&tmp, &Q, q_len, pnT); + else + bn_mul_ex(&tmp, pnT, nt_len, &Q); + } + bn_signed_sub(pT, &t_neg, &tmp, nt_neg); + } + + /* swap T and nT */ + bnswap = pT; pT = pnT; pnT = bnswap; + iswap = t_neg; t_neg = nt_neg; nt_neg = iswap; + } + + if (r_len != 1 || BN_DIGIT(pR, 0) != 1) { + /* gcd not 1; no direct inverse */ + return 0; + } + + if (t_neg) + bn_signed_add(pT, &t_neg, mod, 0); + + bn_set_bn(dst, pT, bn_digits(pT)); + + return 1; +} + +#define PRIME1 3 + +/* + * The array below is an encoding of the first 4096 primes, starting with + * PRIME1. Using 4096 of the first primes results in at least 5% improvement + * in running time over using the first 2048. + * + * Most byte entries in the array contain two sequential differentials between + * two adjacent prime numbers, each differential halved (as the difference is + * always even) and packed into 4 bits. + * + * If a halved differential value exceeds 0xf (and as such does not fit into 4 + * bits), a zero is placed in the array followed by the value literal (no + * halving). + * + * If out of two consecutive differencials only the second one exceeds 0xf, + * the first one still is put into the array in its own byte prepended by a + * zero. + */ +const uint8_t PRIME_DELTAS[] = { + 1, 18, 18, 18, 49, 50, 18, 51, 19, 33, 50, 52, + 33, 33, 39, 35, 21, 19, 50, 51, 21, 18, 22, 98, + 18, 49, 83, 51, 19, 33, 87, 33, 39, 53, 18, 52, + 51, 35, 66, 69, 21, 19, 35, 66, 18, 100, 36, 35, + 97, 147, 83, 49, 53, 51, 19, 50, 22, 81, 35, 49, + 98, 52, 84, 84, 51, 36, 50, 66, 117, 97, 81, 33, + 87, 33, 39, 33, 42, 36, 84, 35, 55, 35, 52, 54, + 35, 21, 19, 81, 81, 57, 33, 35, 52, 51, 177, 84, + 83, 52, 98, 51, 19, 101, 145, 35, 19, 33, 38, 19, + 0, 34, 51, 73, 87, 33, 35, 66, 19, 101, 18, 18, + 54, 100, 99, 35, 66, 66, 114, 49, 35, 19, 90, 50, + 28, 33, 86, 21, 67, 51, 147, 33, 101, 100, 135, 50, + 18, 21, 99, 57, 24, 27, 52, 50, 18, 67, 81, 87, + 83, 97, 33, 86, 24, 19, 33, 84, 156, 35, 72, 18, + 72, 18, 67, 50, 97, 179, 19, 35, 115, 33, 50, 54, + 51, 114, 54, 67, 45, 149, 66, 49, 59, 97, 132, 38, + 117, 18, 67, 50, 18, 52, 33, 53, 21, 66, 117, 97, + 50, 24, 114, 52, 50, 148, 83, 52, 86, 114, 51, 30, + 21, 66, 114, 70, 54, 35, 165, 24, 210, 22, 50, 99, + 66, 75, 18, 22, 225, 51, 50, 49, 98, 97, 81, 129, + 131, 168, 66, 18, 27, 70, 53, 18, 49, 53, 22, 81, + 87, 50, 52, 51, 134, 18, 115, 36, 84, 51, 179, 21, + 114, 57, 21, 114, 21, 114, 73, 35, 18, 49, 98, 171, + 97, 35, 49, 59, 19, 131, 97, 54, 129, 35, 114, 25, + 197, 49, 81, 81, 83, 21, 21, 52, 245, 21, 67, 89, + 54, 97, 147, 35, 57, 21, 115, 33, 44, 22, 56, 67, + 57, 129, 35, 19, 53, 54, 105, 19, 41, 76, 33, 35, + 22, 39, 245, 54, 115, 86, 18, 52, 53, 18, 115, 50, + 49, 81, 134, 73, 35, 97, 51, 62, 55, 36, 84, 105, + 33, 44, 99, 24, 51, 117, 114, 243, 51, 67, 33, 99, + 33, 59, 49, 41, 18, 97, 50, 211, 50, 69, 0, 32, + 129, 50, 18, 21, 115, 36, 83, 162, 19, 242, 69, 51, + 67, 98, 49, 50, 49, 81, 131, 162, 103, 227, 162, 148, + 50, 55, 51, 81, 86, 69, 21, 70, 92, 18, 67, 36, + 149, 51, 19, 86, 21, 51, 52, 53, 49, 51, 53, 76, + 59, 25, 36, 95, 73, 33, 83, 19, 41, 70, 152, 49, + 99, 81, 81, 53, 114, 193, 129, 81, 90, 33, 36, 131, + 49, 104, 66, 63, 21, 19, 35, 52, 50, 99, 70, 39, + 101, 195, 99, 27, 73, 83, 114, 19, 84, 50, 63, 117, + 22, 81, 129, 156, 147, 137, 49, 146, 49, 84, 83, 52, + 35, 21, 22, 35, 49, 98, 121, 35, 162, 67, 36, 39, + 50, 118, 33, 242, 195, 54, 103, 50, 18, 147, 100, 50, + 97, 111, 129, 59, 115, 86, 49, 36, 83, 60, 115, 36, + 105, 81, 81, 35, 163, 39, 33, 39, 54, 197, 52, 81, + 242, 49, 98, 115, 0, 34, 100, 53, 18, 165, 72, 21, + 114, 22, 56, 52, 36, 35, 67, 54, 50, 51, 73, 42, + 38, 21, 49, 86, 18, 163, 243, 36, 86, 49, 225, 50, + 24, 97, 53, 76, 99, 147, 39, 50, 100, 54, 35, 99, + 97, 138, 33, 89, 66, 114, 19, 179, 115, 53, 49, 81, + 33, 177, 35, 54, 55, 86, 52, 0, 4, 0, 36, 118, + 50, 49, 99, 104, 21, 75, 22, 50, 57, 22, 50, 100, + 54, 35, 99, 22, 98, 115, 131, 21, 73, 0, 6, 0, + 34, 30, 27, 49, 86, 19, 36, 179, 21, 66, 52, 38, + 150, 162, 51, 66, 24, 97, 84, 81, 35, 118, 180, 225, + 42, 33, 39, 86, 22, 129, 228, 180, 35, 55, 36, 99, + 50, 162, 145, 99, 35, 121, 84, 0, 10, 0, 32, 53, + 51, 19, 131, 22, 62, 21, 72, 52, 53, 202, 81, 81, + 98, 58, 33, 105, 81, 81, 42, 141, 36, 50, 99, 70, + 99, 36, 177, 135, 83, 102, 115, 42, 38, 49, 51, 132, + 177, 228, 50, 162, 108, 162, 69, 24, 22, 0, 12, 0, + 34, 18, 54, 51, 67, 33, 60, 42, 83, 55, 35, 49, + 99, 81, 83, 162, 210, 19, 177, 194, 49, 35, 195, 66, + 0, 2, 0, 34, 52, 134, 21, 21, 52, 36, 107, 55, + 45, 33, 101, 66, 70, 39, 56, 52, 35, 52, 53, 97, + 51, 132, 51, 101, 19, 146, 51, 54, 148, 53, 73, 39, + 57, 84, 86, 19, 102, 0, 36, 35, 66, 49, 41, 99, + 67, 50, 145, 33, 194, 51, 127, 50, 54, 58, 36, 36, + 51, 47, 21, 100, 84, 195, 98, 114, 49, 231, 129, 99, + 42, 83, 51, 69, 103, 87, 135, 87, 56, 52, 56, 165, + 19, 33, 38, 21, 19, 179, 18, 148, 84, 177, 89, 114, + 18, 145, 35, 69, 31, 47, 21, 25, 41, 55, 81, 42, + 0, 36, 50, 55, 42, 87, 179, 31, 101, 145, 39, 59, + 145, 99, 36, 36, 53, 22, 149, 120, 114, 51, 19, 33, + 225, 227, 18, 55, 38, 120, 114, 52, 50, 51, 52, 36, + 39, 132, 50, 100, 129, 84, 35, 211, 84, 35, 103, 242, + 123, 70, 35, 69, 55, 83, 21, 102, 115, 57, 83, 73, + 35, 19, 81, 84, 51, 81, 149, 22, 35, 69, 103, 98, + 69, 51, 162, 120, 117, 69, 97, 147, 101, 97, 33, 99, + 36, 0, 4, 0, 44, 33, 33, 86, 51, 114, 51, 52, + 0, 6, 0, 36, 146, 49, 99, 51, 39, 182, 25, 83, + 220, 33, 33, 39, 35, 52, 134, 0, 2, 0, 42, 33, + 44, 51, 25, 39, 62, 151, 53, 97, 54, 243, 35, 55, + 33, 194, 51, 213, 147, 67, 63, 38, 97, 129, 50, 105, + 19, 45, 99, 98, 204, 99, 22, 228, 35, 97, 147, 35, + 58, 129, 51, 149, 49, 36, 51, 200, 52, 83, 123, 72, + 49, 98, 27, 73, 0, 34, 19, 146, 51, 69, 73, 50, + 18, 72, 22, 99, 146, 51, 49, 54, 90, 105, 35, 24, + 21, 114, 241, 86, 28, 56, 69, 22, 179, 24, 165, 22, + 105, 86, 49, 81, 53, 145, 99, 35, 28, 225, 33, 81, + 134, 75, 19, 33, 83, 166, 84, 99, 51, 41, 18, 105, + 22, 50, 24, 102, 114, 73, 38, 115, 50, 67, 42, 101, + 114, 24, 22, 242, 60, 172, 84, 101, 99, 102, 52, 135, + 50, 0, 6, 0, 36, 165, 246, 18, 30, 103, 59, 66, + 147, 121, 35, 19, 0, 34, 145, 131, 145, 194, 19, 99, + 101, 67, 134, 69, 0, 14, 0, 40, 49, 50, 103, 33, + 33, 36, 53, 51, 19, 51, 99, 197, 21, 54, 51, 115, + 0, 6, 0, 52, 163, 81, 84, 86, 97, 50, 120, 70, + 59, 21, 67, 177, 179, 69, 102, 21, 54, 18, 117, 19, + 146, 100, 150, 51, 35, 55, 33, 102, 35, 153, 97, 134, + 73, 93, 35, 67, 50, 21, 162, 52, 42, 81, 0, 34, + 18, 193, 102, 83, 22, 243, 104, 97, 185, 103, 81, 102, + 33, 35, 97, 137, 0, 2, 0, 40, 72, 52, 81, 41, + 69, 70, 41, 25, 81, 33, 36, 225, 59, 99, 121, 35, + 67, 53, 66, 25, 83, 171, 67, 242, 18, 147, 241, 36, + 50, 54, 0, 14, 0, 34, 115, 33, 50, 114, 19, 225, + 35, 69, 21, 21, 18, 241, 102, 89, 103, 81, 99, 83, + 118, 39, 41, 21, 66, 69, 105, 148, 57, 135, 51, 87, + 35, 22, 98, 51, 97, 129, 99, 39, 50, 22, 146, 0, + 36, 150, 97, 33, 36, 98, 0, 36, 57, 22, 83, 108, + 67, 56, 97, 149, 165, 19, 146, 0, 2, 0, 40, 49, + 129, 36, 149, 99, 21, 66, 54, 21, 148, 50, 162, 0, + 6, 0, 36, 49, 83, 195, 120, 57, 21, 165, 67, 35, + 21, 22, 33, 36, 83, 105, 118, 132, 56, 66, 19, 156, + 149, 97, 39, 83, 51, 150, 30, 151, 134, 124, 107, 49, + 84, 33, 39, 99, 35, 114, 18, 243, 19, 81, 251, 18, + 52, 51, 134, 99, 66, 28, 98, 52, 51, 81, 54, 231, + 50, 100, 54, 35, 115, 101, 51, 67, 50, 18, 70, 39, + 149, 24, 58, 53, 66, 0, 30, 0, 36, 100, 182, 19, + 104, 51, 25, 45, 36, 149, 69, 55, 42, 185, 100, 230, + 51, 67, 108, 135, 39, 99, 86, 163, 36, 150, 149, 18, + 165, 114, 49, 92, 145, 42, 135, 87, 50, 58, 53, 49, + 99, 245, 67, 35, 0, 8, 0, 40, 18, 22, 146, 52, + 83, 153, 22, 132, 50, 51, 0, 2, 0, 52, 114, 168, + 18, 54, 19, 102, 50, 117, 51, 117, 120, 67, 98, 75, + 49, 155, 49, 147, 135, 83, 97, 50, 73, 104, 18, 114, + 70, 111, 132, 33, 59, 100, 83, 51, 115, 149, 97, 81, + 45, 38, 66, 148, 87, 131, 52, 83, 67, 101, 165, 66, + 109, 146, 105, 63, 52, 59, 97, 35, 49, 81, 35, 49, + 59, 147, 150, 70, 53, 97, 129, 81, 89, 58, 33, 59, + 51, 147, 118, 129, 51, 39, 98, 25, 0, 16, 0, 36, + 99, 126, 22, 54, 50, 24, 244, 195, 245, 25, 35, 100, + 177, 59, 145, 81, 95, 30, 55, 131, 168, 19, 0, 4, + 0, 32, 33, 35, 22, 35, 54, 19, 35, 67, 42, 0, + 4, 0, 32, 84, 129, 177, 35, 67, 135, 41, 66, 163, + 102, 53, 21, 22, 230, 145, 149, 69, 0, 48, 18, 52, + 81, 95, 0, 2, 0, 36, 53, 49, 146, 52, 135, 131, + 114, 162, 49, 86, 19, 99, 50, 97, 50, 99, 66, 19, + 149, 52, 99, 177, 54, 146, 115, 42, 56, 66, 75, 70, + 51, 134, 159, 66, 18, 61, 39, 203, 49, 53, 55, 51, + 101, 49, 101, 100, 153, 83, 72, 51, 72, 162, 21, 21, + 99, 67, 90, 89, 210, 63, 18, 67, 102, 146, 75, 49, + 0, 12, 0, 34, 57, 99, 30, 120, 114, 118, 35, 49, + 0, 36, 35, 166, 195, 177, 137, 102, 145, 51, 50, 55, + 33, 180, 99, 83, 70, 150, 53, 27, 115, 50, 147, 171, + 22, 194, 153, 27, 18, 100, 101, 114, 25, 0, 16, 0, + 38, 51, 54, 83, 100, 50, 55, 243, 84, 179, 70, 81, + 81, 53, 21, 105, 163, 36, 179, 63, 55, 54, 99, 81, + 95, 24, 66, 19, 146, 19, 45, 36, 53, 18, 52, 35, + 246, 19, 50, 171, 66, 18, 0, 72, 66, 75, 18, 117, + 18, 163, 89, 58, 131, 67, 42, 107, 18, 22, 89, 27, + 57, 241, 87, 84, 0, 16, 0, 50, 53, 69, 99, 145, + 179, 18, 52, 51, 89, 27, 24, 117, 49, 101, 162, 115, + 0, 4, 0, 36, 18, 54, 18, 118, 50, 49, 50, 165, + 21, 54, 28, 102, 51, 44, 18, 193, 50, 52, 131, 21, + 103, 0, 6, 0, 34, 55, 50, 31, 180, 35, 66, 30, + 19, 45, 155, 19, 131, 24, 97, 98, 51, 117, 52, 98, + 145, 84, 131, 63, 21, 145, 84, 36, 108, 0, 40, 22, + 83, 97, 98, 18, 57, 118, 50, 127, 36, 84, 53, 148, + 39, 131, 66, 49, 81, 98, 18, 52, 35, 0, 32, 197, + 73, 81, 53, 18, 147, 97, 129, 179, 52, 146, 150, 67, + 42, 63, 182, 19, 146, 0, 62, 33, 99, 81, 102, 225, + 39, 179, 19, 53, 114, 21, 52, 87, 83, 22, 185, 69, + 150, 22, 38, 21, 19, 147, 0, 6, 0, 34, 49, 98, + 57, 145, 131, 52, 53, 148, 84, 81, 41, 214, 177, 33, + 179, 55, 131, 165, 97, 0, 18, 0, 42, 44, 19, 86, + 19, 84, 35, 102, 66, 54, 250, 60, 53, 97, 90, 51, + 38, 117, 150, 67, 98, 117, 22, 248, 22, 50, 18, 61, + 41, 18, 55, 0, 54, 0, 6, 0, 52, 24, 51, 109, + 33, 59, 49, 102, 53, 145, 102, 89, 99, 67, 83, 66, + 18, 172, 51, 87, 81, 179, 117, 210, 148, 102, 86, 52, + 131, 67, 59, 21, 165, 0, 6, 0, 44, 147, 81, 35, + 114, 210, 22, 84, 36, 98, 100, 180, 53, 147, 52, 54, + 36, 149, 99, 97, 50, 24, 102, 117, 115, 86, 22, 50, + 49, 98, 211, 147, 83, 25, 84, 45, 90, 56, 166, 84, + 81, 131, 165, 162, 241, 36, 129, 146, 19, 89, 103, 147, + 138, 50, 67, 35, 100, 81, 99, 33, 53, 24, 103, 83, + 67, 225, 57, 0, 30, 0, 34, 24, 97, 152, 52, 84, + 84, 0, 10, 0, 44, 51, 42, 33, 39, 228, 56, 127, + 63, 39, 83, 52, 41, 99, 27, 100, 54, 39, 35, 18, + 154, 56, 0, 38, 129, 35, 0, 2, 0, 40, 0, 42, + 114, 49, 197, 49, 149, 97, 129, 56, 52, 33, 83, 69, + 25, 132, 105, 99, 101, 51, +}; + +static uint32_t bn_mod_word16(const struct LITE_BIGNUM *p, uint16_t word) +{ + int i; + uint32_t rem = 0; + + for (i = p->dmax - 1; i >= 0; i--) { + rem = ((rem << 16) | + ((BN_DIGIT(p, i) >> 16) & 0xFFFFUL)) % word; + rem = ((rem << 16) | (BN_DIGIT(p, i) & 0xFFFFUL)) % word; + } + + return rem; +} + +static uint32_t bn_mod_f4(const struct LITE_BIGNUM *d) +{ + int i = bn_size(d) - 1; + const uint8_t *p = (const uint8_t *) (d->d); + uint32_t rem = 0; + + for (; i >= 0; --i) { + uint32_t q = RSA_F4 * (rem >> 8); + + if (rem < q) + q -= RSA_F4; + rem <<= 8; + rem |= p[i]; + rem -= q; + } + + if (rem >= RSA_F4) + rem -= RSA_F4; + + return rem; +} + +#define bn_is_even(b) !bn_is_bit_set((b), 0) +/* From HAC Fact 4.48 (ii), the following number of + * rounds suffice for ~2^145 confidence. Each additional + * round provides about another k/100 bits of confidence. */ +#define ROUNDS_1024 7 +#define ROUNDS_512 15 +#define ROUNDS_384 22 + +/* Miller-Rabin from HAC, algorithm 4.24. */ +static int bn_probable_prime(const struct LITE_BIGNUM *p) +{ + int j; + int s = 0; + + uint32_t ONE_buf = 1; + uint8_t r_buf[RSA_MAX_BYTES / 2]; + uint8_t A_buf[RSA_MAX_BYTES / 2]; + uint8_t y_buf[RSA_MAX_BYTES / 2]; + + struct LITE_BIGNUM ONE; + struct LITE_BIGNUM r; + struct LITE_BIGNUM A; + struct LITE_BIGNUM y; + + const int rounds = bn_bits(p) >= 1024 ? ROUNDS_1024 : + bn_bits(p) >= 512 ? ROUNDS_512 : + ROUNDS_384; + + /* Failsafe: update rounds table above to support smaller primes. */ + if (bn_bits(p) < 384) + return 0; + + if (bn_size(p) > sizeof(r_buf)) + return 0; + + DCRYPTO_bn_wrap(&ONE, &ONE_buf, sizeof(ONE_buf)); + DCRYPTO_bn_wrap(&r, r_buf, bn_size(p)); + bn_copy(&r, p); + + /* r * (2 ^ s) = p - 1 */ + bn_sub(&r, &ONE); + while (bn_is_even(&r)) { + bn_rshift(&r, 0, 0); + s++; + } + + DCRYPTO_bn_wrap(&A, A_buf, bn_size(p)); + DCRYPTO_bn_wrap(&y, y_buf, bn_size(p)); + for (j = 0; j < rounds; j++) { + int i; + + /* pick random A, such that A < p */ + rand_bytes(A_buf, bn_size(&A)); + for (i = A.dmax - 1; i >= 0; i--) { + while (BN_DIGIT(&A, i) > BN_DIGIT(p, i)) + BN_DIGIT(&A, i) = rand(); + if (BN_DIGIT(&A, i) < BN_DIGIT(p, i)) + break; + } + + /* y = a ^ r mod p */ + bn_modexp(&y, &A, &r, p); + if (bn_eq(&y, &ONE)) + continue; + bn_add(&y, &ONE); + if (bn_eq(&y, p)) + continue; + bn_sub(&y, &ONE); + + /* y = y ^ 2 mod p */ + for (i = 0; i < s - 1; i++) { + bn_copy(&A, &y); + bn_modexp_word(&y, &A, 2, p); + + if (bn_eq(&y, &ONE)) + return 0; + + bn_add(&y, &ONE); + if (bn_eq(&y, p)) { + bn_sub(&y, &ONE); + break; + } + bn_sub(&y, &ONE); + } + bn_add(&y, &ONE); + if (!bn_eq(&y, p)) + return 0; + } + + return 1; +} + +/* #define PRINT_PRIMES to enable printing predefined prime numbers' set. */ +static void print_primes(uint16_t prime) +{ +#ifdef PRINT_PRIMES + static uint16_t num_per_line; + static uint16_t max_printed; + + if (prime <= max_printed) + return; + + if (!(num_per_line++ % 8)) { + if (num_per_line == 1) + ccprintf("Prime numbers:"); + ccprintf("\n"); + cflush(); + } + max_printed = prime; + ccprintf(" %6d", prime); +#endif +} + +int DCRYPTO_bn_generate_prime(struct LITE_BIGNUM *p) +{ + int i; + int j; + /* Using a sieve size of 2048-bits results in a failure rate + * of ~0.5% @ 1024-bit candidates. The failure rate rises to ~6% + * if the sieve size is halved. */ + uint8_t composites_buf[256]; + struct LITE_BIGNUM composites; + uint16_t prime = PRIME1; + + /* Set top two bits, as well as LSB. */ + bn_set_bit(p, 0); + bn_set_bit(p, bn_bits(p) - 1); + bn_set_bit(p, bn_bits(p) - 2); + + /* Save on trial division by marking known composites. */ + bn_init(&composites, composites_buf, sizeof(composites_buf)); + for (i = 0; i < ARRAY_SIZE(PRIME_DELTAS); i++) { + uint16_t rem; + uint8_t unpacked_deltas[2]; + uint8_t packed_deltas = PRIME_DELTAS[i]; + int k; + int m; + + if (packed_deltas) { + unpacked_deltas[0] = (packed_deltas >> 4) << 1; + unpacked_deltas[1] = (packed_deltas & 0xf) << 1; + m = 2; + } else { + i += 1; + unpacked_deltas[0] = PRIME_DELTAS[i]; + m = 1; + } + + for (k = 0; k < m; k++) { + prime += unpacked_deltas[k]; + print_primes(prime); + rem = bn_mod_word16(p, prime); + /* Skip marking odd offsets (i.e. even candidates). */ + for (j = (rem == 0) ? 0 : prime - rem; + j < bn_bits(&composites) << 1; + j += prime) { + if ((j & 1) == 0) + bn_set_bit(&composites, j >> 1); + } + } + } + + /* composites now marked, apply Miller-Rabin to prime candidates. */ + j = 0; + for (i = 0; i < bn_bits(&composites); i++) { + uint32_t diff_buf; + struct LITE_BIGNUM diff; + + if (bn_is_bit_set(&composites, i)) + continue; + + /* Recover increment from the composites sieve. */ + diff_buf = (i << 1) - j; + j = (i << 1); + DCRYPTO_bn_wrap(&diff, &diff_buf, sizeof(diff_buf)); + bn_add(p, &diff); + /* Make sure prime will work with F4 public exponent. */ + if (bn_mod_f4(p) >= 2) { + if (bn_probable_prime(p)) + return 1; + } + } + + always_memset(composites_buf, 0, sizeof(composites_buf)); + return 0; +} diff --git a/board/cr50/dcrypto/compare.c b/board/cr50/dcrypto/compare.c new file mode 100644 index 0000000000..db6193752b --- /dev/null +++ b/board/cr50/dcrypto/compare.c @@ -0,0 +1,20 @@ +/* Copyright 2016 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" + +/* Constant time comparator. */ +int DCRYPTO_equals(const void *a, const void *b, size_t len) +{ + size_t i; + const uint8_t *pa = a; + const uint8_t *pb = b; + uint8_t diff = 0; + + for (i = 0; i < len; i++) + diff |= pa[i] ^ pb[i]; + + return !diff; +} diff --git a/board/cr50/dcrypto/dcrypto.h b/board/cr50/dcrypto/dcrypto.h new file mode 100644 index 0000000000..8cf1071090 --- /dev/null +++ b/board/cr50/dcrypto/dcrypto.h @@ -0,0 +1,445 @@ +/* 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. + */ + +/* + * Crypto wrapper library for the g chip. + */ +#ifndef __EC_CHIP_G_DCRYPTO_DCRYPTO_H +#define __EC_CHIP_G_DCRYPTO_DCRYPTO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(TEST_FUZZ) || !defined(TEST_BUILD) + +#include "internal.h" + +#include "crypto_api.h" + +#include + +#include "cryptoc/hmac.h" + +enum cipher_mode { + CIPHER_MODE_ECB = 0, /* NIST SP 800-38A */ + CIPHER_MODE_CTR = 1, /* NIST SP 800-38A */ + CIPHER_MODE_CBC = 2, /* NIST SP 800-38A */ + CIPHER_MODE_GCM = 3 /* NIST SP 800-38D */ +}; + +enum encrypt_mode { + DECRYPT_MODE = 0, + ENCRYPT_MODE = 1 +}; + +enum hashing_mode { + HASH_SHA1 = 0, + HASH_SHA256 = 1, + HASH_SHA384 = 2, /* Only supported for PKCS#1 signing */ + HASH_SHA512 = 3, /* Only supported for PKCS#1 signing */ + HASH_NULL = 4 /* Only supported for PKCS#1 signing */ +}; + +/* + * AES implementation, based on a hardware AES block. + * FIPS Publication 197, The Advanced Encryption Standard (AES) + */ +#define AES256_BLOCK_CIPHER_KEY_SIZE 32 + +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); + +void DCRYPTO_aes_write_iv(const uint8_t *iv); +void DCRYPTO_aes_read_iv(uint8_t *iv); + +/* AES-CTR-128/192/256 + * NIST Special Publication 800-38A + */ +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); + +/* AES-GCM-128/192/256 + * NIST Special Publication 800-38D, IV is provided externally + * Caller should use IV length according to section 8.2 of SP 800-38D + * And choose appropriate IV construction method, constrain number + * of invocations according to section 8.3 of SP 800-38D + */ +struct GCM_CTX { + union { + uint32_t d[4]; + uint8_t c[16]; + } block, Ej0; + + uint64_t aad_len; + uint64_t count; + size_t remainder; +}; + +/* Initialize the GCM context structure. */ +void DCRYPTO_gcm_init(struct GCM_CTX *ctx, uint32_t key_bits, + const uint8_t *key, const uint8_t *iv, size_t iv_len); +/* Additional authentication data to include in the tag calculation. */ +void DCRYPTO_gcm_aad(struct GCM_CTX *ctx, const uint8_t *aad_data, size_t len); +/* Encrypt & decrypt return the number of bytes written to out + * (always an integral multiple of 16), or -1 on error. These functions + * may be called repeatedly with incremental data. + * + * NOTE: if in_len is not a integral multiple of 16, then out_len must + * be atleast in_len - (in_len % 16) + 16 bytes. + */ +int DCRYPTO_gcm_encrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len, + const uint8_t *in, size_t in_len); +int DCRYPTO_gcm_decrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len, + const uint8_t *in, size_t in_len); +/* Encrypt & decrypt a partial final block, if any. These functions + * return the number of bytes written to out (<= 15), or -1 on error. + */ +int DCRYPTO_gcm_encrypt_final(struct GCM_CTX *ctx, + uint8_t *out, size_t out_len); +int DCRYPTO_gcm_decrypt_final(struct GCM_CTX *ctx, + uint8_t *out, size_t out_len); +/* Compute the tag over AAD + encrypt or decrypt data, and return the + * number of bytes written to tag. Returns -1 on error. + */ +int DCRYPTO_gcm_tag(struct GCM_CTX *ctx, uint8_t *tag, size_t tag_len); +/* Cleanup secrets. */ +void DCRYPTO_gcm_finish(struct GCM_CTX *ctx); + +/* AES-CMAC-128 + * NIST Special Publication 800-38B, RFC 4493 + * K: 128-bit key, M: message, len: number of bytes in M + * Writes 128-bit tag to T; returns 0 if an error is encountered and 1 + * otherwise. + */ +int DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, const uint32_t len, + uint32_t T[4]); +/* key: 128-bit key, M: message, len: number of bytes in M, + * T: tag to be verified + * Returns 1 if the tag is correct and 0 otherwise. + */ +int DCRYPTO_aes_cmac_verify(const uint8_t *key, const uint8_t *M, const int len, + const uint32_t T[4]); + +/* + * 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(SHA_CTX *ctx, uint32_t sw_required); +/* SHA256/384/512 FIPS 180-4 + */ +void DCRYPTO_SHA256_init(LITE_SHA256_CTX *ctx, uint32_t sw_required); +void DCRYPTO_SHA384_init(LITE_SHA384_CTX *ctx); +void DCRYPTO_SHA512_init(LITE_SHA512_CTX *ctx); +const uint8_t *DCRYPTO_SHA1_hash(const void *data, uint32_t n, + uint8_t *digest); +const uint8_t *DCRYPTO_SHA256_hash(const void *data, uint32_t n, + uint8_t *digest); +const uint8_t *DCRYPTO_SHA384_hash(const void *data, uint32_t n, + uint8_t *digest); +const uint8_t *DCRYPTO_SHA512_hash(const void *data, uint32_t n, + uint8_t *digest); +/* + * HMAC. FIPS 198-1 + */ +void DCRYPTO_HMAC_SHA256_init(LITE_HMAC_CTX *ctx, const void *key, + unsigned int len); +/* DCRYPTO HMAC-SHA256 final */ +const uint8_t *DCRYPTO_HMAC_final(LITE_HMAC_CTX *ctx); + +/* + * BIGNUM utility methods. + */ +void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len); + +/* + * RSA. + */ + +/* Largest supported key size for signing / encryption: 2048-bits. + * Verification is a special case and supports 4096-bits (signing / + * decryption could also support 4k-RSA, but is disabled since support + * is not required, and enabling support would result in increased + * stack usage for all key sizes.) + */ +#define RSA_BYTES_2K 256 +#define RSA_BYTES_4K 512 +#define RSA_WORDS_2K (RSA_BYTES_2K / sizeof(uint32_t)) +#define RSA_WORDS_4K (RSA_BYTES_4K / sizeof(uint32_t)) +#ifndef RSA_MAX_BYTES +#define RSA_MAX_BYTES RSA_BYTES_2K +#endif +#define RSA_MAX_WORDS (RSA_MAX_BYTES / sizeof(uint32_t)) +#define RSA_F4 65537 + +struct RSA { + uint32_t e; + struct LITE_BIGNUM N; + struct LITE_BIGNUM d; +}; + +enum padding_mode { + PADDING_MODE_PKCS1 = 0, + PADDING_MODE_OAEP = 1, + PADDING_MODE_PSS = 2, + /* USE OF NULL PADDING IS NOT RECOMMENDED. + * SUPPORT EXISTS AS A REQUIREMENT FOR TPM2 OPERATION. */ + PADDING_MODE_NULL = 3 +}; + +/* RSA support, FIPS PUB 186-4 * + * Calculate r = m ^ e mod N + */ +int DCRYPTO_rsa_encrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len, + const uint8_t *in, uint32_t in_len, + enum padding_mode padding, enum hashing_mode hashing, + const char *label); + +/* Calculate r = m ^ d mod N + * return 0 if error + */ +int DCRYPTO_rsa_decrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len, + const uint8_t *in, const uint32_t in_len, + enum padding_mode padding, enum hashing_mode hashing, + const char *label); + +/* Calculate r = m ^ d mod N + * return 0 if error + */ +int DCRYPTO_rsa_sign(struct RSA *rsa, uint8_t *out, uint32_t *out_len, + const uint8_t *in, const uint32_t in_len, + enum padding_mode padding, enum hashing_mode hashing); + +/* Calculate r = m ^ e mod N + * return 0 if error + */ +int DCRYPTO_rsa_verify(const struct RSA *rsa, const uint8_t *digest, + uint32_t digest_len, const uint8_t *sig, + const uint32_t sig_len, enum padding_mode padding, + enum hashing_mode hashing); + +/* Calculate n = p * q, d = e ^ -1 mod phi. */ +int DCRYPTO_rsa_key_compute(struct LITE_BIGNUM *N, struct LITE_BIGNUM *d, + struct LITE_BIGNUM *p, struct LITE_BIGNUM *q, + uint32_t e); + +/* + * EC. + */ + +/* DCRYPTO_p256_base_point_mul sets {out_x,out_y} = nG, where n is < the + * order of the group. + */ +int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y, + const p256_int *n); + +/* DCRYPTO_p256_point_mul sets {out_x,out_y} = n*{in_x,in_y}, where n is < + * the order of the group. + */ +int DCRYPTO_p256_point_mul(p256_int *out_x, p256_int *out_y, + const p256_int *n, const p256_int *in_x, + const p256_int *in_y); +/* + * Key selection based on FIPS-186-4, section B.4.2 (Key Pair + * Generation by Testing Candidates). + * Produce uniform private key from seed. + * If x or y is NULL, the public key part is not computed. + * Returns !0 on success. + */ +int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d, + const uint8_t bytes[P256_NBYTES]); + + +/* P256 based integration encryption (DH+AES128+SHA256). + * Not FIPS 140-2 compliant, not used other than for tests + * Authenticated data may be provided, where the first auth_data_len + * bytes of in will be authenticated but not encrypted. * + * Supports in-place encryption / decryption. * + * The output format is: + * 0x04 || PUBKEY || AUTH_DATA || AES128_CTR(PLAINTEXT) || + * HMAC_SHA256(AUTH_DATA || CIPHERTEXT) + */ +size_t DCRYPTO_ecies_encrypt( + void *out, size_t out_len, const void *in, size_t in_len, + size_t auth_data_len, const uint8_t *iv, + const p256_int *pub_x, const p256_int *pub_y, + const uint8_t *salt, size_t salt_len, + const uint8_t *info, size_t info_len); +size_t DCRYPTO_ecies_decrypt( + void *out, size_t out_len, const void *in, size_t in_len, + size_t auth_data_len, const uint8_t *iv, + const p256_int *d, + const uint8_t *salt, size_t salt_len, + const uint8_t *info, size_t info_len); + +/* + * HKDF as per RFC 5869. Mentioned as conforming NIST SP 800-56C Rev.1 + * [RFC 5869] specifies a version of the above extraction-then-expansion + * key-derivation procedure using HMAC for both the extraction and expansion + * steps. + */ +int DCRYPTO_hkdf(uint8_t *OKM, size_t OKM_len, + const uint8_t *salt, size_t salt_len, + const uint8_t *IKM, size_t IKM_len, + const uint8_t *info, size_t info_len); + +/* + * BN. + */ + +/* Apply Miller-Rabin test for prime candidate p. + * Returns 1 if test passed, 0 otherwise + */ +int DCRYPTO_bn_generate_prime(struct LITE_BIGNUM *p); +void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len); +void DCRYPTO_bn_mul(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a, + const struct LITE_BIGNUM *b); +int DCRYPTO_bn_div(struct LITE_BIGNUM *quotient, struct LITE_BIGNUM *remainder, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *divisor); + +/* + * ASN.1 DER + */ +size_t DCRYPTO_asn1_sigp(uint8_t *buf, const p256_int *r, const p256_int *s); +size_t DCRYPTO_asn1_pubp(uint8_t *buf, const p256_int *x, const p256_int *y); + +/* + * X509. + */ +/* DCRYPTO_x509_verify verifies that the provided X509 certificate was issued + * by the specified certifcate authority. + * + * cert is a pointer to a DER encoded X509 certificate, as specified + * in https://tools.ietf.org/html/rfc5280#section-4.1. In ASN.1 + * notation, the certificate has the following structure: + * + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + * + * TBSCertificate ::= SEQUENCE { } + * AlgorithmIdentifier ::= SEQUENCE { } + * + * where signatureValue = SIGN(HASH(tbsCertificate)), with SIGN and + * HASH specified by signatureAlgorithm. + * Accepts only certs with OID: sha256WithRSAEncryption: + * 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 + */ +int DCRYPTO_x509_verify(const uint8_t *cert, size_t len, + const struct RSA *ca_pub_key); + +/* Generate U2F Certificate and sign it + * Use ECDSA with NIST P-256 curve, and SHA2-256 digest + * @param d: key handle, used for NIST SP 800-90A HMAC DRBG + * @param pk_x, pk_y: public key + * @param serial: serial number for certificate + * @param name: certificate issuer and subject + * @param cert: output buffer for certificate + * @param n: max size of cert + */ +int DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x, + const p256_int *pk_y, const p256_int *serial, + const char *name, uint8_t *cert, + const int n); + +/* Generate U2F Certificate with DCRYPTO_x509_gen_u2f_cert_name + * Providing certificate issuer as BOARD or U2F + * @param d: key handle, used for NIST SP 800-90A HMAC DRBG + * @param pk_x, pk_y: public key + * @param serial: serial number for certificate + * @param name: certificate issuer and subject + * @param cert: output buffer for certificate + * @param n: max size of cert + */ +int DCRYPTO_x509_gen_u2f_cert(const p256_int *d, const p256_int *pk_x, + const p256_int *pk_y, const p256_int *serial, + uint8_t *cert, const int n); + +/* + * Memory related functions. + */ +int DCRYPTO_equals(const void *a, const void *b, size_t len); + +/* + * Key-ladder and application key related functions. + */ +enum dcrypto_appid { + RESERVED = 0, + NVMEM = 1, + U2F_ATTEST = 2, + U2F_ORIGIN = 3, + U2F_WRAP = 4, + PERSO_AUTH = 5, + PINWEAVER = 6, + /* This enum value should not exceed 7. */ +}; + +struct APPKEY_CTX { +#ifdef TEST_FUZZ + uint8_t unused_for_cxx_compatibility; +#endif +}; + +int DCRYPTO_ladder_compute_frk2(size_t major_fw_version, uint8_t *frk2); +int DCRYPTO_ladder_random(void *output); +void DCRYPTO_ladder_revoke(void); + +int DCRYPTO_appkey_init(enum dcrypto_appid id, struct APPKEY_CTX *ctx); +void DCRYPTO_appkey_finish(struct APPKEY_CTX *ctx); +int DCRYPTO_appkey_derive(enum dcrypto_appid appid, const uint32_t input[8], + uint32_t output[8]); + +/* Number of bytes in the salt object. */ +#define DCRYPTO_CIPHER_SALT_SIZE 16 +BUILD_ASSERT(DCRYPTO_CIPHER_SALT_SIZE == CIPHER_SALT_SIZE); + +/* + * Encrypt/decrypt a flat blob. + * + * Encrypt or decrypt the input buffer, and write the correspondingly + * ciphered output to out. The number of bytes produced is equal to + * the number of input bytes. Note that the input and output pointers + * MUST be word-aligned. + * + * This API is expected to be applied to a single contiguous region. + + * WARNING: A given salt/"in" pair MUST be unique, i.e. re-using a + * salt with a logically different input buffer is catastrophic. An + * example of a suitable salt is one that is derived from "in", e.g. a + * digest of the input data. + * + * @param appid the application-id of the calling context. + * @param salt pointer to a unique value to be associated with this blob, + * used for derivation of the proper IV, the size of the value + * is as defined by DCRYPTO_CIPHER_SALT_SIZE above. + * @param out Destination pointer where to write plaintext / ciphertext. + * @param in Source pointer where to read ciphertext / plaintext. + * @param len Number of bytes to read from in / write to out. + * @return non-zero on success, and zero otherwise. + */ +int DCRYPTO_app_cipher(enum dcrypto_appid appid, const void *salt, + void *out, const void *in, size_t len); + +#endif /* ^^^^^^^^^^^^^^^^^^^^^ !TEST_BUILD */ +/* + * Query whether Key Ladder is enabled. + * + * @return 1 if Key Ladder is enabled, and 0 otherwise. + */ +int DCRYPTO_ladder_is_enabled(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ! __EC_CHIP_G_DCRYPTO_DCRYPTO_H */ diff --git a/board/cr50/dcrypto/dcrypto_bn.c b/board/cr50/dcrypto/dcrypto_bn.c new file mode 100644 index 0000000000..b8f8fef4f4 --- /dev/null +++ b/board/cr50/dcrypto/dcrypto_bn.c @@ -0,0 +1,1496 @@ +/* Copyright 2016 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 "trng.h" + +/* Firmware blob for crypto accelerator */ + +/* AUTO-GENERATED. DO NOT MODIFY. */ +/* clang-format off */ +static const uint32_t IMEM_dcrypto_bn[] = { +/* @0x0: function tag[1] { */ +#define CF_tag_adr 0 +0xf8000001, /* sigini #1 */ +/* } */ +/* @0x1: function d0inv[14] { */ +#define CF_d0inv_adr 1 +0x4c000000, /* xor r0, r0, r0 */ +0x80000001, /* movi r0.0l, #1 */ +0x7c740000, /* mov r29, r0 */ +0x05100008, /* loop #256 ( */ +0x5807bc00, /* mul128 r1, r28l, r29l */ +0x588bbc00, /* mul128 r2, r28u, r29l */ +0x50044110, /* add r1, r1, r2 << 128 */ +0x590bbc00, /* mul128 r2, r28l, r29u */ +0x50044110, /* add r1, r1, r2 << 128 */ +0x40040100, /* and r1, r1, r0 */ +0x44743d00, /* or r29, r29, r1 */ +0x50000000, /* add r0, r0, r0 */ +/* ) */ +0x5477bf00, /* sub r29, r31, r29 */ +0x0c000000, /* ret */ +/* } */ +/* @0xf: function selcxSub[25] { */ +#define CF_selcxSub_adr 15 +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x99100000, /* strnd r4 */ +0x5013e400, /* add r4, r4, r31 */ +0x1000101e, /* bl selcxSub_invsel */ +0x528c8402, /* addcx r3, r4, r4 << 16 */ +0x0600c007, /* loop *6 ( */ +0x8c081800, /* ld *2, *0++ */ +0x7c8c0000, /* ldr *3, *0 */ +0x7c800400, /* ldr *0, *4 */ +0x54906200, /* subb r4, r2, r3 */ +0x990c0000, /* strnd r3 */ +0x660c4401, /* sellx r3, r4, r2 */ +0x7ca00200, /* ldr *0++, *2 */ +/* ) */ +0x0c000000, /* ret */ +/*selcxSub_invsel: */ +0x528c8402, /* addcx r3, r4, r4 << 16 */ +0x0600c007, /* loop *6 ( */ +0x8c081800, /* ld *2, *0++ */ +0x7c8c0000, /* ldr *3, *0 */ +0x7c800400, /* ldr *0, *4 */ +0x54906200, /* subb r4, r2, r3 */ +0x990c0000, /* strnd r3 */ +0x660c8201, /* sellx r3, r2, r4 */ +0x7ca00200, /* ldr *0++, *2 */ +/* ) */ +0x0c000000, /* ret */ +/* } */ +/* @0x28: function computeRR[41] { */ +#define CF_computeRR_adr 40 +0x4c7fff00, /* xor r31, r31, r31 */ +0x84004000, /* ldi r0, [#0] */ +0x95800000, /* lddmp r0 */ +0x4c0c6300, /* xor r3, r3, r3 */ +0x800cffff, /* movi r3.0l, #65535 */ +0x40040398, /* and r1, r3, r0 >> 192 */ +0x480c6000, /* not r3, r3 */ +0x400c0300, /* and r3, r3, r0 */ +0x500c2301, /* add r3, r3, r1 << 8 */ +0x94800300, /* ldlc r3 */ +0x80040005, /* movi r1.0l, #5 */ +0x81040003, /* movi r1.2l, #3 */ +0x81840002, /* movi r1.3l, #2 */ +0x82040004, /* movi r1.4l, #4 */ +0x97800100, /* ldrfp r1 */ +0x4c0c6300, /* xor r3, r3, r3 */ +0x0600c001, /* loop *6 ( */ +0x7ca00200, /* ldr *0++, *2 */ +/* ) */ +0x560c1f00, /* subx r3, r31, r0 */ +0x0800000f, /* call &selcxSub */ +0x06000010, /* loop *0 ( */ +0x97800100, /* ldrfp r1 */ +0x560c6300, /* subx r3, r3, r3 */ +0x0600c003, /* loop *6 ( */ +0x7c8c0000, /* ldr *3, *0 */ +0x52884200, /* addcx r2, r2, r2 */ +0x7ca00300, /* ldr *0++, *3 */ +/* ) */ +0x0800000f, /* call &selcxSub */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x560c6300, /* subx r3, r3, r3 */ +0x0600c003, /* loop *6 ( */ +0x8c081800, /* ld *2, *0++ */ +0x7c8c0800, /* ldr *3, *0++ */ +0x5e804300, /* cmpbx r3, r2 */ +/* ) */ +0x0800000f, /* call &selcxSub */ +0xfc000000, /* nop */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x0600c001, /* loop *6 ( */ +0x90680800, /* st *0++, *2++ */ +/* ) */ +0x0c000000, /* ret */ +/* } */ +/* @0x51: function dmXd0[9] { */ +#define CF_dmXd0_adr 81 +0x586f3e00, /* mul128 r27, r30l, r25l */ +0x59eb3e00, /* mul128 r26, r30u, r25u */ +0x58df3e00, /* mul128 r23, r30u, r25l */ +0x506efb10, /* add r27, r27, r23 << 128 */ +0x50eafa90, /* addc r26, r26, r23 >> 128 */ +0x595f3e00, /* mul128 r23, r30l, r25u */ +0x506efb10, /* add r27, r27, r23 << 128 */ +0x50eafa90, /* addc r26, r26, r23 >> 128 */ +0x0c000000, /* ret */ +/* } */ +/* @0x5a: function dmXa[9] { */ +#define CF_dmXa_adr 90 +0x586c5e00, /* mul128 r27, r30l, r2l */ +0x59e85e00, /* mul128 r26, r30u, r2u */ +0x58dc5e00, /* mul128 r23, r30u, r2l */ +0x506efb10, /* add r27, r27, r23 << 128 */ +0x50eafa90, /* addc r26, r26, r23 >> 128 */ +0x595c5e00, /* mul128 r23, r30l, r2u */ +0x506efb10, /* add r27, r27, r23 << 128 */ +0x50eafa90, /* addc r26, r26, r23 >> 128 */ +0x0c000000, /* ret */ +/* } */ +/* @0x63: function mma_sub_cx[23] { */ +#define CF_mma_sub_cx_adr 99 +0x99700000, /* strnd r28 */ +0x5073fc00, /* add r28, r28, r31 */ +0x10001070, /* bl mma_invsel */ +0x52f39c02, /* addcx r28, r28, r28 << 16 */ +0x0600c007, /* loop *6 ( */ +0x8c141800, /* ld *5, *0++ */ +0x7c900000, /* ldr *4, *0 */ +0x54f71e00, /* subb r29, r30, r24 */ +0x99600000, /* strnd r24 */ +0x7c800500, /* ldr *0, *5 */ +0x6663dd01, /* sellx r24, r29, r30 */ +0x7ca00500, /* ldr *0++, *5 */ +/* ) */ +0x0c000000, /* ret */ +/*mma_invsel: */ +0x52f39c02, /* addcx r28, r28, r28 << 16 */ +0x0600c007, /* loop *6 ( */ +0x8c141800, /* ld *5, *0++ */ +0x7c900000, /* ldr *4, *0 */ +0x54f71e00, /* subb r29, r30, r24 */ +0x99600000, /* strnd r24 */ +0x7c800500, /* ldr *0, *5 */ +0x6663be01, /* sellx r24, r30, r29 */ +0x7ca00500, /* ldr *0++, *5 */ +/* ) */ +0x0c000000, /* ret */ +/* } */ +/* @0x7a: function mma[39] { */ +#define CF_mma_adr 122 +0x8204001e, /* movi r1.4l, #30 */ +0x82840018, /* movi r1.5l, #24 */ +0x97800100, /* ldrfp r1 */ +0x8c101b00, /* ld *4, *3++ */ +0x0800005a, /* call &dmXa */ +0x7c940800, /* ldr *5, *0++ */ +0x507b1b00, /* add r30, r27, r24 */ +0x50f7fa00, /* addc r29, r26, r31 */ +0x7c640300, /* mov r25, r3 */ +0x08000051, /* call &dmXd0 */ +0x7c641b00, /* mov r25, r27 */ +0x7c701a00, /* mov r28, r26 */ +0x7c601e00, /* mov r24, r30 */ +0x8c101800, /* ld *4, *0++ */ +0x08000051, /* call &dmXd0 */ +0x506f1b00, /* add r27, r27, r24 */ +0x50f3fa00, /* addc r28, r26, r31 */ +0x0600e00e, /* loop *7 ( */ +0x8c101b00, /* ld *4, *3++ */ +0x0800005a, /* call &dmXa */ +0x7c940800, /* ldr *5, *0++ */ +0x506f1b00, /* add r27, r27, r24 */ +0x50ebfa00, /* addc r26, r26, r31 */ +0x5063bb00, /* add r24, r27, r29 */ +0x50f7fa00, /* addc r29, r26, r31 */ +0x8c101800, /* ld *4, *0++ */ +0x08000051, /* call &dmXd0 */ +0x506f1b00, /* add r27, r27, r24 */ +0x50ebfa00, /* addc r26, r26, r31 */ +0x52639b00, /* addx r24, r27, r28 */ +0x7ca80500, /* ldr *2++, *5 */ +0x52f3fa00, /* addcx r28, r26, r31 */ +/* ) */ +0x52e39d00, /* addcx r24, r29, r28 */ +0x7ca80500, /* ldr *2++, *5 */ +0x95800000, /* lddmp r0 */ +0x97800100, /* ldrfp r1 */ +0x08000063, /* call &mma_sub_cx */ +0xfc000000, /* nop */ +0x0c000000, /* ret */ +/* } */ +/* @0xa1: function setupPtrs[11] { */ +#define CF_setupPtrs_adr 161 +0x847c4000, /* ldi r31, [#0] */ +0x4c7fff00, /* xor r31, r31, r31 */ +0x95800000, /* lddmp r0 */ +0x94800000, /* ldlc r0 */ +0x7c041f00, /* mov r1, r31 */ +0x80040004, /* movi r1.0l, #4 */ +0x80840003, /* movi r1.1l, #3 */ +0x81040004, /* movi r1.2l, #4 */ +0x81840002, /* movi r1.3l, #2 */ +0x97800100, /* ldrfp r1 */ +0x0c000000, /* ret */ +/* } */ +/* @0xac: function mulx[19] { */ +#define CF_mulx_adr 172 +0x84004000, /* ldi r0, [#0] */ +0x080000a1, /* call &setupPtrs */ +0x8c041100, /* ld *1, *1 */ +0x7c081f00, /* mov r2, r31 */ +0x0600c001, /* loop *6 ( */ +0x7ca80300, /* ldr *2++, *3 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x0600c004, /* loop *6 ( */ +0x8c0c1c00, /* ld *3, *4++ */ +0x95000000, /* stdmp r0 */ +0x0800007a, /* call &mma */ +0x95800000, /* lddmp r0 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x0600c001, /* loop *6 ( */ +0x90740800, /* st *0++, *5++ */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x0c000000, /* ret */ +/* } */ +/* @0xbf: function mm1_sub_cx[22] { */ +#define CF_mm1_sub_cx_adr 191 +0x990c0000, /* strnd r3 */ +0x500fe300, /* add r3, r3, r31 */ +0x100010cc, /* bl mm1_invsel */ +0x528c6302, /* addcx r3, r3, r3 << 16 */ +0x0600c006, /* loop *6 ( */ +0x8c041800, /* ld *1, *0++ */ +0x7c8c0800, /* ldr *3, *0++ */ +0x548c6200, /* subb r3, r2, r3 */ +0x66084301, /* sellx r2, r3, r2 */ +0x90740300, /* st *3, *5++ */ +0xfc000000, /* nop */ +/* ) */ +0x0c000000, /* ret */ +0xfc000000, /* nop */ +/*mm1_invsel: */ +0x528c6302, /* addcx r3, r3, r3 << 16 */ +0x0600c006, /* loop *6 ( */ +0x8c041800, /* ld *1, *0++ */ +0x7c8c0800, /* ldr *3, *0++ */ +0x548c6200, /* subb r3, r2, r3 */ +0x66086201, /* sellx r2, r2, r3 */ +0x90740300, /* st *3, *5++ */ +0xfc000000, /* nop */ +/* ) */ +0x0c000000, /* ret */ +/* } */ +/* @0xd5: function mul1_exp[23] { */ +#define CF_mul1_exp_adr 213 +0x8c041100, /* ld *1, *1 */ +0x7c081f00, /* mov r2, r31 */ +0x0600c001, /* loop *6 ( */ +0x7ca80300, /* ldr *2++, *3 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x80080001, /* movi r2.0l, #1 */ +0x0600c003, /* loop *6 ( */ +0x95800000, /* lddmp r0 */ +0x0800007a, /* call &mma */ +0x7c081f00, /* mov r2, r31 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x56084200, /* subx r2, r2, r2 */ +0x0600c003, /* loop *6 ( */ +0x8c041800, /* ld *1, *0++ */ +0x7c8c0800, /* ldr *3, *0++ */ +0x5e804300, /* cmpbx r3, r2 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x080000bf, /* call &mm1_sub_cx */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x0c000000, /* ret */ +/* } */ +/* @0xec: function mul1[4] { */ +#define CF_mul1_adr 236 +0x84004000, /* ldi r0, [#0] */ +0x080000a1, /* call &setupPtrs */ +0x080000d5, /* call &mul1_exp */ +0x0c000000, /* ret */ +/* } */ +/* @0xf0: function sqrx_exp[19] { */ +#define CF_sqrx_exp_adr 240 +0x84004020, /* ldi r0, [#1] */ +0x95800000, /* lddmp r0 */ +0x8c041100, /* ld *1, *1 */ +0x7c081f00, /* mov r2, r31 */ +0x0600c001, /* loop *6 ( */ +0x7ca80300, /* ldr *2++, *3 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x0600c004, /* loop *6 ( */ +0x8c0c1c00, /* ld *3, *4++ */ +0x95000000, /* stdmp r0 */ +0x0800007a, /* call &mma */ +0x95800000, /* lddmp r0 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x0600c001, /* loop *6 ( */ +0x90740800, /* st *0++, *5++ */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x0c000000, /* ret */ +/* } */ +/* @0x103: function mulx_exp[14] { */ +#define CF_mulx_exp_adr 259 +0x84004040, /* ldi r0, [#2] */ +0x95800000, /* lddmp r0 */ +0x8c041100, /* ld *1, *1 */ +0x7c081f00, /* mov r2, r31 */ +0x0600c001, /* loop *6 ( */ +0x7ca80300, /* ldr *2++, *3 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x0600c004, /* loop *6 ( */ +0x8c0c1c00, /* ld *3, *4++ */ +0x95000000, /* stdmp r0 */ +0x0800007a, /* call &mma */ +0x95800000, /* lddmp r0 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x0c000000, /* ret */ +/* } */ +/* @0x111: function selOutOrC[30] { */ +#define CF_selOutOrC_adr 273 +0x990c0000, /* strnd r3 */ +0x440c6300, /* or r3, r3, r3 */ +0x10001122, /* bl selOutOrC_invsel */ +0x508c6302, /* addc r3, r3, r3 << 16 */ +0x0600c00a, /* loop *6 ( */ +0x990c0000, /* strnd r3 */ +0x99080000, /* strnd r2 */ +0x8c041500, /* ld *1, *5 */ +0x90540300, /* st *3, *5 */ +0x7c8c0800, /* ldr *3, *0++ */ +0x99000000, /* strnd r0 */ +0x7c000200, /* mov r0, r2 */ +0x99080000, /* strnd r2 */ +0x64086001, /* sell r2, r0, r3 */ +0x90740300, /* st *3, *5++ */ +/* ) */ +0x0c000000, /* ret */ +0xfc000000, /* nop */ +/*selOutOrC_invsel: */ +0x508c6302, /* addc r3, r3, r3 << 16 */ +0x0600c00a, /* loop *6 ( */ +0x990c0000, /* strnd r3 */ +0x99080000, /* strnd r2 */ +0x8c041500, /* ld *1, *5 */ +0x90540300, /* st *3, *5 */ +0x7c8c0800, /* ldr *3, *0++ */ +0x99000000, /* strnd r0 */ +0x7c000200, /* mov r0, r2 */ +0x99080000, /* strnd r2 */ +0x64080301, /* sell r2, r3, r0 */ +0x90740300, /* st *3, *5++ */ +/* ) */ +0x0c000000, /* ret */ +/* } */ +/* @0x12f: function modexp[35] { */ +#define CF_modexp_adr 303 +0x080000ac, /* call &mulx */ +0x84004060, /* ldi r0, [#3] */ +0x95800000, /* lddmp r0 */ +0x54084200, /* sub r2, r2, r2 */ +0x0600c004, /* loop *6 ( */ +0xfc000000, /* nop */ +0x8c0c1800, /* ld *3, *0++ */ +0x54885f00, /* subb r2, r31, r2 */ +0x90740300, /* st *3, *5++ */ +/* ) */ +0xfc000000, /* nop */ +0x7c081f00, /* mov r2, r31 */ +0x8008ffff, /* movi r2.0l, #65535 */ +0x400c0298, /* and r3, r2, r0 >> 192 */ +0x48084000, /* not r2, r2 */ +0x40080200, /* and r2, r2, r0 */ +0x50086201, /* add r2, r2, r3 << 8 */ +0x94800200, /* ldlc r2 */ +0x0600000d, /* loop *0 ( */ +0x080000f0, /* call &sqrx_exp */ +0x08000103, /* call &mulx_exp */ +0x84004060, /* ldi r0, [#3] */ +0x95800000, /* lddmp r0 */ +0x99080000, /* strnd r2 */ +0x50084200, /* add r2, r2, r2 */ +0x0600c004, /* loop *6 ( */ +0x99080000, /* strnd r2 */ +0x8c0c1400, /* ld *3, *4 */ +0x50884200, /* addc r2, r2, r2 */ +0x90700300, /* st *3, *4++ */ +/* ) */ +0x08000111, /* call &selOutOrC */ +0xfc000000, /* nop */ +/* ) */ +0x84004060, /* ldi r0, [#3] */ +0x95800000, /* lddmp r0 */ +0x080000d5, /* call &mul1_exp */ +0x0c000000, /* ret */ +/* } */ +/* @0x152: function modexp_blinded[76] { */ +#define CF_modexp_blinded_adr 338 +0x080000ac, /* call &mulx */ +0x84004060, /* ldi r0, [#3] */ +0x95800000, /* lddmp r0 */ +0x54084200, /* sub r2, r2, r2 */ +0x0600c004, /* loop *6 ( */ +0xfc000000, /* nop */ +0x8c0c1800, /* ld *3, *0++ */ +0x54885f00, /* subb r2, r31, r2 */ +0x90740300, /* st *3, *5++ */ +/* ) */ +0xfc000000, /* nop */ +0x8c0c1900, /* ld *3, *1++ */ +0x8c0c1100, /* ld *3, *1 */ +0x521c5f90, /* addx r7, r31, r2 >> 128 */ +0x590c4200, /* mul128 r3, r2l, r2u */ +0x7c181f00, /* mov r6, r31 */ +0x0600c011, /* loop *6 ( */ +0x99080000, /* strnd r2 */ +0x8c0c1400, /* ld *3, *4 */ +0x58106200, /* mul128 r4, r2l, r3l */ +0x59946200, /* mul128 r5, r2u, r3u */ +0x58806200, /* mul128 r0, r2u, r3l */ +0x50100410, /* add r4, r4, r0 << 128 */ +0x50940590, /* addc r5, r5, r0 >> 128 */ +0x59006200, /* mul128 r0, r2l, r3u */ +0x50100410, /* add r4, r4, r0 << 128 */ +0x50940590, /* addc r5, r5, r0 >> 128 */ +0x5010c400, /* add r4, r4, r6 */ +0x5097e500, /* addc r5, r5, r31 */ +0x50088200, /* add r2, r2, r4 */ +0x509be500, /* addc r6, r5, r31 */ +0x5688e200, /* subbx r2, r2, r7 */ +0x90700300, /* st *3, *4++ */ +0x541ce700, /* sub r7, r7, r7 */ +/* ) */ +0x7c080600, /* mov r2, r6 */ +0x5688e200, /* subbx r2, r2, r7 */ +0x90500300, /* st *3, *4 */ +0xfc000000, /* nop */ +0x84004060, /* ldi r0, [#3] */ +0x7c081f00, /* mov r2, r31 */ +0x8008ffff, /* movi r2.0l, #65535 */ +0x400c0298, /* and r3, r2, r0 >> 192 */ +0x48084000, /* not r2, r2 */ +0x40080200, /* and r2, r2, r0 */ +0x510c0301, /* addi r3, r3, #1 */ +0x50086201, /* add r2, r2, r3 << 8 */ +0x94800200, /* ldlc r2 */ +0x06000019, /* loop *0 ( */ +0x080000f0, /* call &sqrx_exp */ +0x08000103, /* call &mulx_exp */ +0x84004060, /* ldi r0, [#3] */ +0x95800000, /* lddmp r0 */ +0x99080000, /* strnd r2 */ +0x54084200, /* sub r2, r2, r2 */ +0x0600c004, /* loop *6 ( */ +0x99080000, /* strnd r2 */ +0x8c0c1400, /* ld *3, *4 */ +0x50884200, /* addc r2, r2, r2 */ +0x90700300, /* st *3, *4++ */ +/* ) */ +0x99080000, /* strnd r2 */ +0x8c0c1400, /* ld *3, *4 */ +0x50884200, /* addc r2, r2, r2 */ +0x90700300, /* st *3, *4++ */ +0x0600c008, /* loop *6 ( */ +0x99080000, /* strnd r2 */ +0x8c041500, /* ld *1, *5 */ +0x90540300, /* st *3, *5 */ +0x7c8c0800, /* ldr *3, *0++ */ +0x7c000200, /* mov r0, r2 */ +0x99080000, /* strnd r2 */ +0x64086008, /* selc r2, r0, r3 */ +0x90740300, /* st *3, *5++ */ +/* ) */ +0xfc000000, /* nop */ +/* ) */ +0x84004060, /* ldi r0, [#3] */ +0x95800000, /* lddmp r0 */ +0x080000d5, /* call &mul1_exp */ +0x0c000000, /* ret */ +/* } */ +/* @0x19e: function modload[12] { */ +#define CF_modload_adr 414 +0x4c7fff00, /* xor r31, r31, r31 */ +0x84004000, /* ldi r0, [#0] */ +0x95800000, /* lddmp r0 */ +0x94800000, /* ldlc r0 */ +0x8000001c, /* movi r0.0l, #28 */ +0x8080001d, /* movi r0.1l, #29 */ +0x97800000, /* ldrfp r0 */ +0x8c001000, /* ld *0, *0 */ +0x08000001, /* call &d0inv */ +0x90440100, /* st *1, *1 */ +0x08000028, /* call &computeRR */ +0x0c000000, /* ret */ +/* } */ +#ifdef CONFIG_DCRYPTO_RSA_SPEEDUP +/* @0x1aa: function selA0orC4[16] { */ +#define CF_selA0orC4_adr 426 +0x99000000, /* strnd r0 */ +0x44000000, /* or r0, r0, r0 */ +0x100011b4, /* bl selA0orC4_invsel */ +0x50840002, /* addc r1, r0, r0 << 16 */ +0x6458da01, /* sell r22, r26, r6 */ +0x645cfb01, /* sell r23, r27, r7 */ +0x64611c01, /* sell r24, r28, r8 */ +0x64653d01, /* sell r25, r29, r9 */ +0x0c000000, /* ret */ +0xfc000000, /* nop */ +/*selA0orC4_invsel: */ +0x50840002, /* addc r1, r0, r0 << 16 */ +0x645b4601, /* sell r22, r6, r26 */ +0x645f6701, /* sell r23, r7, r27 */ +0x64638801, /* sell r24, r8, r28 */ +0x6467a901, /* sell r25, r9, r29 */ +0x0c000000, /* ret */ +/* } */ +/* @0x1ba: function mul4[169] { */ +#define CF_mul4_adr 442 +0x58594600, /* mul128 r22, r6l, r10l */ +0x59dd4600, /* mul128 r23, r6u, r10u */ +0x58894600, /* mul128 r2, r6u, r10l */ +0x50585610, /* add r22, r22, r2 << 128 */ +0x50dc5790, /* addc r23, r23, r2 >> 128 */ +0x59094600, /* mul128 r2, r6l, r10u */ +0x50585610, /* add r22, r22, r2 << 128 */ +0x50dc5790, /* addc r23, r23, r2 >> 128 */ +0x58616700, /* mul128 r24, r7l, r11l */ +0x59e56700, /* mul128 r25, r7u, r11u */ +0x58896700, /* mul128 r2, r7u, r11l */ +0x50605810, /* add r24, r24, r2 << 128 */ +0x50e45990, /* addc r25, r25, r2 >> 128 */ +0x59096700, /* mul128 r2, r7l, r11u */ +0x50605810, /* add r24, r24, r2 << 128 */ +0x50e45990, /* addc r25, r25, r2 >> 128 */ +0x58698800, /* mul128 r26, r8l, r12l */ +0x59ed8800, /* mul128 r27, r8u, r12u */ +0x58898800, /* mul128 r2, r8u, r12l */ +0x50685a10, /* add r26, r26, r2 << 128 */ +0x50ec5b90, /* addc r27, r27, r2 >> 128 */ +0x59098800, /* mul128 r2, r8l, r12u */ +0x50685a10, /* add r26, r26, r2 << 128 */ +0x50ec5b90, /* addc r27, r27, r2 >> 128 */ +0x5871a900, /* mul128 r28, r9l, r13l */ +0x59f5a900, /* mul128 r29, r9u, r13u */ +0x5889a900, /* mul128 r2, r9u, r13l */ +0x50705c10, /* add r28, r28, r2 << 128 */ +0x50f45d90, /* addc r29, r29, r2 >> 128 */ +0x5909a900, /* mul128 r2, r9l, r13u */ +0x50705c10, /* add r28, r28, r2 << 128 */ +0x50f45d90, /* addc r29, r29, r2 >> 128 */ +0x58016600, /* mul128 r0, r6l, r11l */ +0x59856600, /* mul128 r1, r6u, r11u */ +0x58896600, /* mul128 r2, r6u, r11l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59096600, /* mul128 r2, r6l, r11u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x505c1700, /* add r23, r23, r0 */ +0x50e03800, /* addc r24, r24, r1 */ +0x508fff00, /* addc r3, r31, r31 */ +0x58014700, /* mul128 r0, r7l, r10l */ +0x59854700, /* mul128 r1, r7u, r10u */ +0x58894700, /* mul128 r2, r7u, r10l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59094700, /* mul128 r2, r7l, r10u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x505c1700, /* add r23, r23, r0 */ +0x50e03800, /* addc r24, r24, r1 */ +0x50e47900, /* addc r25, r25, r3 */ +0x508fff00, /* addc r3, r31, r31 */ +0x58018600, /* mul128 r0, r6l, r12l */ +0x59858600, /* mul128 r1, r6u, r12u */ +0x58898600, /* mul128 r2, r6u, r12l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59098600, /* mul128 r2, r6l, r12u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x58014800, /* mul128 r0, r8l, r10l */ +0x59854800, /* mul128 r1, r8u, r10u */ +0x58894800, /* mul128 r2, r8u, r10l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59094800, /* mul128 r2, r8l, r10u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x50e87a00, /* addc r26, r26, r3 */ +0x508fff00, /* addc r3, r31, r31 */ +0x5801a600, /* mul128 r0, r6l, r13l */ +0x5985a600, /* mul128 r1, r6u, r13u */ +0x5889a600, /* mul128 r2, r6u, r13l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x5909a600, /* mul128 r2, r6l, r13u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x58018700, /* mul128 r0, r7l, r12l */ +0x59858700, /* mul128 r1, r7u, r12u */ +0x58898700, /* mul128 r2, r7u, r12l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59098700, /* mul128 r2, r7l, r12u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x58014900, /* mul128 r0, r9l, r10l */ +0x59854900, /* mul128 r1, r9u, r10u */ +0x58894900, /* mul128 r2, r9u, r10l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59094900, /* mul128 r2, r9l, r10u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x58016800, /* mul128 r0, r8l, r11l */ +0x59856800, /* mul128 r1, r8u, r11u */ +0x58896800, /* mul128 r2, r8u, r11l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59096800, /* mul128 r2, r8l, r11u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x50ec7b00, /* addc r27, r27, r3 */ +0x508fff00, /* addc r3, r31, r31 */ +0x5801a700, /* mul128 r0, r7l, r13l */ +0x5985a700, /* mul128 r1, r7u, r13u */ +0x5889a700, /* mul128 r2, r7u, r13l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x5909a700, /* mul128 r2, r7l, r13u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50681a00, /* add r26, r26, r0 */ +0x50ec3b00, /* addc r27, r27, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x58016900, /* mul128 r0, r9l, r11l */ +0x59856900, /* mul128 r1, r9u, r11u */ +0x58896900, /* mul128 r2, r9u, r11l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59096900, /* mul128 r2, r9l, r11u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50681a00, /* add r26, r26, r0 */ +0x50ec3b00, /* addc r27, r27, r1 */ +0x50f07c00, /* addc r28, r28, r3 */ +0x50f7fd00, /* addc r29, r29, r31 */ +0x5801a800, /* mul128 r0, r8l, r13l */ +0x5985a800, /* mul128 r1, r8u, r13u */ +0x5889a800, /* mul128 r2, r8u, r13l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x5909a800, /* mul128 r2, r8l, r13u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x506c1b00, /* add r27, r27, r0 */ +0x50f03c00, /* addc r28, r28, r1 */ +0x50f7fd00, /* addc r29, r29, r31 */ +0x58018900, /* mul128 r0, r9l, r12l */ +0x59858900, /* mul128 r1, r9u, r12u */ +0x58898900, /* mul128 r2, r9u, r12l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59098900, /* mul128 r2, r9l, r12u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x506c1b00, /* add r27, r27, r0 */ +0x50f03c00, /* addc r28, r28, r1 */ +0x50f7fd00, /* addc r29, r29, r31 */ +0x0c000000, /* ret */ +/* } */ +/* @0x263: function sqr4[117] { */ +#define CF_sqr4_adr 611 +0x5858c600, /* mul128 r22, r6l, r6l */ +0x59dcc600, /* mul128 r23, r6u, r6u */ +0x5888c600, /* mul128 r2, r6u, r6l */ +0x50585610, /* add r22, r22, r2 << 128 */ +0x50dc5790, /* addc r23, r23, r2 >> 128 */ +0x50585610, /* add r22, r22, r2 << 128 */ +0x50dc5790, /* addc r23, r23, r2 >> 128 */ +0x5860e700, /* mul128 r24, r7l, r7l */ +0x59e4e700, /* mul128 r25, r7u, r7u */ +0x5888e700, /* mul128 r2, r7u, r7l */ +0x50605810, /* add r24, r24, r2 << 128 */ +0x50e45990, /* addc r25, r25, r2 >> 128 */ +0x50605810, /* add r24, r24, r2 << 128 */ +0x50e45990, /* addc r25, r25, r2 >> 128 */ +0x58690800, /* mul128 r26, r8l, r8l */ +0x59ed0800, /* mul128 r27, r8u, r8u */ +0x58890800, /* mul128 r2, r8u, r8l */ +0x50685a10, /* add r26, r26, r2 << 128 */ +0x50ec5b90, /* addc r27, r27, r2 >> 128 */ +0x50685a10, /* add r26, r26, r2 << 128 */ +0x50ec5b90, /* addc r27, r27, r2 >> 128 */ +0x58712900, /* mul128 r28, r9l, r9l */ +0x59f52900, /* mul128 r29, r9u, r9u */ +0x58892900, /* mul128 r2, r9u, r9l */ +0x50705c10, /* add r28, r28, r2 << 128 */ +0x50f45d90, /* addc r29, r29, r2 >> 128 */ +0x50705c10, /* add r28, r28, r2 << 128 */ +0x50f45d90, /* addc r29, r29, r2 >> 128 */ +0x5800e600, /* mul128 r0, r6l, r7l */ +0x5984e600, /* mul128 r1, r6u, r7u */ +0x5888e600, /* mul128 r2, r6u, r7l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x5908e600, /* mul128 r2, r6l, r7u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x505c1700, /* add r23, r23, r0 */ +0x50e03800, /* addc r24, r24, r1 */ +0x508fff00, /* addc r3, r31, r31 */ +0x505c1700, /* add r23, r23, r0 */ +0x50e03800, /* addc r24, r24, r1 */ +0x50e47900, /* addc r25, r25, r3 */ +0x508fff00, /* addc r3, r31, r31 */ +0x58010600, /* mul128 r0, r6l, r8l */ +0x59850600, /* mul128 r1, r6u, r8u */ +0x58890600, /* mul128 r2, r6u, r8l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59090600, /* mul128 r2, r6l, r8u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x50e87a00, /* addc r26, r26, r3 */ +0x508fff00, /* addc r3, r31, r31 */ +0x58012600, /* mul128 r0, r6l, r9l */ +0x59852600, /* mul128 r1, r6u, r9u */ +0x58892600, /* mul128 r2, r6u, r9l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59092600, /* mul128 r2, r6l, r9u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x58010700, /* mul128 r0, r7l, r8l */ +0x59850700, /* mul128 r1, r7u, r8u */ +0x58890700, /* mul128 r2, r7u, r8l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59090700, /* mul128 r2, r7l, r8u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x50ec7b00, /* addc r27, r27, r3 */ +0x508fff00, /* addc r3, r31, r31 */ +0x58012700, /* mul128 r0, r7l, r9l */ +0x59852700, /* mul128 r1, r7u, r9u */ +0x58892700, /* mul128 r2, r7u, r9l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59092700, /* mul128 r2, r7l, r9u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50681a00, /* add r26, r26, r0 */ +0x50ec3b00, /* addc r27, r27, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x50681a00, /* add r26, r26, r0 */ +0x50ec3b00, /* addc r27, r27, r1 */ +0x50f07c00, /* addc r28, r28, r3 */ +0x50f7fd00, /* addc r29, r29, r31 */ +0x58012800, /* mul128 r0, r8l, r9l */ +0x59852800, /* mul128 r1, r8u, r9u */ +0x58892800, /* mul128 r2, r8u, r9l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59092800, /* mul128 r2, r8l, r9u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x506c1b00, /* add r27, r27, r0 */ +0x50f03c00, /* addc r28, r28, r1 */ +0x50f7fd00, /* addc r29, r29, r31 */ +0x506c1b00, /* add r27, r27, r0 */ +0x50f03c00, /* addc r28, r28, r1 */ +0x50f7fd00, /* addc r29, r29, r31 */ +0x0c000000, /* ret */ +/* } */ +/* @0x2d8: function dod0[15] { */ +#define CF_dod0_adr 728 +0x8c0c1100, /* ld *3, *1 */ +0x58140100, /* mul128 r5, r1l, r0l */ +0x58880100, /* mul128 r2, r1u, r0l */ +0x50144510, /* add r5, r5, r2 << 128 */ +0x59080100, /* mul128 r2, r1l, r0u */ +0x50144510, /* add r5, r5, r2 << 128 */ +0x5801c500, /* mul128 r0, r5l, r14l */ +0x5985c500, /* mul128 r1, r5u, r14u */ +0x5889c500, /* mul128 r2, r5u, r14l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x5909c500, /* mul128 r2, r5l, r14u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x0c000000, /* ret */ +/* } */ +/* @0x2e7: function dod1[9] { */ +#define CF_dod1_adr 743 +0x5801e500, /* mul128 r0, r5l, r15l */ +0x5985e500, /* mul128 r1, r5u, r15u */ +0x5889e500, /* mul128 r2, r5u, r15l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x5909e500, /* mul128 r2, r5l, r15u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x0c000000, /* ret */ +/* } */ +/* @0x2f0: function dod2[9] { */ +#define CF_dod2_adr 752 +0x58020500, /* mul128 r0, r5l, r16l */ +0x59860500, /* mul128 r1, r5u, r16u */ +0x588a0500, /* mul128 r2, r5u, r16l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x590a0500, /* mul128 r2, r5l, r16u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x0c000000, /* ret */ +/* } */ +/* @0x2f9: function dod3[9] { */ +#define CF_dod3_adr 761 +0x58022500, /* mul128 r0, r5l, r17l */ +0x59862500, /* mul128 r1, r5u, r17u */ +0x588a2500, /* mul128 r2, r5u, r17l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x590a2500, /* mul128 r2, r5l, r17u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x0c000000, /* ret */ +/* } */ +/* @0x302: function redc4[97] { */ +#define CF_redc4_adr 770 +0x7c001600, /* mov r0, r22 */ +0x080002d8, /* call &dod0 */ +0x50581600, /* add r22, r22, r0 */ +0x50dc3700, /* addc r23, r23, r1 */ +0x50e3f800, /* addc r24, r24, r31 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002e7, /* call &dod1 */ +0x505c1700, /* add r23, r23, r0 */ +0x50e03800, /* addc r24, r24, r1 */ +0x50e49900, /* addc r25, r25, r4 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002f0, /* call &dod2 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x50e89a00, /* addc r26, r26, r4 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002f9, /* call &dod3 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x50ec9b00, /* addc r27, r27, r4 */ +0x508fff00, /* addc r3, r31, r31 */ +0x7c001700, /* mov r0, r23 */ +0x080002d8, /* call &dod0 */ +0x505c1700, /* add r23, r23, r0 */ +0x50e03800, /* addc r24, r24, r1 */ +0x50e7f900, /* addc r25, r25, r31 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002e7, /* call &dod1 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x50e89a00, /* addc r26, r26, r4 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002f0, /* call &dod2 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x50ec9b00, /* addc r27, r27, r4 */ +0x508fff00, /* addc r3, r31, r31 */ +0x080002f9, /* call &dod3 */ +0x50681a00, /* add r26, r26, r0 */ +0x50ec3b00, /* addc r27, r27, r1 */ +0x50f07c00, /* addc r28, r28, r3 */ +0x508fff00, /* addc r3, r31, r31 */ +0x7c001800, /* mov r0, r24 */ +0x080002d8, /* call &dod0 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x50ebfa00, /* addc r26, r26, r31 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002e7, /* call &dod1 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x50ec9b00, /* addc r27, r27, r4 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002f0, /* call &dod2 */ +0x50681a00, /* add r26, r26, r0 */ +0x50ec3b00, /* addc r27, r27, r1 */ +0x50f09c00, /* addc r28, r28, r4 */ +0x5093e300, /* addc r4, r3, r31 */ +0x080002f9, /* call &dod3 */ +0x506c1b00, /* add r27, r27, r0 */ +0x50f03c00, /* addc r28, r28, r1 */ +0x50f49d00, /* addc r29, r29, r4 */ +0x508fff00, /* addc r3, r31, r31 */ +0x7c001900, /* mov r0, r25 */ +0x080002d8, /* call &dod0 */ +0x50641900, /* add r25, r25, r0 */ +0x50d83a00, /* addc r22, r26, r1 */ +0x50dffb00, /* addc r23, r27, r31 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002e7, /* call &dod1 */ +0x50581600, /* add r22, r22, r0 */ +0x50dc3700, /* addc r23, r23, r1 */ +0x50e09c00, /* addc r24, r28, r4 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002f0, /* call &dod2 */ +0x505c1700, /* add r23, r23, r0 */ +0x50e03800, /* addc r24, r24, r1 */ +0x50e49d00, /* addc r25, r29, r4 */ +0x508fe300, /* addc r3, r3, r31 */ +0x080002f9, /* call &dod3 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x56007f00, /* subx r0, r31, r3 */ +0x99680000, /* strnd r26 */ +0x996c0000, /* strnd r27 */ +0x99700000, /* strnd r28 */ +0x99740000, /* strnd r29 */ +0x5409d600, /* sub r2, r22, r14 */ +0x54e9f700, /* subb r26, r23, r15 */ +0x54ee1800, /* subb r27, r24, r16 */ +0x54f23900, /* subb r28, r25, r17 */ +0x66773c08, /* selcx r29, r28, r25 */ +0x66731b08, /* selcx r28, r27, r24 */ +0x666efa08, /* selcx r27, r26, r23 */ +0x666ac208, /* selcx r26, r2, r22 */ +0x0c000000, /* ret */ +/* } */ +/* @0x363: function modexp_1024[101] { */ +#define CF_modexp_1024_adr 867 +0x7c081f00, /* mov r2, r31 */ +0x80080006, /* movi r2.0l, #6 */ +0x8088000a, /* movi r2.1l, #10 */ +0x81880001, /* movi r2.3l, #1 */ +0x8208000e, /* movi r2.4l, #14 */ +0x82880016, /* movi r2.5l, #22 */ +0x83080012, /* movi r2.6l, #18 */ +0x97800200, /* ldrfp r2 */ +0x7c001f00, /* mov r0, r31 */ +0x8180ffff, /* movi r0.3l, #65535 */ +0x84044000, /* ldi r1, [#0] */ +0x40040100, /* and r1, r1, r0 */ +0x48000000, /* not r0, r0 */ +0x84084060, /* ldi r2, [#3] */ +0x40080200, /* and r2, r2, r0 */ +0x44082200, /* or r2, r2, r1 */ +0x95800200, /* lddmp r2 */ +0x05004004, /* loop #4 ( */ +0x8c201b00, /* ld *0++, *3++ */ +0x8c241a00, /* ld *1++, *2++ */ +0x8c301800, /* ld *4++, *0++ */ +0x8c381c00, /* ld *6++, *4++ */ +/* ) */ +0x99780000, /* strnd r30 */ +0x507bde00, /* add r30, r30, r30 */ +0x080001ba, /* call &mul4 */ +0x08000302, /* call &redc4 */ +0x7c281a00, /* mov r10, r26 */ +0x7c2c1b00, /* mov r11, r27 */ +0x7c301c00, /* mov r12, r28 */ +0x7c341d00, /* mov r13, r29 */ +0x99180000, /* strnd r6 */ +0x991c0000, /* strnd r7 */ +0x99200000, /* strnd r8 */ +0x99240000, /* strnd r9 */ +0x05400033, /* loop #1024 ( */ +0x08000263, /* call &sqr4 */ +0x08000302, /* call &redc4 */ +0x99180000, /* strnd r6 */ +0x991c0000, /* strnd r7 */ +0x99200000, /* strnd r8 */ +0x99240000, /* strnd r9 */ +0x7c181a00, /* mov r6, r26 */ +0x7c1c1b00, /* mov r7, r27 */ +0x7c201c00, /* mov r8, r28 */ +0x7c241d00, /* mov r9, r29 */ +0x080001ba, /* call &mul4 */ +0x08000302, /* call &redc4 */ +0x99000000, /* strnd r0 */ +0x5002b500, /* add r0, r21, r21 */ +0x99000000, /* strnd r0 */ +0x50825200, /* addc r0, r18, r18 */ +0x99480000, /* strnd r18 */ +0x7c480000, /* mov r18, r0 */ +0x99000000, /* strnd r0 */ +0x50827300, /* addc r0, r19, r19 */ +0x994c0000, /* strnd r19 */ +0x7c4c0000, /* mov r19, r0 */ +0x99000000, /* strnd r0 */ +0x50829400, /* addc r0, r20, r20 */ +0x99500000, /* strnd r20 */ +0x7c500000, /* mov r20, r0 */ +0x99000000, /* strnd r0 */ +0x5082b500, /* addc r0, r21, r21 */ +0x99540000, /* strnd r21 */ +0x7c540000, /* mov r21, r0 */ +0x99580000, /* strnd r22 */ +0x995c0000, /* strnd r23 */ +0x99600000, /* strnd r24 */ +0x99640000, /* strnd r25 */ +0x080001aa, /* call &selA0orC4 */ +0x99180000, /* strnd r6 */ +0x991c0000, /* strnd r7 */ +0x99200000, /* strnd r8 */ +0x99240000, /* strnd r9 */ +0x99000000, /* strnd r0 */ +0x50000000, /* add r0, r0, r0 */ +0x4c001e00, /* xor r0, r30, r0 */ +0x99780000, /* strnd r30 */ +0x507bde00, /* add r30, r30, r30 */ +0x4c781e00, /* xor r30, r30, r0 */ +0x447a5e00, /* or r30, r30, r18 */ +0x4c03c000, /* xor r0, r0, r30 */ +0x641aca01, /* sell r6, r10, r22 */ +0x641eeb01, /* sell r7, r11, r23 */ +0x64230c01, /* sell r8, r12, r24 */ +0x64272d01, /* sell r9, r13, r25 */ +/* ) */ +0x7c281f00, /* mov r10, r31 */ +0x80280001, /* movi r10.0l, #1 */ +0x7c2c1f00, /* mov r11, r31 */ +0x7c301f00, /* mov r12, r31 */ +0x7c341f00, /* mov r13, r31 */ +0x080001ba, /* call &mul4 */ +0x08000302, /* call &redc4 */ +0x5419da00, /* sub r6, r26, r14 */ +0x549dfb00, /* subb r7, r27, r15 */ +0x54a21c00, /* subb r8, r28, r16 */ +0x54a63d00, /* subb r9, r29, r17 */ +0x080001aa, /* call &selA0orC4 */ +0x05004001, /* loop #4 ( */ +0x90740d00, /* st *5++, *5++ */ +/* ) */ +0x0c000000, /* ret */ +/* } */ +#endif // CONFIG_DCRYPTO_RSA_SPEEDUP +}; +/* clang-format on */ + +struct DMEM_ctx_ptrs { + uint32_t pMod; + uint32_t pDinv; + uint32_t pRR; + uint32_t pA; + uint32_t pB; + uint32_t pC; + uint32_t n; + uint32_t n1; +}; + +/* + * This struct is "calling convention" for passing parameters into the + * code block above for RSA operations. Parameters start at &DMEM[0]. + */ +struct DMEM_ctx { + struct DMEM_ctx_ptrs in_ptrs; + struct DMEM_ctx_ptrs sqr_ptrs; + struct DMEM_ctx_ptrs mul_ptrs; + struct DMEM_ctx_ptrs out_ptrs; + uint32_t mod[RSA_WORDS_4K]; + uint32_t dInv[8]; + uint32_t pubexp; + uint32_t _pad1[3]; + uint32_t rnd[2]; + uint32_t _pad2[2]; + uint32_t RR[RSA_WORDS_4K]; + uint32_t in[RSA_WORDS_4K]; + uint32_t exp[RSA_WORDS_4K + 8]; /* extra word for randomization */ + uint32_t out[RSA_WORDS_4K]; + uint32_t bin[RSA_WORDS_4K]; + uint32_t bout[RSA_WORDS_4K]; +}; + +#define DMEM_CELL_SIZE 32 +#define DMEM_INDEX(p, f) \ + (((const uint8_t *)&(p)->f - (const uint8_t *)(p)) / DMEM_CELL_SIZE) + +/* Get non-0 64 bit random */ +static void rand64(uint32_t dst[2]) +{ + do { + dst[0] = rand(); + dst[1] = rand(); + } while ((dst[0] | dst[1]) == 0); +} + +/* Grab dcrypto lock and set things up for modulus and input */ +static int setup_and_lock(const struct LITE_BIGNUM *N, + const struct LITE_BIGNUM *input) +{ + struct DMEM_ctx *ctx = + (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); + + /* Initialize hardware; load code page. */ + dcrypto_init_and_lock(); + dcrypto_imem_load(0, IMEM_dcrypto_bn, ARRAY_SIZE(IMEM_dcrypto_bn)); + + /* Setup DMEM pointers (as indices into DMEM which are 256-bit cells). + */ + ctx->in_ptrs.pMod = DMEM_INDEX(ctx, mod); + ctx->in_ptrs.pDinv = DMEM_INDEX(ctx, dInv); + ctx->in_ptrs.pRR = DMEM_INDEX(ctx, RR); + ctx->in_ptrs.pA = DMEM_INDEX(ctx, in); + ctx->in_ptrs.pB = DMEM_INDEX(ctx, exp); + ctx->in_ptrs.pC = DMEM_INDEX(ctx, out); + ctx->in_ptrs.n = bn_bits(N) / (DMEM_CELL_SIZE * 8); + ctx->in_ptrs.n1 = ctx->in_ptrs.n - 1; + + ctx->sqr_ptrs = ctx->in_ptrs; + ctx->mul_ptrs = ctx->in_ptrs; + ctx->out_ptrs = ctx->in_ptrs; + + dcrypto_dmem_load(DMEM_INDEX(ctx, in), input->d, bn_words(input)); + if (dcrypto_dmem_load(DMEM_INDEX(ctx, mod), N->d, bn_words(N)) == 0) { + /* + * No change detected; assume modulus precomputation is cached. + */ + return 0; + } + + /* Calculate RR and d0inv. */ + return dcrypto_call(CF_modload_adr); +} + +#define MONTMUL(ctx, a, b, c) \ + montmul(ctx, DMEM_INDEX(ctx, a), DMEM_INDEX(ctx, b), DMEM_INDEX(ctx, c)) + +static int montmul(struct DMEM_ctx *ctx, uint32_t pA, uint32_t pB, + uint32_t pOut) +{ + + ctx->in_ptrs.pA = pA; + ctx->in_ptrs.pB = pB; + ctx->in_ptrs.pC = pOut; + + return dcrypto_call(CF_mulx_adr); +} + +#define MONTOUT(ctx, a, b) montout(ctx, DMEM_INDEX(ctx, a), DMEM_INDEX(ctx, b)) + +static int montout(struct DMEM_ctx *ctx, uint32_t pA, uint32_t pOut) +{ + + ctx->in_ptrs.pA = pA; + ctx->in_ptrs.pB = 0; + ctx->in_ptrs.pC = pOut; + + return dcrypto_call(CF_mul1_adr); +} + +#define MODEXP(ctx, in, exp, out) \ + modexp(ctx, CF_modexp_adr, DMEM_INDEX(ctx, RR), DMEM_INDEX(ctx, in), \ + DMEM_INDEX(ctx, exp), DMEM_INDEX(ctx, out)) + +#define MODEXP1024(ctx, in, exp, out) \ + modexp(ctx, CF_modexp_1024_adr, DMEM_INDEX(ctx, RR), \ + DMEM_INDEX(ctx, in), DMEM_INDEX(ctx, exp), \ + DMEM_INDEX(ctx, out)) + +#define MODEXP_BLINDED(ctx, in, exp, out) \ + modexp(ctx, CF_modexp_blinded_adr, DMEM_INDEX(ctx, RR), \ + DMEM_INDEX(ctx, in), DMEM_INDEX(ctx, exp), \ + DMEM_INDEX(ctx, out)) + +static int modexp(struct DMEM_ctx *ctx, uint32_t adr, uint32_t rr, uint32_t pIn, + uint32_t pExp, uint32_t pOut) +{ + /* in = in * RR */ + ctx->in_ptrs.pA = pIn; + ctx->in_ptrs.pB = rr; + ctx->in_ptrs.pC = pIn; + + /* out = out * out */ + ctx->sqr_ptrs.pA = pOut; + ctx->sqr_ptrs.pB = pOut; + ctx->sqr_ptrs.pC = pOut; + + /* out = out * in */ + ctx->mul_ptrs.pA = pIn; + ctx->mul_ptrs.pB = pOut; + ctx->mul_ptrs.pC = pOut; + + /* out = out / R */ + ctx->out_ptrs.pA = pOut; + ctx->out_ptrs.pB = pExp; + ctx->out_ptrs.pC = pOut; + + return dcrypto_call(adr); +} + +/* output = input ** exp % N. */ +int dcrypto_modexp_blinded(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, + const struct LITE_BIGNUM *N, uint32_t pubexp) +{ + int i, result; + struct DMEM_ctx *ctx = + (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); + + uint32_t r_buf[RSA_MAX_WORDS]; + uint32_t rinv_buf[RSA_MAX_WORDS]; + + struct LITE_BIGNUM r; + struct LITE_BIGNUM rinv; + + bn_init(&r, r_buf, bn_size(N)); + bn_init(&rinv, rinv_buf, bn_size(N)); + + /* + * pick 64 bit r != 0 + * We cannot tolerate risk of 0 since 0 breaks computation. + */ + rand64(r_buf); + + /* + * compute 1/r mod N + * Note this cannot fail since N is product of two large primes + * and r != 0, so we can ignore return value. + */ + bn_modinv_vartime(&rinv, &r, N); + + /* + * compute r^pubexp mod N + */ + dcrypto_modexp_word(&r, &r, pubexp, N); + + result = setup_and_lock(N, input); + + /* Pick !0 64-bit random for exponent blinding */ + rand64(ctx->rnd); + ctx->pubexp = pubexp; + + ctx->_pad1[0] = ctx->_pad1[1] = ctx->_pad1[2] = 0; + ctx->_pad2[0] = ctx->_pad2[1] = 0; + + dcrypto_dmem_load(DMEM_INDEX(ctx, bin), r.d, bn_words(&r)); + dcrypto_dmem_load(DMEM_INDEX(ctx, bout), rinv.d, bn_words(&rinv)); + dcrypto_dmem_load(DMEM_INDEX(ctx, exp), exp->d, bn_words(exp)); + + /* 0 pad the exponent to full size + 8 */ + for (i = bn_words(exp); i < bn_words(N) + 8; ++i) + ctx->exp[i] = 0; + + /* Blind input */ + result |= MONTMUL(ctx, in, RR, in); + result |= MONTMUL(ctx, in, bin, in); + + result |= MODEXP_BLINDED(ctx, in, exp, out); + + /* remove blinding factor */ + result |= MONTMUL(ctx, out, RR, out); + result |= MONTMUL(ctx, out, bout, out); + /* fully reduce out */ + result |= MONTMUL(ctx, out, RR, out); + result |= MONTOUT(ctx, out, out); + + memcpy(output->d, ctx->out, bn_size(output)); + + dcrypto_unlock(); + return result == 0; +} + +/* output = input ** exp % N. */ +int dcrypto_modexp(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, const struct LITE_BIGNUM *N) +{ + int i, result; + struct DMEM_ctx *ctx = + (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); + + result = setup_and_lock(N, input); + + dcrypto_dmem_load(DMEM_INDEX(ctx, exp), exp->d, bn_words(exp)); + + /* 0 pad the exponent to full size */ + for (i = bn_words(exp); i < bn_words(N); ++i) + ctx->exp[i] = 0; + +#ifdef CONFIG_DCRYPTO_RSA_SPEEDUP + if (bn_bits(N) == 1024) { /* special code for 1024 bits */ + result |= MODEXP1024(ctx, in, exp, out); + } else { + result |= MODEXP(ctx, in, exp, out); + } +#else + result |= MODEXP(ctx, in, exp, out); +#endif + + memcpy(output->d, ctx->out, bn_size(output)); + + dcrypto_unlock(); + return result == 0; +} + +/* output = input ** exp % N. */ +int dcrypto_modexp_word(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, uint32_t exp, + const struct LITE_BIGNUM *N) +{ + int result; + uint32_t e = exp; + uint32_t b = 0x80000000; + struct DMEM_ctx *ctx = + (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); + + result = setup_and_lock(N, input); + + /* Find top bit */ + while (b != 0 && !(b & e)) + b >>= 1; + + /* out = in * RR */ + result |= MONTMUL(ctx, in, RR, out); + /* in = in * RR */ + result |= MONTMUL(ctx, in, RR, in); + + while (b > 1) { + b >>= 1; + + /* out = out * out */ + result |= MONTMUL(ctx, out, out, out); + + if ((b & e) != 0) { + /* out = out * in */ + result |= MONTMUL(ctx, in, out, out); + } + } + + /* out = out / R */ + result |= MONTOUT(ctx, out, out); + + memcpy(output->d, ctx->out, bn_size(output)); + + dcrypto_unlock(); + return result == 0; +} + +#ifdef CRYPTO_TEST_SETUP +#include "console.h" +#include "shared_mem.h" +#include "timer.h" + +static uint8_t genp_seed[32]; +static uint32_t prime_buf[32]; +static timestamp_t genp_start; +static timestamp_t genp_end; + +static int genp_core(void) +{ + struct LITE_BIGNUM prime; + int result; + + // Spin seed out into prng candidate prime. + DCRYPTO_hkdf((uint8_t *)prime_buf, sizeof(prime_buf), genp_seed, + sizeof(genp_seed), 0, 0, 0, 0); + DCRYPTO_bn_wrap(&prime, &prime_buf, sizeof(prime_buf)); + + genp_start = get_time(); + result = (DCRYPTO_bn_generate_prime(&prime) != 0) ? EC_SUCCESS + : EC_ERROR_UNKNOWN; + genp_end = get_time(); + + return result; +} + +static int call_on_bigger_stack(int (*func)(void)) +{ + int result, i; + char *new_stack; + const int new_stack_size = 4 * 1024; + + result = shared_mem_acquire(new_stack_size, &new_stack); + if (result == EC_SUCCESS) { + // Paint stack arena + memset(new_stack, 0x01, new_stack_size); + + // Call whilst switching stacks + __asm__ volatile("mov r4, sp\n" // save sp + "mov sp, %[new_stack]\n" + "blx %[func]\n" + "mov sp, r4\n" // restore sp + "mov %[result], r0\n" + : [result] "=r"(result) + : [new_stack] "r"(new_stack + new_stack_size), + [func] "r"(func) + : "r0", "r1", "r2", "r3", "r4", + "lr" // clobbers + ); + + // Take guess at amount of stack that got used + for (i = 0; i < new_stack_size && new_stack[i] == 0x01; ++i) + ; + ccprintf("stack: %u/%u\n", new_stack_size - i, new_stack_size); + + shared_mem_release(new_stack); + } + + return result; +} + +static int command_genp(int argc, char **argv) +{ + int result; + + memset(genp_seed, 0, sizeof(genp_seed)); + if (argc > 1) + memcpy(genp_seed, argv[1], strlen(argv[1])); + + result = call_on_bigger_stack(genp_core); + + if (result == EC_SUCCESS) { + ccprintf("prime: %ph (lsb first)\n", + HEX_BUF(prime_buf, sizeof(prime_buf))); + ccprintf("μs : %llu\n", + (long long)(genp_end.val - genp_start.val)); + } + + return result; +} +DECLARE_CONSOLE_COMMAND(genp, command_genp, "[seed]", "Generate prng prime"); +#endif diff --git a/board/cr50/dcrypto/dcrypto_p256.c b/board/cr50/dcrypto/dcrypto_p256.c new file mode 100644 index 0000000000..4de8d22f9a --- /dev/null +++ b/board/cr50/dcrypto/dcrypto_p256.c @@ -0,0 +1,1018 @@ +/* Copyright 2016 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 "trng.h" + +/* Firmware blob for crypto accelerator */ + +/* AUTO-GENERATED. DO NOT MODIFY. */ +/* clang-format off */ +static const uint32_t IMEM_dcrypto[] = { +/* @0x0: function tag[1] { */ +#define CF_tag_adr 0 + 0xf8000002, /* sigini #2 */ +/* } */ +/* @0x1: function SetupP256PandMuLow[21] { */ +#define CF_SetupP256PandMuLow_adr 1 + 0x55741f01, /* subi r29, r31, #1 */ + 0x83750000, /* movi r29.6h, #0 */ + 0x83740001, /* movi r29.6l, #1 */ + 0x82f50000, /* movi r29.5h, #0 */ + 0x82f40000, /* movi r29.5l, #0 */ + 0x82750000, /* movi r29.4h, #0 */ + 0x82740000, /* movi r29.4l, #0 */ + 0x81f50000, /* movi r29.3h, #0 */ + 0x81f40000, /* movi r29.3l, #0 */ + 0x98801d00, /* ldmod r29 */ + 0x55701f01, /* subi r28, r31, #1 */ + 0x83f10000, /* movi r28.7h, #0 */ + 0x83f00000, /* movi r28.7l, #0 */ + 0x82f0fffe, /* movi r28.5l, #65534 */ + 0x8270fffe, /* movi r28.4l, #65534 */ + 0x81f0fffe, /* movi r28.3l, #65534 */ + 0x80f10000, /* movi r28.1h, #0 */ + 0x80f00000, /* movi r28.1l, #0 */ + 0x80710000, /* movi r28.0h, #0 */ + 0x80700003, /* movi r28.0l, #3 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x16: function p256init[22] { */ +#define CF_p256init_adr 22 + 0x847c4000, /* ldi r31, [#0] */ + 0x4c7fff00, /* xor r31, r31, r31 */ + 0x51781f01, /* addi r30, r31, #1 */ + 0x08000001, /* call &SetupP256PandMuLow */ + 0x7c6c1f00, /* mov r27, r31 */ + 0x83ed5ac6, /* movi r27.7h, #23238 */ + 0x83ec35d8, /* movi r27.7l, #13784 */ + 0x836daa3a, /* movi r27.6h, #43578 */ + 0x836c93e7, /* movi r27.6l, #37863 */ + 0x82edb3eb, /* movi r27.5h, #46059 */ + 0x82ecbd55, /* movi r27.5l, #48469 */ + 0x826d7698, /* movi r27.4h, #30360 */ + 0x826c86bc, /* movi r27.4l, #34492 */ + 0x81ed651d, /* movi r27.3h, #25885 */ + 0x81ec06b0, /* movi r27.3l, #1712 */ + 0x816dcc53, /* movi r27.2h, #52307 */ + 0x816cb0f6, /* movi r27.2l, #45302 */ + 0x80ed3bce, /* movi r27.1h, #15310 */ + 0x80ec3c3e, /* movi r27.1l, #15422 */ + 0x806d27d2, /* movi r27.0h, #10194 */ + 0x806c604b, /* movi r27.0l, #24651 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x2c: function MulMod[38] { */ +#define CF_MulMod_adr 44 + 0x584f3800, /* mul128 r19, r24l, r25l */ + 0x59d33800, /* mul128 r20, r24u, r25u */ + 0x58d73800, /* mul128 r21, r24u, r25l */ + 0x504eb310, /* add r19, r19, r21 << 128 */ + 0x50d2b490, /* addc r20, r20, r21 >> 128 */ + 0x59573800, /* mul128 r21, r24l, r25u */ + 0x504eb310, /* add r19, r19, r21 << 128 */ + 0x50d2b490, /* addc r20, r20, r21 >> 128 */ + 0x645bfc02, /* selm r22, r28, r31 */ + 0x685693ff, /* rshi r21, r19, r20 >> 255 */ + 0x585f9500, /* mul128 r23, r21l, r28l */ + 0x59e39500, /* mul128 r24, r21u, r28u */ + 0x58e79500, /* mul128 r25, r21u, r28l */ + 0x505f3710, /* add r23, r23, r25 << 128 */ + 0x50e33890, /* addc r24, r24, r25 >> 128 */ + 0x59679500, /* mul128 r25, r21l, r28u */ + 0x505f3710, /* add r23, r23, r25 << 128 */ + 0x50e33890, /* addc r24, r24, r25 >> 128 */ + 0x6867f4ff, /* rshi r25, r20, r31 >> 255 */ + 0x5062b800, /* add r24, r24, r21 */ + 0x50e7f900, /* addc r25, r25, r31 */ + 0x5062d800, /* add r24, r24, r22 */ + 0x50e7f900, /* addc r25, r25, r31 */ + 0x68573801, /* rshi r21, r24, r25 >> 1 */ + 0x585abd00, /* mul128 r22, r29l, r21l */ + 0x59debd00, /* mul128 r23, r29u, r21u */ + 0x58e2bd00, /* mul128 r24, r29u, r21l */ + 0x505b1610, /* add r22, r22, r24 << 128 */ + 0x50df1790, /* addc r23, r23, r24 >> 128 */ + 0x5962bd00, /* mul128 r24, r29l, r21u */ + 0x505b1610, /* add r22, r22, r24 << 128 */ + 0x50df1790, /* addc r23, r23, r24 >> 128 */ + 0x545ad300, /* sub r22, r19, r22 */ + 0x54d2f400, /* subb r20, r20, r23 */ + 0x6457fd01, /* sell r21, r29, r31 */ + 0x5456b600, /* sub r21, r22, r21 */ + 0x9c4ff500, /* addm r19, r21, r31 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x52: function p256isoncurve[24] { */ +#define CF_p256isoncurve_adr 82 + 0x84004000, /* ldi r0, [#0] */ + 0x95800000, /* lddmp r0 */ + 0x82800018, /* movi r0.5l, #24 */ + 0x83000018, /* movi r0.6l, #24 */ + 0x80000000, /* movi r0.0l, #0 */ + 0x97800000, /* ldrfp r0 */ + 0x8c181600, /* ld *6, *6 */ + 0x7c641800, /* mov r25, r24 */ + 0x0800002c, /* call &MulMod */ + 0x7c001300, /* mov r0, r19 */ + 0x8c141500, /* ld *5, *5 */ + 0x7c641800, /* mov r25, r24 */ + 0x0800002c, /* call &MulMod */ + 0x8c141500, /* ld *5, *5 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x8c141500, /* ld *5, *5 */ + 0xa04f1300, /* subm r19, r19, r24 */ + 0xa04f1300, /* subm r19, r19, r24 */ + 0xa04f1300, /* subm r19, r19, r24 */ + 0x9c637300, /* addm r24, r19, r27 */ + 0x904c0500, /* st *5, *3 */ + 0x90500000, /* st *0, *4 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x6a: function ProjAdd[80] { */ +#define CF_ProjAdd_adr 106 + 0x7c600b00, /* mov r24, r11 */ + 0x7c640800, /* mov r25, r8 */ + 0x0800002c, /* call &MulMod */ + 0x7c381300, /* mov r14, r19 */ + 0x7c600c00, /* mov r24, r12 */ + 0x7c640900, /* mov r25, r9 */ + 0x0800002c, /* call &MulMod */ + 0x7c3c1300, /* mov r15, r19 */ + 0x7c600d00, /* mov r24, r13 */ + 0x7c640a00, /* mov r25, r10 */ + 0x0800002c, /* call &MulMod */ + 0x7c401300, /* mov r16, r19 */ + 0x9c458b00, /* addm r17, r11, r12 */ + 0x9c492800, /* addm r18, r8, r9 */ + 0x7c601100, /* mov r24, r17 */ + 0x7c641200, /* mov r25, r18 */ + 0x0800002c, /* call &MulMod */ + 0x9c49ee00, /* addm r18, r14, r15 */ + 0xa0465300, /* subm r17, r19, r18 */ + 0x9c49ac00, /* addm r18, r12, r13 */ + 0x9c4d4900, /* addm r19, r9, r10 */ + 0x7c601200, /* mov r24, r18 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x7c481300, /* mov r18, r19 */ + 0x9c4e0f00, /* addm r19, r15, r16 */ + 0xa04a7200, /* subm r18, r18, r19 */ + 0x9c4dab00, /* addm r19, r11, r13 */ + 0x9c314800, /* addm r12, r8, r10 */ + 0x7c601300, /* mov r24, r19 */ + 0x7c640c00, /* mov r25, r12 */ + 0x0800002c, /* call &MulMod */ + 0x7c2c1300, /* mov r11, r19 */ + 0x9c320e00, /* addm r12, r14, r16 */ + 0xa0318b00, /* subm r12, r11, r12 */ + 0x7c601b00, /* mov r24, r27 */ + 0x7c641000, /* mov r25, r16 */ + 0x0800002c, /* call &MulMod */ + 0xa02e6c00, /* subm r11, r12, r19 */ + 0x9c356b00, /* addm r13, r11, r11 */ + 0x9c2dab00, /* addm r11, r11, r13 */ + 0xa0356f00, /* subm r13, r15, r11 */ + 0x9c2d6f00, /* addm r11, r15, r11 */ + 0x7c601b00, /* mov r24, r27 */ + 0x7c640c00, /* mov r25, r12 */ + 0x0800002c, /* call &MulMod */ + 0x9c3e1000, /* addm r15, r16, r16 */ + 0x9c420f00, /* addm r16, r15, r16 */ + 0xa0321300, /* subm r12, r19, r16 */ + 0xa031cc00, /* subm r12, r12, r14 */ + 0x9c3d8c00, /* addm r15, r12, r12 */ + 0x9c318f00, /* addm r12, r15, r12 */ + 0x9c3dce00, /* addm r15, r14, r14 */ + 0x9c39cf00, /* addm r14, r15, r14 */ + 0xa03a0e00, /* subm r14, r14, r16 */ + 0x7c601200, /* mov r24, r18 */ + 0x7c640c00, /* mov r25, r12 */ + 0x0800002c, /* call &MulMod */ + 0x7c3c1300, /* mov r15, r19 */ + 0x7c600e00, /* mov r24, r14 */ + 0x7c640c00, /* mov r25, r12 */ + 0x0800002c, /* call &MulMod */ + 0x7c401300, /* mov r16, r19 */ + 0x7c600b00, /* mov r24, r11 */ + 0x7c640d00, /* mov r25, r13 */ + 0x0800002c, /* call &MulMod */ + 0x9c321300, /* addm r12, r19, r16 */ + 0x7c601100, /* mov r24, r17 */ + 0x7c640b00, /* mov r25, r11 */ + 0x0800002c, /* call &MulMod */ + 0xa02df300, /* subm r11, r19, r15 */ + 0x7c601200, /* mov r24, r18 */ + 0x7c640d00, /* mov r25, r13 */ + 0x0800002c, /* call &MulMod */ + 0x7c341300, /* mov r13, r19 */ + 0x7c601100, /* mov r24, r17 */ + 0x7c640e00, /* mov r25, r14 */ + 0x0800002c, /* call &MulMod */ + 0x9c366d00, /* addm r13, r13, r19 */ + 0x0c000000, /* ret */ +/* } */ +/* @0xba: function ProjToAffine[116] { */ +#define CF_ProjToAffine_adr 186 + 0x9c2bea00, /* addm r10, r10, r31 */ + 0x7c600a00, /* mov r24, r10 */ + 0x7c640a00, /* mov r25, r10 */ + 0x0800002c, /* call &MulMod */ + 0x7c601300, /* mov r24, r19 */ + 0x7c640a00, /* mov r25, r10 */ + 0x0800002c, /* call &MulMod */ + 0x7c301300, /* mov r12, r19 */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x7c601300, /* mov r24, r19 */ + 0x7c640c00, /* mov r25, r12 */ + 0x0800002c, /* call &MulMod */ + 0x7c341300, /* mov r13, r19 */ + 0x05004004, /* loop #4 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c601300, /* mov r24, r19 */ + 0x7c640d00, /* mov r25, r13 */ + 0x0800002c, /* call &MulMod */ + 0x7c381300, /* mov r14, r19 */ + 0x05008004, /* loop #8 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c601300, /* mov r24, r19 */ + 0x7c640e00, /* mov r25, r14 */ + 0x0800002c, /* call &MulMod */ + 0x7c3c1300, /* mov r15, r19 */ + 0x05010004, /* loop #16 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c601300, /* mov r24, r19 */ + 0x7c640f00, /* mov r25, r15 */ + 0x0800002c, /* call &MulMod */ + 0x7c401300, /* mov r16, r19 */ + 0x05020004, /* loop #32 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c441300, /* mov r17, r19 */ + 0x7c600a00, /* mov r24, r10 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x050c0004, /* loop #192 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c481300, /* mov r18, r19 */ + 0x7c601100, /* mov r24, r17 */ + 0x7c641000, /* mov r25, r16 */ + 0x0800002c, /* call &MulMod */ + 0x05010004, /* loop #16 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c600f00, /* mov r24, r15 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x05008004, /* loop #8 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c600e00, /* mov r24, r14 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x05004004, /* loop #4 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c600d00, /* mov r24, r13 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x05002004, /* loop #2 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c600c00, /* mov r24, r12 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x05002004, /* loop #2 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c600a00, /* mov r24, r10 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641200, /* mov r25, r18 */ + 0x0800002c, /* call &MulMod */ + 0x7c381300, /* mov r14, r19 */ + 0x7c600800, /* mov r24, r8 */ + 0x7c640e00, /* mov r25, r14 */ + 0x0800002c, /* call &MulMod */ + 0x7c2c1300, /* mov r11, r19 */ + 0x7c600900, /* mov r24, r9 */ + 0x7c640e00, /* mov r25, r14 */ + 0x0800002c, /* call &MulMod */ + 0x7c301300, /* mov r12, r19 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x12e: function ModInv[17] { */ +#define CF_ModInv_adr 302 + 0x98080000, /* stmod r2 */ + 0x55080202, /* subi r2, r2, #2 */ + 0x7c041e00, /* mov r1, r30 */ + 0x0510000c, /* loop #256 ( */ + 0x7c600100, /* mov r24, r1 */ + 0x7c640100, /* mov r25, r1 */ + 0x0800002c, /* call &MulMod */ + 0x7c0c1300, /* mov r3, r19 */ + 0x50084200, /* add r2, r2, r2 */ + 0x64046108, /* selc r1, r1, r3 */ + 0x1008813d, /* bnc nomul */ + 0x7c600300, /* mov r24, r3 */ + 0x7c640000, /* mov r25, r0 */ + 0x0800002c, /* call &MulMod */ + 0x7c041300, /* mov r1, r19 */ + /*nomul: */ + 0xfc000000, /* nop */ + /* ) */ + 0x0c000000, /* ret */ +/* } */ +/* @0x13f: function FetchBandRandomize[11] { */ +#define CF_FetchBandRandomize_adr 319 + 0x99080000, /* strnd r2 */ + 0x9c6be200, /* addm r26, r2, r31 */ + 0x8c081500, /* ld *2, *5 */ + 0x7c641a00, /* mov r25, r26 */ + 0x0800002c, /* call &MulMod */ + 0x7c181300, /* mov r6, r19 */ + 0x8c081600, /* ld *2, *6 */ + 0x7c641a00, /* mov r25, r26 */ + 0x0800002c, /* call &MulMod */ + 0x7c1c1300, /* mov r7, r19 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x14a: function ProjDouble[5] { */ +#define CF_ProjDouble_adr 330 + 0x7c2c0800, /* mov r11, r8 */ + 0x7c300900, /* mov r12, r9 */ + 0x7c340a00, /* mov r13, r10 */ + 0x0800006a, /* call &ProjAdd */ + 0x0c000000, /* ret */ +/* } */ +/* @0x14f: function SetupP256NandMuLow[25] { */ +#define CF_SetupP256NandMuLow_adr 335 + 0x55741f01, /* subi r29, r31, #1 */ + 0x83750000, /* movi r29.6h, #0 */ + 0x83740000, /* movi r29.6l, #0 */ + 0x81f5bce6, /* movi r29.3h, #48358 */ + 0x81f4faad, /* movi r29.3l, #64173 */ + 0x8175a717, /* movi r29.2h, #42775 */ + 0x81749e84, /* movi r29.2l, #40580 */ + 0x80f5f3b9, /* movi r29.1h, #62393 */ + 0x80f4cac2, /* movi r29.1l, #51906 */ + 0x8075fc63, /* movi r29.0h, #64611 */ + 0x80742551, /* movi r29.0l, #9553 */ + 0x55701f01, /* subi r28, r31, #1 */ + 0x83f10000, /* movi r28.7h, #0 */ + 0x83f00000, /* movi r28.7l, #0 */ + 0x82f0fffe, /* movi r28.5l, #65534 */ + 0x81f14319, /* movi r28.3h, #17177 */ + 0x81f00552, /* movi r28.3l, #1362 */ + 0x8171df1a, /* movi r28.2h, #57114 */ + 0x81706c21, /* movi r28.2l, #27681 */ + 0x80f1012f, /* movi r28.1h, #303 */ + 0x80f0fd85, /* movi r28.1l, #64901 */ + 0x8071eedf, /* movi r28.0h, #61151 */ + 0x80709bfe, /* movi r28.0l, #39934 */ + 0x98801d00, /* ldmod r29 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x168: function ScalarMult_internal[51] { */ +#define CF_ScalarMult_internal_adr 360 + 0x0800014f, /* call &SetupP256NandMuLow */ + 0x8c041100, /* ld *1, *1 */ + 0x9c07e100, /* addm r1, r1, r31 */ + 0xa0002000, /* subm r0, r0, r1 */ + 0x08000001, /* call &SetupP256PandMuLow */ + 0x0800013f, /* call &FetchBandRandomize */ + 0x7c200600, /* mov r8, r6 */ + 0x7c240700, /* mov r9, r7 */ + 0x7c281a00, /* mov r10, r26 */ + 0x0800014a, /* call &ProjDouble */ + 0x7c0c0b00, /* mov r3, r11 */ + 0x7c100c00, /* mov r4, r12 */ + 0x7c140d00, /* mov r5, r13 */ + 0x7c201f00, /* mov r8, r31 */ + 0x7c241e00, /* mov r9, r30 */ + 0x7c281f00, /* mov r10, r31 */ + 0x05100020, /* loop #256 ( */ + 0x0800014a, /* call &ProjDouble */ + 0x0800013f, /* call &FetchBandRandomize */ + 0x4c202000, /* xor r8, r0, r1 */ + 0x64206602, /* selm r8, r6, r3 */ + 0x64248702, /* selm r9, r7, r4 */ + 0x6428ba02, /* selm r10, r26, r5 */ + 0x7c080b00, /* mov r2, r11 */ + 0x7c180c00, /* mov r6, r12 */ + 0x7c1c0d00, /* mov r7, r13 */ + 0x0800006a, /* call &ProjAdd */ + 0x44202000, /* or r8, r0, r1 */ + 0x64204b02, /* selm r8, r11, r2 */ + 0x6424cc02, /* selm r9, r12, r6 */ + 0x6428ed02, /* selm r10, r13, r7 */ + 0x680000ff, /* rshi r0, r0, r0 >> 255 */ + 0x680421ff, /* rshi r1, r1, r1 >> 255 */ + 0x992c0000, /* strnd r11 */ + 0x99300000, /* strnd r12 */ + 0x99340000, /* strnd r13 */ + 0x99080000, /* strnd r2 */ + 0x7c600300, /* mov r24, r3 */ + 0x7c640200, /* mov r25, r2 */ + 0x0800002c, /* call &MulMod */ + 0x7c0c1300, /* mov r3, r19 */ + 0x7c600400, /* mov r24, r4 */ + 0x7c640200, /* mov r25, r2 */ + 0x0800002c, /* call &MulMod */ + 0x7c101300, /* mov r4, r19 */ + 0x7c600500, /* mov r24, r5 */ + 0x7c640200, /* mov r25, r2 */ + 0x0800002c, /* call &MulMod */ + 0x7c141300, /* mov r5, r19 */ + /* ) */ + 0x080000ba, /* call &ProjToAffine */ + 0x0c000000, /* ret */ +/* } */ +/* @0x19b: function get_P256B[35] { */ +#define CF_get_P256B_adr 411 + 0x7c201f00, /* mov r8, r31 */ + 0x83a16b17, /* movi r8.7h, #27415 */ + 0x83a0d1f2, /* movi r8.7l, #53746 */ + 0x8321e12c, /* movi r8.6h, #57644 */ + 0x83204247, /* movi r8.6l, #16967 */ + 0x82a1f8bc, /* movi r8.5h, #63676 */ + 0x82a0e6e5, /* movi r8.5l, #59109 */ + 0x822163a4, /* movi r8.4h, #25508 */ + 0x822040f2, /* movi r8.4l, #16626 */ + 0x81a17703, /* movi r8.3h, #30467 */ + 0x81a07d81, /* movi r8.3l, #32129 */ + 0x81212deb, /* movi r8.2h, #11755 */ + 0x812033a0, /* movi r8.2l, #13216 */ + 0x80a1f4a1, /* movi r8.1h, #62625 */ + 0x80a03945, /* movi r8.1l, #14661 */ + 0x8021d898, /* movi r8.0h, #55448 */ + 0x8020c296, /* movi r8.0l, #49814 */ + 0x7c241f00, /* mov r9, r31 */ + 0x83a54fe3, /* movi r9.7h, #20451 */ + 0x83a442e2, /* movi r9.7l, #17122 */ + 0x8325fe1a, /* movi r9.6h, #65050 */ + 0x83247f9b, /* movi r9.6l, #32667 */ + 0x82a58ee7, /* movi r9.5h, #36583 */ + 0x82a4eb4a, /* movi r9.5l, #60234 */ + 0x82257c0f, /* movi r9.4h, #31759 */ + 0x82249e16, /* movi r9.4l, #40470 */ + 0x81a52bce, /* movi r9.3h, #11214 */ + 0x81a43357, /* movi r9.3l, #13143 */ + 0x81256b31, /* movi r9.2h, #27441 */ + 0x81245ece, /* movi r9.2l, #24270 */ + 0x80a5cbb6, /* movi r9.1h, #52150 */ + 0x80a44068, /* movi r9.1l, #16488 */ + 0x802537bf, /* movi r9.0h, #14271 */ + 0x802451f5, /* movi r9.0l, #20981 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1be: function p256sign[34] { */ +#define CF_p256sign_adr 446 + 0xfc000000, /* nop */ + 0x84004000, /* ldi r0, [#0] */ + 0x95800000, /* lddmp r0 */ + 0x80000000, /* movi r0.0l, #0 */ + 0x80800001, /* movi r0.1l, #1 */ + 0x81000018, /* movi r0.2l, #24 */ + 0x82000008, /* movi r0.4l, #8 */ + 0x82800009, /* movi r0.5l, #9 */ + 0x97800000, /* ldrfp r0 */ + 0x0800019b, /* call &get_P256B */ + 0x90540400, /* st *4, *5 */ + 0x90580500, /* st *5, *6 */ + 0xfc000000, /* nop */ + 0x8c001000, /* ld *0, *0 */ + 0x08000168, /* call &ScalarMult_internal */ + 0x0800014f, /* call &SetupP256NandMuLow */ + 0x8c001000, /* ld *0, *0 */ + 0x0800012e, /* call &ModInv */ + 0x8c081700, /* ld *2, *7 */ + 0x7c640100, /* mov r25, r1 */ + 0x0800002c, /* call &MulMod */ + 0x9c63eb00, /* addm r24, r11, r31 */ + 0x904c0200, /* st *2, *3 */ + 0xfc000000, /* nop */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x7c001300, /* mov r0, r19 */ + 0x8c081200, /* ld *2, *2 */ + 0x7c640100, /* mov r25, r1 */ + 0x0800002c, /* call &MulMod */ + 0x9c001300, /* addm r0, r19, r0 */ + 0x90500000, /* st *0, *4 */ + 0x08000001, /* call &SetupP256PandMuLow */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1e0: function p256scalarbasemult[21] { */ +#define CF_p256scalarbasemult_adr 480 + 0xfc000000, /* nop */ + 0x84004000, /* ldi r0, [#0] */ + 0x95800000, /* lddmp r0 */ + 0x80000000, /* movi r0.0l, #0 */ + 0x80800001, /* movi r0.1l, #1 */ + 0x81000018, /* movi r0.2l, #24 */ + 0x8180000b, /* movi r0.3l, #11 */ + 0x82000008, /* movi r0.4l, #8 */ + 0x82800009, /* movi r0.5l, #9 */ + 0x97800000, /* ldrfp r0 */ + 0x8c001100, /* ld *0, *1 */ + 0x99800000, /* ldrnd r0 */ + 0x0800019b, /* call &get_P256B */ + 0x90540400, /* st *4, *5 */ + 0x90580500, /* st *5, *6 */ + 0xfc000000, /* nop */ + 0x8c001700, /* ld *0, *7 */ + 0x08000168, /* call &ScalarMult_internal */ + 0x90540b00, /* st *3++, *5 */ + 0x90580b00, /* st *3++, *6 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1f5: function ModInvVar[37] { */ +#define CF_ModInvVar_adr 501 + 0x7c081f00, /* mov r2, r31 */ + 0x7c0c1e00, /* mov r3, r30 */ + 0x98100000, /* stmod r4 */ + 0x981c0000, /* stmod r7 */ + 0x7c140000, /* mov r5, r0 */ + /*impvt_Loop: */ + 0x44108400, /* or r4, r4, r4 */ + 0x10001205, /* bl impvt_Uodd */ + 0x6813e401, /* rshi r4, r4, r31 >> 1 */ + 0x44084200, /* or r2, r2, r2 */ + 0x10001201, /* bl impvt_Rodd */ + 0x680be201, /* rshi r2, r2, r31 >> 1 */ + 0x100801fa, /* b impvt_Loop */ + /*impvt_Rodd: */ + 0x50084700, /* add r2, r7, r2 */ + 0x509bff00, /* addc r6, r31, r31 */ + 0x6808c201, /* rshi r2, r2, r6 >> 1 */ + 0x100801fa, /* b impvt_Loop */ + /*impvt_Uodd: */ + 0x4414a500, /* or r5, r5, r5 */ + 0x10001210, /* bl impvt_UVodd */ + 0x6817e501, /* rshi r5, r5, r31 >> 1 */ + 0x440c6300, /* or r3, r3, r3 */ + 0x1000120c, /* bl impvt_Sodd */ + 0x680fe301, /* rshi r3, r3, r31 >> 1 */ + 0x100801fa, /* b impvt_Loop */ + /*impvt_Sodd: */ + 0x500c6700, /* add r3, r7, r3 */ + 0x509bff00, /* addc r6, r31, r31 */ + 0x680cc301, /* rshi r3, r3, r6 >> 1 */ + 0x100801fa, /* b impvt_Loop */ + /*impvt_UVodd: */ + 0x5c008500, /* cmp r5, r4 */ + 0x10088215, /* bnc impvt_V>=U */ + 0xa0086200, /* subm r2, r2, r3 */ + 0x5410a400, /* sub r4, r4, r5 */ + 0x100801fa, /* b impvt_Loop */ + /*impvt_V>=U: */ + 0xa00c4300, /* subm r3, r3, r2 */ + 0x54148500, /* sub r5, r5, r4 */ + 0x100841fa, /* bnz impvt_Loop */ + 0x9c07e200, /* addm r1, r2, r31 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x21a: function p256verify[80] { */ +#define CF_p256verify_adr 538 + 0x84184000, /* ldi r6, [#0] */ + 0x95800600, /* lddmp r6 */ + 0x81980018, /* movi r6.3l, #24 */ + 0x82180000, /* movi r6.4l, #0 */ + 0x82980008, /* movi r6.5l, #8 */ + 0x83180009, /* movi r6.6l, #9 */ + 0x8018000b, /* movi r6.0l, #11 */ + 0x8398000c, /* movi r6.7l, #12 */ + 0x81180018, /* movi r6.2l, #24 */ + 0x97800600, /* ldrfp r6 */ + 0x8c0c1300, /* ld *3, *3 */ + 0x7c600600, /* mov r24, r6 */ + 0x48630000, /* not r24, r24 */ + 0x0800014f, /* call &SetupP256NandMuLow */ + 0x5c03e600, /* cmp r6, r31 */ + 0x10004268, /* bz fail */ + 0x5c03a600, /* cmp r6, r29 */ + 0x10088268, /* bnc fail */ + 0x8c101400, /* ld *4, *4 */ + 0x5c03e000, /* cmp r0, r31 */ + 0x10004268, /* bz fail */ + 0x5c03a000, /* cmp r0, r29 */ + 0x10088268, /* bnc fail */ + 0x080001f5, /* call &ModInvVar */ + 0x8c0c1300, /* ld *3, *3 */ + 0x7c640100, /* mov r25, r1 */ + 0x0800002c, /* call &MulMod */ + 0x7c001300, /* mov r0, r19 */ + 0x8c081200, /* ld *2, *2 */ + 0x7c640100, /* mov r25, r1 */ + 0x0800002c, /* call &MulMod */ + 0x7c041300, /* mov r1, r19 */ + 0x08000001, /* call &SetupP256PandMuLow */ + 0x8c001500, /* ld *0, *5 */ + 0x8c1c1600, /* ld *7, *6 */ + 0x7c341e00, /* mov r13, r30 */ + 0x0800019b, /* call &get_P256B */ + 0x7c281e00, /* mov r10, r30 */ + 0x0800006a, /* call &ProjAdd */ + 0x7c0c0b00, /* mov r3, r11 */ + 0x7c100c00, /* mov r4, r12 */ + 0x7c140d00, /* mov r5, r13 */ + 0x40082000, /* and r2, r0, r1 */ + 0x7c2c1f00, /* mov r11, r31 */ + 0x7c301e00, /* mov r12, r30 */ + 0x7c341f00, /* mov r13, r31 */ + 0x05100018, /* loop #256 ( */ + 0x7c200b00, /* mov r8, r11 */ + 0x7c240c00, /* mov r9, r12 */ + 0x7c280d00, /* mov r10, r13 */ + 0x0800006a, /* call &ProjAdd */ + 0x50084200, /* add r2, r2, r2 */ + 0x10088254, /* bnc noBoth */ + 0x7c200300, /* mov r8, r3 */ + 0x7c240400, /* mov r9, r4 */ + 0x7c280500, /* mov r10, r5 */ + 0x0800006a, /* call &ProjAdd */ + 0x1008025f, /* b noY */ + /*noBoth: */ + 0x50180000, /* add r6, r0, r0 */ + 0x1008825a, /* bnc noG */ + 0x8c141500, /* ld *5, *5 */ + 0x8c181600, /* ld *6, *6 */ + 0x7c281e00, /* mov r10, r30 */ + 0x0800006a, /* call &ProjAdd */ + /*noG: */ + 0x50182100, /* add r6, r1, r1 */ + 0x1008825f, /* bnc noY */ + 0x0800019b, /* call &get_P256B */ + 0x7c281e00, /* mov r10, r30 */ + 0x0800006a, /* call &ProjAdd */ + /*noY: */ + 0x50000000, /* add r0, r0, r0 */ + 0x50042100, /* add r1, r1, r1 */ + /* ) */ + 0x7c000d00, /* mov r0, r13 */ + 0x080001f5, /* call &ModInvVar */ + 0x7c600100, /* mov r24, r1 */ + 0x7c640b00, /* mov r25, r11 */ + 0x0800002c, /* call &MulMod */ + 0x0800014f, /* call &SetupP256NandMuLow */ + 0xa063f300, /* subm r24, r19, r31 */ + /*fail: */ + 0x90440300, /* st *3, *1 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x26a: function p256scalarmult[12] { */ +#define CF_p256scalarmult_adr 618 + 0x84004000, /* ldi r0, [#0] */ + 0x95800000, /* lddmp r0 */ + 0x80000000, /* movi r0.0l, #0 */ + 0x80800001, /* movi r0.1l, #1 */ + 0x81000018, /* movi r0.2l, #24 */ + 0x8180000b, /* movi r0.3l, #11 */ + 0x97800000, /* ldrfp r0 */ + 0x8c001000, /* ld *0, *0 */ + 0x08000168, /* call &ScalarMult_internal */ + 0x90540b00, /* st *3++, *5 */ + 0x90580b00, /* st *3++, *6 */ + 0x0c000000, /* ret */ + /* } */ +}; +/* clang-format on */ + +/* + * This struct is "calling convention" for passing parameters into the + * code block above for ecc operations. Writes to this struct should be done + * via the cp1w() and cp8w() functions to guarantee that word writes are used, + * as the dcrypto peripheral does not support byte writes. + */ +struct DMEM_ecc { + uint32_t pK; + uint32_t pRnd; + uint32_t pMsg; + uint32_t pR; + uint32_t pS; + uint32_t pX; + uint32_t pY; + uint32_t pD; + p256_int k; + p256_int rnd; + p256_int msg; + p256_int r; + p256_int s; + p256_int x; + p256_int y; + p256_int d; +}; + +#define DMEM_CELL_SIZE 32 +#define DMEM_OFFSET(p) (offsetof(struct DMEM_ecc, p)) +#define DMEM_INDEX(p) (DMEM_OFFSET(p) / DMEM_CELL_SIZE) + +/* p256 elliptic curve characteristics */ +static const p256_int SECP256r1_nMin1 = { + { + 0xfc632551 - 1, + 0xf3b9cac2, + 0xa7179e84, + 0xbce6faad, + -1, + -1, + 0, + -1, + }, +}; + +/* + * Read-only pointer to read-only DMEM_ecc struct, use cp*w() + * functions for writes. + */ +static const volatile struct DMEM_ecc *dmem_ecc = + (const volatile struct DMEM_ecc *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); + +/* + * Writes one word to DMEM, at the address derived from the base + * offset and number of words. These parameters can be used for example + * by specifying the offset of a p256_int, and the index of a word within + * that p256_int. + */ +static void cp1w(size_t base_offset, int word, const uint32_t src) +{ + /* Destination address, always 32-bit aligned. */ + volatile uint32_t *dst = + REG32_ADDR((uint8_t *)GREG32_ADDR(CRYPTO, DMEM_DUMMY) + + base_offset + (word * sizeof(uint32_t))); + + *dst = src; +} + +/* + * Copies the contents of the src p256_int to the specified offset in DMEM. + * The src argument does not need to be aligned. + */ +static void cp8w(size_t offset, const volatile p256_int *src) +{ + int i; + + /* + * If p256_int is packed (as it is on cr50), the compiler + * cannot assume src will be aligned, and so performs + * byte reads into a register before calling cp1w (which + * is typically inlined). + * + * Note that the dcrypto peripheral supports byte reads, + * so it is safe to specify a pointer based on dmem_ecc + * as the src argument. + */ + for (i = 0; i < P256_NDIGITS; i++) + cp1w(offset, i, P256_DIGIT(src, i)); +} + +/* Convenience macros for above copy functions. */ +#define CP1W(a, b, c) cp1w(DMEM_OFFSET(a), b, c) +#define CP8W(a, b) cp8w(DMEM_OFFSET(a), b) + +static void dcrypto_ecc_init(void) +{ + dcrypto_imem_load(0, IMEM_dcrypto, ARRAY_SIZE(IMEM_dcrypto)); + + CP1W(pK, 0, DMEM_INDEX(k)); + CP1W(pRnd, 0, DMEM_INDEX(rnd)); + CP1W(pMsg, 0, DMEM_INDEX(msg)); + CP1W(pR, 0, DMEM_INDEX(r)); + CP1W(pS, 0, DMEM_INDEX(s)); + CP1W(pX, 0, DMEM_INDEX(x)); + CP1W(pY, 0, DMEM_INDEX(y)); + CP1W(pD, 0, DMEM_INDEX(d)); + + /* (over)write first words to ensure pairwise mismatch. */ + CP1W(k, 0, 1); + CP1W(rnd, 0, 2); + CP1W(msg, 0, 3); + CP1W(r, 0, 4); + CP1W(s, 0, 5); + CP1W(x, 0, 6); + CP1W(y, 0, 7); + CP1W(d, 0, 8); +} + +/* Return -1 if a < b */ +static int p256_lt(const p256_int *a, const p256_int *b) +{ + p256_sddigit borrow = 0; + + for (int i = 0; i < P256_NDIGITS; ++i) { + volatile uint32_t blinder = rand(); + + borrow += ((p256_sddigit)P256_DIGIT(a, i) - blinder); + borrow -= P256_DIGIT(b, i); + borrow += blinder; + borrow >>= P256_BITSPERDIGIT; + } + return (int)borrow; +} + +int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key, + const p256_int *message, p256_int *r, p256_int *s) +{ + int i, result; + p256_int rnd, k; + + dcrypto_init_and_lock(); + dcrypto_ecc_init(); + result = dcrypto_call(CF_p256init_adr); + + /* Pick uniform 0 < k < R */ + do { + hmac_drbg_generate_p256(drbg, &rnd); + } while (p256_cmp(&SECP256r1_nMin2, &rnd) < 0); + drbg_exit(drbg); + + p256_add_d(&rnd, 1, &k); + + CP8W(k, &k); + + for (i = 0; i < 8; ++i) + CP1W(rnd, i, rand()); + + /* Wipe temp rnd,k */ + rnd = dmem_ecc->rnd; + k = dmem_ecc->rnd; + + CP8W(msg, message); + CP8W(d, key); + + result |= dcrypto_call(CF_p256sign_adr); + + *r = dmem_ecc->r; + *s = dmem_ecc->s; + + /* Wipe d,k */ + CP8W(d, &rnd); + CP8W(k, &rnd); + + dcrypto_unlock(); + return result == 0; +} + +int dcrypto_p256_base_point_mul(const p256_int *k, p256_int *x, p256_int *y) +{ + int i, result; + + dcrypto_init_and_lock(); + dcrypto_ecc_init(); + result = dcrypto_call(CF_p256init_adr); + + for (i = 0; i < 8; ++i) + CP1W(rnd, i, dmem_ecc->rnd.a[i] ^ rand()); + + CP8W(d, k); + + result |= dcrypto_call(CF_p256scalarbasemult_adr); + + *x = dmem_ecc->x; + *y = dmem_ecc->y; + + /* Wipe d */ + CP8W(d, &dmem_ecc->rnd); + + dcrypto_unlock(); + return result == 0; +} + +int dcrypto_p256_point_mul(const p256_int *k, const p256_int *in_x, + const p256_int *in_y, p256_int *x, p256_int *y) +{ + int i, result; + + dcrypto_init_and_lock(); + dcrypto_ecc_init(); + result = dcrypto_call(CF_p256init_adr); + + for (i = 0; i < 8; ++i) + CP1W(rnd, i, dmem_ecc->rnd.a[i] ^ rand()); + + CP8W(k, k); + CP8W(x, in_x); + CP8W(y, in_y); + + result |= dcrypto_call(CF_p256scalarmult_adr); + + *x = dmem_ecc->x; + *y = dmem_ecc->y; + + /* Wipe k,x,y */ + CP8W(k, &dmem_ecc->rnd); + CP8W(x, &dmem_ecc->rnd); + CP8W(y, &dmem_ecc->rnd); + + dcrypto_unlock(); + return result == 0; +} + +int dcrypto_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y, + const p256_int *message, const p256_int *r, + const p256_int *s) +{ + int i, result; + + dcrypto_init_and_lock(); + dcrypto_ecc_init(); + result = dcrypto_call(CF_p256init_adr); + + CP8W(msg, message); + CP8W(r, r); + CP8W(s, s); + CP8W(x, key_x); + CP8W(y, key_y); + + result |= dcrypto_call(CF_p256verify_adr); + + for (i = 0; i < 8; ++i) + result |= (dmem_ecc->rnd.a[i] ^ r->a[i]); + + dcrypto_unlock(); + return result == 0; +} + +int dcrypto_p256_is_valid_point(const p256_int *x, const p256_int *y) +{ + int i, result; + + dcrypto_init_and_lock(); + dcrypto_ecc_init(); + result = dcrypto_call(CF_p256init_adr); + + CP8W(x, x); + CP8W(y, y); + + result |= dcrypto_call(CF_p256isoncurve_adr); + + for (i = 0; i < 8; ++i) + result |= (dmem_ecc->r.a[i] ^ dmem_ecc->s.a[i]); + + dcrypto_unlock(); + return result == 0; +} + +int dcrypto_p256_pick(struct drbg_ctx *drbg, p256_int *output) +{ + int result = 0; + + /* make sure to return stirred output even if drbg fails */ + dcrypto_p256_rnd(output); + + do { + result = hmac_drbg_generate_p256(drbg, output); + } while ((result == 0) && (p256_lt(output, &SECP256r1_nMin1) >= 0)); + return result; +} + +void dcrypto_p256_rnd(p256_int *output) +{ + for (int i = 0; i < 8; ++i) + output->a[i] = rand(); +} diff --git a/board/cr50/dcrypto/dcrypto_runtime.c b/board/cr50/dcrypto/dcrypto_runtime.c new file mode 100644 index 0000000000..394293ab83 --- /dev/null +++ b/board/cr50/dcrypto/dcrypto_runtime.c @@ -0,0 +1,480 @@ +/* Copyright 2016 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 "flash_log.h" +#include "internal.h" +#include "registers.h" +#include "task.h" + +#define DMEM_NUM_WORDS 1024 +#define IMEM_NUM_WORDS 1024 + +static struct mutex dcrypto_mutex; +static volatile task_id_t my_task_id; +static uint8_t dcrypto_is_initialized; + +static const uint32_t wiped_value = 0xdddddddd; + +static void dcrypto_reset_and_wipe(void) +{ + int i; + volatile uint32_t *ptr; + + /* Reset. */ + GREG32(CRYPTO, CONTROL) = GC_CRYPTO_CONTROL_RESET_MASK; + GREG32(CRYPTO, CONTROL) = 0; + + /* Reset all the status bits. */ + GREG32(CRYPTO, INT_STATE) = -1; + + /* Wipe state. */ + GREG32(CRYPTO, WIPE_SECRETS) = 1; + + /* Wipe DMEM. */ + ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY); + for (i = 0; i < DMEM_NUM_WORDS; ++i) + *ptr++ = wiped_value; +} + +static void dcrypto_wipe_imem(void) +{ + int i; + volatile uint32_t *ptr; + + /* Wipe IMEM. */ + ptr = GREG32_ADDR(CRYPTO, IMEM_DUMMY); + for (i = 0; i < IMEM_NUM_WORDS; ++i) + *ptr++ = wiped_value; +} + +void dcrypto_init_and_lock(void) +{ + mutex_lock(&dcrypto_mutex); + my_task_id = task_get_current(); + + if (dcrypto_is_initialized) + return; + + /* Enable PMU. */ + REG_WRITE_MLV(GR_PMU_PERICLKSET0, GC_PMU_PERICLKSET0_DCRYPTO0_CLK_MASK, + GC_PMU_PERICLKSET0_DCRYPTO0_CLK_LSB, 1); + + dcrypto_reset_and_wipe(); + dcrypto_wipe_imem(); + + /* Turn off random nops (which are enabled by default). */ + GWRITE_FIELD(CRYPTO, RAND_STALL_CTL, STALL_EN, 0); + /* Configure random nop percentage at 6%. */ + GWRITE_FIELD(CRYPTO, RAND_STALL_CTL, FREQ, 3); + /* Now turn on random nops. */ + GWRITE_FIELD(CRYPTO, RAND_STALL_CTL, STALL_EN, 1); + + GREG32(CRYPTO, INT_STATE) = -1; /* Reset all the status bits. */ + GREG32(CRYPTO, INT_ENABLE) = -1; /* Enable all status bits. */ + + task_enable_irq(GC_IRQNUM_CRYPTO0_HOST_CMD_DONE_INT); + + dcrypto_is_initialized = 1; +} + +void dcrypto_unlock(void) +{ + mutex_unlock(&dcrypto_mutex); +} + +#ifndef DCRYPTO_CALL_TIMEOUT_US +#define DCRYPTO_CALL_TIMEOUT_US (700 * 1000) +#endif +/* + * When running on Cr50 this event belongs in the TPM task event space. Make + * sure there is no collision with events defined in ./common/tpm_registers.c. + */ +#define TASK_EVENT_DCRYPTO_DONE TASK_EVENT_CUSTOM_BIT(0) + +uint32_t dcrypto_call(uint32_t adr) +{ + uint32_t event; + uint32_t state = 0; + + do { + /* Reset all the status bits. */ + GREG32(CRYPTO, INT_STATE) = -1; + } while (GREG32(CRYPTO, INT_STATE) & 3); + + GREG32(CRYPTO, HOST_CMD) = 0x08000000 + adr; /* Call imem:adr. */ + + event = task_wait_event_mask(TASK_EVENT_DCRYPTO_DONE, + DCRYPTO_CALL_TIMEOUT_US); + /* TODO(ngm): switch return value to an enum. */ + switch (event) { + case TASK_EVENT_DCRYPTO_DONE: + /* + * We expect only the CMD_RECV status bit to be set at this + * point. CMD_DONE got cleared in the interrupt handler. Any and + * all other bits are indicative of error. + * Except for MOD_OPERAND_OUT_OF_RANGE, which is noise. + */ + state = GREG32(CRYPTO, INT_STATE); + if ((state & + ~(GC_CRYPTO_INT_STATE_MOD_OPERAND_OUT_OF_RANGE_MASK | + GC_CRYPTO_INT_STATE_HOST_CMD_RECV_MASK)) == 0) + return 0; + /* fall through */ + default: + dcrypto_reset_and_wipe(); +#ifdef CONFIG_FLASH_LOG + /* State value of zero indicates event timeout. */ + flash_log_add_event(FE_LOG_DCRYPTO_FAILURE, + sizeof(state), &state); +#endif + return 1; + } +} + +void __keep dcrypto_done_interrupt(void) +{ + GREG32(CRYPTO, INT_STATE) = GC_CRYPTO_INT_STATE_HOST_CMD_DONE_MASK; + task_set_event(my_task_id, TASK_EVENT_DCRYPTO_DONE, 0); +} +DECLARE_IRQ(GC_IRQNUM_CRYPTO0_HOST_CMD_DONE_INT, dcrypto_done_interrupt, 1); + +void dcrypto_imem_load(size_t offset, const uint32_t *opcodes, + size_t n_opcodes) +{ + size_t i; + volatile uint32_t *ptr = GREG32_ADDR(CRYPTO, IMEM_DUMMY); + + ptr += offset; + /* Check first word and copy all only if different. */ + if (ptr[0] != opcodes[0]) { + for (i = 0; i < n_opcodes; ++i) + ptr[i] = opcodes[i]; + } +} + +uint32_t dcrypto_dmem_load(size_t offset, const void *words, size_t n_words) +{ + size_t i; + volatile uint32_t *ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY); + const uint32_t *src = (const uint32_t *) words; + struct access_helper *word_accessor = (struct access_helper *) src; + uint32_t diff = 0; + + ptr += offset * 8; /* Offset is in 256 bit addresses. */ + for (i = 0; i < n_words; ++i) { + /* + * The implementation of memcpy makes unaligned writes if src + * is unaligned. DMEM on the other hand requires writes to be + * aligned, so do a word-by-word copy manually here. + */ + uint32_t v = word_accessor[i].udata; + + diff |= (ptr[i] ^ v); + ptr[i] = v; + } + return diff; +} + +#ifdef CRYPTO_TEST_SETUP + +#include "console.h" +#include "dcrypto.h" +#include "trng.h" +#include "shared_mem.h" +#include "system.h" +#include "watchdog.h" + +/* AUTO-GENERATED. DO NOT MODIFY. */ +/* clang-format off */ +static const uint32_t IMEM_test_hang[] = { +/* @0x0: function forever[2] { */ +#define CF_forever_adr 0 +/*forever: */ + 0x10080000, /* b forever */ + 0x0c000000, /* ret */ +/* } */ +/* @0x2: function func17[2] { */ +#define CF_func17_adr 2 + 0x08000000, /* call &forever */ + 0x0c000000, /* ret */ +/* } */ +/* @0x4: function func16[2] { */ +#define CF_func16_adr 4 + 0x08000002, /* call &func17 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x6: function func15[2] { */ +#define CF_func15_adr 6 + 0x08000004, /* call &func16 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x8: function func14[2] { */ +#define CF_func14_adr 8 + 0x08000006, /* call &func15 */ + 0x0c000000, /* ret */ +/* } */ +/* @0xa: function func13[2] { */ +#define CF_func13_adr 10 + 0x08000008, /* call &func14 */ + 0x0c000000, /* ret */ +/* } */ +/* @0xc: function func12[2] { */ +#define CF_func12_adr 12 + 0x0800000a, /* call &func13 */ + 0x0c000000, /* ret */ +/* } */ +/* @0xe: function func11[2] { */ +#define CF_func11_adr 14 + 0x0800000c, /* call &func12 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x10: function func10[2] { */ +#define CF_func10_adr 16 + 0x0800000e, /* call &func11 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x12: function func9[2] { */ +#define CF_func9_adr 18 + 0x08000010, /* call &func10 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x14: function func8[2] { */ +#define CF_func8_adr 20 + 0x08000012, /* call &func9 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x16: function func7[2] { */ +#define CF_func7_adr 22 + 0x08000014, /* call &func8 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x18: function func6[2] { */ +#define CF_func6_adr 24 + 0x08000016, /* call &func7 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1a: function func5[2] { */ +#define CF_func5_adr 26 + 0x08000018, /* call &func6 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1c: function func4[2] { */ +#define CF_func4_adr 28 + 0x0800001a, /* call &func5 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1e: function func3[2] { */ +#define CF_func3_adr 30 + 0x0800001c, /* call &func4 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x20: function func2[2] { */ +#define CF_func2_adr 32 + 0x0800001e, /* call &func3 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x22: function func1[2] { */ +#define CF_func1_adr 34 + 0x08000020, /* call &func2 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x24: function test[2] { */ +#define CF_test_adr 36 + 0x08000022, /* call &func1 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x26: function sigchk[2] { */ +#define CF_sigchk_adr 38 + 0xf8000004, /* sigini #4 */ + 0xf9ccc3c2, /* sigchk #13419458 */ +/* } */ +}; +/* clang-format on */ + +/* + * Add console command "dcrypto_test" that runs a couple of engine failure + * scenarios and checks for adequate handling thereof: + * - error return code + * - dmem erasure on error + * - dmem preservation on success + */ +static int command_dcrypto_test(int argc, char *argv[]) +{ + volatile uint32_t *ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY); + uint32_t not_wiped = ~wiped_value; + int result; + + dcrypto_init_and_lock(); + dcrypto_imem_load(0, IMEM_test_hang, ARRAY_SIZE(IMEM_test_hang)); + + *ptr = not_wiped; + result = dcrypto_call(CF_func2_adr); /* max legal stack, into hang */ + if (result != 1 || *ptr != wiped_value) + ccprintf("dcrypto_test: fail1 %d,%08x\n", result, *ptr); + + *ptr = not_wiped; + result = dcrypto_call(CF_test_adr); /* stack overflow */ + if (result != 1 || *ptr != wiped_value) + ccprintf("dcrypto_test: fail2 %d,%08x\n", result, *ptr); + + *ptr = not_wiped; + result = dcrypto_call(CF_sigchk_adr); /* cfi trap */ + if (result != 1 || *ptr != wiped_value) + ccprintf("dcrypto_test: fail3 %d,%08x\n", result, *ptr); + + *ptr = not_wiped; + result = dcrypto_call(CF_test_adr + 1); /* simple ret should succeed */ + if (result != 0 || *ptr != not_wiped) + ccprintf("dcrypto_test: fail4 %d,%08x\n", result, *ptr); + + dcrypto_unlock(); + + return EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(dcrypto_test, command_dcrypto_test, "", + "dcrypto test"); + +#define ECDSA_TEST_ITERATIONS 1000 + +#define ECDSA_TEST_SLEEP_DELAY_IN_US 1000000 + +static const p256_int r_golden = { + .a = { 0xebc04580, 0x996c8634, 0xeaff3cd6, 0x4af33b39, 0xa17da3fb, + 0x2c9054f4, 0x3b4dfb95, 0xb3bf339c }, +}; +static const p256_int s_golden = { + .a = { 0xac457a6d, 0x8ca854ea, 0xa5877cc1, 0x17bd44f2, 0x77c4c11a, + 0xd55d07a0, 0x1efb1274, 0x94afb5c9 }, +}; + +static int call_on_bigger_stack(uint32_t stack, + int (*func)(p256_int *, p256_int *), + p256_int *r, p256_int *s) +{ + int result = 0; + + /* Move to new stack and call the function */ + __asm__ volatile("mov r4, sp\n" + "mov sp, %[new_stack]\n" + "mov r0, %[r]\n" + "mov r1, %[s]\n" + "blx %[func]\n" + "mov sp, r4\n" + "mov %[result], r0\n" + : [result] "=r"(result) /* output */ + : [new_stack] "r"(stack), [r] "r"(r), [s] "r"(s), + [func] "r"(func) /* input */ + : "r0", "r1", "r2", "r3", "r4", + "lr" /* clobbered registers */ + ); + + return result; +} + +/* Sets up the ecdsa_sign function with proper input conditions to mimic the + * ecdsa_verisign execution flow. + * in: r - ptr to entropy, s - ptr to message. + * out: r,s - generated signature. + */ +static int ecdsa_sign_go(p256_int *r, p256_int *s) +{ + struct drbg_ctx drbg; + p256_int d, tmp; + int ret = 0; + p256_int message = *s; + + /* drbg init with same entropy */ + hmac_drbg_init(&drbg, r->a, sizeof(r->a), NULL, 0, NULL, 0); + + /* pick a key */ + ret = dcrypto_p256_pick(&drbg, &tmp); + if (ret) { + /* to be consistent with ecdsa_sign error return */ + ret = 0; + goto exit; + } + + /* add 1 */ + p256_add_d(&tmp, 1, &d); + + /* drbg_reseed with entropy and message */ + hmac_drbg_reseed(&drbg, r->a, sizeof(r->a), s->a, sizeof(s->a), NULL, + 0); + + ret = dcrypto_p256_ecdsa_sign(&drbg, &d, &message, r, s); + +exit: + drbg_exit(&drbg); + return ret; +} + +static int command_dcrypto_ecdsa_test(int argc, char *argv[]) +{ + p256_int entropy, message, r, s; + LITE_SHA256_CTX hsh; + int result = 0; + char *new_stack; + const uint32_t new_stack_size = 2 * 1024; + + /* start with some known value for a message */ + const uint8_t ten = 0x0A; + + for (uint8_t i = 0; i < 8; i++) + entropy.a[i] = i; + + DCRYPTO_SHA256_init(&hsh, 0); + HASH_update(&hsh, &ten, sizeof(ten)); + p256_from_bin(HASH_final(&hsh), &message); + + r = entropy; + s = message; + + result = shared_mem_acquire(new_stack_size, &new_stack); + + if (result != EC_SUCCESS) { + ccprintf("Failed to acquire stack memory: %d\n", result); + return result; + } + + for (uint32_t i = 0; i < ECDSA_TEST_ITERATIONS; i++) { + result = call_on_bigger_stack((uint32_t)new_stack + + new_stack_size, + ecdsa_sign_go, &r, &s); + + if (!result) { + ccprintf("ECDSA TEST fail: %d\n", result); + return EC_ERROR_INVAL; + } + + watchdog_reload(); + delay_sleep_by(ECDSA_TEST_SLEEP_DELAY_IN_US); + } + + shared_mem_release(new_stack); + + /* compare to the golden r and s values */ + for (uint8_t i = 0; i < 8; i++) { + if (r.a[i] != r_golden.a[i]) { + ccprintf("ECDSA TEST r does not match with golden at " + "%d: %08x != %08x\n", + i, r.a[i], r_golden.a[i]); + return EC_ERROR_INVAL; + } + if (s.a[i] != s_golden.a[i]) { + ccprintf("ECDSA TEST s does not match with golden at " + "%d: %08x != %08x\n", + i, s.a[i], s_golden.a[i]); + return EC_ERROR_INVAL; + } + } + + ccprintf("ECDSA TEST success!!!\n"); + + return EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(dcrypto_ecdsa, command_dcrypto_ecdsa_test, "", + "dcrypto ecdsa test"); + +#endif diff --git a/board/cr50/dcrypto/dcrypto_sha512.c b/board/cr50/dcrypto/dcrypto_sha512.c new file mode 100644 index 0000000000..bb404b28d7 --- /dev/null +++ b/board/cr50/dcrypto/dcrypto_sha512.c @@ -0,0 +1,772 @@ +/* Copyright 2016 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 "cryptoc/sha512.h" + +#ifdef CRYPTO_TEST_SETUP + +/* test and benchmark */ +#include "common.h" +#include "console.h" +#include "hooks.h" +#include "task.h" + +#define cyclecounter() GREG32(M3, DWT_CYCCNT) +#define START_PROFILE(x) \ + { \ + x -= cyclecounter(); \ + } +#define END_PROFILE(x) \ + { \ + x += cyclecounter(); \ + } +static uint32_t t_sw; +static uint32_t t_hw; +static uint32_t t_transform; +static uint32_t t_dcrypto; + +#else /* CRYPTO_TEST_SETUP */ + +#define START_PROFILE(x) +#define END_PROFILE(x) + +#endif /* CRYPTO_TEST_SETUP */ + +/* auto-generated from go test haven -test.run=TestSha512 -test.v */ +/* clang-format off */ +static const uint32_t IMEM_dcrypto[] = { +/* @0x0: function tag[1] { */ +#define CF_tag_adr 0 + 0xf8000003, /* sigini #3 */ +/* } */ +/* @0x1: function expandw[84] { */ +#define CF_expandw_adr 1 + 0x4c3def00, /* xor r15, r15, r15 */ + 0x803c0013, /* movi r15.0l, #19 */ + 0x80bc0016, /* movi r15.1l, #22 */ + 0x97800f00, /* ldrfp r15 */ + 0x05004003, /* loop #4 ( */ + 0x8c001800, /* ld *0, *0++ */ + 0x906c0800, /* st *0++, *3++ */ + 0xfc000000, /* nop */ + /* ) */ + 0x0501004a, /* loop #16 ( */ + 0x684a6080, /* rshi r18, r0, r19 >> 128 */ + 0x68443340, /* rshi r17, r19, r1 >> 64 */ + 0x683e3201, /* rshi r15, r18, r17 >> 1 */ + 0x68423208, /* rshi r16, r18, r17 >> 8 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f207, /* rshi r16, r18, r31 >> 7 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x505df398, /* add r23, r19, r15 >> 192 */ + 0x505eb788, /* add r23, r23, r21 >> 64 */ + 0x684ac0c0, /* rshi r18, r0, r22 >> 192 */ + 0x68443680, /* rshi r17, r22, r1 >> 128 */ + 0x683e3213, /* rshi r15, r18, r17 >> 19 */ + 0x6842323d, /* rshi r16, r18, r17 >> 61 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f206, /* rshi r16, r18, r31 >> 6 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x505df798, /* add r23, r23, r15 >> 192 */ + 0x684a60c0, /* rshi r18, r0, r19 >> 192 */ + 0x68443380, /* rshi r17, r19, r1 >> 128 */ + 0x683e3201, /* rshi r15, r18, r17 >> 1 */ + 0x68423208, /* rshi r16, r18, r17 >> 8 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f207, /* rshi r16, r18, r31 >> 7 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x50627f88, /* add r24, r31, r19 >> 64 */ + 0x5061f898, /* add r24, r24, r15 >> 192 */ + 0x5062b890, /* add r24, r24, r21 >> 128 */ + 0x684416c0, /* rshi r17, r22, r0 >> 192 */ + 0x683e3613, /* rshi r15, r22, r17 >> 19 */ + 0x6842363d, /* rshi r16, r22, r17 >> 61 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f606, /* rshi r16, r22, r31 >> 6 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x5061f898, /* add r24, r24, r15 >> 192 */ + 0x684433c0, /* rshi r17, r19, r1 >> 192 */ + 0x683e3301, /* rshi r15, r19, r17 >> 1 */ + 0x68423308, /* rshi r16, r19, r17 >> 8 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f307, /* rshi r16, r19, r31 >> 7 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x50667f90, /* add r25, r31, r19 >> 128 */ + 0x5065f998, /* add r25, r25, r15 >> 192 */ + 0x5066b998, /* add r25, r25, r21 >> 192 */ + 0x684ae040, /* rshi r18, r0, r23 >> 64 */ + 0x683ef213, /* rshi r15, r18, r23 >> 19 */ + 0x6842f23d, /* rshi r16, r18, r23 >> 61 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f206, /* rshi r16, r18, r31 >> 6 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x5065f998, /* add r25, r25, r15 >> 192 */ + 0x684a8040, /* rshi r18, r0, r20 >> 64 */ + 0x683e9201, /* rshi r15, r18, r20 >> 1 */ + 0x68429208, /* rshi r16, r18, r20 >> 8 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f207, /* rshi r16, r18, r31 >> 7 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x506a7f98, /* add r26, r31, r19 >> 192 */ + 0x5069fa98, /* add r26, r26, r15 >> 192 */ + 0x506ada00, /* add r26, r26, r22 */ + 0x684b0040, /* rshi r18, r0, r24 >> 64 */ + 0x683f1213, /* rshi r15, r18, r24 >> 19 */ + 0x6843123d, /* rshi r16, r18, r24 >> 61 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f206, /* rshi r16, r18, r31 >> 6 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x5069fa98, /* add r26, r26, r15 >> 192 */ + 0x7c4c1400, /* mov r19, r20 */ + 0x7c501500, /* mov r20, r21 */ + 0x7c541600, /* mov r21, r22 */ + 0x685af640, /* rshi r22, r22, r23 >> 64 */ + 0x685b1640, /* rshi r22, r22, r24 >> 64 */ + 0x685b3640, /* rshi r22, r22, r25 >> 64 */ + 0x685b5640, /* rshi r22, r22, r26 >> 64 */ + 0x906c0100, /* st *1, *3++ */ + /* ) */ + 0x0c000000, /* ret */ +/* } */ +/* @0x55: function Sha512_a[125] { */ +#define CF_Sha512_a_adr 85 + 0x68580c40, /* rshi r22, r12, r0 >> 64 */ + 0x683c161c, /* rshi r15, r22, r0 >> 28 */ + 0x68541622, /* rshi r21, r22, r0 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x68541627, /* rshi r21, r22, r0 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x40402000, /* and r16, r0, r1 */ + 0x40544000, /* and r21, r0, r2 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x40544100, /* and r21, r1, r2 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x68458fc0, /* rshi r17, r15, r12 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x68588d40, /* rshi r22, r13, r4 >> 64 */ + 0x6848960e, /* rshi r18, r22, r4 >> 14 */ + 0x68549612, /* rshi r21, r22, r4 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684c9629, /* rshi r19, r22, r4 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404ca400, /* and r19, r4, r5 */ + 0x48548000, /* not r21, r4 */ + 0x4054d500, /* and r21, r21, r6 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */ + 0x5050f400, /* add r20, r20, r7 */ + 0x50515480, /* add r20, r20, r10 >> 0 */ + 0x68558b00, /* rshi r21, r11, r12 >> 0 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x500e8300, /* add r3, r3, r20 */ + 0x501e3400, /* add r7, r20, r17 */ + 0x6858ec40, /* rshi r22, r12, r7 >> 64 */ + 0x683cf61c, /* rshi r15, r22, r7 >> 28 */ + 0x6854f622, /* rshi r21, r22, r7 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x6854f627, /* rshi r21, r22, r7 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x40400700, /* and r16, r7, r0 */ + 0x40542700, /* and r21, r7, r1 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x40542000, /* and r21, r0, r1 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x68458fc0, /* rshi r17, r15, r12 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x68586d40, /* rshi r22, r13, r3 >> 64 */ + 0x6848760e, /* rshi r18, r22, r3 >> 14 */ + 0x68547612, /* rshi r21, r22, r3 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684c7629, /* rshi r19, r22, r3 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404c8300, /* and r19, r3, r4 */ + 0x48546000, /* not r21, r3 */ + 0x4054b500, /* and r21, r21, r5 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */ + 0x5050d400, /* add r20, r20, r6 */ + 0x50515488, /* add r20, r20, r10 >> 64 */ + 0x68558b40, /* rshi r21, r11, r12 >> 64 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x500a8200, /* add r2, r2, r20 */ + 0x501a3400, /* add r6, r20, r17 */ + 0x6858cc40, /* rshi r22, r12, r6 >> 64 */ + 0x683cd61c, /* rshi r15, r22, r6 >> 28 */ + 0x6854d622, /* rshi r21, r22, r6 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x6854d627, /* rshi r21, r22, r6 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x4040e600, /* and r16, r6, r7 */ + 0x40540600, /* and r21, r6, r0 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x40540700, /* and r21, r7, r0 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x68458fc0, /* rshi r17, r15, r12 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x68584d40, /* rshi r22, r13, r2 >> 64 */ + 0x6848560e, /* rshi r18, r22, r2 >> 14 */ + 0x68545612, /* rshi r21, r22, r2 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684c5629, /* rshi r19, r22, r2 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404c6200, /* and r19, r2, r3 */ + 0x48544000, /* not r21, r2 */ + 0x40549500, /* and r21, r21, r4 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */ + 0x5050b400, /* add r20, r20, r5 */ + 0x50515490, /* add r20, r20, r10 >> 128 */ + 0x68558b80, /* rshi r21, r11, r12 >> 128 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x50068100, /* add r1, r1, r20 */ + 0x50163400, /* add r5, r20, r17 */ + 0x6858ac40, /* rshi r22, r12, r5 >> 64 */ + 0x683cb61c, /* rshi r15, r22, r5 >> 28 */ + 0x6854b622, /* rshi r21, r22, r5 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x6854b627, /* rshi r21, r22, r5 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x4040c500, /* and r16, r5, r6 */ + 0x4054e500, /* and r21, r5, r7 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x4054e600, /* and r21, r6, r7 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x68458fc0, /* rshi r17, r15, r12 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x68582d40, /* rshi r22, r13, r1 >> 64 */ + 0x6848360e, /* rshi r18, r22, r1 >> 14 */ + 0x68543612, /* rshi r21, r22, r1 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684c3629, /* rshi r19, r22, r1 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404c4100, /* and r19, r1, r2 */ + 0x48542000, /* not r21, r1 */ + 0x40547500, /* and r21, r21, r3 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */ + 0x50509400, /* add r20, r20, r4 */ + 0x50515498, /* add r20, r20, r10 >> 192 */ + 0x68558bc0, /* rshi r21, r11, r12 >> 192 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x50028000, /* add r0, r0, r20 */ + 0x50123400, /* add r4, r20, r17 */ + 0x0c000000, /* ret */ +/* } */ +/* @0xd2: function Sha512_b[125] { */ +#define CF_Sha512_b_adr 210 + 0x68588d40, /* rshi r22, r13, r4 >> 64 */ + 0x683c961c, /* rshi r15, r22, r4 >> 28 */ + 0x68549622, /* rshi r21, r22, r4 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x68549627, /* rshi r21, r22, r4 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x4040a400, /* and r16, r4, r5 */ + 0x4054c400, /* and r21, r4, r6 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x4054c500, /* and r21, r5, r6 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x6845afc0, /* rshi r17, r15, r13 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x68580c40, /* rshi r22, r12, r0 >> 64 */ + 0x6848160e, /* rshi r18, r22, r0 >> 14 */ + 0x68541612, /* rshi r21, r22, r0 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684c1629, /* rshi r19, r22, r0 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404c2000, /* and r19, r0, r1 */ + 0x48540000, /* not r21, r0 */ + 0x40545500, /* and r21, r21, r2 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x685192c0, /* rshi r20, r18, r12 >> 192 */ + 0x50507400, /* add r20, r20, r3 */ + 0x50515480, /* add r20, r20, r10 >> 0 */ + 0x6855ab00, /* rshi r21, r11, r13 >> 0 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x501e8700, /* add r7, r7, r20 */ + 0x500e3400, /* add r3, r20, r17 */ + 0x68586d40, /* rshi r22, r13, r3 >> 64 */ + 0x683c761c, /* rshi r15, r22, r3 >> 28 */ + 0x68547622, /* rshi r21, r22, r3 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x68547627, /* rshi r21, r22, r3 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x40408300, /* and r16, r3, r4 */ + 0x4054a300, /* and r21, r3, r5 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x4054a400, /* and r21, r4, r5 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x6845afc0, /* rshi r17, r15, r13 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x6858ec40, /* rshi r22, r12, r7 >> 64 */ + 0x6848f60e, /* rshi r18, r22, r7 >> 14 */ + 0x6854f612, /* rshi r21, r22, r7 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684cf629, /* rshi r19, r22, r7 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404c0700, /* and r19, r7, r0 */ + 0x4854e000, /* not r21, r7 */ + 0x40543500, /* and r21, r21, r1 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x685192c0, /* rshi r20, r18, r12 >> 192 */ + 0x50505400, /* add r20, r20, r2 */ + 0x50515488, /* add r20, r20, r10 >> 64 */ + 0x6855ab40, /* rshi r21, r11, r13 >> 64 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x501a8600, /* add r6, r6, r20 */ + 0x500a3400, /* add r2, r20, r17 */ + 0x68584d40, /* rshi r22, r13, r2 >> 64 */ + 0x683c561c, /* rshi r15, r22, r2 >> 28 */ + 0x68545622, /* rshi r21, r22, r2 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x68545627, /* rshi r21, r22, r2 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x40406200, /* and r16, r2, r3 */ + 0x40548200, /* and r21, r2, r4 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x40548300, /* and r21, r3, r4 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x6845afc0, /* rshi r17, r15, r13 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x6858cc40, /* rshi r22, r12, r6 >> 64 */ + 0x6848d60e, /* rshi r18, r22, r6 >> 14 */ + 0x6854d612, /* rshi r21, r22, r6 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684cd629, /* rshi r19, r22, r6 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404ce600, /* and r19, r6, r7 */ + 0x4854c000, /* not r21, r6 */ + 0x40541500, /* and r21, r21, r0 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x685192c0, /* rshi r20, r18, r12 >> 192 */ + 0x50503400, /* add r20, r20, r1 */ + 0x50515490, /* add r20, r20, r10 >> 128 */ + 0x6855ab80, /* rshi r21, r11, r13 >> 128 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x50168500, /* add r5, r5, r20 */ + 0x50063400, /* add r1, r20, r17 */ + 0x68582d40, /* rshi r22, r13, r1 >> 64 */ + 0x683c361c, /* rshi r15, r22, r1 >> 28 */ + 0x68543622, /* rshi r21, r22, r1 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x68543627, /* rshi r21, r22, r1 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x40404100, /* and r16, r1, r2 */ + 0x40546100, /* and r21, r1, r3 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x40546200, /* and r21, r2, r3 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x6845afc0, /* rshi r17, r15, r13 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x6858ac40, /* rshi r22, r12, r5 >> 64 */ + 0x6848b60e, /* rshi r18, r22, r5 >> 14 */ + 0x6854b612, /* rshi r21, r22, r5 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684cb629, /* rshi r19, r22, r5 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404cc500, /* and r19, r5, r6 */ + 0x4854a000, /* not r21, r5 */ + 0x4054f500, /* and r21, r21, r7 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x685192c0, /* rshi r20, r18, r12 >> 192 */ + 0x50501400, /* add r20, r20, r0 */ + 0x50515498, /* add r20, r20, r10 >> 192 */ + 0x6855abc0, /* rshi r21, r11, r13 >> 192 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x50128400, /* add r4, r4, r20 */ + 0x50023400, /* add r0, r20, r17 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x14f: function compress[70] { */ +#define CF_compress_adr 335 + 0xfc000000, /* nop */ + 0x4c7fff00, /* xor r31, r31, r31 */ + 0x4c000000, /* xor r0, r0, r0 */ + 0x4c042100, /* xor r1, r1, r1 */ + 0x55000001, /* subi r0, r0, #1 */ + 0x55040101, /* subi r1, r1, #1 */ + 0x84204100, /* ldi r8, [#8] */ + 0x94800800, /* ldlc r8 */ + 0x4c3def00, /* xor r15, r15, r15 */ + 0x803c000a, /* movi r15.0l, #10 */ + 0x95800f00, /* lddmp r15 */ + 0x06000039, /* loop *0 ( */ + 0x953c0000, /* stdmp r15 */ + 0x81bc002a, /* movi r15.3l, #42 */ + 0x95800f00, /* lddmp r15 */ + 0x08000001, /* call &expandw */ + 0x84004000, /* ldi r0, [#0] */ + 0x84044020, /* ldi r1, [#1] */ + 0x84084040, /* ldi r2, [#2] */ + 0x840c4060, /* ldi r3, [#3] */ + 0x84104080, /* ldi r4, [#4] */ + 0x841440a0, /* ldi r5, [#5] */ + 0x841840c0, /* ldi r6, [#6] */ + 0x841c40e0, /* ldi r7, [#7] */ + 0x4c3def00, /* xor r15, r15, r15 */ + 0x803c0060, /* movi r15.0l, #96 */ + 0x80bc000a, /* movi r15.1l, #10 */ + 0x813c000b, /* movi r15.2l, #11 */ + 0x96800f00, /* lddrp r15 */ + 0x97800f00, /* ldrfp r15 */ + 0x953c0000, /* stdmp r15 */ + 0x81bc002a, /* movi r15.3l, #42 */ + 0x95800f00, /* lddmp r15 */ + 0x4c318c00, /* xor r12, r12, r12 */ + 0x4c35ad00, /* xor r13, r13, r13 */ + 0x55300c01, /* subi r12, r12, #1 */ + 0x55340d01, /* subi r13, r13, #1 */ + 0x0500a007, /* loop #10 ( */ + 0x8c440800, /* ldc *1, *0++ */ + 0x8c081b00, /* ld *2, *3++ */ + 0x08000055, /* call &Sha512_a */ + 0x8c440800, /* ldc *1, *0++ */ + 0x8c081b00, /* ld *2, *3++ */ + 0x080000d2, /* call &Sha512_b */ + 0xfc000000, /* nop */ + /* ) */ + 0x843c4000, /* ldi r15, [#0] */ + 0x5001e000, /* add r0, r0, r15 */ + 0x843c4020, /* ldi r15, [#1] */ + 0x5005e100, /* add r1, r1, r15 */ + 0x843c4040, /* ldi r15, [#2] */ + 0x5009e200, /* add r2, r2, r15 */ + 0x843c4060, /* ldi r15, [#3] */ + 0x500de300, /* add r3, r3, r15 */ + 0x843c4080, /* ldi r15, [#4] */ + 0x5011e400, /* add r4, r4, r15 */ + 0x843c40a0, /* ldi r15, [#5] */ + 0x5015e500, /* add r5, r5, r15 */ + 0x843c40c0, /* ldi r15, [#6] */ + 0x5019e600, /* add r6, r6, r15 */ + 0x843c40e0, /* ldi r15, [#7] */ + 0x501de700, /* add r7, r7, r15 */ + 0x88004000, /* sti r0, [#0] */ + 0x88044020, /* sti r1, [#1] */ + 0x88084040, /* sti r2, [#2] */ + 0x880c4060, /* sti r3, [#3] */ + 0x88104080, /* sti r4, [#4] */ + 0x881440a0, /* sti r5, [#5] */ + 0x881840c0, /* sti r6, [#6] */ + 0x881c40e0, /* sti r7, [#7] */ + /* ) */ + 0x0c000000, /* ret */ + /* } */ +}; +/* clang-format on */ + +struct DMEM_sha512 { + uint64_t H0[4]; + uint64_t H1[4]; + uint64_t H2[4]; + uint64_t H3[4]; + uint64_t H4[4]; + uint64_t H5[4]; + uint64_t H6[4]; + uint64_t H7[4]; + uint32_t nblocks; + uint32_t unused[2 * 8 - 1]; + uint32_t input[4 * 8 * 8]; // dmem[10..41] +}; + +static void copy_words(const void *in, uint32_t *dst, size_t nwords) +{ + const uint32_t *src = (const uint32_t *) in; + + do { + uint32_t w1 = __builtin_bswap32(*src++); + uint32_t w2 = __builtin_bswap32(*src++); + *dst++ = w2; + *dst++ = w1; + } while (nwords -= 2); +} + +static void dcrypto_SHA512_setup(void) +{ + dcrypto_imem_load(0, IMEM_dcrypto, ARRAY_SIZE(IMEM_dcrypto)); +} + +static void dcrypto_SHA512_Transform(LITE_SHA512_CTX *ctx, const uint32_t *buf, + size_t nwords) +{ + int result = 0; + struct DMEM_sha512 *p512 = + (struct DMEM_sha512 *) GREG32_ADDR(CRYPTO, DMEM_DUMMY); + + START_PROFILE(t_transform) + + /* Pass in H[] */ + p512->H0[0] = ctx->state[0]; + p512->H1[0] = ctx->state[1]; + p512->H2[0] = ctx->state[2]; + p512->H3[0] = ctx->state[3]; + p512->H4[0] = ctx->state[4]; + p512->H5[0] = ctx->state[5]; + p512->H6[0] = ctx->state[6]; + p512->H7[0] = ctx->state[7]; + + p512->nblocks = nwords / 32; + + /* Pass in buf[] */ + copy_words(buf, p512->input, nwords); + + START_PROFILE(t_dcrypto) + result |= dcrypto_call(CF_compress_adr); + END_PROFILE(t_dcrypto) + + /* Retrieve new H[] */ + ctx->state[0] = p512->H0[0]; + ctx->state[1] = p512->H1[0]; + ctx->state[2] = p512->H2[0]; + ctx->state[3] = p512->H3[0]; + ctx->state[4] = p512->H4[0]; + ctx->state[5] = p512->H5[0]; + ctx->state[6] = p512->H6[0]; + ctx->state[7] = p512->H7[0]; + + /* TODO: errno or such to capture errors */ + (void) (result == 0); + + END_PROFILE(t_transform) +} + +static void dcrypto_SHA512_update(LITE_SHA512_CTX *ctx, const void *data, + size_t len) +{ + int i = (int) (ctx->count & (sizeof(ctx->buf) - 1)); + const uint8_t *p = (const uint8_t *) data; + uint8_t *d = &ctx->buf[i]; + + ctx->count += len; + + dcrypto_init_and_lock(); + dcrypto_SHA512_setup(); + + /* Take fast path for 32-bit aligned 1KB inputs */ + if (i == 0 && len == 1024 && (((intptr_t) data) & 3) == 0) { + dcrypto_SHA512_Transform(ctx, (const uint32_t *) data, 8 * 32); + } else { + if (len <= sizeof(ctx->buf) - i) { + memcpy(d, p, len); + if (len == sizeof(ctx->buf) - i) { + dcrypto_SHA512_Transform( + ctx, (uint32_t *) (ctx->buf), 32); + } + } else { + memcpy(d, p, sizeof(ctx->buf) - i); + dcrypto_SHA512_Transform(ctx, (uint32_t *) (ctx->buf), + 32); + d = ctx->buf; + len -= (sizeof(ctx->buf) - i); + p += (sizeof(ctx->buf) - i); + while (len >= sizeof(ctx->buf)) { + memcpy(d, p, sizeof(ctx->buf)); + p += sizeof(ctx->buf); + len -= sizeof(ctx->buf); + dcrypto_SHA512_Transform( + ctx, (uint32_t *) (ctx->buf), 32); + } + /* Leave remainder in ctx->buf */ + memcpy(d, p, len); + } + } + dcrypto_unlock(); +} + +static const uint8_t *dcrypto_SHA512_final(LITE_SHA512_CTX *ctx) +{ + uint64_t cnt = ctx->count * 8; + int i = (int) (ctx->count & (sizeof(ctx->buf) - 1)); + uint8_t *p = &ctx->buf[i]; + + *p++ = 0x80; + i++; + + dcrypto_init_and_lock(); + dcrypto_SHA512_setup(); + + if (i > sizeof(ctx->buf) - 16) { + memset(p, 0, sizeof(ctx->buf) - i); + dcrypto_SHA512_Transform(ctx, (uint32_t *) (ctx->buf), 32); + i = 0; + p = ctx->buf; + } + + memset(p, 0, sizeof(ctx->buf) - 8 - i); + p += sizeof(ctx->buf) - 8 - i; + + for (i = 0; i < 8; ++i) { + uint8_t tmp = (uint8_t)(cnt >> 56); + cnt <<= 8; + *p++ = tmp; + } + + dcrypto_SHA512_Transform(ctx, (uint32_t *) (ctx->buf), 32); + + p = ctx->buf; + for (i = 0; i < 8; i++) { + uint64_t tmp = ctx->state[i]; + *p++ = (uint8_t)(tmp >> 56); + *p++ = (uint8_t)(tmp >> 48); + *p++ = (uint8_t)(tmp >> 40); + *p++ = (uint8_t)(tmp >> 32); + *p++ = (uint8_t)(tmp >> 24); + *p++ = (uint8_t)(tmp >> 16); + *p++ = (uint8_t)(tmp >> 8); + *p++ = (uint8_t)(tmp >> 0); + } + + dcrypto_unlock(); + return ctx->buf; +} + +const uint8_t *DCRYPTO_SHA512_hash(const void *data, size_t len, + uint8_t *digest) +{ + LITE_SHA512_CTX ctx; + + DCRYPTO_SHA512_init(&ctx); + dcrypto_SHA512_update(&ctx, data, len); + memcpy(digest, dcrypto_SHA512_final(&ctx), SHA512_DIGEST_SIZE); + + return digest; +} + +static const HASH_VTAB dcrypto_SHA512_VTAB = { + DCRYPTO_SHA512_init, dcrypto_SHA512_update, dcrypto_SHA512_final, + DCRYPTO_SHA512_hash, SHA512_DIGEST_SIZE}; + +void DCRYPTO_SHA512_init(LITE_SHA512_CTX *ctx) +{ + SHA512_init(ctx); + ctx->f = &dcrypto_SHA512_VTAB; +} + +#ifdef CRYPTO_TEST_SETUP + +static uint32_t msg[256]; // 1KB +static int msg_len; +static int msg_loops; +static LITE_SHA512_CTX sw; +static LITE_SHA512_CTX hw; +static const uint8_t *sw_digest; +static const uint8_t *hw_digest; +static uint32_t t_sw; +static uint32_t t_hw; + +static void run_sha512_cmd(void) +{ + int i; + + t_transform = 0; + t_dcrypto = 0; + t_sw = 0; + t_hw = 0; + + START_PROFILE(t_sw) + SHA512_init(&sw); + for (i = 0; i < msg_loops; ++i) { + HASH_update(&sw, msg, msg_len); + } + sw_digest = HASH_final(&sw); + END_PROFILE(t_sw) + + START_PROFILE(t_hw) + DCRYPTO_SHA512_init(&hw); + for (i = 0; i < msg_loops; ++i) { + HASH_update(&hw, msg, msg_len); + } + hw_digest = HASH_final(&hw); + END_PROFILE(t_hw) + + ccprintf("sw(%u):\n", t_sw); + for (i = 0; i < 64; ++i) + ccprintf("%02x", sw_digest[i]); + ccprintf("\n"); + + ccprintf("hw(%u/%u/%u):\n", t_hw, t_transform, t_dcrypto); + for (i = 0; i < 64; ++i) + ccprintf("%02x", hw_digest[i]); + ccprintf("\n"); + + task_set_event(TASK_ID_CONSOLE, TASK_EVENT_CUSTOM_BIT(0), 0); +} +DECLARE_DEFERRED(run_sha512_cmd); + +static int cmd_sha512_bench(int argc, char *argv[]) +{ + const int max_time = 1000000; + uint32_t events; + + memset(msg, '!', sizeof(msg)); + + if (argc > 1) { + msg_loops = 1; + msg_len = strlen(argv[1]); + memcpy(msg, argv[1], msg_len); + } else { + msg_loops = 64; // benchmark 64K + msg_len = sizeof(msg); + } + + hook_call_deferred(&run_sha512_cmd_data, 0); + ccprintf("Will wait up to %d ms\n", (max_time + 500) / 1000); + + events = task_wait_event_mask(TASK_EVENT_CUSTOM_BIT(0), max_time); + if (!(events & TASK_EVENT_CUSTOM_BIT(0))) { + ccprintf("Timed out, you might want to reboot...\n"); + return EC_ERROR_TIMEOUT; + } + + return EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(sha512_bench, cmd_sha512_bench, NULL, NULL); + +static void run_sha512_test(void) +{ + int i; + + for (i = 0; i < 129; ++i) { + memset(msg, i, i); + + SHA512_init(&sw); + HASH_update(&sw, msg, i); + sw_digest = HASH_final(&sw); + + DCRYPTO_SHA512_init(&hw); + HASH_update(&hw, msg, i); + hw_digest = HASH_final(&hw); + + if (memcmp(sw_digest, hw_digest, SHA512_DIGEST_SIZE) != 0) { + ccprintf("sha512 self-test fail at %d!\n", i); + cflush(); + } + } + + ccprintf("sha512 self-test PASS!\n"); + task_set_event(TASK_ID_CONSOLE, TASK_EVENT_CUSTOM_BIT(0), 0); +} +DECLARE_DEFERRED(run_sha512_test); + +static int cmd_sha512_test(int argc, char *argv[]) +{ + hook_call_deferred(&run_sha512_test_data, 0); + task_wait_event_mask(TASK_EVENT_CUSTOM_BIT(0), 1000000); + return EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(sha512_test, cmd_sha512_test, NULL, NULL); + +#endif /* CRYPTO_TEST_SETUP */ diff --git a/board/cr50/dcrypto/gcm.c b/board/cr50/dcrypto/gcm.c new file mode 100644 index 0000000000..cd035bbd54 --- /dev/null +++ b/board/cr50/dcrypto/gcm.c @@ -0,0 +1,345 @@ +/* Copyright 2017 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 "endian.h" + +#include "cryptoc/util.h" + +static void gcm_mul(uint32_t *counter) +{ + int i; + volatile uint32_t *p; + + /* Set HASH to zero. */ + p = GREG32_ADDR(KEYMGR, GCM_HASH_IN0); + for (i = 0; i < 4; i++) + *p++ = 0; + + /* Initialize GMAC. */ + p = GREG32_ADDR(KEYMGR, GCM_MAC0); + for (i = 0; i < 4; i++) + *p++ = counter[i]; + + /* Crank GMAC. */ + GREG32(KEYMGR, GCM_DO_ACC) = 1; + + /* Read GMAC. */ + p = GREG32_ADDR(KEYMGR, GCM_MAC0); + for (i = 0; i < 4; i++) + counter[i] = *p++; + + /* Reset GMAC. */ + p = GREG32_ADDR(KEYMGR, GCM_MAC0); + for (i = 0; i < 4; ++i) + *p++ = 0; +} + +static void gcm_init_iv( + const uint8_t *iv, uint32_t iv_len, uint32_t *counter) +{ + + if (iv_len == 12) { + memcpy(counter, iv, 12); + counter[3] = BIT(24); + } else { + size_t i; + uint32_t len = iv_len; + uint64_t len0 = len; + uint8_t *ctr = (uint8_t *) counter; + + memset(ctr, 0, 16); + while (len >= 16) { + for (i = 0; i < 16; ++i) + ctr[i] ^= iv[i]; + + gcm_mul(counter); + iv += 16; + len -= 16; + } + if (len) { + for (i = 0; i < len; ++i) + ctr[i] ^= iv[i]; + + gcm_mul(counter); + } + len0 <<= 3; + ctr[8] ^= (uint8_t)(len0 >> 56); + ctr[9] ^= (uint8_t)(len0 >> 48); + ctr[10] ^= (uint8_t)(len0 >> 40); + ctr[11] ^= (uint8_t)(len0 >> 32); + ctr[12] ^= (uint8_t)(len0 >> 24); + ctr[13] ^= (uint8_t)(len0 >> 16); + ctr[14] ^= (uint8_t)(len0 >> 8); + ctr[15] ^= (uint8_t)(len0); + + gcm_mul(counter); + } +} + +void DCRYPTO_gcm_init(struct GCM_CTX *ctx, uint32_t key_bits, + const uint8_t *key, const uint8_t *iv, size_t iv_len) +{ + int i; + const uint32_t zero[4] = {0, 0, 0, 0}; + uint32_t H[4]; + uint32_t counter[4]; + + memset(ctx, 0, sizeof(struct GCM_CTX)); + + /* Initialize AES engine in CTR mode, and set the counter to 0. */ + DCRYPTO_aes_init(key, key_bits, (const uint8_t *) zero, + CIPHER_MODE_CTR, ENCRYPT_MODE); + /* Set H to AES(ZERO). */ + DCRYPTO_aes_block((const uint8_t *) zero, (uint8_t *) H); + + /* Initialize the GMAC accumulator to ZERO. */ + for (i = 0; i < 4; i++) + GR_KEYMGR_GCM_MAC(i) = zero[i]; + + /* Initialize H. */ + for (i = 0; i < 4; i++) + GR_KEYMGR_GCM_H(i) = H[i]; + + /* Map the IV to a 128-bit counter. */ + gcm_init_iv(iv, iv_len, counter); + + /* Re-initialize the IV counter. */ + for (i = 0; i < 4; i++) + GR_KEYMGR_AES_CTR(i) = counter[i]; + + /* Calculate Ej0: encrypt IV counter XOR ZERO. */ + DCRYPTO_aes_block((const uint8_t *) zero, ctx->Ej0.c); +} + +static void gcm_aad_block(const struct GCM_CTX *ctx, const uint32_t *block) +{ + int i; + const struct access_helper *p = (struct access_helper *) block; + + if (ctx->aad_len == 0 && ctx->count <= 16) { + /* Update GMAC. */ + for (i = 0; i < 4; i++) + GR_KEYMGR_GCM_MAC(i) = p[i].udata; + } else { + for (i = 0; i < 4; i++) + GR_KEYMGR_GCM_HASH_IN(i) = p[i].udata; + + /* Crank GMAC. */ + GREG32(KEYMGR, GCM_DO_ACC) = 1; + } +} + +void DCRYPTO_gcm_aad(struct GCM_CTX *ctx, const uint8_t *aad_data, size_t len) +{ + uint32_t block[4]; + + while (len) { + size_t count; + + memset(block, 0, sizeof(block)); + count = MIN(16, len); + memcpy(block, aad_data, count); + + gcm_aad_block(ctx, block); + ctx->aad_len += count; + + len -= count; + aad_data += count; + } + + always_memset(block, 0, sizeof(block)); +} + +int DCRYPTO_gcm_encrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len, + const uint8_t *in, size_t in_len) +{ + uint8_t *outp = out; + + if (out_len < (in_len & ~0x0F) + ((in_len & 0x0F) ? 16 : 0)) + return -1; + + /* Process a previous partial block, if any. */ + if (ctx->remainder) { + size_t count = MIN(in_len, 16 - ctx->remainder); + + memcpy(ctx->block.c + ctx->remainder, in, count); + ctx->remainder += count; + if (ctx->remainder < 16) + return 0; + + DCRYPTO_aes_block(ctx->block.c, outp); + ctx->count += 16; + gcm_aad_block(ctx, (uint32_t *) outp); + ctx->remainder = 0; + in += count; + in_len -= count; + outp += 16; + } + + while (in_len >= 16) { + DCRYPTO_aes_block(in, outp); + ctx->count += 16; + + gcm_aad_block(ctx, (uint32_t *) outp); + + in_len -= 16; + in += 16; + outp += 16; + } + + if (in_len) { + memcpy(ctx->block.c, in, in_len); + ctx->remainder = in_len; + } + + return outp - out; +} + +int DCRYPTO_gcm_encrypt_final(struct GCM_CTX *ctx, uint8_t *out, size_t out_len) +{ + if (out_len < ctx->remainder) + return -1; + + if (ctx->remainder) { + size_t remainder = ctx->remainder; + uint8_t out_block[16]; + + DCRYPTO_aes_block(ctx->block.c, out_block); + ctx->count += ctx->remainder; + memcpy(out, out_block, ctx->remainder); + + memset(out_block + ctx->remainder, 0, 16 - ctx->remainder); + gcm_aad_block(ctx, (uint32_t *) out_block); + ctx->remainder = 0; + return remainder; + } + + return 0; +} + +int DCRYPTO_gcm_decrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len, + const uint8_t *in, size_t in_len) +{ + uint8_t *outp = out; + + if (out_len < (in_len & ~0x0F) + ((in_len & 0x0F) ? 16 : 0)) + return -1; + + if (ctx->remainder) { + size_t count = MIN(in_len, 16 - ctx->remainder); + + memcpy(ctx->block.c + ctx->remainder, in, count); + ctx->remainder += count; + + if (ctx->remainder < 16) + return 0; + + DCRYPTO_aes_block(ctx->block.c, outp); + ctx->remainder = 0; + ctx->count += 16; + gcm_aad_block(ctx, ctx->block.d); + in += count; + in_len -= count; + outp += count; + } + + while (in_len >= 16) { + DCRYPTO_aes_block(in, outp); + ctx->count += 16; + gcm_aad_block(ctx, (uint32_t *) in); + in += 16; + in_len -= 16; + outp += 16; + } + + if (in_len) { + memcpy(ctx->block.c, in, in_len); + ctx->remainder = in_len; + } + + return outp - out; +} + +int DCRYPTO_gcm_decrypt_final(struct GCM_CTX *ctx, + uint8_t *out, size_t out_len) +{ + if (out_len < ctx->remainder) + return -1; + + if (ctx->remainder) { + size_t remainder = ctx->remainder; + uint8_t out_block[16]; + + DCRYPTO_aes_block(ctx->block.c, out_block); + ctx->count += ctx->remainder; + memcpy(out, out_block, ctx->remainder); + + memset(ctx->block.c + ctx->remainder, 0, 16 - ctx->remainder); + gcm_aad_block(ctx, ctx->block.d); + ctx->remainder = 0; + return remainder; + } + + return 0; +} + +static void dcrypto_gcm_len_vector( + const struct GCM_CTX *ctx, void *len_vector) { + uint64_t aad_be; + uint64_t count_be; + + /* Serialize counters to bit-count (big-endian). */ + aad_be = ctx->aad_len * 8; + aad_be = htobe64(aad_be); + count_be = ctx->count * 8; + count_be = htobe64(count_be); + + memcpy(len_vector, &aad_be, 8); + memcpy(((uint8_t *)len_vector) + 8, &count_be, 8); +} + +static void dcrypto_gcm_tag(const struct GCM_CTX *ctx, + const uint32_t *len_vector, uint32_t *tag) { + int i; + + for (i = 0; i < 4; i++) + GR_KEYMGR_GCM_HASH_IN(i) = len_vector[i]; + + /* Crank GMAC. */ + GREG32(KEYMGR, GCM_DO_ACC) = 1; + + for (i = 0; i < 4; i++) + GR_KEYMGR_GCM_HASH_IN(i) = ctx->Ej0.d[i]; + + /* Crank GMAC. */ + GREG32(KEYMGR, GCM_DO_ACC) = 1; + + /* Read tag. */ + for (i = 0; i < 4; i++) + tag[i] = GR_KEYMGR_GCM_MAC(i); +} + +int DCRYPTO_gcm_tag(struct GCM_CTX *ctx, uint8_t *tag, size_t tag_len) +{ + uint32_t len_vector[4]; + uint32_t local_tag[4]; + size_t count = MIN(tag_len, sizeof(local_tag)); + + dcrypto_gcm_len_vector(ctx, len_vector); + dcrypto_gcm_tag(ctx, len_vector, local_tag); + + memcpy(tag, local_tag, count); + return count; +} + +void DCRYPTO_gcm_finish(struct GCM_CTX *ctx) +{ + always_memset(ctx, 0, sizeof(struct GCM_CTX)); + GREG32(KEYMGR, AES_WIPE_SECRETS) = 1; +} diff --git a/board/cr50/dcrypto/hkdf.c b/board/cr50/dcrypto/hkdf.c new file mode 100644 index 0000000000..3afdc6b2eb --- /dev/null +++ b/board/cr50/dcrypto/hkdf.c @@ -0,0 +1,83 @@ +/* Copyright 2016 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. + */ +/* An implementation of HKDF as per RFC 5869. */ + +#include "dcrypto.h" +#include "internal.h" + +#include "cryptoc/sha256.h" +#include "cryptoc/util.h" + +static int hkdf_extract(uint8_t *PRK, const uint8_t *salt, size_t salt_len, + const uint8_t *IKM, size_t IKM_len) +{ + LITE_HMAC_CTX ctx; + + if (PRK == NULL) + return 0; + if (salt == NULL && salt_len > 0) + return 0; + if (IKM == NULL && IKM_len > 0) + return 0; + + DCRYPTO_HMAC_SHA256_init(&ctx, salt, salt_len); + HASH_update(&ctx.hash, IKM, IKM_len); + memcpy(PRK, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE); + return 1; +} + +static int hkdf_expand(uint8_t *OKM, size_t OKM_len, const uint8_t *PRK, + const uint8_t *info, size_t info_len) +{ + uint8_t count = 1; + const uint8_t *T = OKM; + size_t T_len = 0; + uint32_t num_blocks = (OKM_len / SHA256_DIGEST_SIZE) + + (OKM_len % SHA256_DIGEST_SIZE ? 1 : 0); + + if (OKM == NULL || OKM_len == 0) + return 0; + if (PRK == NULL) + return 0; + if (info == NULL && info_len > 0) + return 0; + if (num_blocks > 255) + return 0; + + while (OKM_len > 0) { + LITE_HMAC_CTX ctx; + const size_t block_size = OKM_len < SHA256_DIGEST_SIZE ? + OKM_len : SHA256_DIGEST_SIZE; + + DCRYPTO_HMAC_SHA256_init(&ctx, PRK, SHA256_DIGEST_SIZE); + HASH_update(&ctx.hash, T, T_len); + HASH_update(&ctx.hash, info, info_len); + HASH_update(&ctx.hash, &count, sizeof(count)); + memcpy(OKM, DCRYPTO_HMAC_final(&ctx), block_size); + + T += T_len; + T_len = SHA256_DIGEST_SIZE; + count += 1; + OKM += block_size; + OKM_len -= block_size; + } + return 1; +} + +int DCRYPTO_hkdf(uint8_t *OKM, size_t OKM_len, + const uint8_t *salt, size_t salt_len, + const uint8_t *IKM, size_t IKM_len, + const uint8_t *info, size_t info_len) +{ + int result; + uint8_t PRK[SHA256_DIGEST_SIZE]; + + if (!hkdf_extract(PRK, salt, salt_len, IKM, IKM_len)) + return 0; + + result = hkdf_expand(OKM, OKM_len, PRK, info, info_len); + always_memset(PRK, 0, sizeof(PRK)); + return result; +} diff --git a/board/cr50/dcrypto/hmac.c b/board/cr50/dcrypto/hmac.c new file mode 100644 index 0000000000..7cc45a03ba --- /dev/null +++ b/board/cr50/dcrypto/hmac.c @@ -0,0 +1,63 @@ +/* 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 "internal.h" +#include "dcrypto.h" + +#include + +#include "cryptoc/sha256.h" +#include "cryptoc/util.h" + +/* TODO(sukhomlinov): add support for hardware hmac. */ +static void hmac_sha256_init(LITE_HMAC_CTX *ctx, const void *key, + unsigned int len) +{ + unsigned int i; + + BUILD_ASSERT(sizeof(ctx->opad) >= SHA256_BLOCK_SIZE); + + memset(&ctx->opad[0], 0, SHA256_BLOCK_SIZE); + + if (len > SHA256_BLOCK_SIZE) { + DCRYPTO_SHA256_init(&ctx->hash, 0); + HASH_update(&ctx->hash, key, len); + memcpy(&ctx->opad[0], HASH_final(&ctx->hash), + HASH_size(&ctx->hash)); + } else { + memcpy(&ctx->opad[0], key, len); + } + + for (i = 0; i < SHA256_BLOCK_SIZE; ++i) + ctx->opad[i] ^= 0x36; + + DCRYPTO_SHA256_init(&ctx->hash, 0); + /* hash ipad */ + HASH_update(&ctx->hash, ctx->opad, SHA256_BLOCK_SIZE); + + for (i = 0; i < SHA256_BLOCK_SIZE; ++i) + ctx->opad[i] ^= (0x36 ^ 0x5c); +} + +void DCRYPTO_HMAC_SHA256_init(LITE_HMAC_CTX *ctx, const void *key, + unsigned int len) +{ + hmac_sha256_init(ctx, key, len); +} + +const uint8_t *DCRYPTO_HMAC_final(LITE_HMAC_CTX *ctx) +{ + uint8_t digest[SHA256_DIGEST_SIZE]; /* up to SHA256 */ + + memcpy(digest, HASH_final(&ctx->hash), + (HASH_size(&ctx->hash) <= sizeof(digest) ? + HASH_size(&ctx->hash) : + sizeof(digest))); + DCRYPTO_SHA256_init(&ctx->hash, 0); + HASH_update(&ctx->hash, ctx->opad, SHA256_BLOCK_SIZE); + HASH_update(&ctx->hash, digest, HASH_size(&ctx->hash)); + always_memset(&ctx->opad[0], 0, SHA256_BLOCK_SIZE); /* wipe key */ + return HASH_final(&ctx->hash); +} diff --git a/board/cr50/dcrypto/hmac_drbg.c b/board/cr50/dcrypto/hmac_drbg.c new file mode 100644 index 0000000000..2ca20e03ff --- /dev/null +++ b/board/cr50/dcrypto/hmac_drbg.c @@ -0,0 +1,478 @@ +/* Copyright 2018 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 "console.h" +#include "cryptoc/util.h" +#include "dcrypto.h" +#include "extension.h" +#include "internal.h" +#include "trng.h" + +/* HMAC_DRBG flow in NIST SP 800-90Ar1, 10.2, RFC 6979 + */ +/* V = HMAC(K, V) */ +static void update_v(const uint32_t *k, uint32_t *v) +{ + LITE_HMAC_CTX ctx; + + DCRYPTO_HMAC_SHA256_init(&ctx, k, SHA256_DIGEST_SIZE); + HASH_update(&ctx.hash, v, SHA256_DIGEST_SIZE); + memcpy(v, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE); +} + +/* K = HMAC(K, V || tag || p0 || p1 || p2) */ +/* V = HMAC(K, V) */ +static void update_kv(uint32_t *k, uint32_t *v, uint8_t tag, + const void *p0, size_t p0_len, + const void *p1, size_t p1_len, + const void *p2, size_t p2_len) +{ + LITE_HMAC_CTX ctx; + + DCRYPTO_HMAC_SHA256_init(&ctx, k, SHA256_DIGEST_SIZE); + HASH_update(&ctx.hash, v, SHA256_DIGEST_SIZE); + HASH_update(&ctx.hash, &tag, 1); + HASH_update(&ctx.hash, p0, p0_len); + HASH_update(&ctx.hash, p1, p1_len); + HASH_update(&ctx.hash, p2, p2_len); + memcpy(k, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE); + + update_v(k, v); +} + +static void update(struct drbg_ctx *ctx, + const void *p0, size_t p0_len, + const void *p1, size_t p1_len, + const void *p2, size_t p2_len) +{ + /* K = HMAC(K, V || 0x00 || provided_data) */ + /* V = HMAC(K, V) */ + update_kv(ctx->k, ctx->v, 0x00, + p0, p0_len, p1, p1_len, p2, p2_len); + + /* If no provided_data, stop. */ + if (p0_len + p1_len + p2_len == 0) + return; + + /* K = HMAC(K, V || 0x01 || provided_data) */ + /* V = HMAC(K, V) */ + update_kv(ctx->k, ctx->v, + 0x01, + p0, p0_len, p1, p1_len, p2, p2_len); +} + +void hmac_drbg_init(struct drbg_ctx *ctx, + const void *p0, size_t p0_len, + const void *p1, size_t p1_len, + const void *p2, size_t p2_len) +{ + /* K = 0x00 0x00 0x00 ... 0x00 */ + always_memset(ctx->k, 0x00, sizeof(ctx->k)); + /* V = 0x01 0x01 0x01 ... 0x01 */ + always_memset(ctx->v, 0x01, sizeof(ctx->v)); + + update(ctx, p0, p0_len, p1, p1_len, p2, p2_len); + + ctx->reseed_counter = 1; +} + +void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx, const p256_int *key, + const p256_int *message) +{ + hmac_drbg_init(ctx, + key->a, sizeof(key->a), + message->a, sizeof(message->a), + NULL, 0); +} + +void hmac_drbg_init_rand(struct drbg_ctx *ctx, size_t nbits) +{ + int i; + uint32_t x[(nbits + 31) / 32]; + + for (i = 0; i < ARRAY_SIZE(x); ++i) + x[i] = rand(); + + hmac_drbg_init(ctx, &x, sizeof(x), NULL, 0, NULL, 0); +} + +void hmac_drbg_reseed(struct drbg_ctx *ctx, + const void *p0, size_t p0_len, + const void *p1, size_t p1_len, + const void *p2, size_t p2_len) +{ + update(ctx, p0, p0_len, p1, p1_len, p2, p2_len); + ctx->reseed_counter = 1; +} + +enum hmac_result hmac_drbg_generate(struct drbg_ctx *ctx, + void *out, size_t out_len, + const void *input, size_t input_len) +{ + /* According to NIST SP 800-90A rev 1 B.2 + * Maximum number of bits per request = 7500 bits + * Reseed_interval = 10 000 requests. + */ + if (out_len > 7500 / 8) + return HMAC_DRBG_INVALID_PARAM; + + if (ctx->reseed_counter++ >= 10000) + return HMAC_DRBG_RESEED_REQUIRED; + + if (input_len) + update(ctx, input, input_len, NULL, 0, NULL, 0); + + while (out_len) { + size_t n = out_len > sizeof(ctx->v) ? sizeof(ctx->v) : out_len; + + update_v(ctx->k, ctx->v); + + memcpy(out, ctx->v, n); + out += n; + out_len -= n; + } + + update(ctx, input, input_len, NULL, 0, NULL, 0); + + return HMAC_DRBG_SUCCESS; +} + +enum hmac_result hmac_drbg_generate_p256(struct drbg_ctx *ctx, p256_int *k_out) +{ + return hmac_drbg_generate(ctx, k_out->a, sizeof(k_out->a), NULL, 0); +} + +void drbg_exit(struct drbg_ctx *ctx) +{ + always_memset(ctx->k, 0x00, sizeof(ctx->k)); + always_memset(ctx->v, 0x00, sizeof(ctx->v)); +} + +#ifdef CRYPTO_TEST_SETUP + +/* + * from the RFC 6979 A.2.5 example: + * + * curve: NIST P-256 + * + * q = FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 + * (qlen = 256 bits) + * + * private key: + * x = C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721 + * + * public key: U = xG + * Ux = 60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6 + * Uy = 7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299 + * + * Signature: + * With SHA-256, message = "sample": + * k = A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60 + * r = EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716 + * s = F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8 + */ +static int cmd_rfc6979(int argc, char **argv) +{ + static p256_int h1; + static p256_int k; + static const char message[] = "sample"; + static struct drbg_ctx drbg; + + static HASH_CTX ctx; + int result; + static const uint8_t priv_from_rfc[] = { + 0xC9, 0xAF, 0xA9, 0xD8, 0x45, 0xBA, 0x75, 0x16, + 0x6B, 0x5C, 0x21, 0x57, 0x67, 0xB1, 0xD6, 0x93, + 0x4E, 0x50, 0xC3, 0xDB, 0x36, 0xE8, 0x9B, 0x12, + 0x7B, 0x8A, 0x62, 0x2B, 0x12, 0x0F, 0x67, 0x21 + }; + static const uint8_t k_from_rfc[] = { + 0xA6, 0xE3, 0xC5, 0x7D, 0xD0, 0x1A, 0xBE, 0x90, + 0x08, 0x65, 0x38, 0x39, 0x83, 0x55, 0xDD, 0x4C, + 0x3B, 0x17, 0xAA, 0x87, 0x33, 0x82, 0xB0, 0xF2, + 0x4D, 0x61, 0x29, 0x49, 0x3D, 0x8A, 0xAD, 0x60 + }; + p256_int *x = (p256_int *)priv_from_rfc; + p256_int *reference_k = (p256_int *)k_from_rfc; + + /* h1 = H(m) */ + DCRYPTO_SHA256_init(&ctx, 1); + HASH_update(&ctx, message, sizeof(message) - 1); + memcpy(&h1, HASH_final(&ctx), SHA256_DIGEST_SIZE); + + hmac_drbg_init_rfc6979(&drbg, x, &h1); + do { + hmac_drbg_generate_p256(&drbg, &k); + ccprintf("K = %ph\n", HEX_BUF(&k, 32)); + } while (p256_cmp(&SECP256r1_nMin2, &k) < 0); + drbg_exit(&drbg); + result = p256_cmp(&k, reference_k); + ccprintf("K generation: %s\n", result ? "FAIL" : "PASS"); + + return result ? EC_ERROR_INVAL : EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(rfc6979, cmd_rfc6979, NULL, NULL); + +/* + * Test vectors from the NIST Cryptographic Algorithm Validation Program. + * + * These are the first two examples from the SHA-256, without prediction + * resistance, and with reseed supported. + */ +#define HMAC_TEST_COUNT 2 +static int cmd_hmac_drbg(int argc, char **argv) +{ + static struct drbg_ctx ctx; + + static const uint8_t init_entropy[HMAC_TEST_COUNT][32] = { + { + 0x06, 0x03, 0x2C, 0xD5, 0xEE, 0xD3, 0x3F, 0x39, 0x26, + 0x5F, 0x49, 0xEC, 0xB1, 0x42, 0xC5, 0x11, 0xDA, 0x9A, + 0xFF, 0x2A, 0xF7, 0x12, 0x03, 0xBF, 0xFA, 0xF3, 0x4A, + 0x9C, 0xA5, 0xBD, 0x9C, 0x0D + }, + { + 0xAA, 0xDC, 0xF3, 0x37, 0x78, 0x8B, 0xB8, 0xAC, 0x01, + 0x97, 0x66, 0x40, 0x72, 0x6B, 0xC5, 0x16, 0x35, 0xD4, + 0x17, 0x77, 0x7F, 0xE6, 0x93, 0x9E, 0xDE, 0xD9, 0xCC, + 0xC8, 0xA3, 0x78, 0xC7, 0x6A + }, + }; + + static const uint8_t init_nonce[HMAC_TEST_COUNT][16] = { + { + 0x0E, 0x66, 0xF7, 0x1E, 0xDC, 0x43, 0xE4, 0x2A, 0x45, + 0xAD, 0x3C, 0x6F, 0xC6, 0xCD, 0xC4, 0xDF + }, + { + 0x9C, 0xCC, 0x9D, 0x80, 0xC8, 0x9A, 0xC5, 0x5A, 0x8C, + 0xFE, 0x0F, 0x99, 0x94, 0x2F, 0x5A, 0x4D + }, + }; + + static const uint8_t reseed_entropy[HMAC_TEST_COUNT][32] = { + { + 0x01, 0x92, 0x0A, 0x4E, 0x66, 0x9E, 0xD3, 0xA8, 0x5A, + 0xE8, 0xA3, 0x3B, 0x35, 0xA7, 0x4A, 0xD7, 0xFB, 0x2A, + 0x6B, 0xB4, 0xCF, 0x39, 0x5C, 0xE0, 0x03, 0x34, 0xA9, + 0xC9, 0xA5, 0xA5, 0xD5, 0x52 + }, + { + 0x03, 0xA5, 0x77, 0x92, 0x54, 0x7E, 0x0C, 0x98, 0xEA, + 0x17, 0x76, 0xE4, 0xBA, 0x80, 0xC0, 0x07, 0x34, 0x62, + 0x96, 0xA5, 0x6A, 0x27, 0x0A, 0x35, 0xFD, 0x9E, 0xA2, + 0x84, 0x5C, 0x7E, 0x81, 0xE2 + } + }; + + static const uint8_t expected_output[HMAC_TEST_COUNT][128] = { + { + 0x76, 0xFC, 0x79, 0xFE, 0x9B, 0x50, 0xBE, 0xCC, 0xC9, + 0x91, 0xA1, 0x1B, 0x56, 0x35, 0x78, 0x3A, 0x83, 0x53, + 0x6A, 0xDD, 0x03, 0xC1, 0x57, 0xFB, 0x30, 0x64, 0x5E, + 0x61, 0x1C, 0x28, 0x98, 0xBB, 0x2B, 0x1B, 0xC2, 0x15, + 0x00, 0x02, 0x09, 0x20, 0x8C, 0xD5, 0x06, 0xCB, 0x28, + 0xDA, 0x2A, 0x51, 0xBD, 0xB0, 0x38, 0x26, 0xAA, 0xF2, + 0xBD, 0x23, 0x35, 0xD5, 0x76, 0xD5, 0x19, 0x16, 0x08, + 0x42, 0xE7, 0x15, 0x8A, 0xD0, 0x94, 0x9D, 0x1A, 0x9E, + 0xC3, 0xE6, 0x6E, 0xA1, 0xB1, 0xA0, 0x64, 0xB0, 0x05, + 0xDE, 0x91, 0x4E, 0xAC, 0x2E, 0x9D, 0x4F, 0x2D, 0x72, + 0xA8, 0x61, 0x6A, 0x80, 0x22, 0x54, 0x22, 0x91, 0x82, + 0x50, 0xFF, 0x66, 0xA4, 0x1B, 0xD2, 0xF8, 0x64, 0xA6, + 0xA3, 0x8C, 0xC5, 0xB6, 0x49, 0x9D, 0xC4, 0x3F, 0x7F, + 0x2B, 0xD0, 0x9E, 0x1E, 0x0F, 0x8F, 0x58, 0x85, 0x93, + 0x51, 0x24 + }, + { + 0x17, 0xD0, 0x9F, 0x40, 0xA4, 0x37, 0x71, 0xF4, 0xA2, + 0xF0, 0xDB, 0x32, 0x7D, 0xF6, 0x37, 0xDE, 0xA9, 0x72, + 0xBF, 0xFF, 0x30, 0xC9, 0x8E, 0xBC, 0x88, 0x42, 0xDC, + 0x7A, 0x9E, 0x3D, 0x68, 0x1C, 0x61, 0x90, 0x2F, 0x71, + 0xBF, 0xFA, 0xF5, 0x09, 0x36, 0x07, 0xFB, 0xFB, 0xA9, + 0x67, 0x4A, 0x70, 0xD0, 0x48, 0xE5, 0x62, 0xEE, 0x88, + 0xF0, 0x27, 0xF6, 0x30, 0xA7, 0x85, 0x22, 0xEC, 0x6F, + 0x70, 0x6B, 0xB4, 0x4A, 0xE1, 0x30, 0xE0, 0x5C, 0x8D, + 0x7E, 0xAC, 0x66, 0x8B, 0xF6, 0x98, 0x0D, 0x99, 0xB4, + 0xC0, 0x24, 0x29, 0x46, 0x45, 0x23, 0x99, 0xCB, 0x03, + 0x2C, 0xC6, 0xF9, 0xFD, 0x96, 0x28, 0x47, 0x09, 0xBD, + 0x2F, 0xA5, 0x65, 0xB9, 0xEB, 0x9F, 0x20, 0x04, 0xBE, + 0x6C, 0x9E, 0xA9, 0xFF, 0x91, 0x28, 0xC3, 0xF9, 0x3B, + 0x60, 0xDC, 0x30, 0xC5, 0xFC, 0x85, 0x87, 0xA1, 0x0D, + 0xE6, 0x8C + } + }; + + static uint8_t output[128]; + + int i, cmp_result; + + for (i = 0; i < HMAC_TEST_COUNT; i++) { + hmac_drbg_init(&ctx, + init_entropy[i], sizeof(init_entropy[i]), + init_nonce[i], sizeof(init_nonce[i]), + NULL, 0); + + hmac_drbg_reseed(&ctx, + reseed_entropy[i], sizeof(reseed_entropy[i]), + NULL, 0, + NULL, 0); + + hmac_drbg_generate(&ctx, + output, sizeof(output), + NULL, 0); + + hmac_drbg_generate(&ctx, + output, sizeof(output), + NULL, 0); + + cmp_result = memcmp(output, expected_output[i], sizeof(output)); + ccprintf("HMAC DRBG generate test %d, %s\n", + i, cmp_result ? "failed" : "passed"); + } + + return 0; +} +DECLARE_SAFE_CONSOLE_COMMAND(hmac_drbg, cmd_hmac_drbg, NULL, NULL); + +/* + * Sanity check to exercise random initialization. + */ +static int cmd_hmac_drbg_rand(int argc, char **argv) +{ + static struct drbg_ctx ctx; + static uint8_t output[128]; + + int i; + + hmac_drbg_init_rand(&ctx, 256); + + hmac_drbg_generate(&ctx, output, sizeof(output), NULL, 0); + + ccprintf("Randomly initialized HMAC DRBG, 1024 bit output: "); + + for (i = 0; i < sizeof(output); i++) + ccprintf("%x", output[i]); + ccprintf("\n"); + + return 0; +} +DECLARE_SAFE_CONSOLE_COMMAND(hmac_drbg_rand, cmd_hmac_drbg_rand, NULL, NULL); + +enum drbg_command { + DRBG_INIT = 0, + DRBG_RESEED = 1, + DRBG_GENERATE = 2 +}; + +/* + * DRBG_TEST command structure: + * + * field | size | note + * ========================================================================== + * mode | 1 | 0 - DRBG_INIT, 1 - DRBG_RESEED, 2 - DRBG_GENERATE + * p0_len | 2 | size of first input in bytes + * p0 | p0_len | entropy for INIT & SEED, input for GENERATE + * p1_len | 2 | size of second input in bytes (for INIT & RESEED) + * | | or size of expected output for GENERATE + * p1 | p1_len | nonce for INIT & SEED + * p2_len | 2 | size of third input in bytes for DRBG_INIT + * p2 | p2_len | personalization for INIT & SEED + * + * DRBG_INIT (entropy, nonce, perso) + * DRBG_RESEED (entropy, additional input 1, additional input 2) + * DRBG_INIT and DRBG_RESEED returns empty response + * DRBG_GENERATE (p0_len, p0 - additional input 1, p1_len - size of output) + * DRBG_GENERATE returns p1_len bytes of generated data + * (up to a maximum of 128 bytes) + */ +static enum vendor_cmd_rc drbg_test(enum vendor_cmd_cc code, void *buf, + size_t input_size, size_t *response_size) +{ + static struct drbg_ctx drbg_ctx; + static uint8_t output[512]; + uint8_t *p0 = NULL, *p1 = NULL, *p2 = NULL; + uint16_t p0_len = 0, p1_len = 0, p2_len = 0; + uint8_t *cmd = (uint8_t *)buf; + size_t max_out_len = *response_size; + enum drbg_command drbg_op; + + *response_size = 0; + /* there is always op + first parameter, even if zero length */ + if (input_size < sizeof(p0_len) + 1) + return VENDOR_RC_BOGUS_ARGS; + drbg_op = *cmd++; + p0_len = *cmd++; + p0_len = p0_len * 256 + *cmd++; + input_size -= 3; + if (p0_len > input_size) + return VENDOR_RC_BOGUS_ARGS; + input_size -= p0_len; + if (p0_len) + p0 = cmd; + cmd += p0_len; + + /* there should be enough space for p1_len */ + if (input_size && input_size < sizeof(p1_len)) + return VENDOR_RC_BOGUS_ARGS; + + /* DRBG_GENERATE should just have p1_len defined */ + if (drbg_op == DRBG_GENERATE && input_size != sizeof(p1_len)) + return VENDOR_RC_BOGUS_ARGS; + + if (input_size) { + p1_len = *cmd++; + p1_len = p1_len * 256 + *cmd++; + input_size -= 2; + + if (drbg_op != DRBG_GENERATE) { + if (p1_len > input_size) + return VENDOR_RC_BOGUS_ARGS; + input_size -= p1_len; + if (p1_len) + p1 = cmd; + cmd += p1_len; + } + } + + if (input_size) { + if (drbg_op == DRBG_GENERATE) + return VENDOR_RC_BOGUS_ARGS; + p2_len = *cmd++; + p2_len = p2_len * 256 + *cmd++; + input_size -= 2; + if (p2_len > input_size) + return VENDOR_RC_BOGUS_ARGS; + if (p2_len) + p2 = cmd; + } + + switch (drbg_op) { + case DRBG_INIT: { + hmac_drbg_init(&drbg_ctx, p0, p0_len, p1, p1_len, p2, p2_len); + break; + } + case DRBG_RESEED: { + hmac_drbg_reseed(&drbg_ctx, p0, p0_len, p1, p1_len, p2, p2_len); + break; + } + case DRBG_GENERATE: { + if (p1_len > sizeof(output) || max_out_len < p1_len) + return VENDOR_RC_BOGUS_ARGS; + + hmac_drbg_generate(&drbg_ctx, output, p1_len, p0, p0_len); + + memcpy(buf, output, p1_len); + *response_size = p1_len; + break; + } + default: + return VENDOR_RC_BOGUS_ARGS; + } + + return VENDOR_RC_SUCCESS; +} +DECLARE_VENDOR_COMMAND(VENDOR_CC_DRBG_TEST, drbg_test); + +#endif /* CRYPTO_TEST_SETUP */ diff --git a/board/cr50/dcrypto/internal.h b/board/cr50/dcrypto/internal.h new file mode 100644 index 0000000000..1811426f2a --- /dev/null +++ b/board/cr50/dcrypto/internal.h @@ -0,0 +1,219 @@ +/* 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. + */ + +#ifndef __EC_CHIP_G_DCRYPTO_INTERNAL_H +#define __EC_CHIP_G_DCRYPTO_INTERNAL_H + +#include +#include + +#include "common.h" +#include "util.h" + +#include "cryptoc/p256.h" +#include "cryptoc/sha.h" +#include "cryptoc/sha256.h" +#include "cryptoc/sha384.h" +#include "cryptoc/sha512.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * SHA. + */ +#define CTRL_CTR_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#define CTRL_ENABLE 1 +#define CTRL_ENCRYPT 1 +#define CTRL_NO_SOFT_RESET 0 + +#define SHA_DIGEST_WORDS (SHA_DIGEST_SIZE / sizeof(uint32_t)) +#define SHA256_DIGEST_WORDS (SHA256_DIGEST_SIZE / sizeof(uint32_t)) + +#ifdef SHA512_SUPPORT +#define SHA_DIGEST_MAX_BYTES SHA512_DIGEST_SIZE +#else +#define SHA_DIGEST_MAX_BYTES SHA256_DIGEST_SIZE +#endif + +enum sha_mode { + SHA1_MODE = 0, + SHA256_MODE = 1 +}; + +/* + * Use this structure to avoid alignment problems with input and output + * pointers. + */ +struct access_helper { + uint32_t udata; +} __packed; + +#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 void *data, uint32_t n); +void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest); + +/* + * BIGNUM. + */ +#define LITE_BN_BITS2 32 +#define LITE_BN_BYTES 4 + +struct LITE_BIGNUM { + uint32_t dmax; /* Size of d, in 32-bit words. */ + struct access_helper *d; /* Word array, little endian format ... */ +}; + +#define BN_DIGIT(b, i) ((b)->d[(i)].udata) + +void bn_init(struct LITE_BIGNUM *bn, void *buf, size_t len); +#define bn_size(b) ((b)->dmax * LITE_BN_BYTES) +#define bn_words(b) ((b)->dmax) +#define bn_bits(b) ((b)->dmax * LITE_BN_BITS2) +int bn_eq(const struct LITE_BIGNUM *a, const struct LITE_BIGNUM *b); +int bn_check_topbit(const struct LITE_BIGNUM *N); +int bn_modexp(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, + const struct LITE_BIGNUM *N); +int bn_modexp_word(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + uint32_t pubexp, + const struct LITE_BIGNUM *N); +int bn_modexp_blinded(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, + const struct LITE_BIGNUM *N, + uint32_t pubexp); +uint32_t bn_add(struct LITE_BIGNUM *c, + const struct LITE_BIGNUM *a); +uint32_t bn_sub(struct LITE_BIGNUM *c, + const struct LITE_BIGNUM *a); +int bn_modinv_vartime(struct LITE_BIGNUM *r, + const struct LITE_BIGNUM *e, + const struct LITE_BIGNUM *MOD); +int bn_is_bit_set(const struct LITE_BIGNUM *a, int n); + +/* + * Accelerated bn. + */ +int dcrypto_modexp(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, + const struct LITE_BIGNUM *N); +int dcrypto_modexp_word(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + uint32_t pubexp, + const struct LITE_BIGNUM *N); +int dcrypto_modexp_blinded(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, + const struct LITE_BIGNUM *N, + uint32_t pubexp); + +struct drbg_ctx { + uint32_t k[SHA256_DIGEST_WORDS]; + uint32_t v[SHA256_DIGEST_WORDS]; + uint32_t reseed_counter; +}; + +/* + * NIST SP 800-90A HMAC DRBG. + */ +enum hmac_result { + HMAC_DRBG_SUCCESS = 0, + HMAC_DRBG_INVALID_PARAM = 1, + HMAC_DRBG_RESEED_REQUIRED = 2 +}; + +/* Standard initialization. */ +void hmac_drbg_init(struct drbg_ctx *ctx, + const void *p0, size_t p0_len, + const void *p1, size_t p1_len, + const void *p2, size_t p2_len); +/* Initialize for use as RFC6979 DRBG. */ +void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx, + const p256_int *key, + const p256_int *message); +/* Initialize with at least nbits of random entropy. */ +void hmac_drbg_init_rand(struct drbg_ctx *ctx, size_t nbits); +void hmac_drbg_reseed(struct drbg_ctx *ctx, + const void *p0, size_t p0_len, + const void *p1, size_t p1_len, + const void *p2, size_t p2_len); +enum hmac_result hmac_drbg_generate(struct drbg_ctx *ctx, void *out, + size_t out_len, const void *input, + size_t input_len); +/* Generate p256, with no additional input. */ +enum hmac_result hmac_drbg_generate_p256(struct drbg_ctx *ctx, p256_int *k_out); +void drbg_exit(struct drbg_ctx *ctx); + +/* + * Accelerated p256. FIPS PUB 186-4 + */ +int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key, + const p256_int *message, p256_int *r, p256_int *s) + __attribute__((warn_unused_result)); +int dcrypto_p256_base_point_mul(const p256_int *k, p256_int *x, p256_int *y) + __attribute__((warn_unused_result)); +int dcrypto_p256_point_mul(const p256_int *k, + const p256_int *in_x, const p256_int *in_y, + p256_int *x, p256_int *y) + __attribute__((warn_unused_result)); +int dcrypto_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y, + const p256_int *message, const p256_int *r, + const p256_int *s) + __attribute__((warn_unused_result)); +int dcrypto_p256_is_valid_point(const p256_int *x, const p256_int *y) + __attribute__((warn_unused_result)); + +/* Pick a p256 number between 1 < k < |p256| */ +int dcrypto_p256_pick(struct drbg_ctx *drbg, p256_int *output); + +/* Overwrite with random p256 value */ +void dcrypto_p256_rnd(p256_int *output); + +/* + * Accelerator runtime. + * + * Note dcrypto_init_and_lock grabs a mutex and dcrypto_unlock releases it. + * Do not use dcrypto_call, dcrypto_imem_load or dcrypto_dmem_load w/o holding + * the mutex. + */ +void dcrypto_init_and_lock(void); +void dcrypto_unlock(void); +uint32_t dcrypto_call(uint32_t adr) __attribute__((warn_unused_result)); +void dcrypto_imem_load(size_t offset, const uint32_t *opcodes, + size_t n_opcodes); +/* + * Returns 0 iff no difference was observed between existing and new content. + */ +uint32_t dcrypto_dmem_load(size_t offset, const void *words, size_t n_words); + +/* + * Key ladder. + */ +#ifndef __cplusplus +enum dcrypto_appid; /* Forward declaration. */ + +int dcrypto_ladder_compute_usr(enum dcrypto_appid id, + const uint32_t usr_salt[8]); +int dcrypto_ladder_derive(enum dcrypto_appid appid, const uint32_t salt[8], + const uint32_t input[8], uint32_t output[8]); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ! __EC_CHIP_G_DCRYPTO_INTERNAL_H */ diff --git a/board/cr50/dcrypto/key_ladder.c b/board/cr50/dcrypto/key_ladder.c new file mode 100644 index 0000000000..77055e4159 --- /dev/null +++ b/board/cr50/dcrypto/key_ladder.c @@ -0,0 +1,300 @@ +/* Copyright 2017 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 "endian.h" +#include "registers.h" +#include "trng.h" + +static void ladder_init(void) +{ + /* Do not reset keyladder engine here, as before. + * + * Should not be needed and if it is, it is indicative + * of sync error between this and sha engine usage. + * Reset will make this flow work, but will have broken + * the other pending sha flow. + * Hence leave as is and observe the error. + */ + + /* Enable random stalls for key-ladder usage. Note that + * the stall rate used for key-ladder operations is + * 25% (vs. 12% for generic SHA operations). This distinction + * is made so as to increase the difficulty in characterizng + * the key-ladder engine via random inputs provided over the + * generic SHA interface. + */ + /* Turn off random nops (which are enabled by default). */ + GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 0); + /* Configure random nop percentage at 25%. */ + GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, FREQ, 1); + /* Now turn on random nops. */ + GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 1); +} + +static int ladder_step(uint32_t cert, const uint32_t input[8]) +{ + GREG32(KEYMGR, SHA_ITOP) = 0; /* clear status */ + + GREG32(KEYMGR, SHA_USE_CERT_INDEX) = + (cert << GC_KEYMGR_SHA_USE_CERT_INDEX_LSB) | + GC_KEYMGR_SHA_USE_CERT_ENABLE_MASK; + + GREG32(KEYMGR, SHA_CFG_EN) = + GC_KEYMGR_SHA_CFG_EN_INT_EN_DONE_MASK; + GREG32(KEYMGR, SHA_TRIG) = + GC_KEYMGR_SHA_TRIG_TRIG_GO_MASK; + + if (input) { + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[0]; + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[1]; + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[2]; + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[3]; + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[4]; + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[5]; + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[6]; + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[7]; + + GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_STOP_MASK; + } + + while (!GREG32(KEYMGR, SHA_ITOP)) + ; + + GREG32(KEYMGR, SHA_ITOP) = 0; /* clear status */ + + return !!GREG32(KEYMGR, HKEY_ERR_FLAGS); +} + +static int compute_certs(const uint32_t *certs, size_t num_certs) +{ + int i; + + for (i = 0; i < num_certs; i++) { + if (ladder_step(certs[i], NULL)) + return 0; + } + + return 1; +} + +#define KEYMGR_CERT_0 0 +#define KEYMGR_CERT_3 3 +#define KEYMGR_CERT_4 4 +#define KEYMGR_CERT_5 5 +#define KEYMGR_CERT_7 7 +#define KEYMGR_CERT_15 15 +#define KEYMGR_CERT_20 20 +#define KEYMGR_CERT_25 25 +#define KEYMGR_CERT_26 26 +#define KEYMGR_CERT_27 27 +#define KEYMGR_CERT_28 28 +#define KEYMGR_CERT_34 34 +#define KEYMGR_CERT_35 35 +#define KEYMGR_CERT_38 38 + +static const uint32_t FRK2_CERTS_PREFIX[] = { + KEYMGR_CERT_0, + KEYMGR_CERT_3, + KEYMGR_CERT_4, + KEYMGR_CERT_5, + KEYMGR_CERT_7, + KEYMGR_CERT_15, + KEYMGR_CERT_20, +}; + +static const uint32_t FRK2_CERTS_POSTFIX[] = { + KEYMGR_CERT_26, +}; + +#define MAX_MAJOR_FW_VERSION 254 + +int DCRYPTO_ladder_compute_frk2(size_t fw_version, uint8_t *frk2) +{ + int result = 0; + + if (fw_version > MAX_MAJOR_FW_VERSION) + return 0; + + if (!dcrypto_grab_sha_hw()) + return 0; + + do { + int i; + + ladder_init(); + + if (!compute_certs(FRK2_CERTS_PREFIX, + ARRAY_SIZE(FRK2_CERTS_PREFIX))) + break; + + for (i = 0; i < MAX_MAJOR_FW_VERSION - fw_version; i++) { + if (ladder_step(KEYMGR_CERT_25, NULL)) + break; + } + + if (!compute_certs(FRK2_CERTS_POSTFIX, + ARRAY_SIZE(FRK2_CERTS_POSTFIX))) + break; + + memcpy(frk2, (void *) GREG32_ADDR(KEYMGR, HKEY_FRR0), + AES256_BLOCK_CIPHER_KEY_SIZE); + + result = 1; + } while (0); + + dcrypto_release_sha_hw(); + return result; +} + +/* ISR salt (SHA256("ISR_SALT")) to use for USR generation. */ +static const uint32_t ISR_SALT[8] = { + 0x6ba1b495, 0x4b7ca214, 0xfe07e922, 0x09735185, + 0xfcca43ca, 0xc6d4dfd9, 0x5fc2fcca, 0xaa45400b +}; + +/* Map of populated USR registers. */ +static int usr_ready[8] = {}; + +int dcrypto_ladder_compute_usr(enum dcrypto_appid id, + const uint32_t usr_salt[8]) +{ + int result = 0; + + /* Check for USR readiness. */ + if (usr_ready[id]) + return 1; + + if (!dcrypto_grab_sha_hw()) + return 0; + + do { + int i; + + /* The previous check performed without lock acquisition. */ + if (usr_ready[id]) { + result = 1; + break; + } + + ladder_init(); + + if (!compute_certs(FRK2_CERTS_PREFIX, + ARRAY_SIZE(FRK2_CERTS_PREFIX))) + break; + + /* USR generation requires running the key-ladder till + * the end (version 0), plus one additional iteration. + */ + for (i = 0; i < MAX_MAJOR_FW_VERSION - 0 + 1; i++) { + if (ladder_step(KEYMGR_CERT_25, NULL)) + break; + } + if (i != MAX_MAJOR_FW_VERSION - 0 + 1) + break; + + if (ladder_step(KEYMGR_CERT_34, ISR_SALT)) + break; + + /* Output goes to USR[appid] (the multiply by 2 is an + * artifact of slot addressing). + */ + GWRITE_FIELD(KEYMGR, SHA_CERT_OVERRIDE, DIGEST_PTR, 2 * id); + if (ladder_step(KEYMGR_CERT_35, usr_salt)) + break; + + /* Check for key-ladder errors. */ + if (GREG32(KEYMGR, HKEY_ERR_FLAGS)) + break; + + /* Key deposited in USR[id], and ready to use. */ + usr_ready[id] = 1; + + result = 1; + } while (0); + + dcrypto_release_sha_hw(); + return result; +} + +static void ladder_out(uint32_t output[8]) +{ + output[0] = GREG32(KEYMGR, SHA_STS_H0); + output[1] = GREG32(KEYMGR, SHA_STS_H1); + output[2] = GREG32(KEYMGR, SHA_STS_H2); + output[3] = GREG32(KEYMGR, SHA_STS_H3); + output[4] = GREG32(KEYMGR, SHA_STS_H4); + output[5] = GREG32(KEYMGR, SHA_STS_H5); + output[6] = GREG32(KEYMGR, SHA_STS_H6); + output[7] = GREG32(KEYMGR, SHA_STS_H7); +} + +/* + * Stir TRNG entropy into RSR and pull some out. + */ +int DCRYPTO_ladder_random(void *output) +{ + int error = 1; + uint32_t tmp[8]; + + if (!dcrypto_grab_sha_hw()) + goto fail; + + rand_bytes(tmp, sizeof(tmp)); + /* Mix TRNG bytes with RSR entropy */ + error = ladder_step(KEYMGR_CERT_27, tmp); + if (!error) + ladder_out(output); + +fail: + dcrypto_release_sha_hw(); + return !error; +} + +int dcrypto_ladder_derive(enum dcrypto_appid appid, const uint32_t salt[8], + const uint32_t input[8], uint32_t output[8]) +{ + int error; + + if (!dcrypto_grab_sha_hw()) + return 0; + + GWRITE_FIELD(KEYMGR, SHA_CERT_OVERRIDE, KEY_PTR, 2 * appid); + error = ladder_step(KEYMGR_CERT_38, input); /* HMAC */ + if (!error) + ladder_out(output); + + dcrypto_release_sha_hw(); + return !error; +} + +void DCRYPTO_ladder_revoke(void) +{ + /* Revoke certificates */ + GWRITE(KEYMGR, CERT_REVOKE_CTRL0, 0xffffffff); + GWRITE(KEYMGR, CERT_REVOKE_CTRL1, 0xffffffff); + + /* Wipe out the hidden keys cached in AES and SHA engines. */ + GWRITE_FIELD(KEYMGR, AES_USE_HIDDEN_KEY, ENABLE, 0); + GWRITE_FIELD(KEYMGR, SHA_USE_HIDDEN_KEY, ENABLE, 0); + + /* Clear usr_ready[] */ + memset(usr_ready, 0, sizeof(usr_ready)); +} + +#define KEYMGR_CERT_REVOKE_CTRL0_DEFAULT_VAL 0xa8028a82 +#define KEYMGR_CERT_REVOKE_CTRL1_DEFAULT_VAL 0xaaaaaaaa + +int DCRYPTO_ladder_is_enabled(void) +{ + uint32_t ctrl0; + uint32_t ctrl1; + + ctrl0 = GREAD(KEYMGR, CERT_REVOKE_CTRL0); + ctrl1 = GREAD(KEYMGR, CERT_REVOKE_CTRL1); + + return ctrl0 == KEYMGR_CERT_REVOKE_CTRL0_DEFAULT_VAL && + ctrl1 == KEYMGR_CERT_REVOKE_CTRL1_DEFAULT_VAL; +} diff --git a/board/cr50/dcrypto/p256.c b/board/cr50/dcrypto/p256.c new file mode 100644 index 0000000000..665144e31b --- /dev/null +++ b/board/cr50/dcrypto/p256.c @@ -0,0 +1,30 @@ +/* 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 "cryptoc/p256.h" +#include "cryptoc/util.h" + +static const p256_int p256_one = P256_ONE; + +/* + * Key selection based on FIPS-186-4, section B.4.2 (Key Pair + * Generation by Testing Candidates). + */ +int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d, + const uint8_t key_bytes[P256_NBYTES]) +{ + p256_int key; + + p256_from_bin(key_bytes, &key); + if (p256_cmp(&SECP256r1_nMin2, &key) < 0) + return 0; + p256_add(&key, &p256_one, d); + always_memset(&key, 0, sizeof(key)); + if (x == NULL || y == NULL) + return 1; + return dcrypto_p256_base_point_mul(d, x, y); +} diff --git a/board/cr50/dcrypto/p256_ec.c b/board/cr50/dcrypto/p256_ec.c new file mode 100644 index 0000000000..cb33a15774 --- /dev/null +++ b/board/cr50/dcrypto/p256_ec.c @@ -0,0 +1,39 @@ +/* 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 + +#include "cryptoc/p256.h" + +/* p256_base_point_mul sets {out_x,out_y} = nG, where n is < the + * order of the group. */ +int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y, + const p256_int *n) +{ + if (p256_is_zero(n) != 0) { + p256_clear(out_x); + p256_clear(out_y); + return 0; + } + + return dcrypto_p256_base_point_mul(n, out_x, out_y); +} + +/* DCRYPTO_p256_point_mul sets {out_x,out_y} = n*{in_x,in_y}, where n is < + * the order of the group. */ +int DCRYPTO_p256_point_mul(p256_int *out_x, p256_int *out_y, + const p256_int *n, const p256_int *in_x, + const p256_int *in_y) +{ + if (p256_is_zero(n) != 0) { + p256_clear(out_x); + p256_clear(out_y); + return 0; + } + + return dcrypto_p256_point_mul(n, in_x, in_y, out_x, out_y); +} diff --git a/board/cr50/dcrypto/p256_ecies.c b/board/cr50/dcrypto/p256_ecies.c new file mode 100644 index 0000000000..30a410d828 --- /dev/null +++ b/board/cr50/dcrypto/p256_ecies.c @@ -0,0 +1,175 @@ +/* Copyright 2016 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 "internal.h" +#include "dcrypto.h" + +#include "trng.h" +#include "util.h" + +#include "cryptoc/p256.h" +#include "cryptoc/sha256.h" + +#define AES_KEY_BYTES 16 +#define HMAC_KEY_BYTES 32 + +#define AES_BLOCK_BYTES 16 + +/* P256 based hybrid encryption. The output format is: + * + * 0x04 || PUBKEY || AUTH_DATA || AES128_CTR(PLAINTEXT) || + * HMAC_SHA256(AUTH_DATA || CIPHERTEXT) + */ +size_t DCRYPTO_ecies_encrypt( + void *out, size_t out_len, const void *in, size_t in_len, + size_t auth_data_len, const uint8_t *iv, + const p256_int *pub_x, const p256_int *pub_y, + const uint8_t *salt, size_t salt_len, + const uint8_t *info, size_t info_len) +{ + p256_int eph_d; + p256_int eph_x; + p256_int eph_y; + uint8_t seed[P256_NBYTES]; + p256_int secret_x; + p256_int secret_y; + /* Key bytes to be extracted from HKDF. */ + uint8_t key[AES_KEY_BYTES + HMAC_KEY_BYTES]; + const uint8_t *aes_key; + const uint8_t *hmac_key; + LITE_HMAC_CTX ctx; + uint8_t *outp = out; + uint8_t *ciphertext; + + if (auth_data_len > in_len) + return 0; + if (out_len < 1 + P256_NBYTES + P256_NBYTES + + in_len + SHA256_DIGEST_SIZE) + return 0; + + /* Generate emphemeral EC key. */ + rand_bytes(seed, sizeof(seed)); + if (!DCRYPTO_p256_key_from_bytes(&eph_x, &eph_y, &eph_d, seed)) + return 0; + /* Compute DH point. */ + if (!DCRYPTO_p256_point_mul(&secret_x, &secret_y, + &eph_d, pub_x, pub_y)) + return 0; + /* Check for computational errors. */ + if (!dcrypto_p256_is_valid_point(&secret_x, &secret_y)) + return 0; + /* Convert secret to big-endian. */ + reverse(&secret_x, sizeof(secret_x)); + /* Derive shared secret. */ + if (!DCRYPTO_hkdf(key, sizeof(key), salt, salt_len, + (uint8_t *) &secret_x, sizeof(secret_x), + info, info_len)) + return 0; + + aes_key = &key[0]; + hmac_key = &key[AES_KEY_BYTES]; + + if (out == in) + ciphertext = out + auth_data_len; /* In place encrypt. */ + else + ciphertext = out + 1 + P256_NBYTES + P256_NBYTES + + auth_data_len; + + /* Compute ciphertext. */ + if (!DCRYPTO_aes_ctr(ciphertext, aes_key, AES_KEY_BYTES * 8, iv, + in + auth_data_len, in_len - auth_data_len)) + return 0; + + /* Write out auth_data / ciphertext. */ + outp = out + 1 + P256_NBYTES + P256_NBYTES; + if (out == in) + memmove(outp, in, in_len); + else + memcpy(outp, in, auth_data_len); + + /* Write out ephemeral pub key. */ + outp = out; + *outp++ = 0x04; /* uncompressed EC public key. */ + p256_to_bin(&eph_x, outp); + outp += P256_NBYTES; + p256_to_bin(&eph_y, outp); + outp += P256_NBYTES; + + /* Calculate HMAC(auth_data || ciphertext). */ + DCRYPTO_HMAC_SHA256_init(&ctx, hmac_key, HMAC_KEY_BYTES); + HASH_update(&ctx.hash, outp, in_len); + outp += in_len; + memcpy(outp, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE); + outp += SHA256_DIGEST_SIZE; + + return outp - (uint8_t *) out; +} + +size_t DCRYPTO_ecies_decrypt( + void *out, size_t out_len, const void *in, size_t in_len, + size_t auth_data_len, const uint8_t *iv, + const p256_int *d, + const uint8_t *salt, size_t salt_len, + const uint8_t *info, size_t info_len) +{ + p256_int eph_x; + p256_int eph_y; + p256_int secret_x; + p256_int secret_y; + uint8_t key[AES_KEY_BYTES + HMAC_KEY_BYTES]; + const uint8_t *aes_key; + const uint8_t *hmac_key; + LITE_HMAC_CTX ctx; + const uint8_t *inp = in; + uint8_t *outp = out; + + if (in_len < 1 + P256_NBYTES + P256_NBYTES + auth_data_len + + SHA256_DIGEST_SIZE) + return 0; + if (inp[0] != 0x04) + return 0; + + in_len -= 1 + P256_NBYTES + P256_NBYTES + SHA256_DIGEST_SIZE; + + inp++; + p256_from_bin(inp, &eph_x); + inp += P256_NBYTES; + p256_from_bin(inp, &eph_y); + inp += P256_NBYTES; + + /* Verify that the public point is on the curve. */ + if (!dcrypto_p256_is_valid_point(&eph_x, &eph_y)) + return 0; + /* Compute the DH point. */ + if (!DCRYPTO_p256_point_mul(&secret_x, &secret_y, + d, &eph_x, &eph_y)) + return 0; + /* Check for computational errors. */ + if (!dcrypto_p256_is_valid_point(&secret_x, &secret_y)) + return 0; + /* Convert secret to big-endian. */ + reverse(&secret_x, sizeof(secret_x)); + /* Derive shared secret. */ + if (!DCRYPTO_hkdf(key, sizeof(key), salt, salt_len, + (uint8_t *) &secret_x, sizeof(secret_x), + info, info_len)) + return 0; + + aes_key = &key[0]; + hmac_key = &key[AES_KEY_BYTES]; + DCRYPTO_HMAC_SHA256_init(&ctx, hmac_key, HMAC_KEY_BYTES); + HASH_update(&ctx.hash, inp, in_len); + if (!DCRYPTO_equals(inp + in_len, DCRYPTO_HMAC_final(&ctx), + SHA256_DIGEST_SIZE)) + return 0; + + memmove(outp, inp, auth_data_len); + inp += auth_data_len; + outp += auth_data_len; + if (!DCRYPTO_aes_ctr(outp, aes_key, AES_KEY_BYTES * 8, iv, + inp, in_len - auth_data_len)) + return 0; + return in_len; +} diff --git a/board/cr50/dcrypto/proofs_p256.md b/board/cr50/dcrypto/proofs_p256.md new file mode 100644 index 0000000000..c0fa7ef6ad --- /dev/null +++ b/board/cr50/dcrypto/proofs_p256.md @@ -0,0 +1,28 @@ +Proving P256 dcrypto code +========================= + +In 2018, partial proofs of modular reduction were written in the Coq proof +assistant. +They can be used against the crypto accelerator code in [chip/g/dcrypto/dcrypto_p256.c](dcrypto_p256.c). + +The Coq code is in this file: +[github.com/mit-plv/fiat-crypto/.../Experiments/SimplyTypedArithmetic.v](https://github.com/mit-plv/fiat-crypto/blob/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Experiments/SimplyTypedArithmetic.v) + +Specific lines of interest: + +Instruction specifications: +[fiat-crypto/.../Experiments/SimplyTypedArithmetic.v#L10014](https://github.com/mit-plv/fiat-crypto/blob/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Experiments/SimplyTypedArithmetic.v#L10014) + +Printouts of verified code versions with explanatory comments are at the very +end of the same file (which GitHub cuts off, so here is the link to the raw +version): +https://raw.githubusercontent.com/mit-plv/fiat-crypto/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Experiments/SimplyTypedArithmetic.v + +Additionally, the MulMod procedure in p256 uses a non-standard Barrett +reduction optimization. In particular, it assumes that the quotient estimate is +off by no more than 1, while most resources say it can be off by 2. This +assumption was proven correct for most primes (including p256) here: + +[fiat-crypto/.../Arithmetic/BarrettReduction/Generalized.v#L140](https://github.com/mit-plv/fiat-crypto/blob/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Arithmetic/BarrettReduction/Generalized.v#L140) + +The proofs can be re-checked using Coq version 8.7 or 8.8 (or above, probably). diff --git a/board/cr50/dcrypto/rsa.c b/board/cr50/dcrypto/rsa.c new file mode 100644 index 0000000000..8a4115398d --- /dev/null +++ b/board/cr50/dcrypto/rsa.c @@ -0,0 +1,743 @@ +/* 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 "trng.h" +#include "util.h" + +#include + +#include "cryptoc/sha.h" +#include "cryptoc/sha256.h" +#include "cryptoc/sha384.h" +#include "cryptoc/sha512.h" +#include "cryptoc/util.h" + +/* Extend the MSB throughout the word. */ +static uint32_t msb_extend(uint32_t a) +{ + return 0u - (a >> 31); +} + +/* Return 0xFF..FF if a is zero, and zero otherwise. */ +static uint32_t is_zero(uint32_t a) +{ + return msb_extend(~a & (a - 1)); +} + +/* Select a or b based on mask. Mask expected to be 0xFF..FF or 0. */ +static uint32_t select(uint32_t mask, uint32_t a, uint32_t b) +{ + return (mask & a) | (~mask & b); +} + +static void MGF1_xor(uint8_t *dst, uint32_t dst_len, + const uint8_t *seed, uint32_t seed_len, + enum hashing_mode hashing) +{ + HASH_CTX ctx; + struct { + uint8_t b3; + uint8_t b2; + uint8_t b1; + uint8_t b0; + } cnt; + const uint8_t *digest; + const size_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE + : SHA256_DIGEST_SIZE; + + cnt.b0 = cnt.b1 = cnt.b2 = cnt.b3 = 0; + while (dst_len) { + int i; + + if (hashing == HASH_SHA1) + DCRYPTO_SHA1_init(&ctx, 0); + else + DCRYPTO_SHA256_init(&ctx, 0); + + HASH_update(&ctx, seed, seed_len); + HASH_update(&ctx, (uint8_t *) &cnt, sizeof(cnt)); + digest = HASH_final(&ctx); + for (i = 0; i < dst_len && i < hash_size; ++i) + *dst++ ^= *digest++; + dst_len -= i; + if (!++cnt.b0) + ++cnt.b1; + } +} + +/* + * struct OAEP { // MSB to LSB. + * uint8_t zero; + * uint8_t seed[HASH_SIZE]; + * uint8_t phash[HASH_SIZE]; + * uint8_t PS[]; // Variable length (optional) zero-pad. + * uint8_t one; // 0x01, message demarcator. + * uint8_t msg[]; // Input message. + * }; + */ +/* encrypt */ +static int oaep_pad(uint8_t *output, uint32_t output_len, + const uint8_t *msg, uint32_t msg_len, + enum hashing_mode hashing, const char *label) +{ + int i; + const size_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE + : SHA256_DIGEST_SIZE; + uint8_t *const seed = output + 1; + uint8_t *const phash = seed + hash_size; + uint8_t *const PS = phash + hash_size; + const uint32_t max_msg_len = output_len - 2 - 2 * hash_size; + const uint32_t ps_len = max_msg_len - msg_len; + uint8_t *const one = PS + ps_len; + struct HASH_CTX ctx; + + if (output_len < 2 + 2 * hash_size) + return 0; /* Key size too small for chosen hash. */ + if (msg_len > output_len - 2 - 2 * hash_size) + return 0; /* Input message too large for key size. */ + + always_memset(output, 0, output_len); + for (i = 0; i < hash_size;) { + uint32_t r = rand(); + + seed[i++] = r >> 0; + seed[i++] = r >> 8; + seed[i++] = r >> 16; + seed[i++] = r >> 24; + } + + if (hashing == HASH_SHA1) + DCRYPTO_SHA1_init(&ctx, 0); + else + DCRYPTO_SHA256_init(&ctx, 0); + + HASH_update(&ctx, label, label ? strlen(label) + 1 : 0); + memcpy(phash, HASH_final(&ctx), hash_size); + *one = 1; + memcpy(one + 1, msg, msg_len); + MGF1_xor(phash, hash_size + 1 + max_msg_len, + seed, hash_size, hashing); + MGF1_xor(seed, hash_size, phash, hash_size + 1 + max_msg_len, + hashing); + return 1; +} + +/* decrypt */ +static int check_oaep_pad(uint8_t *out, uint32_t *out_len, + uint8_t *padded, uint32_t padded_len, + enum hashing_mode hashing, const char *label) +{ + const size_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE + : SHA256_DIGEST_SIZE; + uint8_t *seed = padded + 1; + uint8_t *phash = seed + hash_size; + uint8_t *PS = phash + hash_size; + const uint32_t max_msg_len = padded_len - 2 - 2 * hash_size; + struct HASH_CTX ctx; + size_t one_index = 0; + uint32_t looking_for_one_byte = ~0; + int bad; + int i; + + if (padded_len < 2 + 2 * hash_size) + return 0; /* Invalid input size. */ + + /* Recover seed. */ + MGF1_xor(seed, hash_size, phash, hash_size + 1 + max_msg_len, hashing); + /* Recover db. */ + MGF1_xor(phash, hash_size + 1 + max_msg_len, seed, hash_size, hashing); + + if (hashing == HASH_SHA1) + DCRYPTO_SHA1_init(&ctx, 0); + else + DCRYPTO_SHA256_init(&ctx, 0); + HASH_update(&ctx, label, label ? strlen(label) + 1 : 0); + + bad = !DCRYPTO_equals(phash, HASH_final(&ctx), hash_size); + bad |= padded[0]; + + for (i = PS - padded; i < padded_len; i++) { + uint32_t equals0 = is_zero(padded[i]); + uint32_t equals1 = is_zero(padded[i] ^ 1); + + one_index = select(looking_for_one_byte & equals1, + i, one_index); + looking_for_one_byte = select(equals1, 0, looking_for_one_byte); + + /* Bad padding if padded[i] is neither 1 nor 0. */ + bad |= looking_for_one_byte & ~equals0; + } + + bad |= looking_for_one_byte; + + if (bad) + return 0; + + one_index++; + if (*out_len < padded_len - one_index) + return 0; + memcpy(out, padded + one_index, padded_len - one_index); + *out_len = padded_len - one_index; + return 1; +} + +/* Constants from RFC 3447. */ +#define RSA_PKCS1_PADDING_SIZE 11 + +/* encrypt */ +static int pkcs1_type2_pad(uint8_t *padded, uint32_t padded_len, + const uint8_t *in, uint32_t in_len) +{ + uint32_t PS_len; + + if (padded_len < RSA_PKCS1_PADDING_SIZE) + return 0; + if (in_len > padded_len - RSA_PKCS1_PADDING_SIZE) + return 0; + PS_len = padded_len - 3 - in_len; + + *(padded++) = 0; + *(padded++) = 2; + while (PS_len) { + int i; + uint32_t r = rand(); + + for (i = 0; i < 4 && PS_len; i++) { + uint8_t b = ((uint8_t *) &r)[i]; + + if (b) { + *padded++ = b; + PS_len--; + } + } + } + *(padded++) = 0; + memcpy(padded, in, in_len); + return 1; +} + +/* decrypt */ +static int check_pkcs1_type2_pad(uint8_t *out, uint32_t *out_len, + const uint8_t *padded, uint32_t padded_len) +{ + int i; + int valid; + uint32_t zero_index = 0; + uint32_t looking_for_index = ~0; + + if (padded_len < RSA_PKCS1_PADDING_SIZE) + return 0; + + valid = (padded[0] == 0); + valid &= (padded[1] == 2); + + for (i = 2; i < padded_len; i++) { + uint32_t found = is_zero(padded[i]); + + zero_index = select(looking_for_index & found, i, zero_index); + looking_for_index = select(found, 0, looking_for_index); + } + + zero_index++; + + valid &= ~looking_for_index; + valid &= (zero_index >= RSA_PKCS1_PADDING_SIZE); + if (!valid) + return 0; + + if (*out_len < padded_len - zero_index) + return 0; + memcpy(out, &padded[zero_index], padded_len - zero_index); + *out_len = padded_len - zero_index; + return 1; +} + +static const uint8_t SHA1_DER[] = { + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, + 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 +}; +static const uint8_t SHA256_DER[] = { + 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, + 0x00, 0x04, 0x20 +}; +static const uint8_t SHA384_DER[] = { + 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, + 0x00, 0x04, 0x30 +}; +static const uint8_t SHA512_DER[] = { + 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, + 0x00, 0x04, 0x40 +}; + +static int pkcs1_get_der(enum hashing_mode hashing, const uint8_t **der, + uint32_t *der_size, uint32_t *hash_size) +{ + switch (hashing) { + case HASH_SHA1: + *der = &SHA1_DER[0]; + *der_size = sizeof(SHA1_DER); + *hash_size = SHA_DIGEST_SIZE; + break; + case HASH_SHA256: + *der = &SHA256_DER[0]; + *der_size = sizeof(SHA256_DER); + *hash_size = SHA256_DIGEST_SIZE; + break; + case HASH_SHA384: + *der = &SHA384_DER[0]; + *der_size = sizeof(SHA384_DER); + *hash_size = SHA384_DIGEST_SIZE; + break; + case HASH_SHA512: + *der = &SHA512_DER[0]; + *der_size = sizeof(SHA512_DER); + *hash_size = SHA512_DIGEST_SIZE; + break; + case HASH_NULL: + *der = NULL; + *der_size = 0; + *hash_size = 0; /* any size allowed */ + break; + default: + return 0; + } + + return 1; +} + +/* sign */ +static int pkcs1_type1_pad(uint8_t *padded, uint32_t padded_len, + const uint8_t *in, uint32_t in_len, + enum hashing_mode hashing) +{ + const uint8_t *der; + uint32_t der_size; + uint32_t hash_size; + uint32_t ps_len; + + if (!pkcs1_get_der(hashing, &der, &der_size, &hash_size)) + return 0; + if (padded_len < RSA_PKCS1_PADDING_SIZE + der_size) + return 0; + if (!in_len || (hash_size && in_len != hash_size)) + return 0; + if (in_len > padded_len - RSA_PKCS1_PADDING_SIZE - der_size) + return 0; + ps_len = padded_len - 3 - der_size - in_len; + + *(padded++) = 0; + *(padded++) = 1; + always_memset(padded, 0xFF, ps_len); + padded += ps_len; + *(padded++) = 0; + memcpy(padded, der, der_size); + padded += der_size; + memcpy(padded, in, in_len); + return 1; +} + +/* verify */ +static int check_pkcs1_type1_pad(const uint8_t *msg, uint32_t msg_len, + const uint8_t *padded, uint32_t padded_len, + enum hashing_mode hashing) +{ + int i; + const uint8_t *der; + uint32_t der_size; + uint32_t hash_size; + uint32_t ps_len; + + if (!pkcs1_get_der(hashing, &der, &der_size, &hash_size)) + return 0; + if (msg_len != hash_size) + return 0; + if (padded_len < RSA_PKCS1_PADDING_SIZE + der_size + hash_size) + return 0; + ps_len = padded_len - 3 - der_size - hash_size; + + if (padded[0] != 0 || padded[1] != 1) + return 0; + for (i = 2; i < ps_len + 2; i++) { + if (padded[i] != 0xFF) + return 0; + } + + if (padded[i++] != 0) + return 0; + if (!DCRYPTO_equals(&padded[i], der, der_size)) + return 0; + i += der_size; + return DCRYPTO_equals(msg, &padded[i], hash_size); +} + +/* sign */ +static int pkcs1_pss_pad(uint8_t *padded, uint32_t padded_len, + const uint8_t *in, uint32_t in_len, + enum hashing_mode hashing) +{ + const uint32_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE + : SHA256_DIGEST_SIZE; + const uint32_t salt_len = MIN(padded_len - hash_size - 2, hash_size); + uint32_t db_len; + uint32_t ps_len; + struct HASH_CTX ctx; + + if (in_len != hash_size) + return 0; + if (padded_len < hash_size + 2) + return 0; + db_len = padded_len - hash_size - 1; + + if (hashing == HASH_SHA1) + DCRYPTO_SHA1_init(&ctx, 0); + else + DCRYPTO_SHA256_init(&ctx, 0); + + /* Pilfer bits of output for temporary use. */ + memset(padded, 0, 8); + HASH_update(&ctx, padded, 8); + HASH_update(&ctx, in, in_len); + /* Pilfer bits of output for temporary use. */ + rand_bytes(padded, salt_len); + HASH_update(&ctx, padded, salt_len); + + /* Output hash. */ + memcpy(padded + db_len, HASH_final(&ctx), hash_size); + + /* Prepare DB. */ + ps_len = db_len - salt_len - 1; + memmove(padded + ps_len + 1, padded, salt_len); + memset(padded, 0, ps_len); + padded[ps_len] = 0x01; + MGF1_xor(padded, db_len, padded + db_len, hash_size, hashing); + + /* Clear most significant bit. */ + padded[0] &= 0x7F; + /* Set trailing byte. */ + padded[padded_len - 1] = 0xBC; + return 1; +} + +/* verify */ +static int check_pkcs1_pss_pad(const uint8_t *in, uint32_t in_len, + uint8_t *padded, uint32_t padded_len, + enum hashing_mode hashing) +{ + const uint32_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE + : SHA256_DIGEST_SIZE; + const uint8_t zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint32_t db_len; + uint32_t max_ps_len; + uint32_t salt_len; + HASH_CTX ctx; + int bad = 0; + int i; + + if (in_len != hash_size) + return 0; + if (padded_len < hash_size + 2) + return 0; + db_len = padded_len - hash_size - 1; + + /* Top bit should be zero. */ + bad |= padded[0] & 0x80; + /* Check trailing byte. */ + bad |= padded[padded_len - 1] ^ 0xBC; + + /* Recover DB. */ + MGF1_xor(padded, db_len, padded + db_len, hash_size, hashing); + /* Clear top bit. */ + padded[0] &= 0x7F; + /* Verify padding2. */ + max_ps_len = db_len - 1; + for (i = 0; i < max_ps_len; i++) { + if (padded[i] == 0x01) + break; + else + bad |= padded[i]; + } + bad |= (padded[i] ^ 0x01); + /* Continue with zero-length salt if 0x01 was not found. */ + salt_len = max_ps_len - i; + + if (hashing == HASH_SHA1) + DCRYPTO_SHA1_init(&ctx, 0); + else + DCRYPTO_SHA256_init(&ctx, 0); + HASH_update(&ctx, zeros, sizeof(zeros)); + HASH_update(&ctx, in, in_len); + HASH_update(&ctx, padded + db_len - salt_len, salt_len); + bad |= !DCRYPTO_equals(padded + db_len, HASH_final(&ctx), hash_size); + return !bad; +} + +static int check_modulus_params( + const struct LITE_BIGNUM *N, size_t rsa_max_bytes, uint32_t *out_len) +{ + if (bn_size(N) > rsa_max_bytes) + return 0; /* Unsupported key size. */ + if (!bn_check_topbit(N)) /* Check that top bit is set. */ + return 0; + if (out_len && *out_len < bn_size(N)) + return 0; /* Output buffer too small. */ + return 1; +} + +int DCRYPTO_rsa_encrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len, + const uint8_t *in, uint32_t in_len, + enum padding_mode padding, enum hashing_mode hashing, + const char *label) +{ + uint8_t *p; + uint32_t padded_buf[RSA_MAX_WORDS]; + uint32_t e_buf[LITE_BN_BYTES / sizeof(uint32_t)]; + + struct LITE_BIGNUM padded; + struct LITE_BIGNUM encrypted; + int ret; + + if (!check_modulus_params(&rsa->N, sizeof(padded_buf), out_len)) + return 0; + + bn_init(&padded, padded_buf, bn_size(&rsa->N)); + bn_init(&encrypted, out, bn_size(&rsa->N)); + + switch (padding) { + case PADDING_MODE_OAEP: + if (!oaep_pad((uint8_t *) padded.d, bn_size(&padded), + (const uint8_t *) in, in_len, hashing, label)) + return 0; + break; + case PADDING_MODE_PKCS1: + if (!pkcs1_type2_pad((uint8_t *) padded.d, bn_size(&padded), + (const uint8_t *) in, in_len)) + return 0; + break; + case PADDING_MODE_NULL: + /* Input is allowed to have more bytes than N, in + * which case the excess must be zero. */ + for (; in_len > bn_size(&padded); in_len--) + if (*in++ != 0) + return 0; + p = (uint8_t *) padded.d; + /* If in_len < bn_size(&padded), padded will + * have leading zero bytes. */ + memcpy(&p[bn_size(&padded) - in_len], in, in_len); + /* TODO(ngm): in may be > N, bn_mod_exp() should + * handle this case. */ + break; + default: + return 0; /* Unsupported padding mode. */ + } + + /* Reverse from big-endian to little-endian notation. */ + reverse((uint8_t *) padded.d, bn_size(&padded)); + ret = bn_modexp_word(&encrypted, &padded, rsa->e, &rsa->N); + /* Back to big-endian notation. */ + reverse((uint8_t *) encrypted.d, bn_size(&encrypted)); + *out_len = bn_size(&encrypted); + + always_memset(padded_buf, 0, sizeof(padded_buf)); + always_memset(e_buf, 0, sizeof(e_buf)); + return ret; +} + +int DCRYPTO_rsa_decrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len, + const uint8_t *in, const uint32_t in_len, + enum padding_mode padding, enum hashing_mode hashing, + const char *label) +{ + uint32_t encrypted_buf[RSA_MAX_WORDS]; + uint32_t padded_buf[RSA_MAX_WORDS]; + + struct LITE_BIGNUM encrypted; + struct LITE_BIGNUM padded; + int ret; + + if (!check_modulus_params(&rsa->N, sizeof(padded_buf), NULL)) + return 0; + if (in_len != bn_size(&rsa->N)) + return 0; /* Invalid input length. */ + + /* TODO(ngm): this copy can be eliminated if input may be modified. */ + bn_init(&encrypted, encrypted_buf, in_len); + memcpy(encrypted_buf, in, in_len); + bn_init(&padded, padded_buf, in_len); + + /* Reverse from big-endian to little-endian notation. */ + reverse((uint8_t *) encrypted.d, encrypted.dmax * LITE_BN_BYTES); + ret = bn_modexp_blinded(&padded, &encrypted, &rsa->d, &rsa->N, rsa->e); + /* Back to big-endian notation. */ + reverse((uint8_t *) padded.d, padded.dmax * LITE_BN_BYTES); + + switch (padding) { + case PADDING_MODE_OAEP: + if (!check_oaep_pad(out, out_len, (uint8_t *) padded.d, + bn_size(&padded), hashing, label)) + ret = 0; + break; + case PADDING_MODE_PKCS1: + if (!check_pkcs1_type2_pad( + out, out_len, (const uint8_t *) padded.d, + bn_size(&padded))) + ret = 0; + break; + case PADDING_MODE_NULL: + if (*out_len < bn_size(&padded)) { + ret = 0; + } else { + *out_len = bn_size(&padded); + memcpy(out, padded.d, *out_len); + } + break; + default: + /* Unsupported padding mode. */ + ret = 0; + break; + } + + always_memset(encrypted_buf, 0, sizeof(encrypted_buf)); + always_memset(padded_buf, 0, sizeof(padded_buf)); + return ret; +} + +int DCRYPTO_rsa_sign(struct RSA *rsa, uint8_t *out, uint32_t *out_len, + const uint8_t *in, const uint32_t in_len, + enum padding_mode padding, enum hashing_mode hashing) +{ + uint32_t padded_buf[RSA_MAX_WORDS]; + + struct LITE_BIGNUM padded; + struct LITE_BIGNUM signature; + int ret; + + if (!check_modulus_params(&rsa->N, sizeof(padded_buf), out_len)) + return 0; + + bn_init(&padded, padded_buf, bn_size(&rsa->N)); + bn_init(&signature, out, bn_size(&rsa->N)); + + switch (padding) { + case PADDING_MODE_PKCS1: + if (!pkcs1_type1_pad((uint8_t *) padded.d, bn_size(&padded), + (const uint8_t *) in, in_len, hashing)) + return 0; + break; + case PADDING_MODE_PSS: + if (!pkcs1_pss_pad((uint8_t *) padded.d, bn_size(&padded), + (const uint8_t *) in, in_len, hashing)) + return 0; + break; + default: + return 0; + } + + /* Reverse from big-endian to little-endian notation. */ + reverse((uint8_t *) padded.d, bn_size(&padded)); + ret = bn_modexp_blinded(&signature, &padded, &rsa->d, &rsa->N, rsa->e); + /* Back to big-endian notation. */ + reverse((uint8_t *) signature.d, bn_size(&signature)); + *out_len = bn_size(&rsa->N); + + always_memset(padded_buf, 0, sizeof(padded_buf)); + return ret; +} + +int DCRYPTO_rsa_verify(const struct RSA *rsa, const uint8_t *digest, + uint32_t digest_len, const uint8_t *sig, + const uint32_t sig_len, enum padding_mode padding, + enum hashing_mode hashing) +{ + uint32_t padded_buf[RSA_WORDS_4K]; + uint32_t signature_buf[RSA_WORDS_4K]; + + struct LITE_BIGNUM padded; + struct LITE_BIGNUM signature; + int ret; + + if (!check_modulus_params(&rsa->N, sizeof(padded_buf), NULL)) + return 0; + if (sig_len != bn_size(&rsa->N)) + return 0; /* Invalid input length. */ + + bn_init(&signature, signature_buf, bn_size(&rsa->N)); + memcpy(signature_buf, sig, bn_size(&rsa->N)); + bn_init(&padded, padded_buf, bn_size(&rsa->N)); + + /* Reverse from big-endian to little-endian notation. */ + reverse((uint8_t *) signature.d, bn_size(&signature)); + ret = bn_modexp_word(&padded, &signature, rsa->e, &rsa->N); + /* Back to big-endian notation. */ + reverse((uint8_t *) padded.d, bn_size(&padded)); + + switch (padding) { + case PADDING_MODE_PKCS1: + if (!check_pkcs1_type1_pad( + digest, digest_len, (uint8_t *) padded.d, + bn_size(&padded), hashing)) + ret = 0; + break; + case PADDING_MODE_PSS: + if (!check_pkcs1_pss_pad( + digest, digest_len, (uint8_t *) padded.d, + bn_size(&padded), hashing)) + ret = 0; + break; + default: + /* Unsupported padding mode. */ + ret = 0; + break; + } + + always_memset(padded_buf, 0, sizeof(padded_buf)); + always_memset(signature_buf, 0, sizeof(signature_buf)); + return ret; +} + +int DCRYPTO_rsa_key_compute(struct LITE_BIGNUM *N, struct LITE_BIGNUM *d, + struct LITE_BIGNUM *p, struct LITE_BIGNUM *q, + uint32_t e_buf) +{ + uint32_t ONE_buf = 1; + uint32_t phi_buf[RSA_MAX_WORDS]; + uint32_t q_buf[RSA_MAX_WORDS / 2 + 1]; + + struct LITE_BIGNUM ONE; + struct LITE_BIGNUM e; + struct LITE_BIGNUM phi; + struct LITE_BIGNUM q_local; + + DCRYPTO_bn_wrap(&ONE, &ONE_buf, sizeof(ONE_buf)); + DCRYPTO_bn_wrap(&phi, phi_buf, bn_size(N)); + if (!q) { + /* q not provided, calculate it. */ + memcpy(phi_buf, N->d, bn_size(N)); + bn_init(&q_local, q_buf, bn_size(p)); + q = &q_local; + + if (!DCRYPTO_bn_div(q, NULL, &phi, p)) + return 0; + + /* Check that p * q == N */ + DCRYPTO_bn_mul(&phi, p, q); + if (!bn_eq(N, &phi)) + return 0; + } else { + DCRYPTO_bn_mul(N, p, q); + memcpy(phi_buf, N->d, bn_size(N)); + } + + bn_sub(&phi, p); + bn_sub(&phi, q); + bn_add(&phi, &ONE); + DCRYPTO_bn_wrap(&e, &e_buf, sizeof(e_buf)); + return bn_modinv_vartime(d, &e, &phi); +} diff --git a/board/cr50/dcrypto/sha1.c b/board/cr50/dcrypto/sha1.c new file mode 100644 index 0000000000..07ef3a34ef --- /dev/null +++ b/board/cr50/dcrypto/sha1.c @@ -0,0 +1,65 @@ +/* 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 "cryptoc/sha.h" + +static void dcrypto_sha1_init(SHA_CTX *ctx); +static const uint8_t *dcrypto_sha1_final(SHA_CTX *unused); + +/* + * Hardware SHA implementation. + */ +static const HASH_VTAB HW_SHA1_VTAB = { + dcrypto_sha1_init, + dcrypto_sha_update, + dcrypto_sha1_final, + DCRYPTO_SHA1_hash, + SHA_DIGEST_SIZE +}; + +/* Requires dcrypto_grab_sha_hw() to be called first. */ +static void dcrypto_sha1_init(SHA_CTX *ctx) +{ + ctx->f = &HW_SHA1_VTAB; + dcrypto_sha_init(SHA1_MODE); +} + +/* 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(SHA_CTX *ctx, uint32_t sw_required) +{ + if (!sw_required && dcrypto_grab_sha_hw()) + dcrypto_sha1_init(ctx); + else + SHA_init(ctx); +} + +static const uint8_t *dcrypto_sha1_final(SHA_CTX *ctx) +{ + dcrypto_sha_wait(SHA1_MODE, (uint32_t *) ctx->buf); + return ctx->buf; +} + +const uint8_t *DCRYPTO_SHA1_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(SHA1_MODE, data, n, digest); + else + SHA_hash(data, n, digest); + return digest; +} diff --git a/board/cr50/dcrypto/sha256.c b/board/cr50/dcrypto/sha256.c new file mode 100644 index 0000000000..f127ab445a --- /dev/null +++ b/board/cr50/dcrypto/sha256.c @@ -0,0 +1,195 @@ +/* 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" + +#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) +{ + 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) ? + 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(); +} + +/* 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) +{ + 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 void *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) +{ + 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; +} + +static void dcrypto_sha256_init(LITE_SHA256_CTX *ctx) +{ + ctx->f = &HW_SHA256_VTAB; + dcrypto_sha_init(SHA256_MODE); +} + +/* 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 +} + +static const uint8_t *dcrypto_sha256_final(LITE_SHA256_CTX *ctx) +{ + dcrypto_sha_wait(SHA256_MODE, (uint32_t *) ctx->buf); + return ctx->buf; +} + +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 + return digest; +} diff --git a/board/cr50/dcrypto/sha384.c b/board/cr50/dcrypto/sha384.c new file mode 100644 index 0000000000..6f3c6ca096 --- /dev/null +++ b/board/cr50/dcrypto/sha384.c @@ -0,0 +1,20 @@ +/* Copyright 2016 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 "cryptoc/sha384.h" + +void DCRYPTO_SHA384_init(LITE_SHA512_CTX *ctx) +{ + SHA384_init(ctx); +} + +const uint8_t *DCRYPTO_SHA384_hash(const void *data, uint32_t n, + uint8_t *digest) +{ + return SHA384_hash(data, n, digest); +} diff --git a/board/cr50/dcrypto/sha512.c b/board/cr50/dcrypto/sha512.c new file mode 100644 index 0000000000..1446970174 --- /dev/null +++ b/board/cr50/dcrypto/sha512.c @@ -0,0 +1,20 @@ +/* Copyright 2016 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 "cryptoc/sha512.h" + +void DCRYPTO_SHA512_init(LITE_SHA512_CTX *ctx) +{ + SHA512_init(ctx); +} + +const uint8_t *DCRYPTO_SHA512_hash(const void *data, uint32_t n, + uint8_t *digest) +{ + return SHA512_hash(data, n, digest); +} diff --git a/board/cr50/dcrypto/trng.c b/board/cr50/dcrypto/trng.c new file mode 100644 index 0000000000..94363b29c4 --- /dev/null +++ b/board/cr50/dcrypto/trng.c @@ -0,0 +1,236 @@ +/* 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 "common.h" +#include "flash_log.h" +#include "init_chip.h" +#include "registers.h" +#include "trng.h" +#include "watchdog.h" +#include "console.h" + +/** + * The H1 TRNG uses the collapse time of a ring oscillator (RO) that is + * initialized in a 3x mode (three enable pulses) and eventually collapses + * to a stable 1x mode as a result of accumulated jitter (thermal noise). + * A Phase-Frequency Detector (PFD) compares the 3x RO to a reference + * RO (1.5x) and captures the state of a counter that is incremented + * from the reference RO. The resulting reference-cycles-to-collapse + * distribution is log-normal, and truncation of the counter bits results in + * a distribution that approaches uniform. + * + * TRNG_SAMPLE_BITS defines how many bits to use from the 16 bit counter + * output coming from the analog unit. Entropy is highest in least significant + * bits of counter. For FIPS-certified code use just Bit 0 - it provides + * highest entropy, allows better security settings for TRNG and simplifies + * implementation of continuous health tests. + */ +#ifndef TRNG_SAMPLE_BITS +#define TRNG_SAMPLE_BITS 1 +#endif + +/** + * Attempts to read TRNG_EMPTY before reporting a stall. Practically data should + * be available in less than 0x7ff cycles under normal conditions. 0x7ff was + * chosen to match the hardware TRNG TIMEOUT_COUNTER. Test on boards with slow + * TRNG before reducing this number. + */ +#define TRNG_EMPTY_COUNT 0x7ff + +void init_trng(void) +{ +#if (!(defined(CONFIG_CUSTOMIZED_RO) && defined(SECTION_IS_RO))) + /* + * Most of the trng initialization requires high permissions. If RO has + * dropped the permission level, dont try to read or write these high + * permission registers because it will cause rolling reboots. RO + * should do the TRNG initialization before dropping the level. + */ + if (!runlevel_is_high()) + return; +#endif + /** + * According to NIST SP 800-90B only vetted conditioning mechanism + * should be used for post-processing raw entropy. + * See SP 800-90B, 3.1.5.1 Using Vetted Conditioning Components. + * Use of non-vetted algorithms is governed in 3.1.5.2, but + * assumes conservative coefficient 0.85 for entropy estimate, + * which increase number of requests to TRNG to get desirable + * entropy and prevents from getting full entropy. + */ + GWRITE(TRNG, POST_PROCESSING_CTRL, 0); + + /** + * TRNG can return up to 16 bits at a time, but highest bits + * have lower entropy. Practically on Cr50 only 13 bits can be + * used - setting to higher value makes TRNG_EMPTY always set. + * Entropy assessed to be reasonable (one bit H > 0.85) + * for up to 8 bits [7..0]. + * Time to get 32bit random is roughly 160/TRNG_SAMPLE_BITS us. + */ + GWRITE(TRNG, SLICE_MAX_UPPER_LIMIT, TRNG_SAMPLE_BITS - 1); + + /* lowest bit have highest entropy, so always start from it */ + GWRITE(TRNG, SLICE_MIN_LOWER_LIMIT, 0); + + /** + * Analog logic cannot create a value < 8 under normal operating + * conditions, but there's a chance that an attacker could coax + * them out. + * Bit 0 - Enable rejection for values outside of range specified + * by TRNG_ALLOWED_VALUES register + */ + GWRITE(TRNG, SECURE_POST_PROCESSING_CTRL, 0x1); + + /** + * Since for FIPS settings we use TRNG_SAMPLE_BITS = 1, + * and take only bit 0 from internal 16 bit reading, no bias is + * created for bit 0 if allowed_min is set to 6, which + * actually means min accepted value is 8 (RTL adds +2). + * TRNG_ALLOWED_VALUES_MAX=0x04 (accept all values up to 2^16-1). + * So, range will be [8..65535], with probability for bit 0 and 1 + * remaining 50/50. + */ + GWRITE(TRNG, ALLOWED_VALUES_MIN, 0x26); + + GWRITE(TRNG, TIMEOUT_COUNTER, 0x7ff); + GWRITE(TRNG, TIMEOUT_MAX_TRY_NUM, 4); + GWRITE(TRNG, POWER_DOWN_B, 1); + GWRITE(TRNG, GO_EVENT, 1); +} + +uint32_t rand(void) +{ uint32_t empty_count = 0; + + while (GREAD(TRNG, EMPTY)) { + if (GREAD_FIELD(TRNG, FSM_STATE, FSM_IDLE) || + empty_count > TRNG_EMPTY_COUNT) { + /* TRNG timed out, restart */ + GWRITE(TRNG, STOP_WORK, 1); +#if !defined(SECTION_IS_RO) && defined(CONFIG_FLASH_LOG) + flash_log_add_event(FE_LOG_TRNG_STALL, 0, NULL); +#endif + GWRITE(TRNG, GO_EVENT, 1); + empty_count = 0; + } + empty_count++; + } + return GREAD(TRNG, READ_DATA); +} + +void rand_bytes(void *buffer, size_t len) +{ + int random_togo = 0; + int buffer_index = 0; + uint32_t random_value; + uint8_t *buf = (uint8_t *) buffer; + + /* + * Retrieve random numbers in 4 byte quantities and pack as many bytes + * as needed into 'buffer'. If len is not divisible by 4, the + * remaining random bytes get dropped. + */ + while (buffer_index < len) { + if (!random_togo) { + random_value = rand(); + random_togo = sizeof(random_value); + } + buf[buffer_index++] = random_value >> + ((random_togo-- - 1) * 8); + } +} + +#if !defined(SECTION_IS_RO) && defined(CRYPTO_TEST_SETUP) +#include "console.h" +#include "watchdog.h" + +static void print_rand_stat(uint32_t *histogram, size_t size) +{ + struct pair { + uint32_t value; + uint32_t count; + }; + struct pair min; + struct pair max; + size_t count; + + min.count = ~0; + max.count = 0; + max.value = ~0; + min.value = ~0; + + for (count = 0; count < size; count++) { + if (histogram[count] > max.count) { + max.count = histogram[count]; + max.value = count; + } + if (histogram[count] < min.count) { + min.count = histogram[count]; + min.value = count; + } + } + + ccprintf("min %d(%d), max %d(%d)", min.count, min.value, + max.count, max.value); + + for (count = 0; count < size; count++) { + if (!(count % 8)) { + ccprintf("\n"); + cflush(); + } + ccprintf(" %6d", histogram[count]); + } + ccprintf("\n"); +} + +/* histogram at byte level */ +static uint32_t histogram[256]; +/* histogram at level of TRNG samples */ +static uint32_t histogram_trng[1 << TRNG_SAMPLE_BITS]; + +static int command_rand(int argc, char **argv) +{ + int count = 1000; /* Default number of cycles. */ + uint32_t val = 0, bits = 0; + + if (argc == 2) + count = strtoi(argv[1], NULL, 10); + + memset(histogram, 0, sizeof(histogram)); + memset(histogram_trng, 0, sizeof(histogram_trng)); + ccprintf("Retrieving %d 32-bit random words.\n", count); + while (count-- > 0) { + uint32_t rvalue; + int size; + + rvalue = rand(); + /* update byte-level histogram */ + for (size = 0; size < sizeof(rvalue); size++) + histogram[((uint8_t *)&rvalue)[size]]++; + + /* update histogram on TRNG sample size level */ + val = (val | (rvalue << bits)) & ((1 << TRNG_SAMPLE_BITS) - 1); + rvalue >>= TRNG_SAMPLE_BITS - bits; + bits += 32; + while (bits >= TRNG_SAMPLE_BITS) { + histogram_trng[val]++; + val = rvalue & ((1 << TRNG_SAMPLE_BITS) - 1); + rvalue >>= TRNG_SAMPLE_BITS; + bits -= TRNG_SAMPLE_BITS; + }; + + if (!(count % 10000)) + watchdog_reload(); + } + ccprintf("Byte-level histogram:\n"); + print_rand_stat(histogram, ARRAY_SIZE(histogram)); + ccprintf("\nSample-level (%d bits) histogram:\n", TRNG_SAMPLE_BITS); + print_rand_stat(histogram_trng, ARRAY_SIZE(histogram_trng)); + + return EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(rand, command_rand, NULL, NULL); + +#endif /* CRYPTO_TEST_SETUP */ diff --git a/board/cr50/dcrypto/x509.c b/board/cr50/dcrypto/x509.c new file mode 100644 index 0000000000..81f1674db1 --- /dev/null +++ b/board/cr50/dcrypto/x509.c @@ -0,0 +1,545 @@ +/* Copyright 2016 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 + +/* Limit the size of long form encoded objects to < 64 kB. */ +#define MAX_ASN1_OBJ_LEN_BYTES 3 + +/* Reserve space for TLV encoding */ +#define SEQ_SMALL 2 /* < 128 bytes (1B type, 1B 7-bit length) */ +#define SEQ_MEDIUM 3 /* < 256 bytes (1B type, 1B length size, 1B length) */ +#define SEQ_LARGE 4 /* < 65536 bytes (1B type, 1B length size, 2B length) */ + +/* Tag related constants. */ +enum { + V_ASN1_INT = 0x02, + V_ASN1_BIT_STRING = 0x03, + V_ASN1_BYTES = 0x04, + V_ASN1_OBJ = 0x06, + V_ASN1_UTF8 = 0x0c, + V_ASN1_SEQUENCE = 0x10, + V_ASN1_SET = 0x11, + V_ASN1_ASCII = 0x13, + V_ASN1_TIME = 0x18, + V_ASN1_CONSTRUCTED = 0x20, + /* short helpers */ + V_BITS = V_ASN1_BIT_STRING, + V_SEQ = V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE, + V_SET = V_ASN1_CONSTRUCTED | V_ASN1_SET, +}; + +struct asn1 { + uint8_t *p; + size_t n; +}; + + +#define SEQ_START(X, T, L) \ + do { \ + int __old = (X).n; \ + uint8_t __t = (T); \ + int __l = (L); \ + (X).n += __l; +#define SEQ_END(X) \ + (X).n = asn1_seq((X).p + __old, __t, __l, (X).n - __old - __l) + __old;\ + } \ + while (0) + +/* The SHA256 OID, from https://tools.ietf.org/html/rfc5754#section-3.2 + * Only the object bytes below, the DER encoding header ([0x30 0x0d]) + * is verified by the parser. */ +static const uint8_t OID_SHA256_WITH_RSA_ENCRYPTION[13] = { + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00 +}; +static const uint8_t OID_commonName[3] = {0x55, 0x04, 0x03}; +static const uint8_t OID_ecdsa_with_SHA256[8] = {0x2A, 0x86, 0x48, 0xCE, + 0x3D, 0x04, 0x03, 0x02}; +static const uint8_t OID_id_ecPublicKey[7] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, + 0x02, 0x01}; +static const uint8_t OID_prime256v1[8] = {0x2A, 0x86, 0x48, 0xCE, + 0x3D, 0x03, 0x01, 0x07}; +static const uint8_t OID_fido_u2f[11] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, + 0xE5, 0x1C, 0x02, 0x01, 0x01}; +#define OID(X) sizeof(OID_##X), OID_##X + +/* ---- ASN.1 Generation ---- */ + +/* start a tag and return write ptr */ +static uint8_t *asn1_tag(struct asn1 *ctx, uint8_t tag) +{ + ctx->p[(ctx->n)++] = tag; + return ctx->p + ctx->n; +} + +/* DER encode length and return encoded size thereof */ +static int asn1_len(uint8_t *p, size_t size) +{ + if (size < 128) { + p[0] = size; + return 1; + } else if (size < 256) { + p[0] = 0x81; + p[1] = size; + return 2; + } else { + p[0] = 0x82; + p[1] = size >> 8; + p[2] = size; + return 3; + } +} + +/* + * close sequence and move encapsulated data if needed + * return total length. + */ +static size_t asn1_seq(uint8_t *p, uint8_t tag, size_t l, size_t size) +{ + size_t tl; + + p[0] = tag; + tl = asn1_len(p + 1, size) + 1; + /* TODO: tl > l fail */ + if (tl < l) + memmove(p + tl, p + l, size); + + return tl + size; +} + +/* DER encode (small positive) integer */ +static void asn1_int(struct asn1 *ctx, uint32_t val) +{ + uint8_t *p = asn1_tag(ctx, V_ASN1_INT); + + if (!val) { + *p++ = 1; + *p++ = 0; + } else { + int nbits = 32 - __builtin_clz(val); + int nbytes = (nbits + 7) / 8; + + if ((nbits & 7) == 0) { + *p++ = nbytes + 1; + *p++ = 0; + } else { + *p++ = nbytes; + } + while (nbytes--) + *p++ = val >> (nbytes * 8); + } + + ctx->n = p - ctx->p; +} + +/* DER encode positive p256_int */ +static void asn1_p256_int(struct asn1 *ctx, const p256_int *n) +{ + uint8_t *p = asn1_tag(ctx, V_ASN1_INT); + uint8_t bn[P256_NBYTES]; + int i; + + p256_to_bin(n, bn); + for (i = 0; i < P256_NBYTES; ++i) { + if (bn[i] != 0) + break; + } + if (bn[i] & 0x80) { + *p++ = P256_NBYTES - i + 1; + *p++ = 0; + } else { + *p++ = P256_NBYTES - i; + } + for (; i < P256_NBYTES; ++i) + *p++ = bn[i]; + + ctx->n = p - ctx->p; +} + +/* DER encode p256 signature */ +static void asn1_sig(struct asn1 *ctx, const p256_int *r, const p256_int *s) +{ + SEQ_START(*ctx, V_SEQ, SEQ_SMALL) { + asn1_p256_int(ctx, r); + asn1_p256_int(ctx, s); + } + SEQ_END(*ctx); +} + +/* DER encode printable string */ +static void asn1_string(struct asn1 *ctx, uint8_t tag, const char *s) +{ + uint8_t *p = asn1_tag(ctx, tag); + size_t n = strlen(s); + + p += asn1_len(p, n); + while (n--) + *p++ = *s++; + + ctx->n = p - ctx->p; +} + +/* DER encode bytes */ +static void asn1_object(struct asn1 *ctx, size_t n, const uint8_t *b) +{ + uint8_t *p = asn1_tag(ctx, V_ASN1_OBJ); + + p += asn1_len(p, n); + while (n--) + *p++ = *b++; + + ctx->n = p - ctx->p; +} + +/* DER encode p256 pk */ +static void asn1_pub(struct asn1 *ctx, const p256_int *x, const p256_int *y) +{ + uint8_t *p = asn1_tag(ctx, 4); /* uncompressed format */ + + p256_to_bin(x, p); p += P256_NBYTES; + p256_to_bin(y, p); p += P256_NBYTES; + + ctx->n = p - ctx->p; +} + +size_t DCRYPTO_asn1_sigp(uint8_t *buf, const p256_int *r, const p256_int *s) +{ + struct asn1 asn1 = {buf, 0}; + + asn1_sig(&asn1, r, s); + return asn1.n; +} + +size_t DCRYPTO_asn1_pubp(uint8_t *buf, const p256_int *x, const p256_int *y) +{ + struct asn1 asn1 = {buf, 0}; + + asn1_pub(&asn1, x, y); + return asn1.n; +} + +/* ---- ASN.1 Parsing ---- */ + +/* + * An ASN.1 DER (Definite Encoding Rules) parser. + * Details about the format are available here: + * https://en.wikipedia.org/wiki/X.690#Definite_form + */ +static size_t asn1_parse(const uint8_t **p, size_t available, + uint8_t expected_type, const uint8_t **out, + size_t *out_len, size_t *remaining) +{ + const size_t tag_len = 1; + const uint8_t *in = *p; + size_t obj_len = 0; + size_t obj_len_bytes; + size_t consumed; + + if (available < 2) + return 0; + if (in[0] != expected_type) /* in[0] specifies the tag. */ + return 0; + + if ((in[1] & 128) == 0) { + /* Short-length encoding (i.e. obj_len <= 127). */ + obj_len = in[1]; + obj_len_bytes = 1; + } else { + int i; + + obj_len_bytes = 1 + (in[1] & 127); + if (obj_len_bytes > MAX_ASN1_OBJ_LEN_BYTES || + tag_len + obj_len_bytes > available) + return 0; + + if (in[2] == 0) + /* Definite form encoding requires minimal + * length encoding. */ + return 0; + for (i = 0; i < obj_len_bytes - 1; i++) { + obj_len <<= 8; + obj_len |= in[tag_len + 1 + i]; + } + } + + consumed = tag_len + obj_len_bytes + obj_len; + if (consumed > available) + return 0; /* Invalid object length.*/ + if (out) + *out = &in[tag_len + obj_len_bytes]; + if (out_len) + *out_len = obj_len; + + *p = in + consumed; + if (remaining) + *remaining = available - consumed; + return consumed; +} + +static size_t asn1_parse_certificate(const uint8_t **p, size_t *available) +{ + size_t consumed; + size_t obj_len; + const uint8_t *in = *p; + + consumed = asn1_parse(&in, *available, + V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE, + NULL, &obj_len, NULL); + if (consumed == 0 || consumed != *available) /* Invalid SEQUENCE. */ + return 0; + *p += consumed - obj_len; + *available -= consumed - obj_len; + return 1; +} + +static size_t asn1_parse_tbs(const uint8_t **p, size_t *available, + size_t *tbs_len) +{ + size_t consumed; + + consumed = asn1_parse(p, *available, + V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE, + NULL, NULL, available); + if (consumed == 0) + return 0; + *tbs_len = consumed; + return 1; +} + +static size_t asn1_parse_signature_algorithm(const uint8_t **p, + size_t *available) +{ + const uint8_t *alg_oid; + size_t alg_oid_len; + + if (!asn1_parse(p, *available, V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE, + &alg_oid, &alg_oid_len, available)) + return 0; + if (alg_oid_len != sizeof(OID_SHA256_WITH_RSA_ENCRYPTION)) + return 0; + if (memcmp(alg_oid, OID_SHA256_WITH_RSA_ENCRYPTION, + sizeof(OID_SHA256_WITH_RSA_ENCRYPTION)) != 0) + return 0; + return 1; +} + +static size_t asn1_parse_signature_value(const uint8_t **p, size_t *available, + const uint8_t **sig, size_t *sig_len) +{ + if (!asn1_parse(p, *available, V_ASN1_BIT_STRING, + sig, sig_len, available)) + return 0; + if (*available != 0) + return 0; /* Not all input bytes consumed. */ + return 1; +} + +/* This method verifies that the provided X509 certificate was issued + * by the specified certifcate authority. + * + * cert is a pointer to a DER encoded X509 certificate, as specified + * in https://tools.ietf.org/html/rfc5280#section-4.1. In ASN.1 + * notation, the certificate has the following structure: + * + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + * + * TBSCertificate ::= SEQUENCE { } + * AlgorithmIdentifier ::= SEQUENCE { } + * + * where signatureValue = SIGN(HASH(tbsCertificate)), with SIGN and + * HASH specified by signatureAlgorithm. + */ +int DCRYPTO_x509_verify(const uint8_t *cert, size_t len, + const struct RSA *ca_pub_key) +{ + const uint8_t *p = cert; + const uint8_t *tbs; + size_t tbs_len; + const uint8_t *sig; + size_t sig_len; + + uint8_t digest[SHA256_DIGEST_SIZE]; + + /* Read Certificate SEQUENCE. */ + if (!asn1_parse_certificate(&p, &len)) + return 0; + + /* Read tbsCertificate SEQUENCE. */ + tbs = p; + if (!asn1_parse_tbs(&p, &len, &tbs_len)) + return 0; + + /* Read signatureAlgorithm SEQUENCE. */ + if (!asn1_parse_signature_algorithm(&p, &len)) + return 0; + + /* Read signatureValue BIT STRING. */ + if (!asn1_parse_signature_value(&p, &len, &sig, &sig_len)) + return 0; + + /* Check that the signature length corresponds to the issuer's + * public key size. */ + if (sig_len != bn_size(&ca_pub_key->N) && + sig_len != bn_size(&ca_pub_key->N) + 1) + return 0; + /* Check that leading signature bytes (if any) are zero. */ + if (sig_len == bn_size(&ca_pub_key->N) + 1) { + if (sig[0] != 0) + return 0; + sig++; + sig_len--; + } + + DCRYPTO_SHA256_hash(tbs, tbs_len, digest); + return DCRYPTO_rsa_verify(ca_pub_key, digest, sizeof(digest), + sig, sig_len, PADDING_MODE_PKCS1, HASH_SHA256); +} + +/* ---- Certificate generation ---- */ + +static void add_common_name(struct asn1 *ctx, const char *cname) +{ + SEQ_START(*ctx, V_SEQ, SEQ_SMALL) { + SEQ_START(*ctx, V_SET, SEQ_SMALL) { + SEQ_START(*ctx, V_SEQ, SEQ_SMALL) { + asn1_object(ctx, OID(commonName)); + asn1_string(ctx, V_ASN1_ASCII, cname); + } + SEQ_END(*ctx); + } + SEQ_END(*ctx); + } + SEQ_END(*ctx); +} + +int DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x, + const p256_int *pk_y, const p256_int *serial, + const char *name, uint8_t *cert, const int n) +{ + struct asn1 ctx = {cert, 0}; + HASH_CTX sha; + p256_int h, r, s; + struct drbg_ctx drbg; + + SEQ_START(ctx, V_SEQ, SEQ_LARGE) { /* outer seq */ + /* + * Grab current pointer to data to hash later. + * Note this will fail if cert body + cert sign is less + * than 256 bytes (SEQ_MEDIUM) -- not likely. + */ + uint8_t *body = ctx.p + ctx.n; + + /* Cert body seq */ + SEQ_START(ctx, V_SEQ, SEQ_MEDIUM) { + /* X509 v3 */ + SEQ_START(ctx, 0xa0, SEQ_SMALL) { + asn1_int(&ctx, 2); + } + SEQ_END(ctx); + + /* Serial number */ + if (serial) + asn1_p256_int(&ctx, serial); + else + asn1_int(&ctx, 1); + + /* Signature algo */ + SEQ_START(ctx, V_SEQ, SEQ_SMALL) { + asn1_object(&ctx, OID(ecdsa_with_SHA256)); + } + SEQ_END(ctx); + + /* Issuer */ + add_common_name(&ctx, name); + + /* Expiry */ + SEQ_START(ctx, V_SEQ, SEQ_SMALL) { + asn1_string(&ctx, V_ASN1_TIME, "20000101000000Z"); + asn1_string(&ctx, V_ASN1_TIME, "20991231235959Z"); + } + SEQ_END(ctx); + + /* Subject */ + add_common_name(&ctx, name); + + /* Subject pk */ + SEQ_START(ctx, V_SEQ, SEQ_SMALL) { + /* pk parameters */ + SEQ_START(ctx, V_SEQ, SEQ_SMALL) { + asn1_object(&ctx, OID(id_ecPublicKey)); + asn1_object(&ctx, OID(prime256v1)); + } + SEQ_END(ctx); + /* pk bits */ + SEQ_START(ctx, V_BITS, SEQ_SMALL) { + /* No unused bit at the end */ + asn1_tag(&ctx, 0); + asn1_pub(&ctx, pk_x, pk_y); + } + SEQ_END(ctx); + } + SEQ_END(ctx); + + /* U2F transports indicator extension */ + SEQ_START(ctx, 0xa3, SEQ_SMALL) { + SEQ_START(ctx, V_SEQ, SEQ_SMALL) { + SEQ_START(ctx, V_SEQ, SEQ_SMALL) { + asn1_object(&ctx, OID(fido_u2f)); + SEQ_START(ctx, V_ASN1_BYTES, SEQ_SMALL) { + SEQ_START(ctx, V_BITS, SEQ_SMALL) { + /* 3 zero bits */ + asn1_tag(&ctx, 3); + /* usb-internal transport */ + asn1_tag(&ctx, 0x08); + } + SEQ_END(ctx); + } + SEQ_END(ctx); + } + SEQ_END(ctx); + } + SEQ_END(ctx); + } + SEQ_END(ctx); + } + SEQ_END(ctx); /* Cert body */ + + /* Sign all of cert body */ + DCRYPTO_SHA256_init(&sha, 0); + HASH_update(&sha, body, (ctx.p + ctx.n) - body); + p256_from_bin(HASH_final(&sha), &h); + hmac_drbg_init_rfc6979(&drbg, d, &h); + if (!dcrypto_p256_ecdsa_sign(&drbg, d, &h, &r, &s)) + return 0; + + /* Append X509 signature */ + SEQ_START(ctx, V_SEQ, SEQ_SMALL); + asn1_object(&ctx, OID(ecdsa_with_SHA256)); + SEQ_END(ctx); + SEQ_START(ctx, V_BITS, SEQ_SMALL) { + /* no unused/zero bit at the end */ + asn1_tag(&ctx, 0); + asn1_sig(&ctx, &r, &s); + } SEQ_END(ctx); + + } SEQ_END(ctx); /* end of outer seq */ + + return ctx.n; +} + +int DCRYPTO_x509_gen_u2f_cert(const p256_int *d, const p256_int *pk_x, + const p256_int *pk_y, const p256_int *serial, + uint8_t *cert, const int n) +{ + return DCRYPTO_x509_gen_u2f_cert_name(d, pk_x, pk_y, serial, + serial ? STRINGIFY(BOARD) : "U2F", + cert, n); +} diff --git a/chip/g/dcrypto/aes.c b/chip/g/dcrypto/aes.c deleted file mode 100644 index f5cc0e6d8f..0000000000 --- a/chip/g/dcrypto/aes.c +++ /dev/null @@ -1,160 +0,0 @@ -/* 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; -} diff --git a/chip/g/dcrypto/aes_cmac.c b/chip/g/dcrypto/aes_cmac.c deleted file mode 100644 index 4f996f42b6..0000000000 --- a/chip/g/dcrypto/aes_cmac.c +++ /dev/null @@ -1,346 +0,0 @@ -/* Copyright 2018 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. - */ - -/* AES-CMAC-128 implementation according to NIST SP 800-38B, RFC4493 */ -#include "console.h" -#include "dcrypto.h" - -#define BSIZE 16 /* 16 bytes per 128-bit block */ - -/* Given a 128-bit number in 32-bit chunks, shift to the left by one */ -static void shiftl_1(const uint8_t *in, uint8_t *out) -{ - int i; - uint8_t carry = 0; - - for (i = 15; i >= 0; i--) { - out[i] = in[i] << 1; - out[i] |= carry; - carry = (in[i] & 0x80) ? 1 : 0; - } -} - -static void xor128(const uint32_t in1[4], const uint32_t in2[4], - uint32_t out[4]) -{ - int i; - - for (i = 0; i < 4; i++) - out[i] = in1[i] ^ in2[i]; -} - -static void get_and_xor(const uint8_t *arr, const uint32_t nBytes, int i, - const uint8_t *xor_term, uint8_t *out) -{ - int j; - int k; - - for (j = 0; j < 16; j++) { - k = i*16 + j; /* index in arr */ - if (k < nBytes) - out[j] = arr[k]; - else if (k == nBytes) - out[j] = 0x80; - else - out[j] = 0; - out[j] = out[j] ^ xor_term[j]; - } -} - -/* Wrapper for initializing and calling AES-128 */ -static int aes128(const uint8_t *K, const uint32_t in[4], uint32_t out[4]) -{ - const uint32_t zero[4] = {0, 0, 0, 0}; - - if (!DCRYPTO_aes_init((const uint8_t *)K, 128, (const uint8_t *) zero, - CIPHER_MODE_ECB, ENCRYPT_MODE)) - return 0; - if (!DCRYPTO_aes_block((const uint8_t *) in, (uint8_t *) out)) - return 0; - return 1; -} - -static int gen_subkey(const uint8_t *K, uint32_t k1[4], uint32_t k2[4]) -{ - uint32_t L[4]; - uint32_t tmp[4]; - const uint32_t *xor_term; - static const uint32_t zero[4] = {0, 0, 0, 0}; - static const uint32_t Rb[4] = {0, 0, 0, 0x87000000}; - - if (!aes128(K, zero, L)) - return 0; - - xor_term = (L[0] & 0x00000080) ? Rb : zero; - shiftl_1((const uint8_t *)L, (uint8_t *)tmp); - xor128(tmp, xor_term, k1); - - xor_term = (k1[0] & 0x00000080) ? Rb : zero; - shiftl_1((const uint8_t *) k1, (uint8_t *) tmp); - xor128(tmp, xor_term, k2); - - return 1; -} - -int DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, const uint32_t len, - uint32_t T[4]) -{ - uint32_t n; - int i; - int flag; - uint32_t k1[4]; - uint32_t k2[4]; - uint32_t M_last[4]; - uint32_t Y[4]; - uint32_t X[4] = {0, 0, 0, 0}; - - /* Generate the subkeys K1 and K2 */ - if (!gen_subkey(K, k1, k2)) - return 0; - - /* Set n and flag. - * flag = 1 if the last block has a full 128 bits; 0 otherwise - * n = number of 128-bit blocks in input = ceil (len / BSIZE) - * - * Special case: if len = 0, then n = 1 and flag = 0. - */ - flag = (len % BSIZE == 0) ? 1 : 0; - n = len / BSIZE + (flag ? 0 : 1); // ceil (len / BSIZE) - if (len == 0) { - n = 1; - flag = 0; - } - - /* M_last = padded(last 128-bit block of M) ^ (flag ? k1 : k2) */ - get_and_xor(M, len, n-1, (uint8_t *) (flag ? k1 : k2), - (uint8_t *) M_last); - - for (i = 0; i < n - 1; i++) { - /* Y = padded(nth 128-bit block of M) ^ (flag ? k1 : k2) */ - get_and_xor(M, len, i, (uint8_t *)X, (uint8_t *)Y); - if (!aes128(K, Y, X)) - return 0; - } - - /* TODO: This block is separate from the main loop in the RFC. However, - * if we set M[n-1] = M_last, then it is equivalent to running the loop - * for one more step, which might be a nicer way to write it. - */ - xor128(X, M_last, Y); - if (!aes128(K, Y, T)) - return 0; - return 1; -} - -int DCRYPTO_aes_cmac_verify(const uint8_t *key, const uint8_t *M, const int len, - const uint32_t T[4]) -{ - int i; - uint32_t T2[4]; - int match = 1; - - if (!DCRYPTO_aes_cmac(key, M, len, T2)) - return -EC_ERROR_UNKNOWN; - - for (i = 0; i < 4; i++) { - if (T[i] != T2[i]) - match = 0; - } - return match; -} - -#ifdef CRYPTO_TEST_SETUP -static int check_answer(const uint32_t expected[4], uint32_t actual[4]) -{ - int i; - int success = 1; - - for (i = 0; i < 4; i++) { - if (actual[i] != expected[i]) - success = 0; - } - if (success) { - ccprintf("SUCCESS\n"); - } else { - ccprintf("FAILURE:\n"); - ccprintf("actual = 0x%08x 0x%08x 0x%08x 0x%08x\n", actual[0], - actual[1], actual[2], actual[3]); - ccprintf("expected = 0x%08x 0x%08x 0x%08x 0x%08x\n", - expected[0], expected[1], expected[2], expected[3]); - } - return success; -} - -static int command_test_aes_block(int argc, char **argv) -{ - uint32_t actual[4]; - const uint32_t zero[4] = {0, 0, 0, 0}; - const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09}; - const uint32_t expected[4] = {0x0c6bf77d, 0xb399b81a, 0x47f0423e, - 0x6f541bb9}; - - aes128((const uint8_t *) K, zero, actual); - check_answer(expected, actual); - - return 0; -} - -DECLARE_SAFE_CONSOLE_COMMAND(test_aesbk, command_test_aes_block, NULL, - "Test AES block in AES-CMAC subkey generation"); - -static int command_test_subkey_gen(int argc, char **argv) -{ - uint32_t k1[4]; - uint32_t k2[4]; - /* K: 2b7e1516 28aed2a6 abf71588 09cf4f3c - * k1: fbeed618 35713366 7c85e08f 7236a8de - * k2: f7ddac30 6ae266cc f90bc11e e46d513b - */ - const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09}; - const uint32_t k1e[4] = {0x18d6eefb, 0x66337135, 0x8fe0857c, - 0xdea83672}; - const uint32_t k2e[4] = {0x30acddf7, 0xcc66e26a, 0x1ec10bf9, - 0x3b516de4}; - - gen_subkey((const uint8_t *) K, k1, k2); - - ccprintf("Checking K1: "); - check_answer(k1e, k1); - - ccprintf("Checking K2: "); - check_answer(k2e, k2); - - return 0; -} - -DECLARE_SAFE_CONSOLE_COMMAND(test_skgen, command_test_subkey_gen, NULL, - "Test AES-CMAC subkey generation"); - -struct cmac_test_param { - uint32_t len; - uint8_t *M; - uint32_t Te[4]; -}; - -/* N.B. The order of bytes in each 32-bit block is reversed from the form in - * which they are written in the RFC. - */ -const struct cmac_test_param rfctests[4] = { - /* -------------------------------------------------- - * Example 1: len = 0 - * M - * AES-CMAC bb1d6929 e9593728 7fa37d12 9b756746 - * -------------------------------------------------- - */ - { .len = 0, - .M = (uint8_t *) "", - .Te = {0x29691dbb, 0x283759e9, 0x127da37f, 0x4667759b}, - }, - /* -------------------------------------------------- - * Example 2: len = 16 - * M 6bc1bee2 2e409f96 e93d7e11 7393172a - * AES-CMAC 070a16b4 6b4d4144 f79bdd9d d04a287c - * -------------------------------------------------- - */ - { .len = 16, - .M = (uint8_t *) (uint32_t[]) { - 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373 - }, - .Te = {0xb4160a07, 0x44414d6b, 0x9ddd9bf7, 0x7c284ad0}, - }, - /* -------------------------------------------------- - * Example 3: len = 40 - * M 6bc1bee2 2e409f96 e93d7e11 7393172a - * ae2d8a57 1e03ac9c 9eb76fac 45af8e51 - * 30c81c46 a35ce411 - * AES-CMAC dfa66747 de9ae630 30ca3261 1497c827 - * -------------------------------------------------- - */ - { .len = 40, - .M = (uint8_t *) (uint32_t[]) { - 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373, - 0x578a2dae, 0x9cac031e, 0xac6fb79e, 0x518eaf45, - 0x461cc830, 0x11e45ca3 - }, - .Te = {0x4767a6df, 0x30e69ade, 0x6132ca30, 0x27c89714}, - }, - /* -------------------------------------------------- - * Example 4: len = 64 - * M 6bc1bee2 2e409f96 e93d7e11 7393172a - * ae2d8a57 1e03ac9c 9eb76fac 45af8e51 - * 30c81c46 a35ce411 e5fbc119 1a0a52ef - * f69f2445 df4f9b17 ad2b417b e66c3710 - * AES-CMAC 51f0bebf 7e3b9d92 fc497417 79363cfe - * -------------------------------------------------- - */ - { .len = 64, - .M = (uint8_t *) (uint32_t[]) { - 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373, - 0x578a2dae, 0x9cac031e, 0xac6fb79e, 0x518eaf45, - 0x461cc830, 0x11e45ca3, 0x19c1fbe5, 0xef520a1a, - 0x45249ff6, 0x179b4fdf, 0x7b412bad, 0x10376ce6 - }, - .Te = {0xbfbef051, 0x929d3b7e, 0x177449fc, 0xfe3c3679}, - }, -}; - -static int command_test_aes_cmac(int argc, char **argv) -{ - int i; - uint32_t T[4]; - int testN; - struct cmac_test_param param; - const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09}; - - for (i = 1; i < argc; i++) { - testN = strtoi(argv[i], NULL, 10); - param = rfctests[testN - 1]; - - ccprintf("Testing RFC Example #%d (%d-byte message)...", testN, - param.len); - - DCRYPTO_aes_cmac((const uint8_t *)K, param.M, param.len, T); - check_answer(param.Te, T); - } - - return 0; -} - -DECLARE_SAFE_CONSOLE_COMMAND(test_cmac, command_test_aes_cmac, - "[test cases (1-4)]", - "Test AES-CMAC with RFC examples"); - -static int command_test_verify(int argc, char **argv) -{ - int i; - int testN; - int result; - struct cmac_test_param param; - const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09}; - - for (i = 1; i < argc; i++) { - testN = strtoi(argv[i], NULL, 10); - param = rfctests[testN-1]; - - ccprintf("Testing RFC Example #%d (%d-byte message)...", testN, - param.len); - - result = DCRYPTO_aes_cmac_verify((const uint8_t *)K, param.M, - param.len, param.Te); - if (result == 1) - ccprintf("SUCCESS\n"); - else if (result == 0) - ccprintf("FAILURE: verify returned INVALID\n"); - else if (result == -EC_ERROR_UNKNOWN) - ccprintf("FAILURE: verify returned ERROR\n"); - } - - return 0; -} - -DECLARE_SAFE_CONSOLE_COMMAND(test_cmac_ver, command_test_verify, - "[test cases (1-4)]", - "Test AES-CMAC-verify with RFC examples"); -#endif /* CRYPTO_TEST_SETUP */ diff --git a/chip/g/dcrypto/app_cipher.c b/chip/g/dcrypto/app_cipher.c deleted file mode 100644 index 125b443ee6..0000000000 --- a/chip/g/dcrypto/app_cipher.c +++ /dev/null @@ -1,451 +0,0 @@ -/* - * Copyright 2017 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 "registers.h" - -/* The default build options compile for size (-Os); instruct the - * compiler to optimize for speed here. Incidentally -O produces - * faster code than -O2! - */ -static int __attribute__((optimize("O"))) -inner_loop(uint32_t **out, const uint32_t **in, size_t len) -{ - uint32_t *outw = *out; - const uint32_t *inw = *in; - - while (len >= 16) { - uint32_t w0, w1, w2, w3; - - w0 = inw[0]; - w1 = inw[1]; - w2 = inw[2]; - w3 = inw[3]; - GREG32(KEYMGR, AES_WFIFO_DATA) = w0; - GREG32(KEYMGR, AES_WFIFO_DATA) = w1; - GREG32(KEYMGR, AES_WFIFO_DATA) = w2; - GREG32(KEYMGR, AES_WFIFO_DATA) = w3; - - while (GREG32(KEYMGR, AES_RFIFO_EMPTY)) - ; - - w0 = GREG32(KEYMGR, AES_RFIFO_DATA); - w1 = GREG32(KEYMGR, AES_RFIFO_DATA); - w2 = GREG32(KEYMGR, AES_RFIFO_DATA); - w3 = GREG32(KEYMGR, AES_RFIFO_DATA); - outw[0] = w0; - outw[1] = w1; - outw[2] = w2; - outw[3] = w3; - - inw += 4; - outw += 4; - len -= 16; - } - - *in = inw; - *out = outw; - return len; -} - -static int outer_loop(uint32_t **out, const uint32_t **in, size_t len) -{ - uint32_t *outw = *out; - const uint32_t *inw = *in; - - if (len >= 16) { - GREG32(KEYMGR, AES_WFIFO_DATA) = inw[0]; - GREG32(KEYMGR, AES_WFIFO_DATA) = inw[1]; - GREG32(KEYMGR, AES_WFIFO_DATA) = inw[2]; - GREG32(KEYMGR, AES_WFIFO_DATA) = inw[3]; - inw += 4; - len -= 16; - - len = inner_loop(&outw, &inw, len); - - while (GREG32(KEYMGR, AES_RFIFO_EMPTY)) - ; - - outw[0] = GREG32(KEYMGR, AES_RFIFO_DATA); - outw[1] = GREG32(KEYMGR, AES_RFIFO_DATA); - outw[2] = GREG32(KEYMGR, AES_RFIFO_DATA); - outw[3] = GREG32(KEYMGR, AES_RFIFO_DATA); - outw += 4; - } - - *in = inw; - *out = outw; - return len; -} - -static int aes_init(struct APPKEY_CTX *ctx, enum dcrypto_appid appid, - const uint32_t iv[4]) -{ - /* Setup USR-based application key. */ - if (!DCRYPTO_appkey_init(appid, ctx)) - return 0; - - /* Configure AES engine. */ - GWRITE_FIELD(KEYMGR, AES_CTRL, RESET, CTRL_NO_SOFT_RESET); - GWRITE_FIELD(KEYMGR, AES_CTRL, KEYSIZE, 2 /* AES-256 */); - GWRITE_FIELD(KEYMGR, AES_CTRL, CIPHER_MODE, CIPHER_MODE_CTR); - GWRITE_FIELD(KEYMGR, AES_CTRL, ENC_MODE, ENCRYPT_MODE); - GWRITE_FIELD(KEYMGR, AES_CTRL, CTR_ENDIAN, CTRL_CTR_BIG_ENDIAN); - - /* - * For fixed-key, bulk ciphering, turn off random nops (which - * are enabled by default). - */ - GWRITE_FIELD(KEYMGR, AES_RAND_STALL_CTL, STALL_EN, 0); - - /* Enable hidden key usage, each appid gets its own - * USR, with USR0 starting at 0x2a0. - */ - GWRITE_FIELD(KEYMGR, AES_USE_HIDDEN_KEY, INDEX, - 0x2a0 + (appid * 2)); - GWRITE_FIELD(KEYMGR, AES_USE_HIDDEN_KEY, ENABLE, 1); - GWRITE_FIELD(KEYMGR, AES_CTRL, ENABLE, CTRL_ENABLE); - - /* Wait for key-expansion. */ - GREG32(KEYMGR, AES_KEY_START) = 1; - while (GREG32(KEYMGR, AES_KEY_START)) - ; - - /* Check for errors (e.g. USR not correctly setup. */ - if (GREG32(KEYMGR, HKEY_ERR_FLAGS)) - return 0; - - /* Set IV. */ - GR_KEYMGR_AES_CTR(0) = iv[0]; - GR_KEYMGR_AES_CTR(1) = iv[1]; - GR_KEYMGR_AES_CTR(2) = iv[2]; - GR_KEYMGR_AES_CTR(3) = iv[3]; - - return 1; -} - -int DCRYPTO_app_cipher(enum dcrypto_appid appid, const void *salt, - void *out, const void *in, size_t len) -{ - struct APPKEY_CTX ctx; - const uint32_t *inw = in; - uint32_t *outw = out; - - /* Test pointers for word alignment. */ - if (((uintptr_t) in & 0x03) || ((uintptr_t) out & 0x03)) - return 0; - - { - /* Initialize key, and AES engine. */ - uint32_t iv[4]; - - memcpy(iv, salt, sizeof(iv)); - if (!aes_init(&ctx, appid, iv)) - return 0; - } - - len = outer_loop(&outw, &inw, len); - - if (len) { - /* Cipher the final partial block */ - uint32_t tmpin[4]; - uint32_t tmpout[4]; - const uint32_t *tmpinw; - uint32_t *tmpoutw; - - tmpinw = tmpin; - tmpoutw = tmpout; - - memcpy(tmpin, inw, len); - outer_loop(&tmpoutw, &tmpinw, 16); - memcpy(outw, tmpout, len); - } - - DCRYPTO_appkey_finish(&ctx); - return 1; -} - -#ifdef CRYPTO_TEST_SETUP - -#include "common.h" -#include "console.h" -#include "hooks.h" -#include "shared_mem.h" -#include "task.h" -#include "timer.h" -#include "watchdog.h" - -#define HEAP_HEAD_ROOM 0x400 -static uint32_t number_of_iterations; -static uint8_t result; - -/* Staticstics for ecrypt and decryp passes. */ -struct ciph_stats { - uint16_t min_time; - uint16_t max_time; - uint32_t total_time; -} __packed; /* Just in case. */ - -/* A common structure to contain information about the test run. */ -struct test_info { - size_t test_blob_size; - struct ciph_stats enc_stats; - struct ciph_stats dec_stats; - char *p; /* Pointer to an allcoated buffer of test_blob_size bytes. */ -}; - -static void init_stats(struct ciph_stats *stats) -{ - stats->min_time = ~0; - stats->max_time = 0; - stats->total_time = 0; -} - -static void update_stats(struct ciph_stats *stats, uint32_t time) -{ - if (time < stats->min_time) - stats->min_time = time; - - if (time > stats->max_time) - stats->max_time = time; - - stats->total_time += time; -} - -static void report_stats(const char *direction, struct ciph_stats *stats) -{ - ccprintf("%s results: min %d us, max %d us, average %d us\n", - direction, stats->min_time, stats->max_time, - stats->total_time / number_of_iterations); -} - -/* - * Prepare to run the test: allocate memory, initialize stats structures. - * - * Returns EC_SUCCESS if everything is fine, EC_ERROR_OVERFLOW on malloc - * failures. - */ -static int prepare_running(struct test_info *pinfo) -{ - memset(pinfo, 0, sizeof(*pinfo)); - - - pinfo->test_blob_size = shared_mem_size(); - /* - * Leave some room for crypto functions if they need to allocate - * something, just in case. 0x20 extra bytes are needed to be able to - * modify size alignment of the allocated buffer. - */ - if (pinfo->test_blob_size < (HEAP_HEAD_ROOM + 0x20)) { - ccprintf("Not enough memory to run the test\n"); - return EC_ERROR_OVERFLOW; - } - pinfo->test_blob_size = (pinfo->test_blob_size - HEAP_HEAD_ROOM); - - if (shared_mem_acquire(pinfo->test_blob_size, - (char **)&(pinfo->p)) != EC_SUCCESS) { - ccprintf("Failed to allocate %d bytes\n", - pinfo->test_blob_size); - return EC_ERROR_OVERFLOW; - } - - /* - * Use odd block size to make sure unaligned length blocks are handled - * properly. This leaves room in the end of the buffer to check if the - * decryption routine scratches it. - */ - pinfo->test_blob_size &= ~0x1f; - pinfo->test_blob_size |= 7; - - ccprintf("running %d iterations\n", number_of_iterations); - ccprintf("blob size %d at %pP\n", pinfo->test_blob_size, pinfo->p); - - init_stats(&(pinfo->enc_stats)); - init_stats(&(pinfo->dec_stats)); - - return EC_SUCCESS; -} - -/* - * Let's split the buffer in two equal halves, encrypt the lower half into the - * upper half and compare them word by word. There should be no repetitions. - * - * The side effect of this is starting the test with random clear text data. - * - * The first 16 bytes of the allocated buffer are used as the encryption IV. - */ -static int basic_check(struct test_info *pinfo) -{ - size_t half; - int i; - uint32_t *p; - - ccprintf("original data %ph\n", HEX_BUF(pinfo->p, 16)); - - half = (pinfo->test_blob_size/2) & ~3; - if (!DCRYPTO_app_cipher(NVMEM, pinfo->p, pinfo->p, - pinfo->p + half, half)) { - ccprintf("first ecnryption run failed\n"); - return EC_ERROR_UNKNOWN; - } - - p = (uint32_t *)pinfo->p; - half /= sizeof(*p); - - for (i = 0; i < half; i++) - if (p[i] == p[i + half]) { - ccprintf("repeating 32 bit word detected" - " at offset 0x%x!\n", i * 4); - return EC_ERROR_UNKNOWN; - } - - ccprintf("hashed data %ph\n", HEX_BUF(pinfo->p, 16)); - - return EC_SUCCESS; -} - -/* - * Main iteration of the console command, runs ecnryption/decryption cycles, - * vefifying that decrypted text's hash matches the original, and accumulating - * timing statistics. - */ -static int command_loop(struct test_info *pinfo) -{ - uint8_t sha[SHA_DIGEST_SIZE]; - uint8_t sha_after[SHA_DIGEST_SIZE]; - uint32_t iteration; - uint8_t *p_last_byte; - int rv; - - /* - * Prepare the hash of the original data to be able to verify - * results. - */ - DCRYPTO_SHA1_hash(pinfo->p, pinfo->test_blob_size, sha); - - /* Use the hash as an IV for the cipher. */ - memcpy(sha_after, sha, sizeof(sha_after)); - - iteration = number_of_iterations; - p_last_byte = pinfo->p + pinfo->test_blob_size; - - while (iteration--) { - char last_byte = (char) iteration; - uint32_t tstamp; - - *p_last_byte = last_byte; - - if (!(iteration % 500)) - watchdog_reload(); - - tstamp = get_time().val; - rv = DCRYPTO_app_cipher(NVMEM, sha_after, pinfo->p, - pinfo->p, pinfo->test_blob_size); - tstamp = get_time().val - tstamp; - - if (!rv) { - ccprintf("encryption failed\n"); - return EC_ERROR_UNKNOWN; - } - if (*p_last_byte != last_byte) { - ccprintf("encryption overflowed\n"); - return EC_ERROR_UNKNOWN; - } - update_stats(&pinfo->enc_stats, tstamp); - - tstamp = get_time().val; - rv = DCRYPTO_app_cipher(NVMEM, sha_after, pinfo->p, - pinfo->p, pinfo->test_blob_size); - tstamp = get_time().val - tstamp; - - if (!rv) { - ccprintf("decryption failed\n"); - return EC_ERROR_UNKNOWN; - } - if (*p_last_byte != last_byte) { - ccprintf("decryption overflowed\n"); - return EC_ERROR_UNKNOWN; - } - - DCRYPTO_SHA1_hash(pinfo->p, pinfo->test_blob_size, sha_after); - if (memcmp(sha, sha_after, sizeof(sha))) { - ccprintf("\n" - "sha1 before and after mismatch, %d to go!\n", - iteration); - return EC_ERROR_UNKNOWN; - } - - update_stats(&pinfo->dec_stats, tstamp); - - /* get a new IV */ - DCRYPTO_SHA1_hash(sha_after, sizeof(sha), sha_after); - } - - return EC_SUCCESS; -} - -/* - * Run cipher command on the hooks task context, as dcrypto's stack - * requirements exceed console tasks' allowance. - */ -static void run_cipher_cmd(void) -{ - struct test_info info; - - result = prepare_running(&info); - - if (result == EC_SUCCESS) - result = basic_check(&info); - - if (result == EC_SUCCESS) - result = command_loop(&info); - - if (result == EC_SUCCESS) { - report_stats("Encryption", &info.enc_stats); - report_stats("Decryption", &info.dec_stats); - } else if (info.p) { - ccprintf("current data %ph\n", HEX_BUF(info.p, 16)); - } - - if (info.p) - shared_mem_release(info.p); - - task_set_event(TASK_ID_CONSOLE, TASK_EVENT_CUSTOM_BIT(0), 0); -} -DECLARE_DEFERRED(run_cipher_cmd); - -static int cmd_cipher(int argc, char **argv) -{ - uint32_t events; - uint32_t max_time; - - /* Ignore potential input errors, let the user handle them. */ - if (argc > 1) - number_of_iterations = strtoi(argv[1], NULL, 0); - else - number_of_iterations = 1000; - - if (!number_of_iterations) { - ccprintf("not running zero iterations\n"); - return EC_ERROR_PARAM1; - } - - hook_call_deferred(&run_cipher_cmd_data, 0); - - /* Roughly, .5 us per byte should be more than enough. */ - max_time = number_of_iterations * shared_mem_size() / 2; - - ccprintf("Will wait up to %d ms\n", (max_time + 500)/1000); - - events = task_wait_event_mask(TASK_EVENT_CUSTOM_BIT(0), max_time); - if (!(events & TASK_EVENT_CUSTOM_BIT(0))) { - ccprintf("Timed out, you might want to reboot...\n"); - return EC_ERROR_TIMEOUT; - } - - return result; -} -DECLARE_SAFE_CONSOLE_COMMAND(cipher, cmd_cipher, NULL, NULL); -#endif diff --git a/chip/g/dcrypto/app_key.c b/chip/g/dcrypto/app_key.c deleted file mode 100644 index 1fafab9d2e..0000000000 --- a/chip/g/dcrypto/app_key.c +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright 2016 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 "endian.h" -#include "registers.h" - -#include "cryptoc/util.h" - -#include "console.h" - -const char *const dcrypto_app_names[] = { - "RESERVED", - "NVMEM", - "U2F_ATTEST", - "U2F_ORIGIN", - "U2F_WRAP", - /* This key signs data from H1's configured by mn50/scribe. */ - "PERSO_AUTH", - "PINWEAVER", -}; - -static void name_hash(enum dcrypto_appid appid, - uint32_t digest[SHA256_DIGEST_WORDS]) -{ - LITE_SHA256_CTX ctx; - const char *name = dcrypto_app_names[appid]; - size_t x; - - /* The PERSO_AUTH digest was improperly defined, so now this exception - * exists to prevent data loss. - */ - if (appid == PERSO_AUTH) { - digest[0] = 0x2019da34; - digest[1] = 0xf1a01a13; - digest[2] = 0x0fb9f73f; - digest[3] = 0xf2e85f76; - digest[4] = 0x5ecb7690; - digest[5] = 0x09f732c9; - digest[6] = 0xe540bf14; - digest[7] = 0xcc46799a; - return; - } - - DCRYPTO_SHA256_init(&ctx, 0); - HASH_update(&ctx, name, strlen(name)); - memcpy(digest, HASH_final(&ctx), SHA256_DIGEST_SIZE); - - /* The digests were originally endian swapped because xxd was used to - * print them so this operation is needed to keep the derived keys the - * same. Any changes to they key derivation process must result in the - * same keys being produced given the same inputs, or devices will - * effectively be reset and user data will be lost by the key change. - */ - for (x = 0; x < SHA256_DIGEST_WORDS; ++x) - digest[x] = __builtin_bswap32(digest[x]); -} - -int DCRYPTO_appkey_init(enum dcrypto_appid appid, struct APPKEY_CTX *ctx) -{ - uint32_t digest[SHA256_DIGEST_WORDS]; - - memset(ctx, 0, sizeof(*ctx)); - name_hash(appid, digest); - - if (!dcrypto_ladder_compute_usr(appid, digest)) - return 0; - - return 1; -} - -void DCRYPTO_appkey_finish(struct APPKEY_CTX *ctx) -{ - always_memset(ctx, 0, sizeof(struct APPKEY_CTX)); - GREG32(KEYMGR, AES_WIPE_SECRETS) = 1; -} - -int DCRYPTO_appkey_derive(enum dcrypto_appid appid, const uint32_t input[8], - uint32_t output[8]) -{ - uint32_t digest[SHA256_DIGEST_WORDS]; - - name_hash(appid, digest); - return !!dcrypto_ladder_derive(appid, digest, input, output); -} diff --git a/chip/g/dcrypto/bn.c b/chip/g/dcrypto/bn.c deleted file mode 100644 index 94aafa1799..0000000000 --- a/chip/g/dcrypto/bn.c +++ /dev/null @@ -1,1244 +0,0 @@ -/* 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. - */ - -#ifdef PRINT_PRIMES -#include "console.h" -#endif - -#include "dcrypto.h" -#include "internal.h" - -#include "trng.h" - -#include "cryptoc/util.h" - -#include - -#ifdef CONFIG_WATCHDOG -extern void watchdog_reload(void); -#else -static inline void watchdog_reload(void) { } -#endif - -void bn_init(struct LITE_BIGNUM *b, void *buf, size_t len) -{ - DCRYPTO_bn_wrap(b, buf, len); - always_memset(buf, 0x00, len); -} - -void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len) -{ - /* Only word-multiple sized buffers accepted. */ - assert((len & 0x3) == 0); - b->dmax = len / LITE_BN_BYTES; - b->d = (struct access_helper *) buf; -} - -int bn_eq(const struct LITE_BIGNUM *a, const struct LITE_BIGNUM *b) -{ - int i; - uint32_t top = 0; - - for (i = a->dmax - 1; i > b->dmax - 1; --i) - top |= BN_DIGIT(a, i); - if (top) - return 0; - - for (i = b->dmax - 1; i > a->dmax - 1; --i) - top |= BN_DIGIT(b, i); - if (top) - return 0; - - for (i = MIN(a->dmax, b->dmax) - 1; i >= 0; --i) - if (BN_DIGIT(a, i) != BN_DIGIT(b, i)) - return 0; - - return 1; -} - -static void bn_copy(struct LITE_BIGNUM *dst, const struct LITE_BIGNUM *src) -{ - dst->dmax = src->dmax; - memcpy(dst->d, src->d, bn_size(dst)); -} - -int bn_check_topbit(const struct LITE_BIGNUM *N) -{ - return BN_DIGIT(N, N->dmax - 1) >> 31; -} - -/* a[n]. */ -int bn_is_bit_set(const struct LITE_BIGNUM *a, int n) -{ - int i, j; - - if (n < 0) - return 0; - - i = n / LITE_BN_BITS2; - j = n % LITE_BN_BITS2; - if (a->dmax <= i) - return 0; - - return (BN_DIGIT(a, i) >> j) & 1; -} - -static int bn_set_bit(const struct LITE_BIGNUM *a, int n) -{ - int i, j; - - if (n < 0) - return 0; - - i = n / LITE_BN_BITS2; - j = n % LITE_BN_BITS2; - if (a->dmax <= i) - return 0; - - BN_DIGIT(a, i) |= 1 << j; - return 1; -} - -/* a[] >= b[]. */ -/* TODO(ngm): constant time. */ -static int bn_gte(const struct LITE_BIGNUM *a, const struct LITE_BIGNUM *b) -{ - int i; - uint32_t top = 0; - - for (i = a->dmax - 1; i > b->dmax - 1; --i) - top |= BN_DIGIT(a, i); - if (top) - return 1; - - for (i = b->dmax - 1; i > a->dmax - 1; --i) - top |= BN_DIGIT(b, i); - if (top) - return 0; - - for (i = MIN(a->dmax, b->dmax) - 1; - BN_DIGIT(a, i) == BN_DIGIT(b, i) && i > 0; --i) - ; - return BN_DIGIT(a, i) >= BN_DIGIT(b, i); -} - -/* c[] = c[] - a[], assumes c > a. */ -uint32_t bn_sub(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a) -{ - int64_t A = 0; - int i; - - for (i = 0; i < a->dmax; i++) { - A += (uint64_t) BN_DIGIT(c, i) - BN_DIGIT(a, i); - BN_DIGIT(c, i) = (uint32_t) A; - A >>= 32; - } - - for (; A && i < c->dmax; i++) { - A += (uint64_t) BN_DIGIT(c, i); - BN_DIGIT(c, i) = (uint32_t) A; - A >>= 32; - } - - return (uint32_t) A; /* 0 or -1. */ -} - -/* c[] = c[] - a[], negative numbers in 2's complement representation. */ -/* Returns borrow bit. */ -static uint32_t bn_signed_sub(struct LITE_BIGNUM *c, int *c_neg, - const struct LITE_BIGNUM *a, int a_neg) -{ - uint32_t carry = 0; - uint64_t A = 1; - int i; - - for (i = 0; i < a->dmax; ++i) { - A += (uint64_t) BN_DIGIT(c, i) + ~BN_DIGIT(a, i); - BN_DIGIT(c, i) = (uint32_t) A; - A >>= 32; - } - - for (; i < c->dmax; ++i) { - A += (uint64_t) BN_DIGIT(c, i) + 0xFFFFFFFF; - BN_DIGIT(c, i) = (uint32_t) A; - A >>= 32; - } - - A &= 0x01; - carry = (!*c_neg && a_neg && A) || (*c_neg && !a_neg && !A); - *c_neg = carry ? *c_neg : (*c_neg + !a_neg + A) & 0x01; - return carry; -} - -/* c[] = c[] + a[]. */ -uint32_t bn_add(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a) -{ - uint64_t A = 0; - int i; - - for (i = 0; i < a->dmax; ++i) { - A += (uint64_t) BN_DIGIT(c, i) + BN_DIGIT(a, i); - BN_DIGIT(c, i) = (uint32_t) A; - A >>= 32; - } - - for (; A && i < c->dmax; ++i) { - A += (uint64_t) BN_DIGIT(c, i); - BN_DIGIT(c, i) = (uint32_t) A; - A >>= 32; - } - - return (uint32_t) A; /* 0 or 1. */ -} - -/* c[] = c[] + a[], negative numbers in 2's complement representation. */ -/* Returns carry bit. */ -static uint32_t bn_signed_add(struct LITE_BIGNUM *c, int *c_neg, - const struct LITE_BIGNUM *a, int a_neg) -{ - uint32_t A = bn_add(c, a); - uint32_t carry; - - carry = (!*c_neg && !a_neg && A) || (*c_neg && a_neg && !A); - *c_neg = carry ? *c_neg : (*c_neg + a_neg + A) & 0x01; - return carry; -} - -/* r[] <<= 1. */ -static uint32_t bn_lshift(struct LITE_BIGNUM *r) -{ - int i; - uint32_t w; - uint32_t carry = 0; - - for (i = 0; i < r->dmax; i++) { - w = (BN_DIGIT(r, i) << 1) | carry; - carry = BN_DIGIT(r, i) >> 31; - BN_DIGIT(r, i) = w; - } - return carry; -} - -/* r[] >>= 1. Handles 2's complement negative numbers. */ -static void bn_rshift(struct LITE_BIGNUM *r, uint32_t carry, uint32_t neg) -{ - int i; - uint32_t ones = ~0; - uint32_t highbit = (!carry && neg) || (carry && !neg); - - for (i = 0; i < r->dmax - 1; ++i) { - uint32_t accu; - - ones &= BN_DIGIT(r, i); - accu = (BN_DIGIT(r, i) >> 1); - accu |= (BN_DIGIT(r, i + 1) << (LITE_BN_BITS2 - 1)); - BN_DIGIT(r, i) = accu; - } - ones &= BN_DIGIT(r, i); - BN_DIGIT(r, i) = (BN_DIGIT(r, i) >> 1) | - (highbit << (LITE_BN_BITS2 - 1)); - - if (ones == ~0 && highbit && neg) - memset(r->d, 0x00, bn_size(r)); /* -1 >> 1 = 0. */ -} - -/* Montgomery c[] += a * b[] / R % N. */ -/* TODO(ngm): constant time. */ -static void bn_mont_mul_add(struct LITE_BIGNUM *c, const uint32_t a, - const struct LITE_BIGNUM *b, const uint32_t nprime, - const struct LITE_BIGNUM *N) -{ - uint32_t A, B, d0; - int i; - - { - register uint64_t tmp; - - tmp = BN_DIGIT(c, 0) + (uint64_t) a * BN_DIGIT(b, 0); - A = tmp >> 32; - d0 = (uint32_t) tmp * (uint32_t) nprime; - tmp = (uint32_t)tmp + (uint64_t) d0 * BN_DIGIT(N, 0); - B = tmp >> 32; - } - - for (i = 0; i < N->dmax - 1;) { - register uint64_t tmp; - - tmp = A + (uint64_t) a * BN_DIGIT(b, i + 1) + - BN_DIGIT(c, i + 1); - A = tmp >> 32; - tmp = B + (uint64_t) d0 * BN_DIGIT(N, i + 1) + (uint32_t) tmp; - BN_DIGIT(c, i) = (uint32_t) tmp; - B = tmp >> 32; - ++i; - } - - { - uint64_t tmp = (uint64_t) A + B; - - BN_DIGIT(c, i) = (uint32_t) tmp; - A = tmp >> 32; /* 0 or 1. */ - if (A) - bn_sub(c, N); - } -} - -/* Montgomery c[] = a[] * b[] / R % N. */ -static void bn_mont_mul(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a, - const struct LITE_BIGNUM *b, const uint32_t nprime, - const struct LITE_BIGNUM *N) -{ - int i; - - for (i = 0; i < N->dmax; i++) - BN_DIGIT(c, i) = 0; - - bn_mont_mul_add(c, a ? BN_DIGIT(a, 0) : 1, b, nprime, N); - for (i = 1; i < N->dmax; i++) - bn_mont_mul_add(c, a ? BN_DIGIT(a, i) : 0, b, nprime, N); -} - -/* Mongomery R * R % N, R = 1 << (1 + log2N). */ -/* TODO(ngm): constant time. */ -static void bn_compute_RR(struct LITE_BIGNUM *RR, const struct LITE_BIGNUM *N) -{ - int i; - - bn_sub(RR, N); /* R - N = R % N since R < 2N */ - - /* Repeat 2 * R % N, log2(R) times. */ - for (i = 0; i < N->dmax * LITE_BN_BITS2; i++) { - if (bn_lshift(RR)) - assert(bn_sub(RR, N) == -1); - if (bn_gte(RR, N)) - bn_sub(RR, N); - } -} - -/* Montgomery nprime = -1 / n0 % (2 ^ 32). */ -static uint32_t bn_compute_nprime(const uint32_t n0) -{ - int i; - uint32_t ninv = 1; - - /* Repeated Hensel lifting. */ - for (i = 0; i < 5; i++) - ninv *= 2 - (n0 * ninv); - - return ~ninv + 1; /* Two's complement. */ -} - -/* TODO(ngm): this implementation not timing or side-channel safe by - * any measure. */ -static void bn_modexp_internal(struct LITE_BIGNUM *output, - const struct LITE_BIGNUM *input, - const struct LITE_BIGNUM *exp, - const struct LITE_BIGNUM *N) -{ - int i; - uint32_t nprime; - uint32_t RR_buf[RSA_MAX_WORDS]; - uint32_t acc_buf[RSA_MAX_WORDS]; - uint32_t aR_buf[RSA_MAX_WORDS]; - - struct LITE_BIGNUM RR; - struct LITE_BIGNUM acc; - struct LITE_BIGNUM aR; - - bn_init(&RR, RR_buf, bn_size(N)); - bn_init(&acc, acc_buf, bn_size(N)); - bn_init(&aR, aR_buf, bn_size(N)); - - nprime = bn_compute_nprime(BN_DIGIT(N, 0)); - bn_compute_RR(&RR, N); - bn_mont_mul(&acc, NULL, &RR, nprime, N); /* R = 1 * RR / R % N */ - bn_mont_mul(&aR, input, &RR, nprime, N); /* aR = a * RR / R % N */ - - /* TODO(ngm): burn stack space and use windowing. */ - for (i = exp->dmax * LITE_BN_BITS2 - 1; i >= 0; i--) { - bn_mont_mul(output, &acc, &acc, nprime, N); - if (bn_is_bit_set(exp, i)) { - bn_mont_mul(&acc, output, &aR, nprime, N); - } else { - struct LITE_BIGNUM tmp = *output; - - *output = acc; - acc = tmp; - } - /* Poke the watchdog. - * TODO(ngm): may be unnecessary with - * a faster implementation. - */ - watchdog_reload(); - } - - bn_mont_mul(output, NULL, &acc, nprime, N); /* Convert out. */ - /* Copy to output buffer if necessary. */ - if (acc.d != (struct access_helper *) acc_buf) { - memcpy(acc.d, acc_buf, bn_size(output)); - *output = acc; - } - - /* TODO(ngm): constant time. */ - if (bn_sub(output, N)) - bn_add(output, N); /* Final reduce. */ - output->dmax = N->dmax; - - always_memset(RR_buf, 0, sizeof(RR_buf)); - always_memset(acc_buf, 0, sizeof(acc_buf)); - always_memset(aR_buf, 0, sizeof(aR_buf)); -} - -/* output = input ^ exp % N */ -int bn_modexp(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, - const struct LITE_BIGNUM *exp, const struct LITE_BIGNUM *N) -{ -#ifndef CR50_NO_BN_ASM - if ((bn_bits(N) & 255) == 0) { - /* Use hardware support for standard key sizes. */ - return dcrypto_modexp(output, input, exp, N); - } -#endif - bn_modexp_internal(output, input, exp, N); - return 1; -} - -/* output = input ^ exp % N */ -int bn_modexp_word(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, - uint32_t exp, const struct LITE_BIGNUM *N) -{ -#ifndef CR50_NO_BN_ASM - if ((bn_bits(N) & 255) == 0) { - /* Use hardware support for standard key sizes. */ - return dcrypto_modexp_word(output, input, exp, N); - } -#endif - { - struct LITE_BIGNUM pubexp; - - DCRYPTO_bn_wrap(&pubexp, &exp, sizeof(exp)); - bn_modexp_internal(output, input, &pubexp, N); - return 1; - } -} - -/* output = input ^ exp % N */ -int bn_modexp_blinded(struct LITE_BIGNUM *output, - const struct LITE_BIGNUM *input, - const struct LITE_BIGNUM *exp, - const struct LITE_BIGNUM *N, - uint32_t pubexp) -{ -#ifndef CR50_NO_BN_ASM - if ((bn_bits(N) & 255) == 0) { - /* Use hardware support for standard key sizes. */ - return dcrypto_modexp_blinded(output, input, exp, N, pubexp); - } -#endif - bn_modexp_internal(output, input, exp, N); - return 1; -} - -/* c[] += a * b[] */ -static uint32_t bn_mul_add(struct LITE_BIGNUM *c, uint32_t a, - const struct LITE_BIGNUM *b, uint32_t offset) -{ - int i; - uint64_t carry = 0; - - for (i = 0; i < b->dmax; i++) { - carry += BN_DIGIT(c, offset + i) + - (uint64_t) BN_DIGIT(b, i) * a; - BN_DIGIT(c, offset + i) = (uint32_t) carry; - carry >>= 32; - } - - return carry; -} - -/* c[] = a[] * b[] */ -void DCRYPTO_bn_mul(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a, - const struct LITE_BIGNUM *b) -{ - int i; - uint32_t carry = 0; - - memset(c->d, 0, bn_size(c)); - for (i = 0; i < a->dmax; i++) { - BN_DIGIT(c, i + b->dmax - 1) = carry; - carry = bn_mul_add(c, BN_DIGIT(a, i), b, i); - } - - BN_DIGIT(c, i + b->dmax - 1) = carry; -} - -/* c[] = a[] * b[] */ -static void bn_mul_ex(struct LITE_BIGNUM *c, - const struct LITE_BIGNUM *a, int a_len, - const struct LITE_BIGNUM *b) -{ - int i; - uint32_t carry = 0; - - memset(c->d, 0, bn_size(c)); - for (i = 0; i < a_len; i++) { - BN_DIGIT(c, i + b->dmax - 1) = carry; - carry = bn_mul_add(c, BN_DIGIT(a, i), b, i); - } - - BN_DIGIT(c, i + b->dmax - 1) = carry; -} - -static int bn_div_word_ex(struct LITE_BIGNUM *q, - struct LITE_BIGNUM *r, - const struct LITE_BIGNUM *u, int m, - uint32_t div) -{ - uint32_t rem = 0; - int i; - - for (i = m - 1; i >= 0; --i) { - uint64_t tmp = ((uint64_t)rem << 32) + BN_DIGIT(u, i); - uint32_t qd = tmp / div; - - BN_DIGIT(q, i) = qd; - rem = tmp - (uint64_t)qd * div; - } - - if (r != NULL) - BN_DIGIT(r, 0) = rem; - - return 1; -} - -/* - * Knuth's long division. - * - * Returns 0 on error. - * |u| >= |v| - * v[n-1] must not be 0 - * r gets |v| digits written to. - * q gets |u| - |v| + 1 digits written to. - */ -static int bn_div_ex(struct LITE_BIGNUM *q, - struct LITE_BIGNUM *r, - const struct LITE_BIGNUM *u, int m, - const struct LITE_BIGNUM *v, int n) -{ - uint32_t vtop; - int s, i, j; - uint32_t vn[RSA_MAX_WORDS]; /* Normalized v */ - uint32_t un[RSA_MAX_WORDS + 1]; /* Normalized u */ - - if (m < n || n <= 0) - return 0; - - vtop = BN_DIGIT(v, n - 1); - - if (vtop == 0) - return 0; - - if (n == 1) - return bn_div_word_ex(q, r, u, m, vtop); - - /* Compute shift factor to make v have high bit set */ - s = 0; - while ((vtop & 0x80000000) == 0) { - s = s + 1; - vtop = vtop << 1; - } - - /* Normalize u and v into un and vn. - * Note un always gains a leading digit - */ - if (s != 0) { - for (i = n - 1; i > 0; i--) - vn[i] = (BN_DIGIT(v, i) << s) | - (BN_DIGIT(v, i - 1) >> (32 - s)); - vn[0] = BN_DIGIT(v, 0) << s; - - un[m] = BN_DIGIT(u, m - 1) >> (32 - s); - for (i = m - 1; i > 0; i--) - un[i] = (BN_DIGIT(u, i) << s) | - (BN_DIGIT(u, i - 1) >> (32 - s)); - un[0] = BN_DIGIT(u, 0) << s; - } else { - for (i = 0; i < n; ++i) - vn[i] = BN_DIGIT(v, i); - for (i = 0; i < m; ++i) - un[i] = BN_DIGIT(u, i); - un[m] = 0; - } - - /* Main loop, reducing un digit by digit */ - for (j = m - n; j >= 0; j--) { - uint32_t qd; - int64_t t, k; - - /* Estimate quotient digit */ - if (un[j + n] == vn[n - 1]) { - /* Maxed out */ - qd = 0xFFFFFFFF; - } else { - /* Fine tune estimate */ - uint64_t rhat = ((uint64_t)un[j + n] << 32) + - un[j + n - 1]; - - qd = rhat / vn[n - 1]; - rhat = rhat - (uint64_t)qd * vn[n - 1]; - while ((rhat >> 32) == 0 && - (uint64_t)qd * vn[n - 2] > - (rhat << 32) + un[j + n - 2]) { - qd = qd - 1; - rhat = rhat + vn[n - 1]; - } - } - - /* Multiply and subtract */ - k = 0; - for (i = 0; i < n; i++) { - uint64_t p = (uint64_t)qd * vn[i]; - - t = un[i + j] - k - (p & 0xFFFFFFFF); - un[i + j] = t; - k = (p >> 32) - (t >> 32); - } - t = un[j + n] - k; - un[j + n] = t; - - /* If borrowed, add one back and adjust estimate */ - if (t < 0) { - k = 0; - qd = qd - 1; - for (i = 0; i < n; i++) { - t = (uint64_t)un[i + j] + vn[i] + k; - un[i + j] = t; - k = t >> 32; - } - un[j + n] = un[j + n] + k; - } - - BN_DIGIT(q, j) = qd; - } - - if (r != NULL) { - /* Denormalize un into r */ - if (s != 0) { - for (i = 0; i < n - 1; i++) - BN_DIGIT(r, i) = (un[i] >> s) | - (un[i + 1] << (32 - s)); - BN_DIGIT(r, n - 1) = un[n - 1] >> s; - } else { - for (i = 0; i < n; i++) - BN_DIGIT(r, i) = un[i]; - } - } - - return 1; -} - -static void bn_set_bn(struct LITE_BIGNUM *d, const struct LITE_BIGNUM *src, - size_t n) -{ - size_t i = 0; - - for (; i < n && i < d->dmax; ++i) - BN_DIGIT(d, i) = BN_DIGIT(src, i); - for (; i < d->dmax; ++i) - BN_DIGIT(d, i) = 0; -} - -static size_t bn_digits(const struct LITE_BIGNUM *a) -{ - size_t n = a->dmax - 1; - - while (BN_DIGIT(a, n) == 0 && n) - --n; - return n + 1; -} - -int DCRYPTO_bn_div(struct LITE_BIGNUM *quotient, - struct LITE_BIGNUM *remainder, - const struct LITE_BIGNUM *src, - const struct LITE_BIGNUM *divisor) -{ - int src_len = bn_digits(src); - int div_len = bn_digits(divisor); - int i, result; - - if (src_len < div_len) - return 0; - - result = bn_div_ex(quotient, remainder, - src, src_len, - divisor, div_len); - - if (!result) - return 0; - - /* 0-pad the destinations. */ - for (i = src_len - div_len + 1; i < quotient->dmax; ++i) - BN_DIGIT(quotient, i) = 0; - if (remainder) { - for (i = div_len; i < remainder->dmax; ++i) - BN_DIGIT(remainder, i) = 0; - } - - return result; -} - -/* - * Extended Euclid modular inverse. - * - * https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm - * #Computing_multiplicative_inverses_in_modular_structures: - - * function inverse(a, n) - * t := 0; newt := 1; - * r := n; newr := a; - * while newr ≠ 0 - * quotient := r div newr - * (t, newt) := (newt, t - quotient * newt) - * (r, newr) := (newr, r - quotient * newr) - * if r > 1 then return "a is not invertible" - * if t < 0 then t := t + n - * return t - */ -int bn_modinv_vartime(struct LITE_BIGNUM *dst, const struct LITE_BIGNUM *src, - const struct LITE_BIGNUM *mod) -{ - uint32_t R_buf[RSA_MAX_WORDS]; - uint32_t nR_buf[RSA_MAX_WORDS]; - uint32_t Q_buf[RSA_MAX_WORDS]; - - uint32_t nT_buf[RSA_MAX_WORDS + 1]; /* Can go negative, hence +1 */ - uint32_t T_buf[RSA_MAX_WORDS + 1]; /* Can go negative */ - uint32_t tmp_buf[2 * RSA_MAX_WORDS + 1]; /* needs to hold Q*nT */ - - struct LITE_BIGNUM R; - struct LITE_BIGNUM nR; - struct LITE_BIGNUM Q; - struct LITE_BIGNUM T; - struct LITE_BIGNUM nT; - struct LITE_BIGNUM tmp; - - struct LITE_BIGNUM *pT = &T; - struct LITE_BIGNUM *pnT = &nT; - struct LITE_BIGNUM *pR = &R; - struct LITE_BIGNUM *pnR = &nR; - struct LITE_BIGNUM *bnswap; - - int t_neg = 0; - int nt_neg = 0; - int iswap; - - size_t r_len, nr_len; - - bn_init(&R, R_buf, bn_size(mod)); - bn_init(&nR, nR_buf, bn_size(mod)); - bn_init(&Q, Q_buf, bn_size(mod)); - bn_init(&T, T_buf, bn_size(mod) + sizeof(uint32_t)); - bn_init(&nT, nT_buf, bn_size(mod) + sizeof(uint32_t)); - bn_init(&tmp, tmp_buf, bn_size(mod) + sizeof(uint32_t)); - - r_len = bn_digits(mod); - nr_len = bn_digits(src); - - BN_DIGIT(&nT, 0) = 1; /* T = 0, nT = 1 */ - bn_set_bn(&R, mod, r_len); /* R = n */ - bn_set_bn(&nR, src, nr_len); /* nR = input */ - - /* Trim nR */ - while (nr_len && BN_DIGIT(&nR, nr_len - 1) == 0) - --nr_len; - - while (nr_len) { - size_t q_len = r_len - nr_len + 1; - - /* (r, nr) = (nr, r % nr), q = r / nr */ - if (!bn_div_ex(&Q, pR, pR, r_len, pnR, nr_len)) - return 0; - - /* swap R and nR */ - r_len = nr_len; - bnswap = pR; pR = pnR; pnR = bnswap; - - /* trim nR and Q */ - while (nr_len && BN_DIGIT(pnR, nr_len - 1) == 0) - --nr_len; - while (q_len && BN_DIGIT(&Q, q_len - 1) == 0) - --q_len; - - Q.dmax = q_len; - - /* compute t - q*nt */ - if (q_len == 1 && BN_DIGIT(&Q, 0) <= 2) { - /* Doing few direct subs is faster than mul + sub */ - uint32_t n = BN_DIGIT(&Q, 0); - - while (n--) - bn_signed_sub(pT, &t_neg, pnT, nt_neg); - } else { - /* Call bn_mul_ex with smallest operand first */ - if (nt_neg) { - /* Negative numbers use all digits, - * thus pnT is large - */ - bn_mul_ex(&tmp, &Q, q_len, pnT); - } else { - int nt_len = bn_digits(pnT); - - if (q_len < nt_len) - bn_mul_ex(&tmp, &Q, q_len, pnT); - else - bn_mul_ex(&tmp, pnT, nt_len, &Q); - } - bn_signed_sub(pT, &t_neg, &tmp, nt_neg); - } - - /* swap T and nT */ - bnswap = pT; pT = pnT; pnT = bnswap; - iswap = t_neg; t_neg = nt_neg; nt_neg = iswap; - } - - if (r_len != 1 || BN_DIGIT(pR, 0) != 1) { - /* gcd not 1; no direct inverse */ - return 0; - } - - if (t_neg) - bn_signed_add(pT, &t_neg, mod, 0); - - bn_set_bn(dst, pT, bn_digits(pT)); - - return 1; -} - -#define PRIME1 3 - -/* - * The array below is an encoding of the first 4096 primes, starting with - * PRIME1. Using 4096 of the first primes results in at least 5% improvement - * in running time over using the first 2048. - * - * Most byte entries in the array contain two sequential differentials between - * two adjacent prime numbers, each differential halved (as the difference is - * always even) and packed into 4 bits. - * - * If a halved differential value exceeds 0xf (and as such does not fit into 4 - * bits), a zero is placed in the array followed by the value literal (no - * halving). - * - * If out of two consecutive differencials only the second one exceeds 0xf, - * the first one still is put into the array in its own byte prepended by a - * zero. - */ -const uint8_t PRIME_DELTAS[] = { - 1, 18, 18, 18, 49, 50, 18, 51, 19, 33, 50, 52, - 33, 33, 39, 35, 21, 19, 50, 51, 21, 18, 22, 98, - 18, 49, 83, 51, 19, 33, 87, 33, 39, 53, 18, 52, - 51, 35, 66, 69, 21, 19, 35, 66, 18, 100, 36, 35, - 97, 147, 83, 49, 53, 51, 19, 50, 22, 81, 35, 49, - 98, 52, 84, 84, 51, 36, 50, 66, 117, 97, 81, 33, - 87, 33, 39, 33, 42, 36, 84, 35, 55, 35, 52, 54, - 35, 21, 19, 81, 81, 57, 33, 35, 52, 51, 177, 84, - 83, 52, 98, 51, 19, 101, 145, 35, 19, 33, 38, 19, - 0, 34, 51, 73, 87, 33, 35, 66, 19, 101, 18, 18, - 54, 100, 99, 35, 66, 66, 114, 49, 35, 19, 90, 50, - 28, 33, 86, 21, 67, 51, 147, 33, 101, 100, 135, 50, - 18, 21, 99, 57, 24, 27, 52, 50, 18, 67, 81, 87, - 83, 97, 33, 86, 24, 19, 33, 84, 156, 35, 72, 18, - 72, 18, 67, 50, 97, 179, 19, 35, 115, 33, 50, 54, - 51, 114, 54, 67, 45, 149, 66, 49, 59, 97, 132, 38, - 117, 18, 67, 50, 18, 52, 33, 53, 21, 66, 117, 97, - 50, 24, 114, 52, 50, 148, 83, 52, 86, 114, 51, 30, - 21, 66, 114, 70, 54, 35, 165, 24, 210, 22, 50, 99, - 66, 75, 18, 22, 225, 51, 50, 49, 98, 97, 81, 129, - 131, 168, 66, 18, 27, 70, 53, 18, 49, 53, 22, 81, - 87, 50, 52, 51, 134, 18, 115, 36, 84, 51, 179, 21, - 114, 57, 21, 114, 21, 114, 73, 35, 18, 49, 98, 171, - 97, 35, 49, 59, 19, 131, 97, 54, 129, 35, 114, 25, - 197, 49, 81, 81, 83, 21, 21, 52, 245, 21, 67, 89, - 54, 97, 147, 35, 57, 21, 115, 33, 44, 22, 56, 67, - 57, 129, 35, 19, 53, 54, 105, 19, 41, 76, 33, 35, - 22, 39, 245, 54, 115, 86, 18, 52, 53, 18, 115, 50, - 49, 81, 134, 73, 35, 97, 51, 62, 55, 36, 84, 105, - 33, 44, 99, 24, 51, 117, 114, 243, 51, 67, 33, 99, - 33, 59, 49, 41, 18, 97, 50, 211, 50, 69, 0, 32, - 129, 50, 18, 21, 115, 36, 83, 162, 19, 242, 69, 51, - 67, 98, 49, 50, 49, 81, 131, 162, 103, 227, 162, 148, - 50, 55, 51, 81, 86, 69, 21, 70, 92, 18, 67, 36, - 149, 51, 19, 86, 21, 51, 52, 53, 49, 51, 53, 76, - 59, 25, 36, 95, 73, 33, 83, 19, 41, 70, 152, 49, - 99, 81, 81, 53, 114, 193, 129, 81, 90, 33, 36, 131, - 49, 104, 66, 63, 21, 19, 35, 52, 50, 99, 70, 39, - 101, 195, 99, 27, 73, 83, 114, 19, 84, 50, 63, 117, - 22, 81, 129, 156, 147, 137, 49, 146, 49, 84, 83, 52, - 35, 21, 22, 35, 49, 98, 121, 35, 162, 67, 36, 39, - 50, 118, 33, 242, 195, 54, 103, 50, 18, 147, 100, 50, - 97, 111, 129, 59, 115, 86, 49, 36, 83, 60, 115, 36, - 105, 81, 81, 35, 163, 39, 33, 39, 54, 197, 52, 81, - 242, 49, 98, 115, 0, 34, 100, 53, 18, 165, 72, 21, - 114, 22, 56, 52, 36, 35, 67, 54, 50, 51, 73, 42, - 38, 21, 49, 86, 18, 163, 243, 36, 86, 49, 225, 50, - 24, 97, 53, 76, 99, 147, 39, 50, 100, 54, 35, 99, - 97, 138, 33, 89, 66, 114, 19, 179, 115, 53, 49, 81, - 33, 177, 35, 54, 55, 86, 52, 0, 4, 0, 36, 118, - 50, 49, 99, 104, 21, 75, 22, 50, 57, 22, 50, 100, - 54, 35, 99, 22, 98, 115, 131, 21, 73, 0, 6, 0, - 34, 30, 27, 49, 86, 19, 36, 179, 21, 66, 52, 38, - 150, 162, 51, 66, 24, 97, 84, 81, 35, 118, 180, 225, - 42, 33, 39, 86, 22, 129, 228, 180, 35, 55, 36, 99, - 50, 162, 145, 99, 35, 121, 84, 0, 10, 0, 32, 53, - 51, 19, 131, 22, 62, 21, 72, 52, 53, 202, 81, 81, - 98, 58, 33, 105, 81, 81, 42, 141, 36, 50, 99, 70, - 99, 36, 177, 135, 83, 102, 115, 42, 38, 49, 51, 132, - 177, 228, 50, 162, 108, 162, 69, 24, 22, 0, 12, 0, - 34, 18, 54, 51, 67, 33, 60, 42, 83, 55, 35, 49, - 99, 81, 83, 162, 210, 19, 177, 194, 49, 35, 195, 66, - 0, 2, 0, 34, 52, 134, 21, 21, 52, 36, 107, 55, - 45, 33, 101, 66, 70, 39, 56, 52, 35, 52, 53, 97, - 51, 132, 51, 101, 19, 146, 51, 54, 148, 53, 73, 39, - 57, 84, 86, 19, 102, 0, 36, 35, 66, 49, 41, 99, - 67, 50, 145, 33, 194, 51, 127, 50, 54, 58, 36, 36, - 51, 47, 21, 100, 84, 195, 98, 114, 49, 231, 129, 99, - 42, 83, 51, 69, 103, 87, 135, 87, 56, 52, 56, 165, - 19, 33, 38, 21, 19, 179, 18, 148, 84, 177, 89, 114, - 18, 145, 35, 69, 31, 47, 21, 25, 41, 55, 81, 42, - 0, 36, 50, 55, 42, 87, 179, 31, 101, 145, 39, 59, - 145, 99, 36, 36, 53, 22, 149, 120, 114, 51, 19, 33, - 225, 227, 18, 55, 38, 120, 114, 52, 50, 51, 52, 36, - 39, 132, 50, 100, 129, 84, 35, 211, 84, 35, 103, 242, - 123, 70, 35, 69, 55, 83, 21, 102, 115, 57, 83, 73, - 35, 19, 81, 84, 51, 81, 149, 22, 35, 69, 103, 98, - 69, 51, 162, 120, 117, 69, 97, 147, 101, 97, 33, 99, - 36, 0, 4, 0, 44, 33, 33, 86, 51, 114, 51, 52, - 0, 6, 0, 36, 146, 49, 99, 51, 39, 182, 25, 83, - 220, 33, 33, 39, 35, 52, 134, 0, 2, 0, 42, 33, - 44, 51, 25, 39, 62, 151, 53, 97, 54, 243, 35, 55, - 33, 194, 51, 213, 147, 67, 63, 38, 97, 129, 50, 105, - 19, 45, 99, 98, 204, 99, 22, 228, 35, 97, 147, 35, - 58, 129, 51, 149, 49, 36, 51, 200, 52, 83, 123, 72, - 49, 98, 27, 73, 0, 34, 19, 146, 51, 69, 73, 50, - 18, 72, 22, 99, 146, 51, 49, 54, 90, 105, 35, 24, - 21, 114, 241, 86, 28, 56, 69, 22, 179, 24, 165, 22, - 105, 86, 49, 81, 53, 145, 99, 35, 28, 225, 33, 81, - 134, 75, 19, 33, 83, 166, 84, 99, 51, 41, 18, 105, - 22, 50, 24, 102, 114, 73, 38, 115, 50, 67, 42, 101, - 114, 24, 22, 242, 60, 172, 84, 101, 99, 102, 52, 135, - 50, 0, 6, 0, 36, 165, 246, 18, 30, 103, 59, 66, - 147, 121, 35, 19, 0, 34, 145, 131, 145, 194, 19, 99, - 101, 67, 134, 69, 0, 14, 0, 40, 49, 50, 103, 33, - 33, 36, 53, 51, 19, 51, 99, 197, 21, 54, 51, 115, - 0, 6, 0, 52, 163, 81, 84, 86, 97, 50, 120, 70, - 59, 21, 67, 177, 179, 69, 102, 21, 54, 18, 117, 19, - 146, 100, 150, 51, 35, 55, 33, 102, 35, 153, 97, 134, - 73, 93, 35, 67, 50, 21, 162, 52, 42, 81, 0, 34, - 18, 193, 102, 83, 22, 243, 104, 97, 185, 103, 81, 102, - 33, 35, 97, 137, 0, 2, 0, 40, 72, 52, 81, 41, - 69, 70, 41, 25, 81, 33, 36, 225, 59, 99, 121, 35, - 67, 53, 66, 25, 83, 171, 67, 242, 18, 147, 241, 36, - 50, 54, 0, 14, 0, 34, 115, 33, 50, 114, 19, 225, - 35, 69, 21, 21, 18, 241, 102, 89, 103, 81, 99, 83, - 118, 39, 41, 21, 66, 69, 105, 148, 57, 135, 51, 87, - 35, 22, 98, 51, 97, 129, 99, 39, 50, 22, 146, 0, - 36, 150, 97, 33, 36, 98, 0, 36, 57, 22, 83, 108, - 67, 56, 97, 149, 165, 19, 146, 0, 2, 0, 40, 49, - 129, 36, 149, 99, 21, 66, 54, 21, 148, 50, 162, 0, - 6, 0, 36, 49, 83, 195, 120, 57, 21, 165, 67, 35, - 21, 22, 33, 36, 83, 105, 118, 132, 56, 66, 19, 156, - 149, 97, 39, 83, 51, 150, 30, 151, 134, 124, 107, 49, - 84, 33, 39, 99, 35, 114, 18, 243, 19, 81, 251, 18, - 52, 51, 134, 99, 66, 28, 98, 52, 51, 81, 54, 231, - 50, 100, 54, 35, 115, 101, 51, 67, 50, 18, 70, 39, - 149, 24, 58, 53, 66, 0, 30, 0, 36, 100, 182, 19, - 104, 51, 25, 45, 36, 149, 69, 55, 42, 185, 100, 230, - 51, 67, 108, 135, 39, 99, 86, 163, 36, 150, 149, 18, - 165, 114, 49, 92, 145, 42, 135, 87, 50, 58, 53, 49, - 99, 245, 67, 35, 0, 8, 0, 40, 18, 22, 146, 52, - 83, 153, 22, 132, 50, 51, 0, 2, 0, 52, 114, 168, - 18, 54, 19, 102, 50, 117, 51, 117, 120, 67, 98, 75, - 49, 155, 49, 147, 135, 83, 97, 50, 73, 104, 18, 114, - 70, 111, 132, 33, 59, 100, 83, 51, 115, 149, 97, 81, - 45, 38, 66, 148, 87, 131, 52, 83, 67, 101, 165, 66, - 109, 146, 105, 63, 52, 59, 97, 35, 49, 81, 35, 49, - 59, 147, 150, 70, 53, 97, 129, 81, 89, 58, 33, 59, - 51, 147, 118, 129, 51, 39, 98, 25, 0, 16, 0, 36, - 99, 126, 22, 54, 50, 24, 244, 195, 245, 25, 35, 100, - 177, 59, 145, 81, 95, 30, 55, 131, 168, 19, 0, 4, - 0, 32, 33, 35, 22, 35, 54, 19, 35, 67, 42, 0, - 4, 0, 32, 84, 129, 177, 35, 67, 135, 41, 66, 163, - 102, 53, 21, 22, 230, 145, 149, 69, 0, 48, 18, 52, - 81, 95, 0, 2, 0, 36, 53, 49, 146, 52, 135, 131, - 114, 162, 49, 86, 19, 99, 50, 97, 50, 99, 66, 19, - 149, 52, 99, 177, 54, 146, 115, 42, 56, 66, 75, 70, - 51, 134, 159, 66, 18, 61, 39, 203, 49, 53, 55, 51, - 101, 49, 101, 100, 153, 83, 72, 51, 72, 162, 21, 21, - 99, 67, 90, 89, 210, 63, 18, 67, 102, 146, 75, 49, - 0, 12, 0, 34, 57, 99, 30, 120, 114, 118, 35, 49, - 0, 36, 35, 166, 195, 177, 137, 102, 145, 51, 50, 55, - 33, 180, 99, 83, 70, 150, 53, 27, 115, 50, 147, 171, - 22, 194, 153, 27, 18, 100, 101, 114, 25, 0, 16, 0, - 38, 51, 54, 83, 100, 50, 55, 243, 84, 179, 70, 81, - 81, 53, 21, 105, 163, 36, 179, 63, 55, 54, 99, 81, - 95, 24, 66, 19, 146, 19, 45, 36, 53, 18, 52, 35, - 246, 19, 50, 171, 66, 18, 0, 72, 66, 75, 18, 117, - 18, 163, 89, 58, 131, 67, 42, 107, 18, 22, 89, 27, - 57, 241, 87, 84, 0, 16, 0, 50, 53, 69, 99, 145, - 179, 18, 52, 51, 89, 27, 24, 117, 49, 101, 162, 115, - 0, 4, 0, 36, 18, 54, 18, 118, 50, 49, 50, 165, - 21, 54, 28, 102, 51, 44, 18, 193, 50, 52, 131, 21, - 103, 0, 6, 0, 34, 55, 50, 31, 180, 35, 66, 30, - 19, 45, 155, 19, 131, 24, 97, 98, 51, 117, 52, 98, - 145, 84, 131, 63, 21, 145, 84, 36, 108, 0, 40, 22, - 83, 97, 98, 18, 57, 118, 50, 127, 36, 84, 53, 148, - 39, 131, 66, 49, 81, 98, 18, 52, 35, 0, 32, 197, - 73, 81, 53, 18, 147, 97, 129, 179, 52, 146, 150, 67, - 42, 63, 182, 19, 146, 0, 62, 33, 99, 81, 102, 225, - 39, 179, 19, 53, 114, 21, 52, 87, 83, 22, 185, 69, - 150, 22, 38, 21, 19, 147, 0, 6, 0, 34, 49, 98, - 57, 145, 131, 52, 53, 148, 84, 81, 41, 214, 177, 33, - 179, 55, 131, 165, 97, 0, 18, 0, 42, 44, 19, 86, - 19, 84, 35, 102, 66, 54, 250, 60, 53, 97, 90, 51, - 38, 117, 150, 67, 98, 117, 22, 248, 22, 50, 18, 61, - 41, 18, 55, 0, 54, 0, 6, 0, 52, 24, 51, 109, - 33, 59, 49, 102, 53, 145, 102, 89, 99, 67, 83, 66, - 18, 172, 51, 87, 81, 179, 117, 210, 148, 102, 86, 52, - 131, 67, 59, 21, 165, 0, 6, 0, 44, 147, 81, 35, - 114, 210, 22, 84, 36, 98, 100, 180, 53, 147, 52, 54, - 36, 149, 99, 97, 50, 24, 102, 117, 115, 86, 22, 50, - 49, 98, 211, 147, 83, 25, 84, 45, 90, 56, 166, 84, - 81, 131, 165, 162, 241, 36, 129, 146, 19, 89, 103, 147, - 138, 50, 67, 35, 100, 81, 99, 33, 53, 24, 103, 83, - 67, 225, 57, 0, 30, 0, 34, 24, 97, 152, 52, 84, - 84, 0, 10, 0, 44, 51, 42, 33, 39, 228, 56, 127, - 63, 39, 83, 52, 41, 99, 27, 100, 54, 39, 35, 18, - 154, 56, 0, 38, 129, 35, 0, 2, 0, 40, 0, 42, - 114, 49, 197, 49, 149, 97, 129, 56, 52, 33, 83, 69, - 25, 132, 105, 99, 101, 51, -}; - -static uint32_t bn_mod_word16(const struct LITE_BIGNUM *p, uint16_t word) -{ - int i; - uint32_t rem = 0; - - for (i = p->dmax - 1; i >= 0; i--) { - rem = ((rem << 16) | - ((BN_DIGIT(p, i) >> 16) & 0xFFFFUL)) % word; - rem = ((rem << 16) | (BN_DIGIT(p, i) & 0xFFFFUL)) % word; - } - - return rem; -} - -static uint32_t bn_mod_f4(const struct LITE_BIGNUM *d) -{ - int i = bn_size(d) - 1; - const uint8_t *p = (const uint8_t *) (d->d); - uint32_t rem = 0; - - for (; i >= 0; --i) { - uint32_t q = RSA_F4 * (rem >> 8); - - if (rem < q) - q -= RSA_F4; - rem <<= 8; - rem |= p[i]; - rem -= q; - } - - if (rem >= RSA_F4) - rem -= RSA_F4; - - return rem; -} - -#define bn_is_even(b) !bn_is_bit_set((b), 0) -/* From HAC Fact 4.48 (ii), the following number of - * rounds suffice for ~2^145 confidence. Each additional - * round provides about another k/100 bits of confidence. */ -#define ROUNDS_1024 7 -#define ROUNDS_512 15 -#define ROUNDS_384 22 - -/* Miller-Rabin from HAC, algorithm 4.24. */ -static int bn_probable_prime(const struct LITE_BIGNUM *p) -{ - int j; - int s = 0; - - uint32_t ONE_buf = 1; - uint8_t r_buf[RSA_MAX_BYTES / 2]; - uint8_t A_buf[RSA_MAX_BYTES / 2]; - uint8_t y_buf[RSA_MAX_BYTES / 2]; - - struct LITE_BIGNUM ONE; - struct LITE_BIGNUM r; - struct LITE_BIGNUM A; - struct LITE_BIGNUM y; - - const int rounds = bn_bits(p) >= 1024 ? ROUNDS_1024 : - bn_bits(p) >= 512 ? ROUNDS_512 : - ROUNDS_384; - - /* Failsafe: update rounds table above to support smaller primes. */ - if (bn_bits(p) < 384) - return 0; - - if (bn_size(p) > sizeof(r_buf)) - return 0; - - DCRYPTO_bn_wrap(&ONE, &ONE_buf, sizeof(ONE_buf)); - DCRYPTO_bn_wrap(&r, r_buf, bn_size(p)); - bn_copy(&r, p); - - /* r * (2 ^ s) = p - 1 */ - bn_sub(&r, &ONE); - while (bn_is_even(&r)) { - bn_rshift(&r, 0, 0); - s++; - } - - DCRYPTO_bn_wrap(&A, A_buf, bn_size(p)); - DCRYPTO_bn_wrap(&y, y_buf, bn_size(p)); - for (j = 0; j < rounds; j++) { - int i; - - /* pick random A, such that A < p */ - rand_bytes(A_buf, bn_size(&A)); - for (i = A.dmax - 1; i >= 0; i--) { - while (BN_DIGIT(&A, i) > BN_DIGIT(p, i)) - BN_DIGIT(&A, i) = rand(); - if (BN_DIGIT(&A, i) < BN_DIGIT(p, i)) - break; - } - - /* y = a ^ r mod p */ - bn_modexp(&y, &A, &r, p); - if (bn_eq(&y, &ONE)) - continue; - bn_add(&y, &ONE); - if (bn_eq(&y, p)) - continue; - bn_sub(&y, &ONE); - - /* y = y ^ 2 mod p */ - for (i = 0; i < s - 1; i++) { - bn_copy(&A, &y); - bn_modexp_word(&y, &A, 2, p); - - if (bn_eq(&y, &ONE)) - return 0; - - bn_add(&y, &ONE); - if (bn_eq(&y, p)) { - bn_sub(&y, &ONE); - break; - } - bn_sub(&y, &ONE); - } - bn_add(&y, &ONE); - if (!bn_eq(&y, p)) - return 0; - } - - return 1; -} - -/* #define PRINT_PRIMES to enable printing predefined prime numbers' set. */ -static void print_primes(uint16_t prime) -{ -#ifdef PRINT_PRIMES - static uint16_t num_per_line; - static uint16_t max_printed; - - if (prime <= max_printed) - return; - - if (!(num_per_line++ % 8)) { - if (num_per_line == 1) - ccprintf("Prime numbers:"); - ccprintf("\n"); - cflush(); - } - max_printed = prime; - ccprintf(" %6d", prime); -#endif -} - -int DCRYPTO_bn_generate_prime(struct LITE_BIGNUM *p) -{ - int i; - int j; - /* Using a sieve size of 2048-bits results in a failure rate - * of ~0.5% @ 1024-bit candidates. The failure rate rises to ~6% - * if the sieve size is halved. */ - uint8_t composites_buf[256]; - struct LITE_BIGNUM composites; - uint16_t prime = PRIME1; - - /* Set top two bits, as well as LSB. */ - bn_set_bit(p, 0); - bn_set_bit(p, bn_bits(p) - 1); - bn_set_bit(p, bn_bits(p) - 2); - - /* Save on trial division by marking known composites. */ - bn_init(&composites, composites_buf, sizeof(composites_buf)); - for (i = 0; i < ARRAY_SIZE(PRIME_DELTAS); i++) { - uint16_t rem; - uint8_t unpacked_deltas[2]; - uint8_t packed_deltas = PRIME_DELTAS[i]; - int k; - int m; - - if (packed_deltas) { - unpacked_deltas[0] = (packed_deltas >> 4) << 1; - unpacked_deltas[1] = (packed_deltas & 0xf) << 1; - m = 2; - } else { - i += 1; - unpacked_deltas[0] = PRIME_DELTAS[i]; - m = 1; - } - - for (k = 0; k < m; k++) { - prime += unpacked_deltas[k]; - print_primes(prime); - rem = bn_mod_word16(p, prime); - /* Skip marking odd offsets (i.e. even candidates). */ - for (j = (rem == 0) ? 0 : prime - rem; - j < bn_bits(&composites) << 1; - j += prime) { - if ((j & 1) == 0) - bn_set_bit(&composites, j >> 1); - } - } - } - - /* composites now marked, apply Miller-Rabin to prime candidates. */ - j = 0; - for (i = 0; i < bn_bits(&composites); i++) { - uint32_t diff_buf; - struct LITE_BIGNUM diff; - - if (bn_is_bit_set(&composites, i)) - continue; - - /* Recover increment from the composites sieve. */ - diff_buf = (i << 1) - j; - j = (i << 1); - DCRYPTO_bn_wrap(&diff, &diff_buf, sizeof(diff_buf)); - bn_add(p, &diff); - /* Make sure prime will work with F4 public exponent. */ - if (bn_mod_f4(p) >= 2) { - if (bn_probable_prime(p)) - return 1; - } - } - - always_memset(composites_buf, 0, sizeof(composites_buf)); - return 0; -} diff --git a/chip/g/dcrypto/compare.c b/chip/g/dcrypto/compare.c deleted file mode 100644 index db6193752b..0000000000 --- a/chip/g/dcrypto/compare.c +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright 2016 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" - -/* Constant time comparator. */ -int DCRYPTO_equals(const void *a, const void *b, size_t len) -{ - size_t i; - const uint8_t *pa = a; - const uint8_t *pb = b; - uint8_t diff = 0; - - for (i = 0; i < len; i++) - diff |= pa[i] ^ pb[i]; - - return !diff; -} diff --git a/chip/g/dcrypto/dcrypto.h b/chip/g/dcrypto/dcrypto.h deleted file mode 100644 index 8cf1071090..0000000000 --- a/chip/g/dcrypto/dcrypto.h +++ /dev/null @@ -1,445 +0,0 @@ -/* 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. - */ - -/* - * Crypto wrapper library for the g chip. - */ -#ifndef __EC_CHIP_G_DCRYPTO_DCRYPTO_H -#define __EC_CHIP_G_DCRYPTO_DCRYPTO_H - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(TEST_FUZZ) || !defined(TEST_BUILD) - -#include "internal.h" - -#include "crypto_api.h" - -#include - -#include "cryptoc/hmac.h" - -enum cipher_mode { - CIPHER_MODE_ECB = 0, /* NIST SP 800-38A */ - CIPHER_MODE_CTR = 1, /* NIST SP 800-38A */ - CIPHER_MODE_CBC = 2, /* NIST SP 800-38A */ - CIPHER_MODE_GCM = 3 /* NIST SP 800-38D */ -}; - -enum encrypt_mode { - DECRYPT_MODE = 0, - ENCRYPT_MODE = 1 -}; - -enum hashing_mode { - HASH_SHA1 = 0, - HASH_SHA256 = 1, - HASH_SHA384 = 2, /* Only supported for PKCS#1 signing */ - HASH_SHA512 = 3, /* Only supported for PKCS#1 signing */ - HASH_NULL = 4 /* Only supported for PKCS#1 signing */ -}; - -/* - * AES implementation, based on a hardware AES block. - * FIPS Publication 197, The Advanced Encryption Standard (AES) - */ -#define AES256_BLOCK_CIPHER_KEY_SIZE 32 - -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); - -void DCRYPTO_aes_write_iv(const uint8_t *iv); -void DCRYPTO_aes_read_iv(uint8_t *iv); - -/* AES-CTR-128/192/256 - * NIST Special Publication 800-38A - */ -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); - -/* AES-GCM-128/192/256 - * NIST Special Publication 800-38D, IV is provided externally - * Caller should use IV length according to section 8.2 of SP 800-38D - * And choose appropriate IV construction method, constrain number - * of invocations according to section 8.3 of SP 800-38D - */ -struct GCM_CTX { - union { - uint32_t d[4]; - uint8_t c[16]; - } block, Ej0; - - uint64_t aad_len; - uint64_t count; - size_t remainder; -}; - -/* Initialize the GCM context structure. */ -void DCRYPTO_gcm_init(struct GCM_CTX *ctx, uint32_t key_bits, - const uint8_t *key, const uint8_t *iv, size_t iv_len); -/* Additional authentication data to include in the tag calculation. */ -void DCRYPTO_gcm_aad(struct GCM_CTX *ctx, const uint8_t *aad_data, size_t len); -/* Encrypt & decrypt return the number of bytes written to out - * (always an integral multiple of 16), or -1 on error. These functions - * may be called repeatedly with incremental data. - * - * NOTE: if in_len is not a integral multiple of 16, then out_len must - * be atleast in_len - (in_len % 16) + 16 bytes. - */ -int DCRYPTO_gcm_encrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len, - const uint8_t *in, size_t in_len); -int DCRYPTO_gcm_decrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len, - const uint8_t *in, size_t in_len); -/* Encrypt & decrypt a partial final block, if any. These functions - * return the number of bytes written to out (<= 15), or -1 on error. - */ -int DCRYPTO_gcm_encrypt_final(struct GCM_CTX *ctx, - uint8_t *out, size_t out_len); -int DCRYPTO_gcm_decrypt_final(struct GCM_CTX *ctx, - uint8_t *out, size_t out_len); -/* Compute the tag over AAD + encrypt or decrypt data, and return the - * number of bytes written to tag. Returns -1 on error. - */ -int DCRYPTO_gcm_tag(struct GCM_CTX *ctx, uint8_t *tag, size_t tag_len); -/* Cleanup secrets. */ -void DCRYPTO_gcm_finish(struct GCM_CTX *ctx); - -/* AES-CMAC-128 - * NIST Special Publication 800-38B, RFC 4493 - * K: 128-bit key, M: message, len: number of bytes in M - * Writes 128-bit tag to T; returns 0 if an error is encountered and 1 - * otherwise. - */ -int DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, const uint32_t len, - uint32_t T[4]); -/* key: 128-bit key, M: message, len: number of bytes in M, - * T: tag to be verified - * Returns 1 if the tag is correct and 0 otherwise. - */ -int DCRYPTO_aes_cmac_verify(const uint8_t *key, const uint8_t *M, const int len, - const uint32_t T[4]); - -/* - * 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(SHA_CTX *ctx, uint32_t sw_required); -/* SHA256/384/512 FIPS 180-4 - */ -void DCRYPTO_SHA256_init(LITE_SHA256_CTX *ctx, uint32_t sw_required); -void DCRYPTO_SHA384_init(LITE_SHA384_CTX *ctx); -void DCRYPTO_SHA512_init(LITE_SHA512_CTX *ctx); -const uint8_t *DCRYPTO_SHA1_hash(const void *data, uint32_t n, - uint8_t *digest); -const uint8_t *DCRYPTO_SHA256_hash(const void *data, uint32_t n, - uint8_t *digest); -const uint8_t *DCRYPTO_SHA384_hash(const void *data, uint32_t n, - uint8_t *digest); -const uint8_t *DCRYPTO_SHA512_hash(const void *data, uint32_t n, - uint8_t *digest); -/* - * HMAC. FIPS 198-1 - */ -void DCRYPTO_HMAC_SHA256_init(LITE_HMAC_CTX *ctx, const void *key, - unsigned int len); -/* DCRYPTO HMAC-SHA256 final */ -const uint8_t *DCRYPTO_HMAC_final(LITE_HMAC_CTX *ctx); - -/* - * BIGNUM utility methods. - */ -void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len); - -/* - * RSA. - */ - -/* Largest supported key size for signing / encryption: 2048-bits. - * Verification is a special case and supports 4096-bits (signing / - * decryption could also support 4k-RSA, but is disabled since support - * is not required, and enabling support would result in increased - * stack usage for all key sizes.) - */ -#define RSA_BYTES_2K 256 -#define RSA_BYTES_4K 512 -#define RSA_WORDS_2K (RSA_BYTES_2K / sizeof(uint32_t)) -#define RSA_WORDS_4K (RSA_BYTES_4K / sizeof(uint32_t)) -#ifndef RSA_MAX_BYTES -#define RSA_MAX_BYTES RSA_BYTES_2K -#endif -#define RSA_MAX_WORDS (RSA_MAX_BYTES / sizeof(uint32_t)) -#define RSA_F4 65537 - -struct RSA { - uint32_t e; - struct LITE_BIGNUM N; - struct LITE_BIGNUM d; -}; - -enum padding_mode { - PADDING_MODE_PKCS1 = 0, - PADDING_MODE_OAEP = 1, - PADDING_MODE_PSS = 2, - /* USE OF NULL PADDING IS NOT RECOMMENDED. - * SUPPORT EXISTS AS A REQUIREMENT FOR TPM2 OPERATION. */ - PADDING_MODE_NULL = 3 -}; - -/* RSA support, FIPS PUB 186-4 * - * Calculate r = m ^ e mod N - */ -int DCRYPTO_rsa_encrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len, - const uint8_t *in, uint32_t in_len, - enum padding_mode padding, enum hashing_mode hashing, - const char *label); - -/* Calculate r = m ^ d mod N - * return 0 if error - */ -int DCRYPTO_rsa_decrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len, - const uint8_t *in, const uint32_t in_len, - enum padding_mode padding, enum hashing_mode hashing, - const char *label); - -/* Calculate r = m ^ d mod N - * return 0 if error - */ -int DCRYPTO_rsa_sign(struct RSA *rsa, uint8_t *out, uint32_t *out_len, - const uint8_t *in, const uint32_t in_len, - enum padding_mode padding, enum hashing_mode hashing); - -/* Calculate r = m ^ e mod N - * return 0 if error - */ -int DCRYPTO_rsa_verify(const struct RSA *rsa, const uint8_t *digest, - uint32_t digest_len, const uint8_t *sig, - const uint32_t sig_len, enum padding_mode padding, - enum hashing_mode hashing); - -/* Calculate n = p * q, d = e ^ -1 mod phi. */ -int DCRYPTO_rsa_key_compute(struct LITE_BIGNUM *N, struct LITE_BIGNUM *d, - struct LITE_BIGNUM *p, struct LITE_BIGNUM *q, - uint32_t e); - -/* - * EC. - */ - -/* DCRYPTO_p256_base_point_mul sets {out_x,out_y} = nG, where n is < the - * order of the group. - */ -int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y, - const p256_int *n); - -/* DCRYPTO_p256_point_mul sets {out_x,out_y} = n*{in_x,in_y}, where n is < - * the order of the group. - */ -int DCRYPTO_p256_point_mul(p256_int *out_x, p256_int *out_y, - const p256_int *n, const p256_int *in_x, - const p256_int *in_y); -/* - * Key selection based on FIPS-186-4, section B.4.2 (Key Pair - * Generation by Testing Candidates). - * Produce uniform private key from seed. - * If x or y is NULL, the public key part is not computed. - * Returns !0 on success. - */ -int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d, - const uint8_t bytes[P256_NBYTES]); - - -/* P256 based integration encryption (DH+AES128+SHA256). - * Not FIPS 140-2 compliant, not used other than for tests - * Authenticated data may be provided, where the first auth_data_len - * bytes of in will be authenticated but not encrypted. * - * Supports in-place encryption / decryption. * - * The output format is: - * 0x04 || PUBKEY || AUTH_DATA || AES128_CTR(PLAINTEXT) || - * HMAC_SHA256(AUTH_DATA || CIPHERTEXT) - */ -size_t DCRYPTO_ecies_encrypt( - void *out, size_t out_len, const void *in, size_t in_len, - size_t auth_data_len, const uint8_t *iv, - const p256_int *pub_x, const p256_int *pub_y, - const uint8_t *salt, size_t salt_len, - const uint8_t *info, size_t info_len); -size_t DCRYPTO_ecies_decrypt( - void *out, size_t out_len, const void *in, size_t in_len, - size_t auth_data_len, const uint8_t *iv, - const p256_int *d, - const uint8_t *salt, size_t salt_len, - const uint8_t *info, size_t info_len); - -/* - * HKDF as per RFC 5869. Mentioned as conforming NIST SP 800-56C Rev.1 - * [RFC 5869] specifies a version of the above extraction-then-expansion - * key-derivation procedure using HMAC for both the extraction and expansion - * steps. - */ -int DCRYPTO_hkdf(uint8_t *OKM, size_t OKM_len, - const uint8_t *salt, size_t salt_len, - const uint8_t *IKM, size_t IKM_len, - const uint8_t *info, size_t info_len); - -/* - * BN. - */ - -/* Apply Miller-Rabin test for prime candidate p. - * Returns 1 if test passed, 0 otherwise - */ -int DCRYPTO_bn_generate_prime(struct LITE_BIGNUM *p); -void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len); -void DCRYPTO_bn_mul(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a, - const struct LITE_BIGNUM *b); -int DCRYPTO_bn_div(struct LITE_BIGNUM *quotient, struct LITE_BIGNUM *remainder, - const struct LITE_BIGNUM *input, - const struct LITE_BIGNUM *divisor); - -/* - * ASN.1 DER - */ -size_t DCRYPTO_asn1_sigp(uint8_t *buf, const p256_int *r, const p256_int *s); -size_t DCRYPTO_asn1_pubp(uint8_t *buf, const p256_int *x, const p256_int *y); - -/* - * X509. - */ -/* DCRYPTO_x509_verify verifies that the provided X509 certificate was issued - * by the specified certifcate authority. - * - * cert is a pointer to a DER encoded X509 certificate, as specified - * in https://tools.ietf.org/html/rfc5280#section-4.1. In ASN.1 - * notation, the certificate has the following structure: - * - * Certificate ::= SEQUENCE { - * tbsCertificate TBSCertificate, - * signatureAlgorithm AlgorithmIdentifier, - * signatureValue BIT STRING } - * - * TBSCertificate ::= SEQUENCE { } - * AlgorithmIdentifier ::= SEQUENCE { } - * - * where signatureValue = SIGN(HASH(tbsCertificate)), with SIGN and - * HASH specified by signatureAlgorithm. - * Accepts only certs with OID: sha256WithRSAEncryption: - * 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 - */ -int DCRYPTO_x509_verify(const uint8_t *cert, size_t len, - const struct RSA *ca_pub_key); - -/* Generate U2F Certificate and sign it - * Use ECDSA with NIST P-256 curve, and SHA2-256 digest - * @param d: key handle, used for NIST SP 800-90A HMAC DRBG - * @param pk_x, pk_y: public key - * @param serial: serial number for certificate - * @param name: certificate issuer and subject - * @param cert: output buffer for certificate - * @param n: max size of cert - */ -int DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x, - const p256_int *pk_y, const p256_int *serial, - const char *name, uint8_t *cert, - const int n); - -/* Generate U2F Certificate with DCRYPTO_x509_gen_u2f_cert_name - * Providing certificate issuer as BOARD or U2F - * @param d: key handle, used for NIST SP 800-90A HMAC DRBG - * @param pk_x, pk_y: public key - * @param serial: serial number for certificate - * @param name: certificate issuer and subject - * @param cert: output buffer for certificate - * @param n: max size of cert - */ -int DCRYPTO_x509_gen_u2f_cert(const p256_int *d, const p256_int *pk_x, - const p256_int *pk_y, const p256_int *serial, - uint8_t *cert, const int n); - -/* - * Memory related functions. - */ -int DCRYPTO_equals(const void *a, const void *b, size_t len); - -/* - * Key-ladder and application key related functions. - */ -enum dcrypto_appid { - RESERVED = 0, - NVMEM = 1, - U2F_ATTEST = 2, - U2F_ORIGIN = 3, - U2F_WRAP = 4, - PERSO_AUTH = 5, - PINWEAVER = 6, - /* This enum value should not exceed 7. */ -}; - -struct APPKEY_CTX { -#ifdef TEST_FUZZ - uint8_t unused_for_cxx_compatibility; -#endif -}; - -int DCRYPTO_ladder_compute_frk2(size_t major_fw_version, uint8_t *frk2); -int DCRYPTO_ladder_random(void *output); -void DCRYPTO_ladder_revoke(void); - -int DCRYPTO_appkey_init(enum dcrypto_appid id, struct APPKEY_CTX *ctx); -void DCRYPTO_appkey_finish(struct APPKEY_CTX *ctx); -int DCRYPTO_appkey_derive(enum dcrypto_appid appid, const uint32_t input[8], - uint32_t output[8]); - -/* Number of bytes in the salt object. */ -#define DCRYPTO_CIPHER_SALT_SIZE 16 -BUILD_ASSERT(DCRYPTO_CIPHER_SALT_SIZE == CIPHER_SALT_SIZE); - -/* - * Encrypt/decrypt a flat blob. - * - * Encrypt or decrypt the input buffer, and write the correspondingly - * ciphered output to out. The number of bytes produced is equal to - * the number of input bytes. Note that the input and output pointers - * MUST be word-aligned. - * - * This API is expected to be applied to a single contiguous region. - - * WARNING: A given salt/"in" pair MUST be unique, i.e. re-using a - * salt with a logically different input buffer is catastrophic. An - * example of a suitable salt is one that is derived from "in", e.g. a - * digest of the input data. - * - * @param appid the application-id of the calling context. - * @param salt pointer to a unique value to be associated with this blob, - * used for derivation of the proper IV, the size of the value - * is as defined by DCRYPTO_CIPHER_SALT_SIZE above. - * @param out Destination pointer where to write plaintext / ciphertext. - * @param in Source pointer where to read ciphertext / plaintext. - * @param len Number of bytes to read from in / write to out. - * @return non-zero on success, and zero otherwise. - */ -int DCRYPTO_app_cipher(enum dcrypto_appid appid, const void *salt, - void *out, const void *in, size_t len); - -#endif /* ^^^^^^^^^^^^^^^^^^^^^ !TEST_BUILD */ -/* - * Query whether Key Ladder is enabled. - * - * @return 1 if Key Ladder is enabled, and 0 otherwise. - */ -int DCRYPTO_ladder_is_enabled(void); - -#ifdef __cplusplus -} -#endif - -#endif /* ! __EC_CHIP_G_DCRYPTO_DCRYPTO_H */ diff --git a/chip/g/dcrypto/dcrypto_bn.c b/chip/g/dcrypto/dcrypto_bn.c deleted file mode 100644 index b8f8fef4f4..0000000000 --- a/chip/g/dcrypto/dcrypto_bn.c +++ /dev/null @@ -1,1496 +0,0 @@ -/* Copyright 2016 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 "trng.h" - -/* Firmware blob for crypto accelerator */ - -/* AUTO-GENERATED. DO NOT MODIFY. */ -/* clang-format off */ -static const uint32_t IMEM_dcrypto_bn[] = { -/* @0x0: function tag[1] { */ -#define CF_tag_adr 0 -0xf8000001, /* sigini #1 */ -/* } */ -/* @0x1: function d0inv[14] { */ -#define CF_d0inv_adr 1 -0x4c000000, /* xor r0, r0, r0 */ -0x80000001, /* movi r0.0l, #1 */ -0x7c740000, /* mov r29, r0 */ -0x05100008, /* loop #256 ( */ -0x5807bc00, /* mul128 r1, r28l, r29l */ -0x588bbc00, /* mul128 r2, r28u, r29l */ -0x50044110, /* add r1, r1, r2 << 128 */ -0x590bbc00, /* mul128 r2, r28l, r29u */ -0x50044110, /* add r1, r1, r2 << 128 */ -0x40040100, /* and r1, r1, r0 */ -0x44743d00, /* or r29, r29, r1 */ -0x50000000, /* add r0, r0, r0 */ -/* ) */ -0x5477bf00, /* sub r29, r31, r29 */ -0x0c000000, /* ret */ -/* } */ -/* @0xf: function selcxSub[25] { */ -#define CF_selcxSub_adr 15 -0x97800100, /* ldrfp r1 */ -0x95800000, /* lddmp r0 */ -0x99100000, /* strnd r4 */ -0x5013e400, /* add r4, r4, r31 */ -0x1000101e, /* bl selcxSub_invsel */ -0x528c8402, /* addcx r3, r4, r4 << 16 */ -0x0600c007, /* loop *6 ( */ -0x8c081800, /* ld *2, *0++ */ -0x7c8c0000, /* ldr *3, *0 */ -0x7c800400, /* ldr *0, *4 */ -0x54906200, /* subb r4, r2, r3 */ -0x990c0000, /* strnd r3 */ -0x660c4401, /* sellx r3, r4, r2 */ -0x7ca00200, /* ldr *0++, *2 */ -/* ) */ -0x0c000000, /* ret */ -/*selcxSub_invsel: */ -0x528c8402, /* addcx r3, r4, r4 << 16 */ -0x0600c007, /* loop *6 ( */ -0x8c081800, /* ld *2, *0++ */ -0x7c8c0000, /* ldr *3, *0 */ -0x7c800400, /* ldr *0, *4 */ -0x54906200, /* subb r4, r2, r3 */ -0x990c0000, /* strnd r3 */ -0x660c8201, /* sellx r3, r2, r4 */ -0x7ca00200, /* ldr *0++, *2 */ -/* ) */ -0x0c000000, /* ret */ -/* } */ -/* @0x28: function computeRR[41] { */ -#define CF_computeRR_adr 40 -0x4c7fff00, /* xor r31, r31, r31 */ -0x84004000, /* ldi r0, [#0] */ -0x95800000, /* lddmp r0 */ -0x4c0c6300, /* xor r3, r3, r3 */ -0x800cffff, /* movi r3.0l, #65535 */ -0x40040398, /* and r1, r3, r0 >> 192 */ -0x480c6000, /* not r3, r3 */ -0x400c0300, /* and r3, r3, r0 */ -0x500c2301, /* add r3, r3, r1 << 8 */ -0x94800300, /* ldlc r3 */ -0x80040005, /* movi r1.0l, #5 */ -0x81040003, /* movi r1.2l, #3 */ -0x81840002, /* movi r1.3l, #2 */ -0x82040004, /* movi r1.4l, #4 */ -0x97800100, /* ldrfp r1 */ -0x4c0c6300, /* xor r3, r3, r3 */ -0x0600c001, /* loop *6 ( */ -0x7ca00200, /* ldr *0++, *2 */ -/* ) */ -0x560c1f00, /* subx r3, r31, r0 */ -0x0800000f, /* call &selcxSub */ -0x06000010, /* loop *0 ( */ -0x97800100, /* ldrfp r1 */ -0x560c6300, /* subx r3, r3, r3 */ -0x0600c003, /* loop *6 ( */ -0x7c8c0000, /* ldr *3, *0 */ -0x52884200, /* addcx r2, r2, r2 */ -0x7ca00300, /* ldr *0++, *3 */ -/* ) */ -0x0800000f, /* call &selcxSub */ -0x97800100, /* ldrfp r1 */ -0x95800000, /* lddmp r0 */ -0x560c6300, /* subx r3, r3, r3 */ -0x0600c003, /* loop *6 ( */ -0x8c081800, /* ld *2, *0++ */ -0x7c8c0800, /* ldr *3, *0++ */ -0x5e804300, /* cmpbx r3, r2 */ -/* ) */ -0x0800000f, /* call &selcxSub */ -0xfc000000, /* nop */ -/* ) */ -0x97800100, /* ldrfp r1 */ -0x0600c001, /* loop *6 ( */ -0x90680800, /* st *0++, *2++ */ -/* ) */ -0x0c000000, /* ret */ -/* } */ -/* @0x51: function dmXd0[9] { */ -#define CF_dmXd0_adr 81 -0x586f3e00, /* mul128 r27, r30l, r25l */ -0x59eb3e00, /* mul128 r26, r30u, r25u */ -0x58df3e00, /* mul128 r23, r30u, r25l */ -0x506efb10, /* add r27, r27, r23 << 128 */ -0x50eafa90, /* addc r26, r26, r23 >> 128 */ -0x595f3e00, /* mul128 r23, r30l, r25u */ -0x506efb10, /* add r27, r27, r23 << 128 */ -0x50eafa90, /* addc r26, r26, r23 >> 128 */ -0x0c000000, /* ret */ -/* } */ -/* @0x5a: function dmXa[9] { */ -#define CF_dmXa_adr 90 -0x586c5e00, /* mul128 r27, r30l, r2l */ -0x59e85e00, /* mul128 r26, r30u, r2u */ -0x58dc5e00, /* mul128 r23, r30u, r2l */ -0x506efb10, /* add r27, r27, r23 << 128 */ -0x50eafa90, /* addc r26, r26, r23 >> 128 */ -0x595c5e00, /* mul128 r23, r30l, r2u */ -0x506efb10, /* add r27, r27, r23 << 128 */ -0x50eafa90, /* addc r26, r26, r23 >> 128 */ -0x0c000000, /* ret */ -/* } */ -/* @0x63: function mma_sub_cx[23] { */ -#define CF_mma_sub_cx_adr 99 -0x99700000, /* strnd r28 */ -0x5073fc00, /* add r28, r28, r31 */ -0x10001070, /* bl mma_invsel */ -0x52f39c02, /* addcx r28, r28, r28 << 16 */ -0x0600c007, /* loop *6 ( */ -0x8c141800, /* ld *5, *0++ */ -0x7c900000, /* ldr *4, *0 */ -0x54f71e00, /* subb r29, r30, r24 */ -0x99600000, /* strnd r24 */ -0x7c800500, /* ldr *0, *5 */ -0x6663dd01, /* sellx r24, r29, r30 */ -0x7ca00500, /* ldr *0++, *5 */ -/* ) */ -0x0c000000, /* ret */ -/*mma_invsel: */ -0x52f39c02, /* addcx r28, r28, r28 << 16 */ -0x0600c007, /* loop *6 ( */ -0x8c141800, /* ld *5, *0++ */ -0x7c900000, /* ldr *4, *0 */ -0x54f71e00, /* subb r29, r30, r24 */ -0x99600000, /* strnd r24 */ -0x7c800500, /* ldr *0, *5 */ -0x6663be01, /* sellx r24, r30, r29 */ -0x7ca00500, /* ldr *0++, *5 */ -/* ) */ -0x0c000000, /* ret */ -/* } */ -/* @0x7a: function mma[39] { */ -#define CF_mma_adr 122 -0x8204001e, /* movi r1.4l, #30 */ -0x82840018, /* movi r1.5l, #24 */ -0x97800100, /* ldrfp r1 */ -0x8c101b00, /* ld *4, *3++ */ -0x0800005a, /* call &dmXa */ -0x7c940800, /* ldr *5, *0++ */ -0x507b1b00, /* add r30, r27, r24 */ -0x50f7fa00, /* addc r29, r26, r31 */ -0x7c640300, /* mov r25, r3 */ -0x08000051, /* call &dmXd0 */ -0x7c641b00, /* mov r25, r27 */ -0x7c701a00, /* mov r28, r26 */ -0x7c601e00, /* mov r24, r30 */ -0x8c101800, /* ld *4, *0++ */ -0x08000051, /* call &dmXd0 */ -0x506f1b00, /* add r27, r27, r24 */ -0x50f3fa00, /* addc r28, r26, r31 */ -0x0600e00e, /* loop *7 ( */ -0x8c101b00, /* ld *4, *3++ */ -0x0800005a, /* call &dmXa */ -0x7c940800, /* ldr *5, *0++ */ -0x506f1b00, /* add r27, r27, r24 */ -0x50ebfa00, /* addc r26, r26, r31 */ -0x5063bb00, /* add r24, r27, r29 */ -0x50f7fa00, /* addc r29, r26, r31 */ -0x8c101800, /* ld *4, *0++ */ -0x08000051, /* call &dmXd0 */ -0x506f1b00, /* add r27, r27, r24 */ -0x50ebfa00, /* addc r26, r26, r31 */ -0x52639b00, /* addx r24, r27, r28 */ -0x7ca80500, /* ldr *2++, *5 */ -0x52f3fa00, /* addcx r28, r26, r31 */ -/* ) */ -0x52e39d00, /* addcx r24, r29, r28 */ -0x7ca80500, /* ldr *2++, *5 */ -0x95800000, /* lddmp r0 */ -0x97800100, /* ldrfp r1 */ -0x08000063, /* call &mma_sub_cx */ -0xfc000000, /* nop */ -0x0c000000, /* ret */ -/* } */ -/* @0xa1: function setupPtrs[11] { */ -#define CF_setupPtrs_adr 161 -0x847c4000, /* ldi r31, [#0] */ -0x4c7fff00, /* xor r31, r31, r31 */ -0x95800000, /* lddmp r0 */ -0x94800000, /* ldlc r0 */ -0x7c041f00, /* mov r1, r31 */ -0x80040004, /* movi r1.0l, #4 */ -0x80840003, /* movi r1.1l, #3 */ -0x81040004, /* movi r1.2l, #4 */ -0x81840002, /* movi r1.3l, #2 */ -0x97800100, /* ldrfp r1 */ -0x0c000000, /* ret */ -/* } */ -/* @0xac: function mulx[19] { */ -#define CF_mulx_adr 172 -0x84004000, /* ldi r0, [#0] */ -0x080000a1, /* call &setupPtrs */ -0x8c041100, /* ld *1, *1 */ -0x7c081f00, /* mov r2, r31 */ -0x0600c001, /* loop *6 ( */ -0x7ca80300, /* ldr *2++, *3 */ -/* ) */ -0x97800100, /* ldrfp r1 */ -0x0600c004, /* loop *6 ( */ -0x8c0c1c00, /* ld *3, *4++ */ -0x95000000, /* stdmp r0 */ -0x0800007a, /* call &mma */ -0x95800000, /* lddmp r0 */ -/* ) */ -0x97800100, /* ldrfp r1 */ -0x95800000, /* lddmp r0 */ -0x0600c001, /* loop *6 ( */ -0x90740800, /* st *0++, *5++ */ -/* ) */ -0x97800100, /* ldrfp r1 */ -0x95800000, /* lddmp r0 */ -0x0c000000, /* ret */ -/* } */ -/* @0xbf: function mm1_sub_cx[22] { */ -#define CF_mm1_sub_cx_adr 191 -0x990c0000, /* strnd r3 */ -0x500fe300, /* add r3, r3, r31 */ -0x100010cc, /* bl mm1_invsel */ -0x528c6302, /* addcx r3, r3, r3 << 16 */ -0x0600c006, /* loop *6 ( */ -0x8c041800, /* ld *1, *0++ */ -0x7c8c0800, /* ldr *3, *0++ */ -0x548c6200, /* subb r3, r2, r3 */ -0x66084301, /* sellx r2, r3, r2 */ -0x90740300, /* st *3, *5++ */ -0xfc000000, /* nop */ -/* ) */ -0x0c000000, /* ret */ -0xfc000000, /* nop */ -/*mm1_invsel: */ -0x528c6302, /* addcx r3, r3, r3 << 16 */ -0x0600c006, /* loop *6 ( */ -0x8c041800, /* ld *1, *0++ */ -0x7c8c0800, /* ldr *3, *0++ */ -0x548c6200, /* subb r3, r2, r3 */ -0x66086201, /* sellx r2, r2, r3 */ -0x90740300, /* st *3, *5++ */ -0xfc000000, /* nop */ -/* ) */ -0x0c000000, /* ret */ -/* } */ -/* @0xd5: function mul1_exp[23] { */ -#define CF_mul1_exp_adr 213 -0x8c041100, /* ld *1, *1 */ -0x7c081f00, /* mov r2, r31 */ -0x0600c001, /* loop *6 ( */ -0x7ca80300, /* ldr *2++, *3 */ -/* ) */ -0x97800100, /* ldrfp r1 */ -0x80080001, /* movi r2.0l, #1 */ -0x0600c003, /* loop *6 ( */ -0x95800000, /* lddmp r0 */ -0x0800007a, /* call &mma */ -0x7c081f00, /* mov r2, r31 */ -/* ) */ -0x97800100, /* ldrfp r1 */ -0x95800000, /* lddmp r0 */ -0x56084200, /* subx r2, r2, r2 */ -0x0600c003, /* loop *6 ( */ -0x8c041800, /* ld *1, *0++ */ -0x7c8c0800, /* ldr *3, *0++ */ -0x5e804300, /* cmpbx r3, r2 */ -/* ) */ -0x97800100, /* ldrfp r1 */ -0x95800000, /* lddmp r0 */ -0x080000bf, /* call &mm1_sub_cx */ -0x97800100, /* ldrfp r1 */ -0x95800000, /* lddmp r0 */ -0x0c000000, /* ret */ -/* } */ -/* @0xec: function mul1[4] { */ -#define CF_mul1_adr 236 -0x84004000, /* ldi r0, [#0] */ -0x080000a1, /* call &setupPtrs */ -0x080000d5, /* call &mul1_exp */ -0x0c000000, /* ret */ -/* } */ -/* @0xf0: function sqrx_exp[19] { */ -#define CF_sqrx_exp_adr 240 -0x84004020, /* ldi r0, [#1] */ -0x95800000, /* lddmp r0 */ -0x8c041100, /* ld *1, *1 */ -0x7c081f00, /* mov r2, r31 */ -0x0600c001, /* loop *6 ( */ -0x7ca80300, /* ldr *2++, *3 */ -/* ) */ -0x97800100, /* ldrfp r1 */ -0x0600c004, /* loop *6 ( */ -0x8c0c1c00, /* ld *3, *4++ */ -0x95000000, /* stdmp r0 */ -0x0800007a, /* call &mma */ -0x95800000, /* lddmp r0 */ -/* ) */ -0x97800100, /* ldrfp r1 */ -0x95800000, /* lddmp r0 */ -0x0600c001, /* loop *6 ( */ -0x90740800, /* st *0++, *5++ */ -/* ) */ -0x97800100, /* ldrfp r1 */ -0x95800000, /* lddmp r0 */ -0x0c000000, /* ret */ -/* } */ -/* @0x103: function mulx_exp[14] { */ -#define CF_mulx_exp_adr 259 -0x84004040, /* ldi r0, [#2] */ -0x95800000, /* lddmp r0 */ -0x8c041100, /* ld *1, *1 */ -0x7c081f00, /* mov r2, r31 */ -0x0600c001, /* loop *6 ( */ -0x7ca80300, /* ldr *2++, *3 */ -/* ) */ -0x97800100, /* ldrfp r1 */ -0x0600c004, /* loop *6 ( */ -0x8c0c1c00, /* ld *3, *4++ */ -0x95000000, /* stdmp r0 */ -0x0800007a, /* call &mma */ -0x95800000, /* lddmp r0 */ -/* ) */ -0x97800100, /* ldrfp r1 */ -0x0c000000, /* ret */ -/* } */ -/* @0x111: function selOutOrC[30] { */ -#define CF_selOutOrC_adr 273 -0x990c0000, /* strnd r3 */ -0x440c6300, /* or r3, r3, r3 */ -0x10001122, /* bl selOutOrC_invsel */ -0x508c6302, /* addc r3, r3, r3 << 16 */ -0x0600c00a, /* loop *6 ( */ -0x990c0000, /* strnd r3 */ -0x99080000, /* strnd r2 */ -0x8c041500, /* ld *1, *5 */ -0x90540300, /* st *3, *5 */ -0x7c8c0800, /* ldr *3, *0++ */ -0x99000000, /* strnd r0 */ -0x7c000200, /* mov r0, r2 */ -0x99080000, /* strnd r2 */ -0x64086001, /* sell r2, r0, r3 */ -0x90740300, /* st *3, *5++ */ -/* ) */ -0x0c000000, /* ret */ -0xfc000000, /* nop */ -/*selOutOrC_invsel: */ -0x508c6302, /* addc r3, r3, r3 << 16 */ -0x0600c00a, /* loop *6 ( */ -0x990c0000, /* strnd r3 */ -0x99080000, /* strnd r2 */ -0x8c041500, /* ld *1, *5 */ -0x90540300, /* st *3, *5 */ -0x7c8c0800, /* ldr *3, *0++ */ -0x99000000, /* strnd r0 */ -0x7c000200, /* mov r0, r2 */ -0x99080000, /* strnd r2 */ -0x64080301, /* sell r2, r3, r0 */ -0x90740300, /* st *3, *5++ */ -/* ) */ -0x0c000000, /* ret */ -/* } */ -/* @0x12f: function modexp[35] { */ -#define CF_modexp_adr 303 -0x080000ac, /* call &mulx */ -0x84004060, /* ldi r0, [#3] */ -0x95800000, /* lddmp r0 */ -0x54084200, /* sub r2, r2, r2 */ -0x0600c004, /* loop *6 ( */ -0xfc000000, /* nop */ -0x8c0c1800, /* ld *3, *0++ */ -0x54885f00, /* subb r2, r31, r2 */ -0x90740300, /* st *3, *5++ */ -/* ) */ -0xfc000000, /* nop */ -0x7c081f00, /* mov r2, r31 */ -0x8008ffff, /* movi r2.0l, #65535 */ -0x400c0298, /* and r3, r2, r0 >> 192 */ -0x48084000, /* not r2, r2 */ -0x40080200, /* and r2, r2, r0 */ -0x50086201, /* add r2, r2, r3 << 8 */ -0x94800200, /* ldlc r2 */ -0x0600000d, /* loop *0 ( */ -0x080000f0, /* call &sqrx_exp */ -0x08000103, /* call &mulx_exp */ -0x84004060, /* ldi r0, [#3] */ -0x95800000, /* lddmp r0 */ -0x99080000, /* strnd r2 */ -0x50084200, /* add r2, r2, r2 */ -0x0600c004, /* loop *6 ( */ -0x99080000, /* strnd r2 */ -0x8c0c1400, /* ld *3, *4 */ -0x50884200, /* addc r2, r2, r2 */ -0x90700300, /* st *3, *4++ */ -/* ) */ -0x08000111, /* call &selOutOrC */ -0xfc000000, /* nop */ -/* ) */ -0x84004060, /* ldi r0, [#3] */ -0x95800000, /* lddmp r0 */ -0x080000d5, /* call &mul1_exp */ -0x0c000000, /* ret */ -/* } */ -/* @0x152: function modexp_blinded[76] { */ -#define CF_modexp_blinded_adr 338 -0x080000ac, /* call &mulx */ -0x84004060, /* ldi r0, [#3] */ -0x95800000, /* lddmp r0 */ -0x54084200, /* sub r2, r2, r2 */ -0x0600c004, /* loop *6 ( */ -0xfc000000, /* nop */ -0x8c0c1800, /* ld *3, *0++ */ -0x54885f00, /* subb r2, r31, r2 */ -0x90740300, /* st *3, *5++ */ -/* ) */ -0xfc000000, /* nop */ -0x8c0c1900, /* ld *3, *1++ */ -0x8c0c1100, /* ld *3, *1 */ -0x521c5f90, /* addx r7, r31, r2 >> 128 */ -0x590c4200, /* mul128 r3, r2l, r2u */ -0x7c181f00, /* mov r6, r31 */ -0x0600c011, /* loop *6 ( */ -0x99080000, /* strnd r2 */ -0x8c0c1400, /* ld *3, *4 */ -0x58106200, /* mul128 r4, r2l, r3l */ -0x59946200, /* mul128 r5, r2u, r3u */ -0x58806200, /* mul128 r0, r2u, r3l */ -0x50100410, /* add r4, r4, r0 << 128 */ -0x50940590, /* addc r5, r5, r0 >> 128 */ -0x59006200, /* mul128 r0, r2l, r3u */ -0x50100410, /* add r4, r4, r0 << 128 */ -0x50940590, /* addc r5, r5, r0 >> 128 */ -0x5010c400, /* add r4, r4, r6 */ -0x5097e500, /* addc r5, r5, r31 */ -0x50088200, /* add r2, r2, r4 */ -0x509be500, /* addc r6, r5, r31 */ -0x5688e200, /* subbx r2, r2, r7 */ -0x90700300, /* st *3, *4++ */ -0x541ce700, /* sub r7, r7, r7 */ -/* ) */ -0x7c080600, /* mov r2, r6 */ -0x5688e200, /* subbx r2, r2, r7 */ -0x90500300, /* st *3, *4 */ -0xfc000000, /* nop */ -0x84004060, /* ldi r0, [#3] */ -0x7c081f00, /* mov r2, r31 */ -0x8008ffff, /* movi r2.0l, #65535 */ -0x400c0298, /* and r3, r2, r0 >> 192 */ -0x48084000, /* not r2, r2 */ -0x40080200, /* and r2, r2, r0 */ -0x510c0301, /* addi r3, r3, #1 */ -0x50086201, /* add r2, r2, r3 << 8 */ -0x94800200, /* ldlc r2 */ -0x06000019, /* loop *0 ( */ -0x080000f0, /* call &sqrx_exp */ -0x08000103, /* call &mulx_exp */ -0x84004060, /* ldi r0, [#3] */ -0x95800000, /* lddmp r0 */ -0x99080000, /* strnd r2 */ -0x54084200, /* sub r2, r2, r2 */ -0x0600c004, /* loop *6 ( */ -0x99080000, /* strnd r2 */ -0x8c0c1400, /* ld *3, *4 */ -0x50884200, /* addc r2, r2, r2 */ -0x90700300, /* st *3, *4++ */ -/* ) */ -0x99080000, /* strnd r2 */ -0x8c0c1400, /* ld *3, *4 */ -0x50884200, /* addc r2, r2, r2 */ -0x90700300, /* st *3, *4++ */ -0x0600c008, /* loop *6 ( */ -0x99080000, /* strnd r2 */ -0x8c041500, /* ld *1, *5 */ -0x90540300, /* st *3, *5 */ -0x7c8c0800, /* ldr *3, *0++ */ -0x7c000200, /* mov r0, r2 */ -0x99080000, /* strnd r2 */ -0x64086008, /* selc r2, r0, r3 */ -0x90740300, /* st *3, *5++ */ -/* ) */ -0xfc000000, /* nop */ -/* ) */ -0x84004060, /* ldi r0, [#3] */ -0x95800000, /* lddmp r0 */ -0x080000d5, /* call &mul1_exp */ -0x0c000000, /* ret */ -/* } */ -/* @0x19e: function modload[12] { */ -#define CF_modload_adr 414 -0x4c7fff00, /* xor r31, r31, r31 */ -0x84004000, /* ldi r0, [#0] */ -0x95800000, /* lddmp r0 */ -0x94800000, /* ldlc r0 */ -0x8000001c, /* movi r0.0l, #28 */ -0x8080001d, /* movi r0.1l, #29 */ -0x97800000, /* ldrfp r0 */ -0x8c001000, /* ld *0, *0 */ -0x08000001, /* call &d0inv */ -0x90440100, /* st *1, *1 */ -0x08000028, /* call &computeRR */ -0x0c000000, /* ret */ -/* } */ -#ifdef CONFIG_DCRYPTO_RSA_SPEEDUP -/* @0x1aa: function selA0orC4[16] { */ -#define CF_selA0orC4_adr 426 -0x99000000, /* strnd r0 */ -0x44000000, /* or r0, r0, r0 */ -0x100011b4, /* bl selA0orC4_invsel */ -0x50840002, /* addc r1, r0, r0 << 16 */ -0x6458da01, /* sell r22, r26, r6 */ -0x645cfb01, /* sell r23, r27, r7 */ -0x64611c01, /* sell r24, r28, r8 */ -0x64653d01, /* sell r25, r29, r9 */ -0x0c000000, /* ret */ -0xfc000000, /* nop */ -/*selA0orC4_invsel: */ -0x50840002, /* addc r1, r0, r0 << 16 */ -0x645b4601, /* sell r22, r6, r26 */ -0x645f6701, /* sell r23, r7, r27 */ -0x64638801, /* sell r24, r8, r28 */ -0x6467a901, /* sell r25, r9, r29 */ -0x0c000000, /* ret */ -/* } */ -/* @0x1ba: function mul4[169] { */ -#define CF_mul4_adr 442 -0x58594600, /* mul128 r22, r6l, r10l */ -0x59dd4600, /* mul128 r23, r6u, r10u */ -0x58894600, /* mul128 r2, r6u, r10l */ -0x50585610, /* add r22, r22, r2 << 128 */ -0x50dc5790, /* addc r23, r23, r2 >> 128 */ -0x59094600, /* mul128 r2, r6l, r10u */ -0x50585610, /* add r22, r22, r2 << 128 */ -0x50dc5790, /* addc r23, r23, r2 >> 128 */ -0x58616700, /* mul128 r24, r7l, r11l */ -0x59e56700, /* mul128 r25, r7u, r11u */ -0x58896700, /* mul128 r2, r7u, r11l */ -0x50605810, /* add r24, r24, r2 << 128 */ -0x50e45990, /* addc r25, r25, r2 >> 128 */ -0x59096700, /* mul128 r2, r7l, r11u */ -0x50605810, /* add r24, r24, r2 << 128 */ -0x50e45990, /* addc r25, r25, r2 >> 128 */ -0x58698800, /* mul128 r26, r8l, r12l */ -0x59ed8800, /* mul128 r27, r8u, r12u */ -0x58898800, /* mul128 r2, r8u, r12l */ -0x50685a10, /* add r26, r26, r2 << 128 */ -0x50ec5b90, /* addc r27, r27, r2 >> 128 */ -0x59098800, /* mul128 r2, r8l, r12u */ -0x50685a10, /* add r26, r26, r2 << 128 */ -0x50ec5b90, /* addc r27, r27, r2 >> 128 */ -0x5871a900, /* mul128 r28, r9l, r13l */ -0x59f5a900, /* mul128 r29, r9u, r13u */ -0x5889a900, /* mul128 r2, r9u, r13l */ -0x50705c10, /* add r28, r28, r2 << 128 */ -0x50f45d90, /* addc r29, r29, r2 >> 128 */ -0x5909a900, /* mul128 r2, r9l, r13u */ -0x50705c10, /* add r28, r28, r2 << 128 */ -0x50f45d90, /* addc r29, r29, r2 >> 128 */ -0x58016600, /* mul128 r0, r6l, r11l */ -0x59856600, /* mul128 r1, r6u, r11u */ -0x58896600, /* mul128 r2, r6u, r11l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x59096600, /* mul128 r2, r6l, r11u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x505c1700, /* add r23, r23, r0 */ -0x50e03800, /* addc r24, r24, r1 */ -0x508fff00, /* addc r3, r31, r31 */ -0x58014700, /* mul128 r0, r7l, r10l */ -0x59854700, /* mul128 r1, r7u, r10u */ -0x58894700, /* mul128 r2, r7u, r10l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x59094700, /* mul128 r2, r7l, r10u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x505c1700, /* add r23, r23, r0 */ -0x50e03800, /* addc r24, r24, r1 */ -0x50e47900, /* addc r25, r25, r3 */ -0x508fff00, /* addc r3, r31, r31 */ -0x58018600, /* mul128 r0, r6l, r12l */ -0x59858600, /* mul128 r1, r6u, r12u */ -0x58898600, /* mul128 r2, r6u, r12l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x59098600, /* mul128 r2, r6l, r12u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x50601800, /* add r24, r24, r0 */ -0x50e43900, /* addc r25, r25, r1 */ -0x508fe300, /* addc r3, r3, r31 */ -0x58014800, /* mul128 r0, r8l, r10l */ -0x59854800, /* mul128 r1, r8u, r10u */ -0x58894800, /* mul128 r2, r8u, r10l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x59094800, /* mul128 r2, r8l, r10u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x50601800, /* add r24, r24, r0 */ -0x50e43900, /* addc r25, r25, r1 */ -0x50e87a00, /* addc r26, r26, r3 */ -0x508fff00, /* addc r3, r31, r31 */ -0x5801a600, /* mul128 r0, r6l, r13l */ -0x5985a600, /* mul128 r1, r6u, r13u */ -0x5889a600, /* mul128 r2, r6u, r13l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x5909a600, /* mul128 r2, r6l, r13u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x50641900, /* add r25, r25, r0 */ -0x50e83a00, /* addc r26, r26, r1 */ -0x508fe300, /* addc r3, r3, r31 */ -0x58018700, /* mul128 r0, r7l, r12l */ -0x59858700, /* mul128 r1, r7u, r12u */ -0x58898700, /* mul128 r2, r7u, r12l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x59098700, /* mul128 r2, r7l, r12u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x50641900, /* add r25, r25, r0 */ -0x50e83a00, /* addc r26, r26, r1 */ -0x508fe300, /* addc r3, r3, r31 */ -0x58014900, /* mul128 r0, r9l, r10l */ -0x59854900, /* mul128 r1, r9u, r10u */ -0x58894900, /* mul128 r2, r9u, r10l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x59094900, /* mul128 r2, r9l, r10u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x50641900, /* add r25, r25, r0 */ -0x50e83a00, /* addc r26, r26, r1 */ -0x508fe300, /* addc r3, r3, r31 */ -0x58016800, /* mul128 r0, r8l, r11l */ -0x59856800, /* mul128 r1, r8u, r11u */ -0x58896800, /* mul128 r2, r8u, r11l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x59096800, /* mul128 r2, r8l, r11u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x50641900, /* add r25, r25, r0 */ -0x50e83a00, /* addc r26, r26, r1 */ -0x50ec7b00, /* addc r27, r27, r3 */ -0x508fff00, /* addc r3, r31, r31 */ -0x5801a700, /* mul128 r0, r7l, r13l */ -0x5985a700, /* mul128 r1, r7u, r13u */ -0x5889a700, /* mul128 r2, r7u, r13l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x5909a700, /* mul128 r2, r7l, r13u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x50681a00, /* add r26, r26, r0 */ -0x50ec3b00, /* addc r27, r27, r1 */ -0x508fe300, /* addc r3, r3, r31 */ -0x58016900, /* mul128 r0, r9l, r11l */ -0x59856900, /* mul128 r1, r9u, r11u */ -0x58896900, /* mul128 r2, r9u, r11l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x59096900, /* mul128 r2, r9l, r11u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x50681a00, /* add r26, r26, r0 */ -0x50ec3b00, /* addc r27, r27, r1 */ -0x50f07c00, /* addc r28, r28, r3 */ -0x50f7fd00, /* addc r29, r29, r31 */ -0x5801a800, /* mul128 r0, r8l, r13l */ -0x5985a800, /* mul128 r1, r8u, r13u */ -0x5889a800, /* mul128 r2, r8u, r13l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x5909a800, /* mul128 r2, r8l, r13u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x506c1b00, /* add r27, r27, r0 */ -0x50f03c00, /* addc r28, r28, r1 */ -0x50f7fd00, /* addc r29, r29, r31 */ -0x58018900, /* mul128 r0, r9l, r12l */ -0x59858900, /* mul128 r1, r9u, r12u */ -0x58898900, /* mul128 r2, r9u, r12l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x59098900, /* mul128 r2, r9l, r12u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x506c1b00, /* add r27, r27, r0 */ -0x50f03c00, /* addc r28, r28, r1 */ -0x50f7fd00, /* addc r29, r29, r31 */ -0x0c000000, /* ret */ -/* } */ -/* @0x263: function sqr4[117] { */ -#define CF_sqr4_adr 611 -0x5858c600, /* mul128 r22, r6l, r6l */ -0x59dcc600, /* mul128 r23, r6u, r6u */ -0x5888c600, /* mul128 r2, r6u, r6l */ -0x50585610, /* add r22, r22, r2 << 128 */ -0x50dc5790, /* addc r23, r23, r2 >> 128 */ -0x50585610, /* add r22, r22, r2 << 128 */ -0x50dc5790, /* addc r23, r23, r2 >> 128 */ -0x5860e700, /* mul128 r24, r7l, r7l */ -0x59e4e700, /* mul128 r25, r7u, r7u */ -0x5888e700, /* mul128 r2, r7u, r7l */ -0x50605810, /* add r24, r24, r2 << 128 */ -0x50e45990, /* addc r25, r25, r2 >> 128 */ -0x50605810, /* add r24, r24, r2 << 128 */ -0x50e45990, /* addc r25, r25, r2 >> 128 */ -0x58690800, /* mul128 r26, r8l, r8l */ -0x59ed0800, /* mul128 r27, r8u, r8u */ -0x58890800, /* mul128 r2, r8u, r8l */ -0x50685a10, /* add r26, r26, r2 << 128 */ -0x50ec5b90, /* addc r27, r27, r2 >> 128 */ -0x50685a10, /* add r26, r26, r2 << 128 */ -0x50ec5b90, /* addc r27, r27, r2 >> 128 */ -0x58712900, /* mul128 r28, r9l, r9l */ -0x59f52900, /* mul128 r29, r9u, r9u */ -0x58892900, /* mul128 r2, r9u, r9l */ -0x50705c10, /* add r28, r28, r2 << 128 */ -0x50f45d90, /* addc r29, r29, r2 >> 128 */ -0x50705c10, /* add r28, r28, r2 << 128 */ -0x50f45d90, /* addc r29, r29, r2 >> 128 */ -0x5800e600, /* mul128 r0, r6l, r7l */ -0x5984e600, /* mul128 r1, r6u, r7u */ -0x5888e600, /* mul128 r2, r6u, r7l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x5908e600, /* mul128 r2, r6l, r7u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x505c1700, /* add r23, r23, r0 */ -0x50e03800, /* addc r24, r24, r1 */ -0x508fff00, /* addc r3, r31, r31 */ -0x505c1700, /* add r23, r23, r0 */ -0x50e03800, /* addc r24, r24, r1 */ -0x50e47900, /* addc r25, r25, r3 */ -0x508fff00, /* addc r3, r31, r31 */ -0x58010600, /* mul128 r0, r6l, r8l */ -0x59850600, /* mul128 r1, r6u, r8u */ -0x58890600, /* mul128 r2, r6u, r8l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x59090600, /* mul128 r2, r6l, r8u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x50601800, /* add r24, r24, r0 */ -0x50e43900, /* addc r25, r25, r1 */ -0x508fe300, /* addc r3, r3, r31 */ -0x50601800, /* add r24, r24, r0 */ -0x50e43900, /* addc r25, r25, r1 */ -0x50e87a00, /* addc r26, r26, r3 */ -0x508fff00, /* addc r3, r31, r31 */ -0x58012600, /* mul128 r0, r6l, r9l */ -0x59852600, /* mul128 r1, r6u, r9u */ -0x58892600, /* mul128 r2, r6u, r9l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x59092600, /* mul128 r2, r6l, r9u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x50641900, /* add r25, r25, r0 */ -0x50e83a00, /* addc r26, r26, r1 */ -0x508fe300, /* addc r3, r3, r31 */ -0x50641900, /* add r25, r25, r0 */ -0x50e83a00, /* addc r26, r26, r1 */ -0x508fe300, /* addc r3, r3, r31 */ -0x58010700, /* mul128 r0, r7l, r8l */ -0x59850700, /* mul128 r1, r7u, r8u */ -0x58890700, /* mul128 r2, r7u, r8l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x59090700, /* mul128 r2, r7l, r8u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x50641900, /* add r25, r25, r0 */ -0x50e83a00, /* addc r26, r26, r1 */ -0x508fe300, /* addc r3, r3, r31 */ -0x50641900, /* add r25, r25, r0 */ -0x50e83a00, /* addc r26, r26, r1 */ -0x50ec7b00, /* addc r27, r27, r3 */ -0x508fff00, /* addc r3, r31, r31 */ -0x58012700, /* mul128 r0, r7l, r9l */ -0x59852700, /* mul128 r1, r7u, r9u */ -0x58892700, /* mul128 r2, r7u, r9l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x59092700, /* mul128 r2, r7l, r9u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x50681a00, /* add r26, r26, r0 */ -0x50ec3b00, /* addc r27, r27, r1 */ -0x508fe300, /* addc r3, r3, r31 */ -0x50681a00, /* add r26, r26, r0 */ -0x50ec3b00, /* addc r27, r27, r1 */ -0x50f07c00, /* addc r28, r28, r3 */ -0x50f7fd00, /* addc r29, r29, r31 */ -0x58012800, /* mul128 r0, r8l, r9l */ -0x59852800, /* mul128 r1, r8u, r9u */ -0x58892800, /* mul128 r2, r8u, r9l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x59092800, /* mul128 r2, r8l, r9u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x506c1b00, /* add r27, r27, r0 */ -0x50f03c00, /* addc r28, r28, r1 */ -0x50f7fd00, /* addc r29, r29, r31 */ -0x506c1b00, /* add r27, r27, r0 */ -0x50f03c00, /* addc r28, r28, r1 */ -0x50f7fd00, /* addc r29, r29, r31 */ -0x0c000000, /* ret */ -/* } */ -/* @0x2d8: function dod0[15] { */ -#define CF_dod0_adr 728 -0x8c0c1100, /* ld *3, *1 */ -0x58140100, /* mul128 r5, r1l, r0l */ -0x58880100, /* mul128 r2, r1u, r0l */ -0x50144510, /* add r5, r5, r2 << 128 */ -0x59080100, /* mul128 r2, r1l, r0u */ -0x50144510, /* add r5, r5, r2 << 128 */ -0x5801c500, /* mul128 r0, r5l, r14l */ -0x5985c500, /* mul128 r1, r5u, r14u */ -0x5889c500, /* mul128 r2, r5u, r14l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x5909c500, /* mul128 r2, r5l, r14u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x0c000000, /* ret */ -/* } */ -/* @0x2e7: function dod1[9] { */ -#define CF_dod1_adr 743 -0x5801e500, /* mul128 r0, r5l, r15l */ -0x5985e500, /* mul128 r1, r5u, r15u */ -0x5889e500, /* mul128 r2, r5u, r15l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x5909e500, /* mul128 r2, r5l, r15u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x0c000000, /* ret */ -/* } */ -/* @0x2f0: function dod2[9] { */ -#define CF_dod2_adr 752 -0x58020500, /* mul128 r0, r5l, r16l */ -0x59860500, /* mul128 r1, r5u, r16u */ -0x588a0500, /* mul128 r2, r5u, r16l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x590a0500, /* mul128 r2, r5l, r16u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x0c000000, /* ret */ -/* } */ -/* @0x2f9: function dod3[9] { */ -#define CF_dod3_adr 761 -0x58022500, /* mul128 r0, r5l, r17l */ -0x59862500, /* mul128 r1, r5u, r17u */ -0x588a2500, /* mul128 r2, r5u, r17l */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x590a2500, /* mul128 r2, r5l, r17u */ -0x50004010, /* add r0, r0, r2 << 128 */ -0x50844190, /* addc r1, r1, r2 >> 128 */ -0x0c000000, /* ret */ -/* } */ -/* @0x302: function redc4[97] { */ -#define CF_redc4_adr 770 -0x7c001600, /* mov r0, r22 */ -0x080002d8, /* call &dod0 */ -0x50581600, /* add r22, r22, r0 */ -0x50dc3700, /* addc r23, r23, r1 */ -0x50e3f800, /* addc r24, r24, r31 */ -0x5093ff00, /* addc r4, r31, r31 */ -0x080002e7, /* call &dod1 */ -0x505c1700, /* add r23, r23, r0 */ -0x50e03800, /* addc r24, r24, r1 */ -0x50e49900, /* addc r25, r25, r4 */ -0x5093ff00, /* addc r4, r31, r31 */ -0x080002f0, /* call &dod2 */ -0x50601800, /* add r24, r24, r0 */ -0x50e43900, /* addc r25, r25, r1 */ -0x50e89a00, /* addc r26, r26, r4 */ -0x5093ff00, /* addc r4, r31, r31 */ -0x080002f9, /* call &dod3 */ -0x50641900, /* add r25, r25, r0 */ -0x50e83a00, /* addc r26, r26, r1 */ -0x50ec9b00, /* addc r27, r27, r4 */ -0x508fff00, /* addc r3, r31, r31 */ -0x7c001700, /* mov r0, r23 */ -0x080002d8, /* call &dod0 */ -0x505c1700, /* add r23, r23, r0 */ -0x50e03800, /* addc r24, r24, r1 */ -0x50e7f900, /* addc r25, r25, r31 */ -0x5093ff00, /* addc r4, r31, r31 */ -0x080002e7, /* call &dod1 */ -0x50601800, /* add r24, r24, r0 */ -0x50e43900, /* addc r25, r25, r1 */ -0x50e89a00, /* addc r26, r26, r4 */ -0x5093ff00, /* addc r4, r31, r31 */ -0x080002f0, /* call &dod2 */ -0x50641900, /* add r25, r25, r0 */ -0x50e83a00, /* addc r26, r26, r1 */ -0x50ec9b00, /* addc r27, r27, r4 */ -0x508fff00, /* addc r3, r31, r31 */ -0x080002f9, /* call &dod3 */ -0x50681a00, /* add r26, r26, r0 */ -0x50ec3b00, /* addc r27, r27, r1 */ -0x50f07c00, /* addc r28, r28, r3 */ -0x508fff00, /* addc r3, r31, r31 */ -0x7c001800, /* mov r0, r24 */ -0x080002d8, /* call &dod0 */ -0x50601800, /* add r24, r24, r0 */ -0x50e43900, /* addc r25, r25, r1 */ -0x50ebfa00, /* addc r26, r26, r31 */ -0x5093ff00, /* addc r4, r31, r31 */ -0x080002e7, /* call &dod1 */ -0x50641900, /* add r25, r25, r0 */ -0x50e83a00, /* addc r26, r26, r1 */ -0x50ec9b00, /* addc r27, r27, r4 */ -0x5093ff00, /* addc r4, r31, r31 */ -0x080002f0, /* call &dod2 */ -0x50681a00, /* add r26, r26, r0 */ -0x50ec3b00, /* addc r27, r27, r1 */ -0x50f09c00, /* addc r28, r28, r4 */ -0x5093e300, /* addc r4, r3, r31 */ -0x080002f9, /* call &dod3 */ -0x506c1b00, /* add r27, r27, r0 */ -0x50f03c00, /* addc r28, r28, r1 */ -0x50f49d00, /* addc r29, r29, r4 */ -0x508fff00, /* addc r3, r31, r31 */ -0x7c001900, /* mov r0, r25 */ -0x080002d8, /* call &dod0 */ -0x50641900, /* add r25, r25, r0 */ -0x50d83a00, /* addc r22, r26, r1 */ -0x50dffb00, /* addc r23, r27, r31 */ -0x5093ff00, /* addc r4, r31, r31 */ -0x080002e7, /* call &dod1 */ -0x50581600, /* add r22, r22, r0 */ -0x50dc3700, /* addc r23, r23, r1 */ -0x50e09c00, /* addc r24, r28, r4 */ -0x5093ff00, /* addc r4, r31, r31 */ -0x080002f0, /* call &dod2 */ -0x505c1700, /* add r23, r23, r0 */ -0x50e03800, /* addc r24, r24, r1 */ -0x50e49d00, /* addc r25, r29, r4 */ -0x508fe300, /* addc r3, r3, r31 */ -0x080002f9, /* call &dod3 */ -0x50601800, /* add r24, r24, r0 */ -0x50e43900, /* addc r25, r25, r1 */ -0x508fe300, /* addc r3, r3, r31 */ -0x56007f00, /* subx r0, r31, r3 */ -0x99680000, /* strnd r26 */ -0x996c0000, /* strnd r27 */ -0x99700000, /* strnd r28 */ -0x99740000, /* strnd r29 */ -0x5409d600, /* sub r2, r22, r14 */ -0x54e9f700, /* subb r26, r23, r15 */ -0x54ee1800, /* subb r27, r24, r16 */ -0x54f23900, /* subb r28, r25, r17 */ -0x66773c08, /* selcx r29, r28, r25 */ -0x66731b08, /* selcx r28, r27, r24 */ -0x666efa08, /* selcx r27, r26, r23 */ -0x666ac208, /* selcx r26, r2, r22 */ -0x0c000000, /* ret */ -/* } */ -/* @0x363: function modexp_1024[101] { */ -#define CF_modexp_1024_adr 867 -0x7c081f00, /* mov r2, r31 */ -0x80080006, /* movi r2.0l, #6 */ -0x8088000a, /* movi r2.1l, #10 */ -0x81880001, /* movi r2.3l, #1 */ -0x8208000e, /* movi r2.4l, #14 */ -0x82880016, /* movi r2.5l, #22 */ -0x83080012, /* movi r2.6l, #18 */ -0x97800200, /* ldrfp r2 */ -0x7c001f00, /* mov r0, r31 */ -0x8180ffff, /* movi r0.3l, #65535 */ -0x84044000, /* ldi r1, [#0] */ -0x40040100, /* and r1, r1, r0 */ -0x48000000, /* not r0, r0 */ -0x84084060, /* ldi r2, [#3] */ -0x40080200, /* and r2, r2, r0 */ -0x44082200, /* or r2, r2, r1 */ -0x95800200, /* lddmp r2 */ -0x05004004, /* loop #4 ( */ -0x8c201b00, /* ld *0++, *3++ */ -0x8c241a00, /* ld *1++, *2++ */ -0x8c301800, /* ld *4++, *0++ */ -0x8c381c00, /* ld *6++, *4++ */ -/* ) */ -0x99780000, /* strnd r30 */ -0x507bde00, /* add r30, r30, r30 */ -0x080001ba, /* call &mul4 */ -0x08000302, /* call &redc4 */ -0x7c281a00, /* mov r10, r26 */ -0x7c2c1b00, /* mov r11, r27 */ -0x7c301c00, /* mov r12, r28 */ -0x7c341d00, /* mov r13, r29 */ -0x99180000, /* strnd r6 */ -0x991c0000, /* strnd r7 */ -0x99200000, /* strnd r8 */ -0x99240000, /* strnd r9 */ -0x05400033, /* loop #1024 ( */ -0x08000263, /* call &sqr4 */ -0x08000302, /* call &redc4 */ -0x99180000, /* strnd r6 */ -0x991c0000, /* strnd r7 */ -0x99200000, /* strnd r8 */ -0x99240000, /* strnd r9 */ -0x7c181a00, /* mov r6, r26 */ -0x7c1c1b00, /* mov r7, r27 */ -0x7c201c00, /* mov r8, r28 */ -0x7c241d00, /* mov r9, r29 */ -0x080001ba, /* call &mul4 */ -0x08000302, /* call &redc4 */ -0x99000000, /* strnd r0 */ -0x5002b500, /* add r0, r21, r21 */ -0x99000000, /* strnd r0 */ -0x50825200, /* addc r0, r18, r18 */ -0x99480000, /* strnd r18 */ -0x7c480000, /* mov r18, r0 */ -0x99000000, /* strnd r0 */ -0x50827300, /* addc r0, r19, r19 */ -0x994c0000, /* strnd r19 */ -0x7c4c0000, /* mov r19, r0 */ -0x99000000, /* strnd r0 */ -0x50829400, /* addc r0, r20, r20 */ -0x99500000, /* strnd r20 */ -0x7c500000, /* mov r20, r0 */ -0x99000000, /* strnd r0 */ -0x5082b500, /* addc r0, r21, r21 */ -0x99540000, /* strnd r21 */ -0x7c540000, /* mov r21, r0 */ -0x99580000, /* strnd r22 */ -0x995c0000, /* strnd r23 */ -0x99600000, /* strnd r24 */ -0x99640000, /* strnd r25 */ -0x080001aa, /* call &selA0orC4 */ -0x99180000, /* strnd r6 */ -0x991c0000, /* strnd r7 */ -0x99200000, /* strnd r8 */ -0x99240000, /* strnd r9 */ -0x99000000, /* strnd r0 */ -0x50000000, /* add r0, r0, r0 */ -0x4c001e00, /* xor r0, r30, r0 */ -0x99780000, /* strnd r30 */ -0x507bde00, /* add r30, r30, r30 */ -0x4c781e00, /* xor r30, r30, r0 */ -0x447a5e00, /* or r30, r30, r18 */ -0x4c03c000, /* xor r0, r0, r30 */ -0x641aca01, /* sell r6, r10, r22 */ -0x641eeb01, /* sell r7, r11, r23 */ -0x64230c01, /* sell r8, r12, r24 */ -0x64272d01, /* sell r9, r13, r25 */ -/* ) */ -0x7c281f00, /* mov r10, r31 */ -0x80280001, /* movi r10.0l, #1 */ -0x7c2c1f00, /* mov r11, r31 */ -0x7c301f00, /* mov r12, r31 */ -0x7c341f00, /* mov r13, r31 */ -0x080001ba, /* call &mul4 */ -0x08000302, /* call &redc4 */ -0x5419da00, /* sub r6, r26, r14 */ -0x549dfb00, /* subb r7, r27, r15 */ -0x54a21c00, /* subb r8, r28, r16 */ -0x54a63d00, /* subb r9, r29, r17 */ -0x080001aa, /* call &selA0orC4 */ -0x05004001, /* loop #4 ( */ -0x90740d00, /* st *5++, *5++ */ -/* ) */ -0x0c000000, /* ret */ -/* } */ -#endif // CONFIG_DCRYPTO_RSA_SPEEDUP -}; -/* clang-format on */ - -struct DMEM_ctx_ptrs { - uint32_t pMod; - uint32_t pDinv; - uint32_t pRR; - uint32_t pA; - uint32_t pB; - uint32_t pC; - uint32_t n; - uint32_t n1; -}; - -/* - * This struct is "calling convention" for passing parameters into the - * code block above for RSA operations. Parameters start at &DMEM[0]. - */ -struct DMEM_ctx { - struct DMEM_ctx_ptrs in_ptrs; - struct DMEM_ctx_ptrs sqr_ptrs; - struct DMEM_ctx_ptrs mul_ptrs; - struct DMEM_ctx_ptrs out_ptrs; - uint32_t mod[RSA_WORDS_4K]; - uint32_t dInv[8]; - uint32_t pubexp; - uint32_t _pad1[3]; - uint32_t rnd[2]; - uint32_t _pad2[2]; - uint32_t RR[RSA_WORDS_4K]; - uint32_t in[RSA_WORDS_4K]; - uint32_t exp[RSA_WORDS_4K + 8]; /* extra word for randomization */ - uint32_t out[RSA_WORDS_4K]; - uint32_t bin[RSA_WORDS_4K]; - uint32_t bout[RSA_WORDS_4K]; -}; - -#define DMEM_CELL_SIZE 32 -#define DMEM_INDEX(p, f) \ - (((const uint8_t *)&(p)->f - (const uint8_t *)(p)) / DMEM_CELL_SIZE) - -/* Get non-0 64 bit random */ -static void rand64(uint32_t dst[2]) -{ - do { - dst[0] = rand(); - dst[1] = rand(); - } while ((dst[0] | dst[1]) == 0); -} - -/* Grab dcrypto lock and set things up for modulus and input */ -static int setup_and_lock(const struct LITE_BIGNUM *N, - const struct LITE_BIGNUM *input) -{ - struct DMEM_ctx *ctx = - (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); - - /* Initialize hardware; load code page. */ - dcrypto_init_and_lock(); - dcrypto_imem_load(0, IMEM_dcrypto_bn, ARRAY_SIZE(IMEM_dcrypto_bn)); - - /* Setup DMEM pointers (as indices into DMEM which are 256-bit cells). - */ - ctx->in_ptrs.pMod = DMEM_INDEX(ctx, mod); - ctx->in_ptrs.pDinv = DMEM_INDEX(ctx, dInv); - ctx->in_ptrs.pRR = DMEM_INDEX(ctx, RR); - ctx->in_ptrs.pA = DMEM_INDEX(ctx, in); - ctx->in_ptrs.pB = DMEM_INDEX(ctx, exp); - ctx->in_ptrs.pC = DMEM_INDEX(ctx, out); - ctx->in_ptrs.n = bn_bits(N) / (DMEM_CELL_SIZE * 8); - ctx->in_ptrs.n1 = ctx->in_ptrs.n - 1; - - ctx->sqr_ptrs = ctx->in_ptrs; - ctx->mul_ptrs = ctx->in_ptrs; - ctx->out_ptrs = ctx->in_ptrs; - - dcrypto_dmem_load(DMEM_INDEX(ctx, in), input->d, bn_words(input)); - if (dcrypto_dmem_load(DMEM_INDEX(ctx, mod), N->d, bn_words(N)) == 0) { - /* - * No change detected; assume modulus precomputation is cached. - */ - return 0; - } - - /* Calculate RR and d0inv. */ - return dcrypto_call(CF_modload_adr); -} - -#define MONTMUL(ctx, a, b, c) \ - montmul(ctx, DMEM_INDEX(ctx, a), DMEM_INDEX(ctx, b), DMEM_INDEX(ctx, c)) - -static int montmul(struct DMEM_ctx *ctx, uint32_t pA, uint32_t pB, - uint32_t pOut) -{ - - ctx->in_ptrs.pA = pA; - ctx->in_ptrs.pB = pB; - ctx->in_ptrs.pC = pOut; - - return dcrypto_call(CF_mulx_adr); -} - -#define MONTOUT(ctx, a, b) montout(ctx, DMEM_INDEX(ctx, a), DMEM_INDEX(ctx, b)) - -static int montout(struct DMEM_ctx *ctx, uint32_t pA, uint32_t pOut) -{ - - ctx->in_ptrs.pA = pA; - ctx->in_ptrs.pB = 0; - ctx->in_ptrs.pC = pOut; - - return dcrypto_call(CF_mul1_adr); -} - -#define MODEXP(ctx, in, exp, out) \ - modexp(ctx, CF_modexp_adr, DMEM_INDEX(ctx, RR), DMEM_INDEX(ctx, in), \ - DMEM_INDEX(ctx, exp), DMEM_INDEX(ctx, out)) - -#define MODEXP1024(ctx, in, exp, out) \ - modexp(ctx, CF_modexp_1024_adr, DMEM_INDEX(ctx, RR), \ - DMEM_INDEX(ctx, in), DMEM_INDEX(ctx, exp), \ - DMEM_INDEX(ctx, out)) - -#define MODEXP_BLINDED(ctx, in, exp, out) \ - modexp(ctx, CF_modexp_blinded_adr, DMEM_INDEX(ctx, RR), \ - DMEM_INDEX(ctx, in), DMEM_INDEX(ctx, exp), \ - DMEM_INDEX(ctx, out)) - -static int modexp(struct DMEM_ctx *ctx, uint32_t adr, uint32_t rr, uint32_t pIn, - uint32_t pExp, uint32_t pOut) -{ - /* in = in * RR */ - ctx->in_ptrs.pA = pIn; - ctx->in_ptrs.pB = rr; - ctx->in_ptrs.pC = pIn; - - /* out = out * out */ - ctx->sqr_ptrs.pA = pOut; - ctx->sqr_ptrs.pB = pOut; - ctx->sqr_ptrs.pC = pOut; - - /* out = out * in */ - ctx->mul_ptrs.pA = pIn; - ctx->mul_ptrs.pB = pOut; - ctx->mul_ptrs.pC = pOut; - - /* out = out / R */ - ctx->out_ptrs.pA = pOut; - ctx->out_ptrs.pB = pExp; - ctx->out_ptrs.pC = pOut; - - return dcrypto_call(adr); -} - -/* output = input ** exp % N. */ -int dcrypto_modexp_blinded(struct LITE_BIGNUM *output, - const struct LITE_BIGNUM *input, - const struct LITE_BIGNUM *exp, - const struct LITE_BIGNUM *N, uint32_t pubexp) -{ - int i, result; - struct DMEM_ctx *ctx = - (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); - - uint32_t r_buf[RSA_MAX_WORDS]; - uint32_t rinv_buf[RSA_MAX_WORDS]; - - struct LITE_BIGNUM r; - struct LITE_BIGNUM rinv; - - bn_init(&r, r_buf, bn_size(N)); - bn_init(&rinv, rinv_buf, bn_size(N)); - - /* - * pick 64 bit r != 0 - * We cannot tolerate risk of 0 since 0 breaks computation. - */ - rand64(r_buf); - - /* - * compute 1/r mod N - * Note this cannot fail since N is product of two large primes - * and r != 0, so we can ignore return value. - */ - bn_modinv_vartime(&rinv, &r, N); - - /* - * compute r^pubexp mod N - */ - dcrypto_modexp_word(&r, &r, pubexp, N); - - result = setup_and_lock(N, input); - - /* Pick !0 64-bit random for exponent blinding */ - rand64(ctx->rnd); - ctx->pubexp = pubexp; - - ctx->_pad1[0] = ctx->_pad1[1] = ctx->_pad1[2] = 0; - ctx->_pad2[0] = ctx->_pad2[1] = 0; - - dcrypto_dmem_load(DMEM_INDEX(ctx, bin), r.d, bn_words(&r)); - dcrypto_dmem_load(DMEM_INDEX(ctx, bout), rinv.d, bn_words(&rinv)); - dcrypto_dmem_load(DMEM_INDEX(ctx, exp), exp->d, bn_words(exp)); - - /* 0 pad the exponent to full size + 8 */ - for (i = bn_words(exp); i < bn_words(N) + 8; ++i) - ctx->exp[i] = 0; - - /* Blind input */ - result |= MONTMUL(ctx, in, RR, in); - result |= MONTMUL(ctx, in, bin, in); - - result |= MODEXP_BLINDED(ctx, in, exp, out); - - /* remove blinding factor */ - result |= MONTMUL(ctx, out, RR, out); - result |= MONTMUL(ctx, out, bout, out); - /* fully reduce out */ - result |= MONTMUL(ctx, out, RR, out); - result |= MONTOUT(ctx, out, out); - - memcpy(output->d, ctx->out, bn_size(output)); - - dcrypto_unlock(); - return result == 0; -} - -/* output = input ** exp % N. */ -int dcrypto_modexp(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, - const struct LITE_BIGNUM *exp, const struct LITE_BIGNUM *N) -{ - int i, result; - struct DMEM_ctx *ctx = - (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); - - result = setup_and_lock(N, input); - - dcrypto_dmem_load(DMEM_INDEX(ctx, exp), exp->d, bn_words(exp)); - - /* 0 pad the exponent to full size */ - for (i = bn_words(exp); i < bn_words(N); ++i) - ctx->exp[i] = 0; - -#ifdef CONFIG_DCRYPTO_RSA_SPEEDUP - if (bn_bits(N) == 1024) { /* special code for 1024 bits */ - result |= MODEXP1024(ctx, in, exp, out); - } else { - result |= MODEXP(ctx, in, exp, out); - } -#else - result |= MODEXP(ctx, in, exp, out); -#endif - - memcpy(output->d, ctx->out, bn_size(output)); - - dcrypto_unlock(); - return result == 0; -} - -/* output = input ** exp % N. */ -int dcrypto_modexp_word(struct LITE_BIGNUM *output, - const struct LITE_BIGNUM *input, uint32_t exp, - const struct LITE_BIGNUM *N) -{ - int result; - uint32_t e = exp; - uint32_t b = 0x80000000; - struct DMEM_ctx *ctx = - (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); - - result = setup_and_lock(N, input); - - /* Find top bit */ - while (b != 0 && !(b & e)) - b >>= 1; - - /* out = in * RR */ - result |= MONTMUL(ctx, in, RR, out); - /* in = in * RR */ - result |= MONTMUL(ctx, in, RR, in); - - while (b > 1) { - b >>= 1; - - /* out = out * out */ - result |= MONTMUL(ctx, out, out, out); - - if ((b & e) != 0) { - /* out = out * in */ - result |= MONTMUL(ctx, in, out, out); - } - } - - /* out = out / R */ - result |= MONTOUT(ctx, out, out); - - memcpy(output->d, ctx->out, bn_size(output)); - - dcrypto_unlock(); - return result == 0; -} - -#ifdef CRYPTO_TEST_SETUP -#include "console.h" -#include "shared_mem.h" -#include "timer.h" - -static uint8_t genp_seed[32]; -static uint32_t prime_buf[32]; -static timestamp_t genp_start; -static timestamp_t genp_end; - -static int genp_core(void) -{ - struct LITE_BIGNUM prime; - int result; - - // Spin seed out into prng candidate prime. - DCRYPTO_hkdf((uint8_t *)prime_buf, sizeof(prime_buf), genp_seed, - sizeof(genp_seed), 0, 0, 0, 0); - DCRYPTO_bn_wrap(&prime, &prime_buf, sizeof(prime_buf)); - - genp_start = get_time(); - result = (DCRYPTO_bn_generate_prime(&prime) != 0) ? EC_SUCCESS - : EC_ERROR_UNKNOWN; - genp_end = get_time(); - - return result; -} - -static int call_on_bigger_stack(int (*func)(void)) -{ - int result, i; - char *new_stack; - const int new_stack_size = 4 * 1024; - - result = shared_mem_acquire(new_stack_size, &new_stack); - if (result == EC_SUCCESS) { - // Paint stack arena - memset(new_stack, 0x01, new_stack_size); - - // Call whilst switching stacks - __asm__ volatile("mov r4, sp\n" // save sp - "mov sp, %[new_stack]\n" - "blx %[func]\n" - "mov sp, r4\n" // restore sp - "mov %[result], r0\n" - : [result] "=r"(result) - : [new_stack] "r"(new_stack + new_stack_size), - [func] "r"(func) - : "r0", "r1", "r2", "r3", "r4", - "lr" // clobbers - ); - - // Take guess at amount of stack that got used - for (i = 0; i < new_stack_size && new_stack[i] == 0x01; ++i) - ; - ccprintf("stack: %u/%u\n", new_stack_size - i, new_stack_size); - - shared_mem_release(new_stack); - } - - return result; -} - -static int command_genp(int argc, char **argv) -{ - int result; - - memset(genp_seed, 0, sizeof(genp_seed)); - if (argc > 1) - memcpy(genp_seed, argv[1], strlen(argv[1])); - - result = call_on_bigger_stack(genp_core); - - if (result == EC_SUCCESS) { - ccprintf("prime: %ph (lsb first)\n", - HEX_BUF(prime_buf, sizeof(prime_buf))); - ccprintf("μs : %llu\n", - (long long)(genp_end.val - genp_start.val)); - } - - return result; -} -DECLARE_CONSOLE_COMMAND(genp, command_genp, "[seed]", "Generate prng prime"); -#endif diff --git a/chip/g/dcrypto/dcrypto_p256.c b/chip/g/dcrypto/dcrypto_p256.c deleted file mode 100644 index 4de8d22f9a..0000000000 --- a/chip/g/dcrypto/dcrypto_p256.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* Copyright 2016 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 "trng.h" - -/* Firmware blob for crypto accelerator */ - -/* AUTO-GENERATED. DO NOT MODIFY. */ -/* clang-format off */ -static const uint32_t IMEM_dcrypto[] = { -/* @0x0: function tag[1] { */ -#define CF_tag_adr 0 - 0xf8000002, /* sigini #2 */ -/* } */ -/* @0x1: function SetupP256PandMuLow[21] { */ -#define CF_SetupP256PandMuLow_adr 1 - 0x55741f01, /* subi r29, r31, #1 */ - 0x83750000, /* movi r29.6h, #0 */ - 0x83740001, /* movi r29.6l, #1 */ - 0x82f50000, /* movi r29.5h, #0 */ - 0x82f40000, /* movi r29.5l, #0 */ - 0x82750000, /* movi r29.4h, #0 */ - 0x82740000, /* movi r29.4l, #0 */ - 0x81f50000, /* movi r29.3h, #0 */ - 0x81f40000, /* movi r29.3l, #0 */ - 0x98801d00, /* ldmod r29 */ - 0x55701f01, /* subi r28, r31, #1 */ - 0x83f10000, /* movi r28.7h, #0 */ - 0x83f00000, /* movi r28.7l, #0 */ - 0x82f0fffe, /* movi r28.5l, #65534 */ - 0x8270fffe, /* movi r28.4l, #65534 */ - 0x81f0fffe, /* movi r28.3l, #65534 */ - 0x80f10000, /* movi r28.1h, #0 */ - 0x80f00000, /* movi r28.1l, #0 */ - 0x80710000, /* movi r28.0h, #0 */ - 0x80700003, /* movi r28.0l, #3 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x16: function p256init[22] { */ -#define CF_p256init_adr 22 - 0x847c4000, /* ldi r31, [#0] */ - 0x4c7fff00, /* xor r31, r31, r31 */ - 0x51781f01, /* addi r30, r31, #1 */ - 0x08000001, /* call &SetupP256PandMuLow */ - 0x7c6c1f00, /* mov r27, r31 */ - 0x83ed5ac6, /* movi r27.7h, #23238 */ - 0x83ec35d8, /* movi r27.7l, #13784 */ - 0x836daa3a, /* movi r27.6h, #43578 */ - 0x836c93e7, /* movi r27.6l, #37863 */ - 0x82edb3eb, /* movi r27.5h, #46059 */ - 0x82ecbd55, /* movi r27.5l, #48469 */ - 0x826d7698, /* movi r27.4h, #30360 */ - 0x826c86bc, /* movi r27.4l, #34492 */ - 0x81ed651d, /* movi r27.3h, #25885 */ - 0x81ec06b0, /* movi r27.3l, #1712 */ - 0x816dcc53, /* movi r27.2h, #52307 */ - 0x816cb0f6, /* movi r27.2l, #45302 */ - 0x80ed3bce, /* movi r27.1h, #15310 */ - 0x80ec3c3e, /* movi r27.1l, #15422 */ - 0x806d27d2, /* movi r27.0h, #10194 */ - 0x806c604b, /* movi r27.0l, #24651 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x2c: function MulMod[38] { */ -#define CF_MulMod_adr 44 - 0x584f3800, /* mul128 r19, r24l, r25l */ - 0x59d33800, /* mul128 r20, r24u, r25u */ - 0x58d73800, /* mul128 r21, r24u, r25l */ - 0x504eb310, /* add r19, r19, r21 << 128 */ - 0x50d2b490, /* addc r20, r20, r21 >> 128 */ - 0x59573800, /* mul128 r21, r24l, r25u */ - 0x504eb310, /* add r19, r19, r21 << 128 */ - 0x50d2b490, /* addc r20, r20, r21 >> 128 */ - 0x645bfc02, /* selm r22, r28, r31 */ - 0x685693ff, /* rshi r21, r19, r20 >> 255 */ - 0x585f9500, /* mul128 r23, r21l, r28l */ - 0x59e39500, /* mul128 r24, r21u, r28u */ - 0x58e79500, /* mul128 r25, r21u, r28l */ - 0x505f3710, /* add r23, r23, r25 << 128 */ - 0x50e33890, /* addc r24, r24, r25 >> 128 */ - 0x59679500, /* mul128 r25, r21l, r28u */ - 0x505f3710, /* add r23, r23, r25 << 128 */ - 0x50e33890, /* addc r24, r24, r25 >> 128 */ - 0x6867f4ff, /* rshi r25, r20, r31 >> 255 */ - 0x5062b800, /* add r24, r24, r21 */ - 0x50e7f900, /* addc r25, r25, r31 */ - 0x5062d800, /* add r24, r24, r22 */ - 0x50e7f900, /* addc r25, r25, r31 */ - 0x68573801, /* rshi r21, r24, r25 >> 1 */ - 0x585abd00, /* mul128 r22, r29l, r21l */ - 0x59debd00, /* mul128 r23, r29u, r21u */ - 0x58e2bd00, /* mul128 r24, r29u, r21l */ - 0x505b1610, /* add r22, r22, r24 << 128 */ - 0x50df1790, /* addc r23, r23, r24 >> 128 */ - 0x5962bd00, /* mul128 r24, r29l, r21u */ - 0x505b1610, /* add r22, r22, r24 << 128 */ - 0x50df1790, /* addc r23, r23, r24 >> 128 */ - 0x545ad300, /* sub r22, r19, r22 */ - 0x54d2f400, /* subb r20, r20, r23 */ - 0x6457fd01, /* sell r21, r29, r31 */ - 0x5456b600, /* sub r21, r22, r21 */ - 0x9c4ff500, /* addm r19, r21, r31 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x52: function p256isoncurve[24] { */ -#define CF_p256isoncurve_adr 82 - 0x84004000, /* ldi r0, [#0] */ - 0x95800000, /* lddmp r0 */ - 0x82800018, /* movi r0.5l, #24 */ - 0x83000018, /* movi r0.6l, #24 */ - 0x80000000, /* movi r0.0l, #0 */ - 0x97800000, /* ldrfp r0 */ - 0x8c181600, /* ld *6, *6 */ - 0x7c641800, /* mov r25, r24 */ - 0x0800002c, /* call &MulMod */ - 0x7c001300, /* mov r0, r19 */ - 0x8c141500, /* ld *5, *5 */ - 0x7c641800, /* mov r25, r24 */ - 0x0800002c, /* call &MulMod */ - 0x8c141500, /* ld *5, *5 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0x8c141500, /* ld *5, *5 */ - 0xa04f1300, /* subm r19, r19, r24 */ - 0xa04f1300, /* subm r19, r19, r24 */ - 0xa04f1300, /* subm r19, r19, r24 */ - 0x9c637300, /* addm r24, r19, r27 */ - 0x904c0500, /* st *5, *3 */ - 0x90500000, /* st *0, *4 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x6a: function ProjAdd[80] { */ -#define CF_ProjAdd_adr 106 - 0x7c600b00, /* mov r24, r11 */ - 0x7c640800, /* mov r25, r8 */ - 0x0800002c, /* call &MulMod */ - 0x7c381300, /* mov r14, r19 */ - 0x7c600c00, /* mov r24, r12 */ - 0x7c640900, /* mov r25, r9 */ - 0x0800002c, /* call &MulMod */ - 0x7c3c1300, /* mov r15, r19 */ - 0x7c600d00, /* mov r24, r13 */ - 0x7c640a00, /* mov r25, r10 */ - 0x0800002c, /* call &MulMod */ - 0x7c401300, /* mov r16, r19 */ - 0x9c458b00, /* addm r17, r11, r12 */ - 0x9c492800, /* addm r18, r8, r9 */ - 0x7c601100, /* mov r24, r17 */ - 0x7c641200, /* mov r25, r18 */ - 0x0800002c, /* call &MulMod */ - 0x9c49ee00, /* addm r18, r14, r15 */ - 0xa0465300, /* subm r17, r19, r18 */ - 0x9c49ac00, /* addm r18, r12, r13 */ - 0x9c4d4900, /* addm r19, r9, r10 */ - 0x7c601200, /* mov r24, r18 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0x7c481300, /* mov r18, r19 */ - 0x9c4e0f00, /* addm r19, r15, r16 */ - 0xa04a7200, /* subm r18, r18, r19 */ - 0x9c4dab00, /* addm r19, r11, r13 */ - 0x9c314800, /* addm r12, r8, r10 */ - 0x7c601300, /* mov r24, r19 */ - 0x7c640c00, /* mov r25, r12 */ - 0x0800002c, /* call &MulMod */ - 0x7c2c1300, /* mov r11, r19 */ - 0x9c320e00, /* addm r12, r14, r16 */ - 0xa0318b00, /* subm r12, r11, r12 */ - 0x7c601b00, /* mov r24, r27 */ - 0x7c641000, /* mov r25, r16 */ - 0x0800002c, /* call &MulMod */ - 0xa02e6c00, /* subm r11, r12, r19 */ - 0x9c356b00, /* addm r13, r11, r11 */ - 0x9c2dab00, /* addm r11, r11, r13 */ - 0xa0356f00, /* subm r13, r15, r11 */ - 0x9c2d6f00, /* addm r11, r15, r11 */ - 0x7c601b00, /* mov r24, r27 */ - 0x7c640c00, /* mov r25, r12 */ - 0x0800002c, /* call &MulMod */ - 0x9c3e1000, /* addm r15, r16, r16 */ - 0x9c420f00, /* addm r16, r15, r16 */ - 0xa0321300, /* subm r12, r19, r16 */ - 0xa031cc00, /* subm r12, r12, r14 */ - 0x9c3d8c00, /* addm r15, r12, r12 */ - 0x9c318f00, /* addm r12, r15, r12 */ - 0x9c3dce00, /* addm r15, r14, r14 */ - 0x9c39cf00, /* addm r14, r15, r14 */ - 0xa03a0e00, /* subm r14, r14, r16 */ - 0x7c601200, /* mov r24, r18 */ - 0x7c640c00, /* mov r25, r12 */ - 0x0800002c, /* call &MulMod */ - 0x7c3c1300, /* mov r15, r19 */ - 0x7c600e00, /* mov r24, r14 */ - 0x7c640c00, /* mov r25, r12 */ - 0x0800002c, /* call &MulMod */ - 0x7c401300, /* mov r16, r19 */ - 0x7c600b00, /* mov r24, r11 */ - 0x7c640d00, /* mov r25, r13 */ - 0x0800002c, /* call &MulMod */ - 0x9c321300, /* addm r12, r19, r16 */ - 0x7c601100, /* mov r24, r17 */ - 0x7c640b00, /* mov r25, r11 */ - 0x0800002c, /* call &MulMod */ - 0xa02df300, /* subm r11, r19, r15 */ - 0x7c601200, /* mov r24, r18 */ - 0x7c640d00, /* mov r25, r13 */ - 0x0800002c, /* call &MulMod */ - 0x7c341300, /* mov r13, r19 */ - 0x7c601100, /* mov r24, r17 */ - 0x7c640e00, /* mov r25, r14 */ - 0x0800002c, /* call &MulMod */ - 0x9c366d00, /* addm r13, r13, r19 */ - 0x0c000000, /* ret */ -/* } */ -/* @0xba: function ProjToAffine[116] { */ -#define CF_ProjToAffine_adr 186 - 0x9c2bea00, /* addm r10, r10, r31 */ - 0x7c600a00, /* mov r24, r10 */ - 0x7c640a00, /* mov r25, r10 */ - 0x0800002c, /* call &MulMod */ - 0x7c601300, /* mov r24, r19 */ - 0x7c640a00, /* mov r25, r10 */ - 0x0800002c, /* call &MulMod */ - 0x7c301300, /* mov r12, r19 */ - 0x7c601300, /* mov r24, r19 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0x7c601300, /* mov r24, r19 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0x7c601300, /* mov r24, r19 */ - 0x7c640c00, /* mov r25, r12 */ - 0x0800002c, /* call &MulMod */ - 0x7c341300, /* mov r13, r19 */ - 0x05004004, /* loop #4 ( */ - 0x7c601300, /* mov r24, r19 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0xfc000000, /* nop */ - /* ) */ - 0x7c601300, /* mov r24, r19 */ - 0x7c640d00, /* mov r25, r13 */ - 0x0800002c, /* call &MulMod */ - 0x7c381300, /* mov r14, r19 */ - 0x05008004, /* loop #8 ( */ - 0x7c601300, /* mov r24, r19 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0xfc000000, /* nop */ - /* ) */ - 0x7c601300, /* mov r24, r19 */ - 0x7c640e00, /* mov r25, r14 */ - 0x0800002c, /* call &MulMod */ - 0x7c3c1300, /* mov r15, r19 */ - 0x05010004, /* loop #16 ( */ - 0x7c601300, /* mov r24, r19 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0xfc000000, /* nop */ - /* ) */ - 0x7c601300, /* mov r24, r19 */ - 0x7c640f00, /* mov r25, r15 */ - 0x0800002c, /* call &MulMod */ - 0x7c401300, /* mov r16, r19 */ - 0x05020004, /* loop #32 ( */ - 0x7c601300, /* mov r24, r19 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0xfc000000, /* nop */ - /* ) */ - 0x7c441300, /* mov r17, r19 */ - 0x7c600a00, /* mov r24, r10 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0x050c0004, /* loop #192 ( */ - 0x7c601300, /* mov r24, r19 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0xfc000000, /* nop */ - /* ) */ - 0x7c481300, /* mov r18, r19 */ - 0x7c601100, /* mov r24, r17 */ - 0x7c641000, /* mov r25, r16 */ - 0x0800002c, /* call &MulMod */ - 0x05010004, /* loop #16 ( */ - 0x7c601300, /* mov r24, r19 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0xfc000000, /* nop */ - /* ) */ - 0x7c600f00, /* mov r24, r15 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0x05008004, /* loop #8 ( */ - 0x7c601300, /* mov r24, r19 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0xfc000000, /* nop */ - /* ) */ - 0x7c600e00, /* mov r24, r14 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0x05004004, /* loop #4 ( */ - 0x7c601300, /* mov r24, r19 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0xfc000000, /* nop */ - /* ) */ - 0x7c600d00, /* mov r24, r13 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0x05002004, /* loop #2 ( */ - 0x7c601300, /* mov r24, r19 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0xfc000000, /* nop */ - /* ) */ - 0x7c600c00, /* mov r24, r12 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0x05002004, /* loop #2 ( */ - 0x7c601300, /* mov r24, r19 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0xfc000000, /* nop */ - /* ) */ - 0x7c600a00, /* mov r24, r10 */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0x7c601300, /* mov r24, r19 */ - 0x7c641200, /* mov r25, r18 */ - 0x0800002c, /* call &MulMod */ - 0x7c381300, /* mov r14, r19 */ - 0x7c600800, /* mov r24, r8 */ - 0x7c640e00, /* mov r25, r14 */ - 0x0800002c, /* call &MulMod */ - 0x7c2c1300, /* mov r11, r19 */ - 0x7c600900, /* mov r24, r9 */ - 0x7c640e00, /* mov r25, r14 */ - 0x0800002c, /* call &MulMod */ - 0x7c301300, /* mov r12, r19 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x12e: function ModInv[17] { */ -#define CF_ModInv_adr 302 - 0x98080000, /* stmod r2 */ - 0x55080202, /* subi r2, r2, #2 */ - 0x7c041e00, /* mov r1, r30 */ - 0x0510000c, /* loop #256 ( */ - 0x7c600100, /* mov r24, r1 */ - 0x7c640100, /* mov r25, r1 */ - 0x0800002c, /* call &MulMod */ - 0x7c0c1300, /* mov r3, r19 */ - 0x50084200, /* add r2, r2, r2 */ - 0x64046108, /* selc r1, r1, r3 */ - 0x1008813d, /* bnc nomul */ - 0x7c600300, /* mov r24, r3 */ - 0x7c640000, /* mov r25, r0 */ - 0x0800002c, /* call &MulMod */ - 0x7c041300, /* mov r1, r19 */ - /*nomul: */ - 0xfc000000, /* nop */ - /* ) */ - 0x0c000000, /* ret */ -/* } */ -/* @0x13f: function FetchBandRandomize[11] { */ -#define CF_FetchBandRandomize_adr 319 - 0x99080000, /* strnd r2 */ - 0x9c6be200, /* addm r26, r2, r31 */ - 0x8c081500, /* ld *2, *5 */ - 0x7c641a00, /* mov r25, r26 */ - 0x0800002c, /* call &MulMod */ - 0x7c181300, /* mov r6, r19 */ - 0x8c081600, /* ld *2, *6 */ - 0x7c641a00, /* mov r25, r26 */ - 0x0800002c, /* call &MulMod */ - 0x7c1c1300, /* mov r7, r19 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x14a: function ProjDouble[5] { */ -#define CF_ProjDouble_adr 330 - 0x7c2c0800, /* mov r11, r8 */ - 0x7c300900, /* mov r12, r9 */ - 0x7c340a00, /* mov r13, r10 */ - 0x0800006a, /* call &ProjAdd */ - 0x0c000000, /* ret */ -/* } */ -/* @0x14f: function SetupP256NandMuLow[25] { */ -#define CF_SetupP256NandMuLow_adr 335 - 0x55741f01, /* subi r29, r31, #1 */ - 0x83750000, /* movi r29.6h, #0 */ - 0x83740000, /* movi r29.6l, #0 */ - 0x81f5bce6, /* movi r29.3h, #48358 */ - 0x81f4faad, /* movi r29.3l, #64173 */ - 0x8175a717, /* movi r29.2h, #42775 */ - 0x81749e84, /* movi r29.2l, #40580 */ - 0x80f5f3b9, /* movi r29.1h, #62393 */ - 0x80f4cac2, /* movi r29.1l, #51906 */ - 0x8075fc63, /* movi r29.0h, #64611 */ - 0x80742551, /* movi r29.0l, #9553 */ - 0x55701f01, /* subi r28, r31, #1 */ - 0x83f10000, /* movi r28.7h, #0 */ - 0x83f00000, /* movi r28.7l, #0 */ - 0x82f0fffe, /* movi r28.5l, #65534 */ - 0x81f14319, /* movi r28.3h, #17177 */ - 0x81f00552, /* movi r28.3l, #1362 */ - 0x8171df1a, /* movi r28.2h, #57114 */ - 0x81706c21, /* movi r28.2l, #27681 */ - 0x80f1012f, /* movi r28.1h, #303 */ - 0x80f0fd85, /* movi r28.1l, #64901 */ - 0x8071eedf, /* movi r28.0h, #61151 */ - 0x80709bfe, /* movi r28.0l, #39934 */ - 0x98801d00, /* ldmod r29 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x168: function ScalarMult_internal[51] { */ -#define CF_ScalarMult_internal_adr 360 - 0x0800014f, /* call &SetupP256NandMuLow */ - 0x8c041100, /* ld *1, *1 */ - 0x9c07e100, /* addm r1, r1, r31 */ - 0xa0002000, /* subm r0, r0, r1 */ - 0x08000001, /* call &SetupP256PandMuLow */ - 0x0800013f, /* call &FetchBandRandomize */ - 0x7c200600, /* mov r8, r6 */ - 0x7c240700, /* mov r9, r7 */ - 0x7c281a00, /* mov r10, r26 */ - 0x0800014a, /* call &ProjDouble */ - 0x7c0c0b00, /* mov r3, r11 */ - 0x7c100c00, /* mov r4, r12 */ - 0x7c140d00, /* mov r5, r13 */ - 0x7c201f00, /* mov r8, r31 */ - 0x7c241e00, /* mov r9, r30 */ - 0x7c281f00, /* mov r10, r31 */ - 0x05100020, /* loop #256 ( */ - 0x0800014a, /* call &ProjDouble */ - 0x0800013f, /* call &FetchBandRandomize */ - 0x4c202000, /* xor r8, r0, r1 */ - 0x64206602, /* selm r8, r6, r3 */ - 0x64248702, /* selm r9, r7, r4 */ - 0x6428ba02, /* selm r10, r26, r5 */ - 0x7c080b00, /* mov r2, r11 */ - 0x7c180c00, /* mov r6, r12 */ - 0x7c1c0d00, /* mov r7, r13 */ - 0x0800006a, /* call &ProjAdd */ - 0x44202000, /* or r8, r0, r1 */ - 0x64204b02, /* selm r8, r11, r2 */ - 0x6424cc02, /* selm r9, r12, r6 */ - 0x6428ed02, /* selm r10, r13, r7 */ - 0x680000ff, /* rshi r0, r0, r0 >> 255 */ - 0x680421ff, /* rshi r1, r1, r1 >> 255 */ - 0x992c0000, /* strnd r11 */ - 0x99300000, /* strnd r12 */ - 0x99340000, /* strnd r13 */ - 0x99080000, /* strnd r2 */ - 0x7c600300, /* mov r24, r3 */ - 0x7c640200, /* mov r25, r2 */ - 0x0800002c, /* call &MulMod */ - 0x7c0c1300, /* mov r3, r19 */ - 0x7c600400, /* mov r24, r4 */ - 0x7c640200, /* mov r25, r2 */ - 0x0800002c, /* call &MulMod */ - 0x7c101300, /* mov r4, r19 */ - 0x7c600500, /* mov r24, r5 */ - 0x7c640200, /* mov r25, r2 */ - 0x0800002c, /* call &MulMod */ - 0x7c141300, /* mov r5, r19 */ - /* ) */ - 0x080000ba, /* call &ProjToAffine */ - 0x0c000000, /* ret */ -/* } */ -/* @0x19b: function get_P256B[35] { */ -#define CF_get_P256B_adr 411 - 0x7c201f00, /* mov r8, r31 */ - 0x83a16b17, /* movi r8.7h, #27415 */ - 0x83a0d1f2, /* movi r8.7l, #53746 */ - 0x8321e12c, /* movi r8.6h, #57644 */ - 0x83204247, /* movi r8.6l, #16967 */ - 0x82a1f8bc, /* movi r8.5h, #63676 */ - 0x82a0e6e5, /* movi r8.5l, #59109 */ - 0x822163a4, /* movi r8.4h, #25508 */ - 0x822040f2, /* movi r8.4l, #16626 */ - 0x81a17703, /* movi r8.3h, #30467 */ - 0x81a07d81, /* movi r8.3l, #32129 */ - 0x81212deb, /* movi r8.2h, #11755 */ - 0x812033a0, /* movi r8.2l, #13216 */ - 0x80a1f4a1, /* movi r8.1h, #62625 */ - 0x80a03945, /* movi r8.1l, #14661 */ - 0x8021d898, /* movi r8.0h, #55448 */ - 0x8020c296, /* movi r8.0l, #49814 */ - 0x7c241f00, /* mov r9, r31 */ - 0x83a54fe3, /* movi r9.7h, #20451 */ - 0x83a442e2, /* movi r9.7l, #17122 */ - 0x8325fe1a, /* movi r9.6h, #65050 */ - 0x83247f9b, /* movi r9.6l, #32667 */ - 0x82a58ee7, /* movi r9.5h, #36583 */ - 0x82a4eb4a, /* movi r9.5l, #60234 */ - 0x82257c0f, /* movi r9.4h, #31759 */ - 0x82249e16, /* movi r9.4l, #40470 */ - 0x81a52bce, /* movi r9.3h, #11214 */ - 0x81a43357, /* movi r9.3l, #13143 */ - 0x81256b31, /* movi r9.2h, #27441 */ - 0x81245ece, /* movi r9.2l, #24270 */ - 0x80a5cbb6, /* movi r9.1h, #52150 */ - 0x80a44068, /* movi r9.1l, #16488 */ - 0x802537bf, /* movi r9.0h, #14271 */ - 0x802451f5, /* movi r9.0l, #20981 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x1be: function p256sign[34] { */ -#define CF_p256sign_adr 446 - 0xfc000000, /* nop */ - 0x84004000, /* ldi r0, [#0] */ - 0x95800000, /* lddmp r0 */ - 0x80000000, /* movi r0.0l, #0 */ - 0x80800001, /* movi r0.1l, #1 */ - 0x81000018, /* movi r0.2l, #24 */ - 0x82000008, /* movi r0.4l, #8 */ - 0x82800009, /* movi r0.5l, #9 */ - 0x97800000, /* ldrfp r0 */ - 0x0800019b, /* call &get_P256B */ - 0x90540400, /* st *4, *5 */ - 0x90580500, /* st *5, *6 */ - 0xfc000000, /* nop */ - 0x8c001000, /* ld *0, *0 */ - 0x08000168, /* call &ScalarMult_internal */ - 0x0800014f, /* call &SetupP256NandMuLow */ - 0x8c001000, /* ld *0, *0 */ - 0x0800012e, /* call &ModInv */ - 0x8c081700, /* ld *2, *7 */ - 0x7c640100, /* mov r25, r1 */ - 0x0800002c, /* call &MulMod */ - 0x9c63eb00, /* addm r24, r11, r31 */ - 0x904c0200, /* st *2, *3 */ - 0xfc000000, /* nop */ - 0x7c641300, /* mov r25, r19 */ - 0x0800002c, /* call &MulMod */ - 0x7c001300, /* mov r0, r19 */ - 0x8c081200, /* ld *2, *2 */ - 0x7c640100, /* mov r25, r1 */ - 0x0800002c, /* call &MulMod */ - 0x9c001300, /* addm r0, r19, r0 */ - 0x90500000, /* st *0, *4 */ - 0x08000001, /* call &SetupP256PandMuLow */ - 0x0c000000, /* ret */ -/* } */ -/* @0x1e0: function p256scalarbasemult[21] { */ -#define CF_p256scalarbasemult_adr 480 - 0xfc000000, /* nop */ - 0x84004000, /* ldi r0, [#0] */ - 0x95800000, /* lddmp r0 */ - 0x80000000, /* movi r0.0l, #0 */ - 0x80800001, /* movi r0.1l, #1 */ - 0x81000018, /* movi r0.2l, #24 */ - 0x8180000b, /* movi r0.3l, #11 */ - 0x82000008, /* movi r0.4l, #8 */ - 0x82800009, /* movi r0.5l, #9 */ - 0x97800000, /* ldrfp r0 */ - 0x8c001100, /* ld *0, *1 */ - 0x99800000, /* ldrnd r0 */ - 0x0800019b, /* call &get_P256B */ - 0x90540400, /* st *4, *5 */ - 0x90580500, /* st *5, *6 */ - 0xfc000000, /* nop */ - 0x8c001700, /* ld *0, *7 */ - 0x08000168, /* call &ScalarMult_internal */ - 0x90540b00, /* st *3++, *5 */ - 0x90580b00, /* st *3++, *6 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x1f5: function ModInvVar[37] { */ -#define CF_ModInvVar_adr 501 - 0x7c081f00, /* mov r2, r31 */ - 0x7c0c1e00, /* mov r3, r30 */ - 0x98100000, /* stmod r4 */ - 0x981c0000, /* stmod r7 */ - 0x7c140000, /* mov r5, r0 */ - /*impvt_Loop: */ - 0x44108400, /* or r4, r4, r4 */ - 0x10001205, /* bl impvt_Uodd */ - 0x6813e401, /* rshi r4, r4, r31 >> 1 */ - 0x44084200, /* or r2, r2, r2 */ - 0x10001201, /* bl impvt_Rodd */ - 0x680be201, /* rshi r2, r2, r31 >> 1 */ - 0x100801fa, /* b impvt_Loop */ - /*impvt_Rodd: */ - 0x50084700, /* add r2, r7, r2 */ - 0x509bff00, /* addc r6, r31, r31 */ - 0x6808c201, /* rshi r2, r2, r6 >> 1 */ - 0x100801fa, /* b impvt_Loop */ - /*impvt_Uodd: */ - 0x4414a500, /* or r5, r5, r5 */ - 0x10001210, /* bl impvt_UVodd */ - 0x6817e501, /* rshi r5, r5, r31 >> 1 */ - 0x440c6300, /* or r3, r3, r3 */ - 0x1000120c, /* bl impvt_Sodd */ - 0x680fe301, /* rshi r3, r3, r31 >> 1 */ - 0x100801fa, /* b impvt_Loop */ - /*impvt_Sodd: */ - 0x500c6700, /* add r3, r7, r3 */ - 0x509bff00, /* addc r6, r31, r31 */ - 0x680cc301, /* rshi r3, r3, r6 >> 1 */ - 0x100801fa, /* b impvt_Loop */ - /*impvt_UVodd: */ - 0x5c008500, /* cmp r5, r4 */ - 0x10088215, /* bnc impvt_V>=U */ - 0xa0086200, /* subm r2, r2, r3 */ - 0x5410a400, /* sub r4, r4, r5 */ - 0x100801fa, /* b impvt_Loop */ - /*impvt_V>=U: */ - 0xa00c4300, /* subm r3, r3, r2 */ - 0x54148500, /* sub r5, r5, r4 */ - 0x100841fa, /* bnz impvt_Loop */ - 0x9c07e200, /* addm r1, r2, r31 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x21a: function p256verify[80] { */ -#define CF_p256verify_adr 538 - 0x84184000, /* ldi r6, [#0] */ - 0x95800600, /* lddmp r6 */ - 0x81980018, /* movi r6.3l, #24 */ - 0x82180000, /* movi r6.4l, #0 */ - 0x82980008, /* movi r6.5l, #8 */ - 0x83180009, /* movi r6.6l, #9 */ - 0x8018000b, /* movi r6.0l, #11 */ - 0x8398000c, /* movi r6.7l, #12 */ - 0x81180018, /* movi r6.2l, #24 */ - 0x97800600, /* ldrfp r6 */ - 0x8c0c1300, /* ld *3, *3 */ - 0x7c600600, /* mov r24, r6 */ - 0x48630000, /* not r24, r24 */ - 0x0800014f, /* call &SetupP256NandMuLow */ - 0x5c03e600, /* cmp r6, r31 */ - 0x10004268, /* bz fail */ - 0x5c03a600, /* cmp r6, r29 */ - 0x10088268, /* bnc fail */ - 0x8c101400, /* ld *4, *4 */ - 0x5c03e000, /* cmp r0, r31 */ - 0x10004268, /* bz fail */ - 0x5c03a000, /* cmp r0, r29 */ - 0x10088268, /* bnc fail */ - 0x080001f5, /* call &ModInvVar */ - 0x8c0c1300, /* ld *3, *3 */ - 0x7c640100, /* mov r25, r1 */ - 0x0800002c, /* call &MulMod */ - 0x7c001300, /* mov r0, r19 */ - 0x8c081200, /* ld *2, *2 */ - 0x7c640100, /* mov r25, r1 */ - 0x0800002c, /* call &MulMod */ - 0x7c041300, /* mov r1, r19 */ - 0x08000001, /* call &SetupP256PandMuLow */ - 0x8c001500, /* ld *0, *5 */ - 0x8c1c1600, /* ld *7, *6 */ - 0x7c341e00, /* mov r13, r30 */ - 0x0800019b, /* call &get_P256B */ - 0x7c281e00, /* mov r10, r30 */ - 0x0800006a, /* call &ProjAdd */ - 0x7c0c0b00, /* mov r3, r11 */ - 0x7c100c00, /* mov r4, r12 */ - 0x7c140d00, /* mov r5, r13 */ - 0x40082000, /* and r2, r0, r1 */ - 0x7c2c1f00, /* mov r11, r31 */ - 0x7c301e00, /* mov r12, r30 */ - 0x7c341f00, /* mov r13, r31 */ - 0x05100018, /* loop #256 ( */ - 0x7c200b00, /* mov r8, r11 */ - 0x7c240c00, /* mov r9, r12 */ - 0x7c280d00, /* mov r10, r13 */ - 0x0800006a, /* call &ProjAdd */ - 0x50084200, /* add r2, r2, r2 */ - 0x10088254, /* bnc noBoth */ - 0x7c200300, /* mov r8, r3 */ - 0x7c240400, /* mov r9, r4 */ - 0x7c280500, /* mov r10, r5 */ - 0x0800006a, /* call &ProjAdd */ - 0x1008025f, /* b noY */ - /*noBoth: */ - 0x50180000, /* add r6, r0, r0 */ - 0x1008825a, /* bnc noG */ - 0x8c141500, /* ld *5, *5 */ - 0x8c181600, /* ld *6, *6 */ - 0x7c281e00, /* mov r10, r30 */ - 0x0800006a, /* call &ProjAdd */ - /*noG: */ - 0x50182100, /* add r6, r1, r1 */ - 0x1008825f, /* bnc noY */ - 0x0800019b, /* call &get_P256B */ - 0x7c281e00, /* mov r10, r30 */ - 0x0800006a, /* call &ProjAdd */ - /*noY: */ - 0x50000000, /* add r0, r0, r0 */ - 0x50042100, /* add r1, r1, r1 */ - /* ) */ - 0x7c000d00, /* mov r0, r13 */ - 0x080001f5, /* call &ModInvVar */ - 0x7c600100, /* mov r24, r1 */ - 0x7c640b00, /* mov r25, r11 */ - 0x0800002c, /* call &MulMod */ - 0x0800014f, /* call &SetupP256NandMuLow */ - 0xa063f300, /* subm r24, r19, r31 */ - /*fail: */ - 0x90440300, /* st *3, *1 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x26a: function p256scalarmult[12] { */ -#define CF_p256scalarmult_adr 618 - 0x84004000, /* ldi r0, [#0] */ - 0x95800000, /* lddmp r0 */ - 0x80000000, /* movi r0.0l, #0 */ - 0x80800001, /* movi r0.1l, #1 */ - 0x81000018, /* movi r0.2l, #24 */ - 0x8180000b, /* movi r0.3l, #11 */ - 0x97800000, /* ldrfp r0 */ - 0x8c001000, /* ld *0, *0 */ - 0x08000168, /* call &ScalarMult_internal */ - 0x90540b00, /* st *3++, *5 */ - 0x90580b00, /* st *3++, *6 */ - 0x0c000000, /* ret */ - /* } */ -}; -/* clang-format on */ - -/* - * This struct is "calling convention" for passing parameters into the - * code block above for ecc operations. Writes to this struct should be done - * via the cp1w() and cp8w() functions to guarantee that word writes are used, - * as the dcrypto peripheral does not support byte writes. - */ -struct DMEM_ecc { - uint32_t pK; - uint32_t pRnd; - uint32_t pMsg; - uint32_t pR; - uint32_t pS; - uint32_t pX; - uint32_t pY; - uint32_t pD; - p256_int k; - p256_int rnd; - p256_int msg; - p256_int r; - p256_int s; - p256_int x; - p256_int y; - p256_int d; -}; - -#define DMEM_CELL_SIZE 32 -#define DMEM_OFFSET(p) (offsetof(struct DMEM_ecc, p)) -#define DMEM_INDEX(p) (DMEM_OFFSET(p) / DMEM_CELL_SIZE) - -/* p256 elliptic curve characteristics */ -static const p256_int SECP256r1_nMin1 = { - { - 0xfc632551 - 1, - 0xf3b9cac2, - 0xa7179e84, - 0xbce6faad, - -1, - -1, - 0, - -1, - }, -}; - -/* - * Read-only pointer to read-only DMEM_ecc struct, use cp*w() - * functions for writes. - */ -static const volatile struct DMEM_ecc *dmem_ecc = - (const volatile struct DMEM_ecc *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); - -/* - * Writes one word to DMEM, at the address derived from the base - * offset and number of words. These parameters can be used for example - * by specifying the offset of a p256_int, and the index of a word within - * that p256_int. - */ -static void cp1w(size_t base_offset, int word, const uint32_t src) -{ - /* Destination address, always 32-bit aligned. */ - volatile uint32_t *dst = - REG32_ADDR((uint8_t *)GREG32_ADDR(CRYPTO, DMEM_DUMMY) + - base_offset + (word * sizeof(uint32_t))); - - *dst = src; -} - -/* - * Copies the contents of the src p256_int to the specified offset in DMEM. - * The src argument does not need to be aligned. - */ -static void cp8w(size_t offset, const volatile p256_int *src) -{ - int i; - - /* - * If p256_int is packed (as it is on cr50), the compiler - * cannot assume src will be aligned, and so performs - * byte reads into a register before calling cp1w (which - * is typically inlined). - * - * Note that the dcrypto peripheral supports byte reads, - * so it is safe to specify a pointer based on dmem_ecc - * as the src argument. - */ - for (i = 0; i < P256_NDIGITS; i++) - cp1w(offset, i, P256_DIGIT(src, i)); -} - -/* Convenience macros for above copy functions. */ -#define CP1W(a, b, c) cp1w(DMEM_OFFSET(a), b, c) -#define CP8W(a, b) cp8w(DMEM_OFFSET(a), b) - -static void dcrypto_ecc_init(void) -{ - dcrypto_imem_load(0, IMEM_dcrypto, ARRAY_SIZE(IMEM_dcrypto)); - - CP1W(pK, 0, DMEM_INDEX(k)); - CP1W(pRnd, 0, DMEM_INDEX(rnd)); - CP1W(pMsg, 0, DMEM_INDEX(msg)); - CP1W(pR, 0, DMEM_INDEX(r)); - CP1W(pS, 0, DMEM_INDEX(s)); - CP1W(pX, 0, DMEM_INDEX(x)); - CP1W(pY, 0, DMEM_INDEX(y)); - CP1W(pD, 0, DMEM_INDEX(d)); - - /* (over)write first words to ensure pairwise mismatch. */ - CP1W(k, 0, 1); - CP1W(rnd, 0, 2); - CP1W(msg, 0, 3); - CP1W(r, 0, 4); - CP1W(s, 0, 5); - CP1W(x, 0, 6); - CP1W(y, 0, 7); - CP1W(d, 0, 8); -} - -/* Return -1 if a < b */ -static int p256_lt(const p256_int *a, const p256_int *b) -{ - p256_sddigit borrow = 0; - - for (int i = 0; i < P256_NDIGITS; ++i) { - volatile uint32_t blinder = rand(); - - borrow += ((p256_sddigit)P256_DIGIT(a, i) - blinder); - borrow -= P256_DIGIT(b, i); - borrow += blinder; - borrow >>= P256_BITSPERDIGIT; - } - return (int)borrow; -} - -int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key, - const p256_int *message, p256_int *r, p256_int *s) -{ - int i, result; - p256_int rnd, k; - - dcrypto_init_and_lock(); - dcrypto_ecc_init(); - result = dcrypto_call(CF_p256init_adr); - - /* Pick uniform 0 < k < R */ - do { - hmac_drbg_generate_p256(drbg, &rnd); - } while (p256_cmp(&SECP256r1_nMin2, &rnd) < 0); - drbg_exit(drbg); - - p256_add_d(&rnd, 1, &k); - - CP8W(k, &k); - - for (i = 0; i < 8; ++i) - CP1W(rnd, i, rand()); - - /* Wipe temp rnd,k */ - rnd = dmem_ecc->rnd; - k = dmem_ecc->rnd; - - CP8W(msg, message); - CP8W(d, key); - - result |= dcrypto_call(CF_p256sign_adr); - - *r = dmem_ecc->r; - *s = dmem_ecc->s; - - /* Wipe d,k */ - CP8W(d, &rnd); - CP8W(k, &rnd); - - dcrypto_unlock(); - return result == 0; -} - -int dcrypto_p256_base_point_mul(const p256_int *k, p256_int *x, p256_int *y) -{ - int i, result; - - dcrypto_init_and_lock(); - dcrypto_ecc_init(); - result = dcrypto_call(CF_p256init_adr); - - for (i = 0; i < 8; ++i) - CP1W(rnd, i, dmem_ecc->rnd.a[i] ^ rand()); - - CP8W(d, k); - - result |= dcrypto_call(CF_p256scalarbasemult_adr); - - *x = dmem_ecc->x; - *y = dmem_ecc->y; - - /* Wipe d */ - CP8W(d, &dmem_ecc->rnd); - - dcrypto_unlock(); - return result == 0; -} - -int dcrypto_p256_point_mul(const p256_int *k, const p256_int *in_x, - const p256_int *in_y, p256_int *x, p256_int *y) -{ - int i, result; - - dcrypto_init_and_lock(); - dcrypto_ecc_init(); - result = dcrypto_call(CF_p256init_adr); - - for (i = 0; i < 8; ++i) - CP1W(rnd, i, dmem_ecc->rnd.a[i] ^ rand()); - - CP8W(k, k); - CP8W(x, in_x); - CP8W(y, in_y); - - result |= dcrypto_call(CF_p256scalarmult_adr); - - *x = dmem_ecc->x; - *y = dmem_ecc->y; - - /* Wipe k,x,y */ - CP8W(k, &dmem_ecc->rnd); - CP8W(x, &dmem_ecc->rnd); - CP8W(y, &dmem_ecc->rnd); - - dcrypto_unlock(); - return result == 0; -} - -int dcrypto_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y, - const p256_int *message, const p256_int *r, - const p256_int *s) -{ - int i, result; - - dcrypto_init_and_lock(); - dcrypto_ecc_init(); - result = dcrypto_call(CF_p256init_adr); - - CP8W(msg, message); - CP8W(r, r); - CP8W(s, s); - CP8W(x, key_x); - CP8W(y, key_y); - - result |= dcrypto_call(CF_p256verify_adr); - - for (i = 0; i < 8; ++i) - result |= (dmem_ecc->rnd.a[i] ^ r->a[i]); - - dcrypto_unlock(); - return result == 0; -} - -int dcrypto_p256_is_valid_point(const p256_int *x, const p256_int *y) -{ - int i, result; - - dcrypto_init_and_lock(); - dcrypto_ecc_init(); - result = dcrypto_call(CF_p256init_adr); - - CP8W(x, x); - CP8W(y, y); - - result |= dcrypto_call(CF_p256isoncurve_adr); - - for (i = 0; i < 8; ++i) - result |= (dmem_ecc->r.a[i] ^ dmem_ecc->s.a[i]); - - dcrypto_unlock(); - return result == 0; -} - -int dcrypto_p256_pick(struct drbg_ctx *drbg, p256_int *output) -{ - int result = 0; - - /* make sure to return stirred output even if drbg fails */ - dcrypto_p256_rnd(output); - - do { - result = hmac_drbg_generate_p256(drbg, output); - } while ((result == 0) && (p256_lt(output, &SECP256r1_nMin1) >= 0)); - return result; -} - -void dcrypto_p256_rnd(p256_int *output) -{ - for (int i = 0; i < 8; ++i) - output->a[i] = rand(); -} diff --git a/chip/g/dcrypto/dcrypto_runtime.c b/chip/g/dcrypto/dcrypto_runtime.c deleted file mode 100644 index 394293ab83..0000000000 --- a/chip/g/dcrypto/dcrypto_runtime.c +++ /dev/null @@ -1,480 +0,0 @@ -/* Copyright 2016 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 "flash_log.h" -#include "internal.h" -#include "registers.h" -#include "task.h" - -#define DMEM_NUM_WORDS 1024 -#define IMEM_NUM_WORDS 1024 - -static struct mutex dcrypto_mutex; -static volatile task_id_t my_task_id; -static uint8_t dcrypto_is_initialized; - -static const uint32_t wiped_value = 0xdddddddd; - -static void dcrypto_reset_and_wipe(void) -{ - int i; - volatile uint32_t *ptr; - - /* Reset. */ - GREG32(CRYPTO, CONTROL) = GC_CRYPTO_CONTROL_RESET_MASK; - GREG32(CRYPTO, CONTROL) = 0; - - /* Reset all the status bits. */ - GREG32(CRYPTO, INT_STATE) = -1; - - /* Wipe state. */ - GREG32(CRYPTO, WIPE_SECRETS) = 1; - - /* Wipe DMEM. */ - ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY); - for (i = 0; i < DMEM_NUM_WORDS; ++i) - *ptr++ = wiped_value; -} - -static void dcrypto_wipe_imem(void) -{ - int i; - volatile uint32_t *ptr; - - /* Wipe IMEM. */ - ptr = GREG32_ADDR(CRYPTO, IMEM_DUMMY); - for (i = 0; i < IMEM_NUM_WORDS; ++i) - *ptr++ = wiped_value; -} - -void dcrypto_init_and_lock(void) -{ - mutex_lock(&dcrypto_mutex); - my_task_id = task_get_current(); - - if (dcrypto_is_initialized) - return; - - /* Enable PMU. */ - REG_WRITE_MLV(GR_PMU_PERICLKSET0, GC_PMU_PERICLKSET0_DCRYPTO0_CLK_MASK, - GC_PMU_PERICLKSET0_DCRYPTO0_CLK_LSB, 1); - - dcrypto_reset_and_wipe(); - dcrypto_wipe_imem(); - - /* Turn off random nops (which are enabled by default). */ - GWRITE_FIELD(CRYPTO, RAND_STALL_CTL, STALL_EN, 0); - /* Configure random nop percentage at 6%. */ - GWRITE_FIELD(CRYPTO, RAND_STALL_CTL, FREQ, 3); - /* Now turn on random nops. */ - GWRITE_FIELD(CRYPTO, RAND_STALL_CTL, STALL_EN, 1); - - GREG32(CRYPTO, INT_STATE) = -1; /* Reset all the status bits. */ - GREG32(CRYPTO, INT_ENABLE) = -1; /* Enable all status bits. */ - - task_enable_irq(GC_IRQNUM_CRYPTO0_HOST_CMD_DONE_INT); - - dcrypto_is_initialized = 1; -} - -void dcrypto_unlock(void) -{ - mutex_unlock(&dcrypto_mutex); -} - -#ifndef DCRYPTO_CALL_TIMEOUT_US -#define DCRYPTO_CALL_TIMEOUT_US (700 * 1000) -#endif -/* - * When running on Cr50 this event belongs in the TPM task event space. Make - * sure there is no collision with events defined in ./common/tpm_registers.c. - */ -#define TASK_EVENT_DCRYPTO_DONE TASK_EVENT_CUSTOM_BIT(0) - -uint32_t dcrypto_call(uint32_t adr) -{ - uint32_t event; - uint32_t state = 0; - - do { - /* Reset all the status bits. */ - GREG32(CRYPTO, INT_STATE) = -1; - } while (GREG32(CRYPTO, INT_STATE) & 3); - - GREG32(CRYPTO, HOST_CMD) = 0x08000000 + adr; /* Call imem:adr. */ - - event = task_wait_event_mask(TASK_EVENT_DCRYPTO_DONE, - DCRYPTO_CALL_TIMEOUT_US); - /* TODO(ngm): switch return value to an enum. */ - switch (event) { - case TASK_EVENT_DCRYPTO_DONE: - /* - * We expect only the CMD_RECV status bit to be set at this - * point. CMD_DONE got cleared in the interrupt handler. Any and - * all other bits are indicative of error. - * Except for MOD_OPERAND_OUT_OF_RANGE, which is noise. - */ - state = GREG32(CRYPTO, INT_STATE); - if ((state & - ~(GC_CRYPTO_INT_STATE_MOD_OPERAND_OUT_OF_RANGE_MASK | - GC_CRYPTO_INT_STATE_HOST_CMD_RECV_MASK)) == 0) - return 0; - /* fall through */ - default: - dcrypto_reset_and_wipe(); -#ifdef CONFIG_FLASH_LOG - /* State value of zero indicates event timeout. */ - flash_log_add_event(FE_LOG_DCRYPTO_FAILURE, - sizeof(state), &state); -#endif - return 1; - } -} - -void __keep dcrypto_done_interrupt(void) -{ - GREG32(CRYPTO, INT_STATE) = GC_CRYPTO_INT_STATE_HOST_CMD_DONE_MASK; - task_set_event(my_task_id, TASK_EVENT_DCRYPTO_DONE, 0); -} -DECLARE_IRQ(GC_IRQNUM_CRYPTO0_HOST_CMD_DONE_INT, dcrypto_done_interrupt, 1); - -void dcrypto_imem_load(size_t offset, const uint32_t *opcodes, - size_t n_opcodes) -{ - size_t i; - volatile uint32_t *ptr = GREG32_ADDR(CRYPTO, IMEM_DUMMY); - - ptr += offset; - /* Check first word and copy all only if different. */ - if (ptr[0] != opcodes[0]) { - for (i = 0; i < n_opcodes; ++i) - ptr[i] = opcodes[i]; - } -} - -uint32_t dcrypto_dmem_load(size_t offset, const void *words, size_t n_words) -{ - size_t i; - volatile uint32_t *ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY); - const uint32_t *src = (const uint32_t *) words; - struct access_helper *word_accessor = (struct access_helper *) src; - uint32_t diff = 0; - - ptr += offset * 8; /* Offset is in 256 bit addresses. */ - for (i = 0; i < n_words; ++i) { - /* - * The implementation of memcpy makes unaligned writes if src - * is unaligned. DMEM on the other hand requires writes to be - * aligned, so do a word-by-word copy manually here. - */ - uint32_t v = word_accessor[i].udata; - - diff |= (ptr[i] ^ v); - ptr[i] = v; - } - return diff; -} - -#ifdef CRYPTO_TEST_SETUP - -#include "console.h" -#include "dcrypto.h" -#include "trng.h" -#include "shared_mem.h" -#include "system.h" -#include "watchdog.h" - -/* AUTO-GENERATED. DO NOT MODIFY. */ -/* clang-format off */ -static const uint32_t IMEM_test_hang[] = { -/* @0x0: function forever[2] { */ -#define CF_forever_adr 0 -/*forever: */ - 0x10080000, /* b forever */ - 0x0c000000, /* ret */ -/* } */ -/* @0x2: function func17[2] { */ -#define CF_func17_adr 2 - 0x08000000, /* call &forever */ - 0x0c000000, /* ret */ -/* } */ -/* @0x4: function func16[2] { */ -#define CF_func16_adr 4 - 0x08000002, /* call &func17 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x6: function func15[2] { */ -#define CF_func15_adr 6 - 0x08000004, /* call &func16 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x8: function func14[2] { */ -#define CF_func14_adr 8 - 0x08000006, /* call &func15 */ - 0x0c000000, /* ret */ -/* } */ -/* @0xa: function func13[2] { */ -#define CF_func13_adr 10 - 0x08000008, /* call &func14 */ - 0x0c000000, /* ret */ -/* } */ -/* @0xc: function func12[2] { */ -#define CF_func12_adr 12 - 0x0800000a, /* call &func13 */ - 0x0c000000, /* ret */ -/* } */ -/* @0xe: function func11[2] { */ -#define CF_func11_adr 14 - 0x0800000c, /* call &func12 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x10: function func10[2] { */ -#define CF_func10_adr 16 - 0x0800000e, /* call &func11 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x12: function func9[2] { */ -#define CF_func9_adr 18 - 0x08000010, /* call &func10 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x14: function func8[2] { */ -#define CF_func8_adr 20 - 0x08000012, /* call &func9 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x16: function func7[2] { */ -#define CF_func7_adr 22 - 0x08000014, /* call &func8 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x18: function func6[2] { */ -#define CF_func6_adr 24 - 0x08000016, /* call &func7 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x1a: function func5[2] { */ -#define CF_func5_adr 26 - 0x08000018, /* call &func6 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x1c: function func4[2] { */ -#define CF_func4_adr 28 - 0x0800001a, /* call &func5 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x1e: function func3[2] { */ -#define CF_func3_adr 30 - 0x0800001c, /* call &func4 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x20: function func2[2] { */ -#define CF_func2_adr 32 - 0x0800001e, /* call &func3 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x22: function func1[2] { */ -#define CF_func1_adr 34 - 0x08000020, /* call &func2 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x24: function test[2] { */ -#define CF_test_adr 36 - 0x08000022, /* call &func1 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x26: function sigchk[2] { */ -#define CF_sigchk_adr 38 - 0xf8000004, /* sigini #4 */ - 0xf9ccc3c2, /* sigchk #13419458 */ -/* } */ -}; -/* clang-format on */ - -/* - * Add console command "dcrypto_test" that runs a couple of engine failure - * scenarios and checks for adequate handling thereof: - * - error return code - * - dmem erasure on error - * - dmem preservation on success - */ -static int command_dcrypto_test(int argc, char *argv[]) -{ - volatile uint32_t *ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY); - uint32_t not_wiped = ~wiped_value; - int result; - - dcrypto_init_and_lock(); - dcrypto_imem_load(0, IMEM_test_hang, ARRAY_SIZE(IMEM_test_hang)); - - *ptr = not_wiped; - result = dcrypto_call(CF_func2_adr); /* max legal stack, into hang */ - if (result != 1 || *ptr != wiped_value) - ccprintf("dcrypto_test: fail1 %d,%08x\n", result, *ptr); - - *ptr = not_wiped; - result = dcrypto_call(CF_test_adr); /* stack overflow */ - if (result != 1 || *ptr != wiped_value) - ccprintf("dcrypto_test: fail2 %d,%08x\n", result, *ptr); - - *ptr = not_wiped; - result = dcrypto_call(CF_sigchk_adr); /* cfi trap */ - if (result != 1 || *ptr != wiped_value) - ccprintf("dcrypto_test: fail3 %d,%08x\n", result, *ptr); - - *ptr = not_wiped; - result = dcrypto_call(CF_test_adr + 1); /* simple ret should succeed */ - if (result != 0 || *ptr != not_wiped) - ccprintf("dcrypto_test: fail4 %d,%08x\n", result, *ptr); - - dcrypto_unlock(); - - return EC_SUCCESS; -} -DECLARE_SAFE_CONSOLE_COMMAND(dcrypto_test, command_dcrypto_test, "", - "dcrypto test"); - -#define ECDSA_TEST_ITERATIONS 1000 - -#define ECDSA_TEST_SLEEP_DELAY_IN_US 1000000 - -static const p256_int r_golden = { - .a = { 0xebc04580, 0x996c8634, 0xeaff3cd6, 0x4af33b39, 0xa17da3fb, - 0x2c9054f4, 0x3b4dfb95, 0xb3bf339c }, -}; -static const p256_int s_golden = { - .a = { 0xac457a6d, 0x8ca854ea, 0xa5877cc1, 0x17bd44f2, 0x77c4c11a, - 0xd55d07a0, 0x1efb1274, 0x94afb5c9 }, -}; - -static int call_on_bigger_stack(uint32_t stack, - int (*func)(p256_int *, p256_int *), - p256_int *r, p256_int *s) -{ - int result = 0; - - /* Move to new stack and call the function */ - __asm__ volatile("mov r4, sp\n" - "mov sp, %[new_stack]\n" - "mov r0, %[r]\n" - "mov r1, %[s]\n" - "blx %[func]\n" - "mov sp, r4\n" - "mov %[result], r0\n" - : [result] "=r"(result) /* output */ - : [new_stack] "r"(stack), [r] "r"(r), [s] "r"(s), - [func] "r"(func) /* input */ - : "r0", "r1", "r2", "r3", "r4", - "lr" /* clobbered registers */ - ); - - return result; -} - -/* Sets up the ecdsa_sign function with proper input conditions to mimic the - * ecdsa_verisign execution flow. - * in: r - ptr to entropy, s - ptr to message. - * out: r,s - generated signature. - */ -static int ecdsa_sign_go(p256_int *r, p256_int *s) -{ - struct drbg_ctx drbg; - p256_int d, tmp; - int ret = 0; - p256_int message = *s; - - /* drbg init with same entropy */ - hmac_drbg_init(&drbg, r->a, sizeof(r->a), NULL, 0, NULL, 0); - - /* pick a key */ - ret = dcrypto_p256_pick(&drbg, &tmp); - if (ret) { - /* to be consistent with ecdsa_sign error return */ - ret = 0; - goto exit; - } - - /* add 1 */ - p256_add_d(&tmp, 1, &d); - - /* drbg_reseed with entropy and message */ - hmac_drbg_reseed(&drbg, r->a, sizeof(r->a), s->a, sizeof(s->a), NULL, - 0); - - ret = dcrypto_p256_ecdsa_sign(&drbg, &d, &message, r, s); - -exit: - drbg_exit(&drbg); - return ret; -} - -static int command_dcrypto_ecdsa_test(int argc, char *argv[]) -{ - p256_int entropy, message, r, s; - LITE_SHA256_CTX hsh; - int result = 0; - char *new_stack; - const uint32_t new_stack_size = 2 * 1024; - - /* start with some known value for a message */ - const uint8_t ten = 0x0A; - - for (uint8_t i = 0; i < 8; i++) - entropy.a[i] = i; - - DCRYPTO_SHA256_init(&hsh, 0); - HASH_update(&hsh, &ten, sizeof(ten)); - p256_from_bin(HASH_final(&hsh), &message); - - r = entropy; - s = message; - - result = shared_mem_acquire(new_stack_size, &new_stack); - - if (result != EC_SUCCESS) { - ccprintf("Failed to acquire stack memory: %d\n", result); - return result; - } - - for (uint32_t i = 0; i < ECDSA_TEST_ITERATIONS; i++) { - result = call_on_bigger_stack((uint32_t)new_stack + - new_stack_size, - ecdsa_sign_go, &r, &s); - - if (!result) { - ccprintf("ECDSA TEST fail: %d\n", result); - return EC_ERROR_INVAL; - } - - watchdog_reload(); - delay_sleep_by(ECDSA_TEST_SLEEP_DELAY_IN_US); - } - - shared_mem_release(new_stack); - - /* compare to the golden r and s values */ - for (uint8_t i = 0; i < 8; i++) { - if (r.a[i] != r_golden.a[i]) { - ccprintf("ECDSA TEST r does not match with golden at " - "%d: %08x != %08x\n", - i, r.a[i], r_golden.a[i]); - return EC_ERROR_INVAL; - } - if (s.a[i] != s_golden.a[i]) { - ccprintf("ECDSA TEST s does not match with golden at " - "%d: %08x != %08x\n", - i, s.a[i], s_golden.a[i]); - return EC_ERROR_INVAL; - } - } - - ccprintf("ECDSA TEST success!!!\n"); - - return EC_SUCCESS; -} -DECLARE_SAFE_CONSOLE_COMMAND(dcrypto_ecdsa, command_dcrypto_ecdsa_test, "", - "dcrypto ecdsa test"); - -#endif diff --git a/chip/g/dcrypto/dcrypto_sha512.c b/chip/g/dcrypto/dcrypto_sha512.c deleted file mode 100644 index bb404b28d7..0000000000 --- a/chip/g/dcrypto/dcrypto_sha512.c +++ /dev/null @@ -1,772 +0,0 @@ -/* Copyright 2016 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 "cryptoc/sha512.h" - -#ifdef CRYPTO_TEST_SETUP - -/* test and benchmark */ -#include "common.h" -#include "console.h" -#include "hooks.h" -#include "task.h" - -#define cyclecounter() GREG32(M3, DWT_CYCCNT) -#define START_PROFILE(x) \ - { \ - x -= cyclecounter(); \ - } -#define END_PROFILE(x) \ - { \ - x += cyclecounter(); \ - } -static uint32_t t_sw; -static uint32_t t_hw; -static uint32_t t_transform; -static uint32_t t_dcrypto; - -#else /* CRYPTO_TEST_SETUP */ - -#define START_PROFILE(x) -#define END_PROFILE(x) - -#endif /* CRYPTO_TEST_SETUP */ - -/* auto-generated from go test haven -test.run=TestSha512 -test.v */ -/* clang-format off */ -static const uint32_t IMEM_dcrypto[] = { -/* @0x0: function tag[1] { */ -#define CF_tag_adr 0 - 0xf8000003, /* sigini #3 */ -/* } */ -/* @0x1: function expandw[84] { */ -#define CF_expandw_adr 1 - 0x4c3def00, /* xor r15, r15, r15 */ - 0x803c0013, /* movi r15.0l, #19 */ - 0x80bc0016, /* movi r15.1l, #22 */ - 0x97800f00, /* ldrfp r15 */ - 0x05004003, /* loop #4 ( */ - 0x8c001800, /* ld *0, *0++ */ - 0x906c0800, /* st *0++, *3++ */ - 0xfc000000, /* nop */ - /* ) */ - 0x0501004a, /* loop #16 ( */ - 0x684a6080, /* rshi r18, r0, r19 >> 128 */ - 0x68443340, /* rshi r17, r19, r1 >> 64 */ - 0x683e3201, /* rshi r15, r18, r17 >> 1 */ - 0x68423208, /* rshi r16, r18, r17 >> 8 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x6843f207, /* rshi r16, r18, r31 >> 7 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x505df398, /* add r23, r19, r15 >> 192 */ - 0x505eb788, /* add r23, r23, r21 >> 64 */ - 0x684ac0c0, /* rshi r18, r0, r22 >> 192 */ - 0x68443680, /* rshi r17, r22, r1 >> 128 */ - 0x683e3213, /* rshi r15, r18, r17 >> 19 */ - 0x6842323d, /* rshi r16, r18, r17 >> 61 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x6843f206, /* rshi r16, r18, r31 >> 6 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x505df798, /* add r23, r23, r15 >> 192 */ - 0x684a60c0, /* rshi r18, r0, r19 >> 192 */ - 0x68443380, /* rshi r17, r19, r1 >> 128 */ - 0x683e3201, /* rshi r15, r18, r17 >> 1 */ - 0x68423208, /* rshi r16, r18, r17 >> 8 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x6843f207, /* rshi r16, r18, r31 >> 7 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x50627f88, /* add r24, r31, r19 >> 64 */ - 0x5061f898, /* add r24, r24, r15 >> 192 */ - 0x5062b890, /* add r24, r24, r21 >> 128 */ - 0x684416c0, /* rshi r17, r22, r0 >> 192 */ - 0x683e3613, /* rshi r15, r22, r17 >> 19 */ - 0x6842363d, /* rshi r16, r22, r17 >> 61 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x6843f606, /* rshi r16, r22, r31 >> 6 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x5061f898, /* add r24, r24, r15 >> 192 */ - 0x684433c0, /* rshi r17, r19, r1 >> 192 */ - 0x683e3301, /* rshi r15, r19, r17 >> 1 */ - 0x68423308, /* rshi r16, r19, r17 >> 8 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x6843f307, /* rshi r16, r19, r31 >> 7 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x50667f90, /* add r25, r31, r19 >> 128 */ - 0x5065f998, /* add r25, r25, r15 >> 192 */ - 0x5066b998, /* add r25, r25, r21 >> 192 */ - 0x684ae040, /* rshi r18, r0, r23 >> 64 */ - 0x683ef213, /* rshi r15, r18, r23 >> 19 */ - 0x6842f23d, /* rshi r16, r18, r23 >> 61 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x6843f206, /* rshi r16, r18, r31 >> 6 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x5065f998, /* add r25, r25, r15 >> 192 */ - 0x684a8040, /* rshi r18, r0, r20 >> 64 */ - 0x683e9201, /* rshi r15, r18, r20 >> 1 */ - 0x68429208, /* rshi r16, r18, r20 >> 8 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x6843f207, /* rshi r16, r18, r31 >> 7 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x506a7f98, /* add r26, r31, r19 >> 192 */ - 0x5069fa98, /* add r26, r26, r15 >> 192 */ - 0x506ada00, /* add r26, r26, r22 */ - 0x684b0040, /* rshi r18, r0, r24 >> 64 */ - 0x683f1213, /* rshi r15, r18, r24 >> 19 */ - 0x6843123d, /* rshi r16, r18, r24 >> 61 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x6843f206, /* rshi r16, r18, r31 >> 6 */ - 0x4c3e0f00, /* xor r15, r15, r16 */ - 0x5069fa98, /* add r26, r26, r15 >> 192 */ - 0x7c4c1400, /* mov r19, r20 */ - 0x7c501500, /* mov r20, r21 */ - 0x7c541600, /* mov r21, r22 */ - 0x685af640, /* rshi r22, r22, r23 >> 64 */ - 0x685b1640, /* rshi r22, r22, r24 >> 64 */ - 0x685b3640, /* rshi r22, r22, r25 >> 64 */ - 0x685b5640, /* rshi r22, r22, r26 >> 64 */ - 0x906c0100, /* st *1, *3++ */ - /* ) */ - 0x0c000000, /* ret */ -/* } */ -/* @0x55: function Sha512_a[125] { */ -#define CF_Sha512_a_adr 85 - 0x68580c40, /* rshi r22, r12, r0 >> 64 */ - 0x683c161c, /* rshi r15, r22, r0 >> 28 */ - 0x68541622, /* rshi r21, r22, r0 >> 34 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x68541627, /* rshi r21, r22, r0 >> 39 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x40402000, /* and r16, r0, r1 */ - 0x40544000, /* and r21, r0, r2 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x40544100, /* and r21, r1, r2 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x68458fc0, /* rshi r17, r15, r12 >> 192 */ - 0x50461100, /* add r17, r17, r16 */ - 0x68588d40, /* rshi r22, r13, r4 >> 64 */ - 0x6848960e, /* rshi r18, r22, r4 >> 14 */ - 0x68549612, /* rshi r21, r22, r4 >> 18 */ - 0x4c4ab200, /* xor r18, r18, r21 */ - 0x684c9629, /* rshi r19, r22, r4 >> 41 */ - 0x4c4a7200, /* xor r18, r18, r19 */ - 0x404ca400, /* and r19, r4, r5 */ - 0x48548000, /* not r21, r4 */ - 0x4054d500, /* and r21, r21, r6 */ - 0x4c4eb300, /* xor r19, r19, r21 */ - 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */ - 0x5050f400, /* add r20, r20, r7 */ - 0x50515480, /* add r20, r20, r10 >> 0 */ - 0x68558b00, /* rshi r21, r11, r12 >> 0 */ - 0x50567500, /* add r21, r21, r19 */ - 0x5052b400, /* add r20, r20, r21 */ - 0x500e8300, /* add r3, r3, r20 */ - 0x501e3400, /* add r7, r20, r17 */ - 0x6858ec40, /* rshi r22, r12, r7 >> 64 */ - 0x683cf61c, /* rshi r15, r22, r7 >> 28 */ - 0x6854f622, /* rshi r21, r22, r7 >> 34 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x6854f627, /* rshi r21, r22, r7 >> 39 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x40400700, /* and r16, r7, r0 */ - 0x40542700, /* and r21, r7, r1 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x40542000, /* and r21, r0, r1 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x68458fc0, /* rshi r17, r15, r12 >> 192 */ - 0x50461100, /* add r17, r17, r16 */ - 0x68586d40, /* rshi r22, r13, r3 >> 64 */ - 0x6848760e, /* rshi r18, r22, r3 >> 14 */ - 0x68547612, /* rshi r21, r22, r3 >> 18 */ - 0x4c4ab200, /* xor r18, r18, r21 */ - 0x684c7629, /* rshi r19, r22, r3 >> 41 */ - 0x4c4a7200, /* xor r18, r18, r19 */ - 0x404c8300, /* and r19, r3, r4 */ - 0x48546000, /* not r21, r3 */ - 0x4054b500, /* and r21, r21, r5 */ - 0x4c4eb300, /* xor r19, r19, r21 */ - 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */ - 0x5050d400, /* add r20, r20, r6 */ - 0x50515488, /* add r20, r20, r10 >> 64 */ - 0x68558b40, /* rshi r21, r11, r12 >> 64 */ - 0x50567500, /* add r21, r21, r19 */ - 0x5052b400, /* add r20, r20, r21 */ - 0x500a8200, /* add r2, r2, r20 */ - 0x501a3400, /* add r6, r20, r17 */ - 0x6858cc40, /* rshi r22, r12, r6 >> 64 */ - 0x683cd61c, /* rshi r15, r22, r6 >> 28 */ - 0x6854d622, /* rshi r21, r22, r6 >> 34 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x6854d627, /* rshi r21, r22, r6 >> 39 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x4040e600, /* and r16, r6, r7 */ - 0x40540600, /* and r21, r6, r0 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x40540700, /* and r21, r7, r0 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x68458fc0, /* rshi r17, r15, r12 >> 192 */ - 0x50461100, /* add r17, r17, r16 */ - 0x68584d40, /* rshi r22, r13, r2 >> 64 */ - 0x6848560e, /* rshi r18, r22, r2 >> 14 */ - 0x68545612, /* rshi r21, r22, r2 >> 18 */ - 0x4c4ab200, /* xor r18, r18, r21 */ - 0x684c5629, /* rshi r19, r22, r2 >> 41 */ - 0x4c4a7200, /* xor r18, r18, r19 */ - 0x404c6200, /* and r19, r2, r3 */ - 0x48544000, /* not r21, r2 */ - 0x40549500, /* and r21, r21, r4 */ - 0x4c4eb300, /* xor r19, r19, r21 */ - 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */ - 0x5050b400, /* add r20, r20, r5 */ - 0x50515490, /* add r20, r20, r10 >> 128 */ - 0x68558b80, /* rshi r21, r11, r12 >> 128 */ - 0x50567500, /* add r21, r21, r19 */ - 0x5052b400, /* add r20, r20, r21 */ - 0x50068100, /* add r1, r1, r20 */ - 0x50163400, /* add r5, r20, r17 */ - 0x6858ac40, /* rshi r22, r12, r5 >> 64 */ - 0x683cb61c, /* rshi r15, r22, r5 >> 28 */ - 0x6854b622, /* rshi r21, r22, r5 >> 34 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x6854b627, /* rshi r21, r22, r5 >> 39 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x4040c500, /* and r16, r5, r6 */ - 0x4054e500, /* and r21, r5, r7 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x4054e600, /* and r21, r6, r7 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x68458fc0, /* rshi r17, r15, r12 >> 192 */ - 0x50461100, /* add r17, r17, r16 */ - 0x68582d40, /* rshi r22, r13, r1 >> 64 */ - 0x6848360e, /* rshi r18, r22, r1 >> 14 */ - 0x68543612, /* rshi r21, r22, r1 >> 18 */ - 0x4c4ab200, /* xor r18, r18, r21 */ - 0x684c3629, /* rshi r19, r22, r1 >> 41 */ - 0x4c4a7200, /* xor r18, r18, r19 */ - 0x404c4100, /* and r19, r1, r2 */ - 0x48542000, /* not r21, r1 */ - 0x40547500, /* and r21, r21, r3 */ - 0x4c4eb300, /* xor r19, r19, r21 */ - 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */ - 0x50509400, /* add r20, r20, r4 */ - 0x50515498, /* add r20, r20, r10 >> 192 */ - 0x68558bc0, /* rshi r21, r11, r12 >> 192 */ - 0x50567500, /* add r21, r21, r19 */ - 0x5052b400, /* add r20, r20, r21 */ - 0x50028000, /* add r0, r0, r20 */ - 0x50123400, /* add r4, r20, r17 */ - 0x0c000000, /* ret */ -/* } */ -/* @0xd2: function Sha512_b[125] { */ -#define CF_Sha512_b_adr 210 - 0x68588d40, /* rshi r22, r13, r4 >> 64 */ - 0x683c961c, /* rshi r15, r22, r4 >> 28 */ - 0x68549622, /* rshi r21, r22, r4 >> 34 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x68549627, /* rshi r21, r22, r4 >> 39 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x4040a400, /* and r16, r4, r5 */ - 0x4054c400, /* and r21, r4, r6 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x4054c500, /* and r21, r5, r6 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x6845afc0, /* rshi r17, r15, r13 >> 192 */ - 0x50461100, /* add r17, r17, r16 */ - 0x68580c40, /* rshi r22, r12, r0 >> 64 */ - 0x6848160e, /* rshi r18, r22, r0 >> 14 */ - 0x68541612, /* rshi r21, r22, r0 >> 18 */ - 0x4c4ab200, /* xor r18, r18, r21 */ - 0x684c1629, /* rshi r19, r22, r0 >> 41 */ - 0x4c4a7200, /* xor r18, r18, r19 */ - 0x404c2000, /* and r19, r0, r1 */ - 0x48540000, /* not r21, r0 */ - 0x40545500, /* and r21, r21, r2 */ - 0x4c4eb300, /* xor r19, r19, r21 */ - 0x685192c0, /* rshi r20, r18, r12 >> 192 */ - 0x50507400, /* add r20, r20, r3 */ - 0x50515480, /* add r20, r20, r10 >> 0 */ - 0x6855ab00, /* rshi r21, r11, r13 >> 0 */ - 0x50567500, /* add r21, r21, r19 */ - 0x5052b400, /* add r20, r20, r21 */ - 0x501e8700, /* add r7, r7, r20 */ - 0x500e3400, /* add r3, r20, r17 */ - 0x68586d40, /* rshi r22, r13, r3 >> 64 */ - 0x683c761c, /* rshi r15, r22, r3 >> 28 */ - 0x68547622, /* rshi r21, r22, r3 >> 34 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x68547627, /* rshi r21, r22, r3 >> 39 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x40408300, /* and r16, r3, r4 */ - 0x4054a300, /* and r21, r3, r5 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x4054a400, /* and r21, r4, r5 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x6845afc0, /* rshi r17, r15, r13 >> 192 */ - 0x50461100, /* add r17, r17, r16 */ - 0x6858ec40, /* rshi r22, r12, r7 >> 64 */ - 0x6848f60e, /* rshi r18, r22, r7 >> 14 */ - 0x6854f612, /* rshi r21, r22, r7 >> 18 */ - 0x4c4ab200, /* xor r18, r18, r21 */ - 0x684cf629, /* rshi r19, r22, r7 >> 41 */ - 0x4c4a7200, /* xor r18, r18, r19 */ - 0x404c0700, /* and r19, r7, r0 */ - 0x4854e000, /* not r21, r7 */ - 0x40543500, /* and r21, r21, r1 */ - 0x4c4eb300, /* xor r19, r19, r21 */ - 0x685192c0, /* rshi r20, r18, r12 >> 192 */ - 0x50505400, /* add r20, r20, r2 */ - 0x50515488, /* add r20, r20, r10 >> 64 */ - 0x6855ab40, /* rshi r21, r11, r13 >> 64 */ - 0x50567500, /* add r21, r21, r19 */ - 0x5052b400, /* add r20, r20, r21 */ - 0x501a8600, /* add r6, r6, r20 */ - 0x500a3400, /* add r2, r20, r17 */ - 0x68584d40, /* rshi r22, r13, r2 >> 64 */ - 0x683c561c, /* rshi r15, r22, r2 >> 28 */ - 0x68545622, /* rshi r21, r22, r2 >> 34 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x68545627, /* rshi r21, r22, r2 >> 39 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x40406200, /* and r16, r2, r3 */ - 0x40548200, /* and r21, r2, r4 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x40548300, /* and r21, r3, r4 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x6845afc0, /* rshi r17, r15, r13 >> 192 */ - 0x50461100, /* add r17, r17, r16 */ - 0x6858cc40, /* rshi r22, r12, r6 >> 64 */ - 0x6848d60e, /* rshi r18, r22, r6 >> 14 */ - 0x6854d612, /* rshi r21, r22, r6 >> 18 */ - 0x4c4ab200, /* xor r18, r18, r21 */ - 0x684cd629, /* rshi r19, r22, r6 >> 41 */ - 0x4c4a7200, /* xor r18, r18, r19 */ - 0x404ce600, /* and r19, r6, r7 */ - 0x4854c000, /* not r21, r6 */ - 0x40541500, /* and r21, r21, r0 */ - 0x4c4eb300, /* xor r19, r19, r21 */ - 0x685192c0, /* rshi r20, r18, r12 >> 192 */ - 0x50503400, /* add r20, r20, r1 */ - 0x50515490, /* add r20, r20, r10 >> 128 */ - 0x6855ab80, /* rshi r21, r11, r13 >> 128 */ - 0x50567500, /* add r21, r21, r19 */ - 0x5052b400, /* add r20, r20, r21 */ - 0x50168500, /* add r5, r5, r20 */ - 0x50063400, /* add r1, r20, r17 */ - 0x68582d40, /* rshi r22, r13, r1 >> 64 */ - 0x683c361c, /* rshi r15, r22, r1 >> 28 */ - 0x68543622, /* rshi r21, r22, r1 >> 34 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x68543627, /* rshi r21, r22, r1 >> 39 */ - 0x4c3eaf00, /* xor r15, r15, r21 */ - 0x40404100, /* and r16, r1, r2 */ - 0x40546100, /* and r21, r1, r3 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x40546200, /* and r21, r2, r3 */ - 0x4c42b000, /* xor r16, r16, r21 */ - 0x6845afc0, /* rshi r17, r15, r13 >> 192 */ - 0x50461100, /* add r17, r17, r16 */ - 0x6858ac40, /* rshi r22, r12, r5 >> 64 */ - 0x6848b60e, /* rshi r18, r22, r5 >> 14 */ - 0x6854b612, /* rshi r21, r22, r5 >> 18 */ - 0x4c4ab200, /* xor r18, r18, r21 */ - 0x684cb629, /* rshi r19, r22, r5 >> 41 */ - 0x4c4a7200, /* xor r18, r18, r19 */ - 0x404cc500, /* and r19, r5, r6 */ - 0x4854a000, /* not r21, r5 */ - 0x4054f500, /* and r21, r21, r7 */ - 0x4c4eb300, /* xor r19, r19, r21 */ - 0x685192c0, /* rshi r20, r18, r12 >> 192 */ - 0x50501400, /* add r20, r20, r0 */ - 0x50515498, /* add r20, r20, r10 >> 192 */ - 0x6855abc0, /* rshi r21, r11, r13 >> 192 */ - 0x50567500, /* add r21, r21, r19 */ - 0x5052b400, /* add r20, r20, r21 */ - 0x50128400, /* add r4, r4, r20 */ - 0x50023400, /* add r0, r20, r17 */ - 0x0c000000, /* ret */ -/* } */ -/* @0x14f: function compress[70] { */ -#define CF_compress_adr 335 - 0xfc000000, /* nop */ - 0x4c7fff00, /* xor r31, r31, r31 */ - 0x4c000000, /* xor r0, r0, r0 */ - 0x4c042100, /* xor r1, r1, r1 */ - 0x55000001, /* subi r0, r0, #1 */ - 0x55040101, /* subi r1, r1, #1 */ - 0x84204100, /* ldi r8, [#8] */ - 0x94800800, /* ldlc r8 */ - 0x4c3def00, /* xor r15, r15, r15 */ - 0x803c000a, /* movi r15.0l, #10 */ - 0x95800f00, /* lddmp r15 */ - 0x06000039, /* loop *0 ( */ - 0x953c0000, /* stdmp r15 */ - 0x81bc002a, /* movi r15.3l, #42 */ - 0x95800f00, /* lddmp r15 */ - 0x08000001, /* call &expandw */ - 0x84004000, /* ldi r0, [#0] */ - 0x84044020, /* ldi r1, [#1] */ - 0x84084040, /* ldi r2, [#2] */ - 0x840c4060, /* ldi r3, [#3] */ - 0x84104080, /* ldi r4, [#4] */ - 0x841440a0, /* ldi r5, [#5] */ - 0x841840c0, /* ldi r6, [#6] */ - 0x841c40e0, /* ldi r7, [#7] */ - 0x4c3def00, /* xor r15, r15, r15 */ - 0x803c0060, /* movi r15.0l, #96 */ - 0x80bc000a, /* movi r15.1l, #10 */ - 0x813c000b, /* movi r15.2l, #11 */ - 0x96800f00, /* lddrp r15 */ - 0x97800f00, /* ldrfp r15 */ - 0x953c0000, /* stdmp r15 */ - 0x81bc002a, /* movi r15.3l, #42 */ - 0x95800f00, /* lddmp r15 */ - 0x4c318c00, /* xor r12, r12, r12 */ - 0x4c35ad00, /* xor r13, r13, r13 */ - 0x55300c01, /* subi r12, r12, #1 */ - 0x55340d01, /* subi r13, r13, #1 */ - 0x0500a007, /* loop #10 ( */ - 0x8c440800, /* ldc *1, *0++ */ - 0x8c081b00, /* ld *2, *3++ */ - 0x08000055, /* call &Sha512_a */ - 0x8c440800, /* ldc *1, *0++ */ - 0x8c081b00, /* ld *2, *3++ */ - 0x080000d2, /* call &Sha512_b */ - 0xfc000000, /* nop */ - /* ) */ - 0x843c4000, /* ldi r15, [#0] */ - 0x5001e000, /* add r0, r0, r15 */ - 0x843c4020, /* ldi r15, [#1] */ - 0x5005e100, /* add r1, r1, r15 */ - 0x843c4040, /* ldi r15, [#2] */ - 0x5009e200, /* add r2, r2, r15 */ - 0x843c4060, /* ldi r15, [#3] */ - 0x500de300, /* add r3, r3, r15 */ - 0x843c4080, /* ldi r15, [#4] */ - 0x5011e400, /* add r4, r4, r15 */ - 0x843c40a0, /* ldi r15, [#5] */ - 0x5015e500, /* add r5, r5, r15 */ - 0x843c40c0, /* ldi r15, [#6] */ - 0x5019e600, /* add r6, r6, r15 */ - 0x843c40e0, /* ldi r15, [#7] */ - 0x501de700, /* add r7, r7, r15 */ - 0x88004000, /* sti r0, [#0] */ - 0x88044020, /* sti r1, [#1] */ - 0x88084040, /* sti r2, [#2] */ - 0x880c4060, /* sti r3, [#3] */ - 0x88104080, /* sti r4, [#4] */ - 0x881440a0, /* sti r5, [#5] */ - 0x881840c0, /* sti r6, [#6] */ - 0x881c40e0, /* sti r7, [#7] */ - /* ) */ - 0x0c000000, /* ret */ - /* } */ -}; -/* clang-format on */ - -struct DMEM_sha512 { - uint64_t H0[4]; - uint64_t H1[4]; - uint64_t H2[4]; - uint64_t H3[4]; - uint64_t H4[4]; - uint64_t H5[4]; - uint64_t H6[4]; - uint64_t H7[4]; - uint32_t nblocks; - uint32_t unused[2 * 8 - 1]; - uint32_t input[4 * 8 * 8]; // dmem[10..41] -}; - -static void copy_words(const void *in, uint32_t *dst, size_t nwords) -{ - const uint32_t *src = (const uint32_t *) in; - - do { - uint32_t w1 = __builtin_bswap32(*src++); - uint32_t w2 = __builtin_bswap32(*src++); - *dst++ = w2; - *dst++ = w1; - } while (nwords -= 2); -} - -static void dcrypto_SHA512_setup(void) -{ - dcrypto_imem_load(0, IMEM_dcrypto, ARRAY_SIZE(IMEM_dcrypto)); -} - -static void dcrypto_SHA512_Transform(LITE_SHA512_CTX *ctx, const uint32_t *buf, - size_t nwords) -{ - int result = 0; - struct DMEM_sha512 *p512 = - (struct DMEM_sha512 *) GREG32_ADDR(CRYPTO, DMEM_DUMMY); - - START_PROFILE(t_transform) - - /* Pass in H[] */ - p512->H0[0] = ctx->state[0]; - p512->H1[0] = ctx->state[1]; - p512->H2[0] = ctx->state[2]; - p512->H3[0] = ctx->state[3]; - p512->H4[0] = ctx->state[4]; - p512->H5[0] = ctx->state[5]; - p512->H6[0] = ctx->state[6]; - p512->H7[0] = ctx->state[7]; - - p512->nblocks = nwords / 32; - - /* Pass in buf[] */ - copy_words(buf, p512->input, nwords); - - START_PROFILE(t_dcrypto) - result |= dcrypto_call(CF_compress_adr); - END_PROFILE(t_dcrypto) - - /* Retrieve new H[] */ - ctx->state[0] = p512->H0[0]; - ctx->state[1] = p512->H1[0]; - ctx->state[2] = p512->H2[0]; - ctx->state[3] = p512->H3[0]; - ctx->state[4] = p512->H4[0]; - ctx->state[5] = p512->H5[0]; - ctx->state[6] = p512->H6[0]; - ctx->state[7] = p512->H7[0]; - - /* TODO: errno or such to capture errors */ - (void) (result == 0); - - END_PROFILE(t_transform) -} - -static void dcrypto_SHA512_update(LITE_SHA512_CTX *ctx, const void *data, - size_t len) -{ - int i = (int) (ctx->count & (sizeof(ctx->buf) - 1)); - const uint8_t *p = (const uint8_t *) data; - uint8_t *d = &ctx->buf[i]; - - ctx->count += len; - - dcrypto_init_and_lock(); - dcrypto_SHA512_setup(); - - /* Take fast path for 32-bit aligned 1KB inputs */ - if (i == 0 && len == 1024 && (((intptr_t) data) & 3) == 0) { - dcrypto_SHA512_Transform(ctx, (const uint32_t *) data, 8 * 32); - } else { - if (len <= sizeof(ctx->buf) - i) { - memcpy(d, p, len); - if (len == sizeof(ctx->buf) - i) { - dcrypto_SHA512_Transform( - ctx, (uint32_t *) (ctx->buf), 32); - } - } else { - memcpy(d, p, sizeof(ctx->buf) - i); - dcrypto_SHA512_Transform(ctx, (uint32_t *) (ctx->buf), - 32); - d = ctx->buf; - len -= (sizeof(ctx->buf) - i); - p += (sizeof(ctx->buf) - i); - while (len >= sizeof(ctx->buf)) { - memcpy(d, p, sizeof(ctx->buf)); - p += sizeof(ctx->buf); - len -= sizeof(ctx->buf); - dcrypto_SHA512_Transform( - ctx, (uint32_t *) (ctx->buf), 32); - } - /* Leave remainder in ctx->buf */ - memcpy(d, p, len); - } - } - dcrypto_unlock(); -} - -static const uint8_t *dcrypto_SHA512_final(LITE_SHA512_CTX *ctx) -{ - uint64_t cnt = ctx->count * 8; - int i = (int) (ctx->count & (sizeof(ctx->buf) - 1)); - uint8_t *p = &ctx->buf[i]; - - *p++ = 0x80; - i++; - - dcrypto_init_and_lock(); - dcrypto_SHA512_setup(); - - if (i > sizeof(ctx->buf) - 16) { - memset(p, 0, sizeof(ctx->buf) - i); - dcrypto_SHA512_Transform(ctx, (uint32_t *) (ctx->buf), 32); - i = 0; - p = ctx->buf; - } - - memset(p, 0, sizeof(ctx->buf) - 8 - i); - p += sizeof(ctx->buf) - 8 - i; - - for (i = 0; i < 8; ++i) { - uint8_t tmp = (uint8_t)(cnt >> 56); - cnt <<= 8; - *p++ = tmp; - } - - dcrypto_SHA512_Transform(ctx, (uint32_t *) (ctx->buf), 32); - - p = ctx->buf; - for (i = 0; i < 8; i++) { - uint64_t tmp = ctx->state[i]; - *p++ = (uint8_t)(tmp >> 56); - *p++ = (uint8_t)(tmp >> 48); - *p++ = (uint8_t)(tmp >> 40); - *p++ = (uint8_t)(tmp >> 32); - *p++ = (uint8_t)(tmp >> 24); - *p++ = (uint8_t)(tmp >> 16); - *p++ = (uint8_t)(tmp >> 8); - *p++ = (uint8_t)(tmp >> 0); - } - - dcrypto_unlock(); - return ctx->buf; -} - -const uint8_t *DCRYPTO_SHA512_hash(const void *data, size_t len, - uint8_t *digest) -{ - LITE_SHA512_CTX ctx; - - DCRYPTO_SHA512_init(&ctx); - dcrypto_SHA512_update(&ctx, data, len); - memcpy(digest, dcrypto_SHA512_final(&ctx), SHA512_DIGEST_SIZE); - - return digest; -} - -static const HASH_VTAB dcrypto_SHA512_VTAB = { - DCRYPTO_SHA512_init, dcrypto_SHA512_update, dcrypto_SHA512_final, - DCRYPTO_SHA512_hash, SHA512_DIGEST_SIZE}; - -void DCRYPTO_SHA512_init(LITE_SHA512_CTX *ctx) -{ - SHA512_init(ctx); - ctx->f = &dcrypto_SHA512_VTAB; -} - -#ifdef CRYPTO_TEST_SETUP - -static uint32_t msg[256]; // 1KB -static int msg_len; -static int msg_loops; -static LITE_SHA512_CTX sw; -static LITE_SHA512_CTX hw; -static const uint8_t *sw_digest; -static const uint8_t *hw_digest; -static uint32_t t_sw; -static uint32_t t_hw; - -static void run_sha512_cmd(void) -{ - int i; - - t_transform = 0; - t_dcrypto = 0; - t_sw = 0; - t_hw = 0; - - START_PROFILE(t_sw) - SHA512_init(&sw); - for (i = 0; i < msg_loops; ++i) { - HASH_update(&sw, msg, msg_len); - } - sw_digest = HASH_final(&sw); - END_PROFILE(t_sw) - - START_PROFILE(t_hw) - DCRYPTO_SHA512_init(&hw); - for (i = 0; i < msg_loops; ++i) { - HASH_update(&hw, msg, msg_len); - } - hw_digest = HASH_final(&hw); - END_PROFILE(t_hw) - - ccprintf("sw(%u):\n", t_sw); - for (i = 0; i < 64; ++i) - ccprintf("%02x", sw_digest[i]); - ccprintf("\n"); - - ccprintf("hw(%u/%u/%u):\n", t_hw, t_transform, t_dcrypto); - for (i = 0; i < 64; ++i) - ccprintf("%02x", hw_digest[i]); - ccprintf("\n"); - - task_set_event(TASK_ID_CONSOLE, TASK_EVENT_CUSTOM_BIT(0), 0); -} -DECLARE_DEFERRED(run_sha512_cmd); - -static int cmd_sha512_bench(int argc, char *argv[]) -{ - const int max_time = 1000000; - uint32_t events; - - memset(msg, '!', sizeof(msg)); - - if (argc > 1) { - msg_loops = 1; - msg_len = strlen(argv[1]); - memcpy(msg, argv[1], msg_len); - } else { - msg_loops = 64; // benchmark 64K - msg_len = sizeof(msg); - } - - hook_call_deferred(&run_sha512_cmd_data, 0); - ccprintf("Will wait up to %d ms\n", (max_time + 500) / 1000); - - events = task_wait_event_mask(TASK_EVENT_CUSTOM_BIT(0), max_time); - if (!(events & TASK_EVENT_CUSTOM_BIT(0))) { - ccprintf("Timed out, you might want to reboot...\n"); - return EC_ERROR_TIMEOUT; - } - - return EC_SUCCESS; -} -DECLARE_SAFE_CONSOLE_COMMAND(sha512_bench, cmd_sha512_bench, NULL, NULL); - -static void run_sha512_test(void) -{ - int i; - - for (i = 0; i < 129; ++i) { - memset(msg, i, i); - - SHA512_init(&sw); - HASH_update(&sw, msg, i); - sw_digest = HASH_final(&sw); - - DCRYPTO_SHA512_init(&hw); - HASH_update(&hw, msg, i); - hw_digest = HASH_final(&hw); - - if (memcmp(sw_digest, hw_digest, SHA512_DIGEST_SIZE) != 0) { - ccprintf("sha512 self-test fail at %d!\n", i); - cflush(); - } - } - - ccprintf("sha512 self-test PASS!\n"); - task_set_event(TASK_ID_CONSOLE, TASK_EVENT_CUSTOM_BIT(0), 0); -} -DECLARE_DEFERRED(run_sha512_test); - -static int cmd_sha512_test(int argc, char *argv[]) -{ - hook_call_deferred(&run_sha512_test_data, 0); - task_wait_event_mask(TASK_EVENT_CUSTOM_BIT(0), 1000000); - return EC_SUCCESS; -} -DECLARE_SAFE_CONSOLE_COMMAND(sha512_test, cmd_sha512_test, NULL, NULL); - -#endif /* CRYPTO_TEST_SETUP */ diff --git a/chip/g/dcrypto/gcm.c b/chip/g/dcrypto/gcm.c deleted file mode 100644 index cd035bbd54..0000000000 --- a/chip/g/dcrypto/gcm.c +++ /dev/null @@ -1,345 +0,0 @@ -/* Copyright 2017 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 "endian.h" - -#include "cryptoc/util.h" - -static void gcm_mul(uint32_t *counter) -{ - int i; - volatile uint32_t *p; - - /* Set HASH to zero. */ - p = GREG32_ADDR(KEYMGR, GCM_HASH_IN0); - for (i = 0; i < 4; i++) - *p++ = 0; - - /* Initialize GMAC. */ - p = GREG32_ADDR(KEYMGR, GCM_MAC0); - for (i = 0; i < 4; i++) - *p++ = counter[i]; - - /* Crank GMAC. */ - GREG32(KEYMGR, GCM_DO_ACC) = 1; - - /* Read GMAC. */ - p = GREG32_ADDR(KEYMGR, GCM_MAC0); - for (i = 0; i < 4; i++) - counter[i] = *p++; - - /* Reset GMAC. */ - p = GREG32_ADDR(KEYMGR, GCM_MAC0); - for (i = 0; i < 4; ++i) - *p++ = 0; -} - -static void gcm_init_iv( - const uint8_t *iv, uint32_t iv_len, uint32_t *counter) -{ - - if (iv_len == 12) { - memcpy(counter, iv, 12); - counter[3] = BIT(24); - } else { - size_t i; - uint32_t len = iv_len; - uint64_t len0 = len; - uint8_t *ctr = (uint8_t *) counter; - - memset(ctr, 0, 16); - while (len >= 16) { - for (i = 0; i < 16; ++i) - ctr[i] ^= iv[i]; - - gcm_mul(counter); - iv += 16; - len -= 16; - } - if (len) { - for (i = 0; i < len; ++i) - ctr[i] ^= iv[i]; - - gcm_mul(counter); - } - len0 <<= 3; - ctr[8] ^= (uint8_t)(len0 >> 56); - ctr[9] ^= (uint8_t)(len0 >> 48); - ctr[10] ^= (uint8_t)(len0 >> 40); - ctr[11] ^= (uint8_t)(len0 >> 32); - ctr[12] ^= (uint8_t)(len0 >> 24); - ctr[13] ^= (uint8_t)(len0 >> 16); - ctr[14] ^= (uint8_t)(len0 >> 8); - ctr[15] ^= (uint8_t)(len0); - - gcm_mul(counter); - } -} - -void DCRYPTO_gcm_init(struct GCM_CTX *ctx, uint32_t key_bits, - const uint8_t *key, const uint8_t *iv, size_t iv_len) -{ - int i; - const uint32_t zero[4] = {0, 0, 0, 0}; - uint32_t H[4]; - uint32_t counter[4]; - - memset(ctx, 0, sizeof(struct GCM_CTX)); - - /* Initialize AES engine in CTR mode, and set the counter to 0. */ - DCRYPTO_aes_init(key, key_bits, (const uint8_t *) zero, - CIPHER_MODE_CTR, ENCRYPT_MODE); - /* Set H to AES(ZERO). */ - DCRYPTO_aes_block((const uint8_t *) zero, (uint8_t *) H); - - /* Initialize the GMAC accumulator to ZERO. */ - for (i = 0; i < 4; i++) - GR_KEYMGR_GCM_MAC(i) = zero[i]; - - /* Initialize H. */ - for (i = 0; i < 4; i++) - GR_KEYMGR_GCM_H(i) = H[i]; - - /* Map the IV to a 128-bit counter. */ - gcm_init_iv(iv, iv_len, counter); - - /* Re-initialize the IV counter. */ - for (i = 0; i < 4; i++) - GR_KEYMGR_AES_CTR(i) = counter[i]; - - /* Calculate Ej0: encrypt IV counter XOR ZERO. */ - DCRYPTO_aes_block((const uint8_t *) zero, ctx->Ej0.c); -} - -static void gcm_aad_block(const struct GCM_CTX *ctx, const uint32_t *block) -{ - int i; - const struct access_helper *p = (struct access_helper *) block; - - if (ctx->aad_len == 0 && ctx->count <= 16) { - /* Update GMAC. */ - for (i = 0; i < 4; i++) - GR_KEYMGR_GCM_MAC(i) = p[i].udata; - } else { - for (i = 0; i < 4; i++) - GR_KEYMGR_GCM_HASH_IN(i) = p[i].udata; - - /* Crank GMAC. */ - GREG32(KEYMGR, GCM_DO_ACC) = 1; - } -} - -void DCRYPTO_gcm_aad(struct GCM_CTX *ctx, const uint8_t *aad_data, size_t len) -{ - uint32_t block[4]; - - while (len) { - size_t count; - - memset(block, 0, sizeof(block)); - count = MIN(16, len); - memcpy(block, aad_data, count); - - gcm_aad_block(ctx, block); - ctx->aad_len += count; - - len -= count; - aad_data += count; - } - - always_memset(block, 0, sizeof(block)); -} - -int DCRYPTO_gcm_encrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len, - const uint8_t *in, size_t in_len) -{ - uint8_t *outp = out; - - if (out_len < (in_len & ~0x0F) + ((in_len & 0x0F) ? 16 : 0)) - return -1; - - /* Process a previous partial block, if any. */ - if (ctx->remainder) { - size_t count = MIN(in_len, 16 - ctx->remainder); - - memcpy(ctx->block.c + ctx->remainder, in, count); - ctx->remainder += count; - if (ctx->remainder < 16) - return 0; - - DCRYPTO_aes_block(ctx->block.c, outp); - ctx->count += 16; - gcm_aad_block(ctx, (uint32_t *) outp); - ctx->remainder = 0; - in += count; - in_len -= count; - outp += 16; - } - - while (in_len >= 16) { - DCRYPTO_aes_block(in, outp); - ctx->count += 16; - - gcm_aad_block(ctx, (uint32_t *) outp); - - in_len -= 16; - in += 16; - outp += 16; - } - - if (in_len) { - memcpy(ctx->block.c, in, in_len); - ctx->remainder = in_len; - } - - return outp - out; -} - -int DCRYPTO_gcm_encrypt_final(struct GCM_CTX *ctx, uint8_t *out, size_t out_len) -{ - if (out_len < ctx->remainder) - return -1; - - if (ctx->remainder) { - size_t remainder = ctx->remainder; - uint8_t out_block[16]; - - DCRYPTO_aes_block(ctx->block.c, out_block); - ctx->count += ctx->remainder; - memcpy(out, out_block, ctx->remainder); - - memset(out_block + ctx->remainder, 0, 16 - ctx->remainder); - gcm_aad_block(ctx, (uint32_t *) out_block); - ctx->remainder = 0; - return remainder; - } - - return 0; -} - -int DCRYPTO_gcm_decrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len, - const uint8_t *in, size_t in_len) -{ - uint8_t *outp = out; - - if (out_len < (in_len & ~0x0F) + ((in_len & 0x0F) ? 16 : 0)) - return -1; - - if (ctx->remainder) { - size_t count = MIN(in_len, 16 - ctx->remainder); - - memcpy(ctx->block.c + ctx->remainder, in, count); - ctx->remainder += count; - - if (ctx->remainder < 16) - return 0; - - DCRYPTO_aes_block(ctx->block.c, outp); - ctx->remainder = 0; - ctx->count += 16; - gcm_aad_block(ctx, ctx->block.d); - in += count; - in_len -= count; - outp += count; - } - - while (in_len >= 16) { - DCRYPTO_aes_block(in, outp); - ctx->count += 16; - gcm_aad_block(ctx, (uint32_t *) in); - in += 16; - in_len -= 16; - outp += 16; - } - - if (in_len) { - memcpy(ctx->block.c, in, in_len); - ctx->remainder = in_len; - } - - return outp - out; -} - -int DCRYPTO_gcm_decrypt_final(struct GCM_CTX *ctx, - uint8_t *out, size_t out_len) -{ - if (out_len < ctx->remainder) - return -1; - - if (ctx->remainder) { - size_t remainder = ctx->remainder; - uint8_t out_block[16]; - - DCRYPTO_aes_block(ctx->block.c, out_block); - ctx->count += ctx->remainder; - memcpy(out, out_block, ctx->remainder); - - memset(ctx->block.c + ctx->remainder, 0, 16 - ctx->remainder); - gcm_aad_block(ctx, ctx->block.d); - ctx->remainder = 0; - return remainder; - } - - return 0; -} - -static void dcrypto_gcm_len_vector( - const struct GCM_CTX *ctx, void *len_vector) { - uint64_t aad_be; - uint64_t count_be; - - /* Serialize counters to bit-count (big-endian). */ - aad_be = ctx->aad_len * 8; - aad_be = htobe64(aad_be); - count_be = ctx->count * 8; - count_be = htobe64(count_be); - - memcpy(len_vector, &aad_be, 8); - memcpy(((uint8_t *)len_vector) + 8, &count_be, 8); -} - -static void dcrypto_gcm_tag(const struct GCM_CTX *ctx, - const uint32_t *len_vector, uint32_t *tag) { - int i; - - for (i = 0; i < 4; i++) - GR_KEYMGR_GCM_HASH_IN(i) = len_vector[i]; - - /* Crank GMAC. */ - GREG32(KEYMGR, GCM_DO_ACC) = 1; - - for (i = 0; i < 4; i++) - GR_KEYMGR_GCM_HASH_IN(i) = ctx->Ej0.d[i]; - - /* Crank GMAC. */ - GREG32(KEYMGR, GCM_DO_ACC) = 1; - - /* Read tag. */ - for (i = 0; i < 4; i++) - tag[i] = GR_KEYMGR_GCM_MAC(i); -} - -int DCRYPTO_gcm_tag(struct GCM_CTX *ctx, uint8_t *tag, size_t tag_len) -{ - uint32_t len_vector[4]; - uint32_t local_tag[4]; - size_t count = MIN(tag_len, sizeof(local_tag)); - - dcrypto_gcm_len_vector(ctx, len_vector); - dcrypto_gcm_tag(ctx, len_vector, local_tag); - - memcpy(tag, local_tag, count); - return count; -} - -void DCRYPTO_gcm_finish(struct GCM_CTX *ctx) -{ - always_memset(ctx, 0, sizeof(struct GCM_CTX)); - GREG32(KEYMGR, AES_WIPE_SECRETS) = 1; -} diff --git a/chip/g/dcrypto/hkdf.c b/chip/g/dcrypto/hkdf.c deleted file mode 100644 index 3afdc6b2eb..0000000000 --- a/chip/g/dcrypto/hkdf.c +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright 2016 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. - */ -/* An implementation of HKDF as per RFC 5869. */ - -#include "dcrypto.h" -#include "internal.h" - -#include "cryptoc/sha256.h" -#include "cryptoc/util.h" - -static int hkdf_extract(uint8_t *PRK, const uint8_t *salt, size_t salt_len, - const uint8_t *IKM, size_t IKM_len) -{ - LITE_HMAC_CTX ctx; - - if (PRK == NULL) - return 0; - if (salt == NULL && salt_len > 0) - return 0; - if (IKM == NULL && IKM_len > 0) - return 0; - - DCRYPTO_HMAC_SHA256_init(&ctx, salt, salt_len); - HASH_update(&ctx.hash, IKM, IKM_len); - memcpy(PRK, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE); - return 1; -} - -static int hkdf_expand(uint8_t *OKM, size_t OKM_len, const uint8_t *PRK, - const uint8_t *info, size_t info_len) -{ - uint8_t count = 1; - const uint8_t *T = OKM; - size_t T_len = 0; - uint32_t num_blocks = (OKM_len / SHA256_DIGEST_SIZE) + - (OKM_len % SHA256_DIGEST_SIZE ? 1 : 0); - - if (OKM == NULL || OKM_len == 0) - return 0; - if (PRK == NULL) - return 0; - if (info == NULL && info_len > 0) - return 0; - if (num_blocks > 255) - return 0; - - while (OKM_len > 0) { - LITE_HMAC_CTX ctx; - const size_t block_size = OKM_len < SHA256_DIGEST_SIZE ? - OKM_len : SHA256_DIGEST_SIZE; - - DCRYPTO_HMAC_SHA256_init(&ctx, PRK, SHA256_DIGEST_SIZE); - HASH_update(&ctx.hash, T, T_len); - HASH_update(&ctx.hash, info, info_len); - HASH_update(&ctx.hash, &count, sizeof(count)); - memcpy(OKM, DCRYPTO_HMAC_final(&ctx), block_size); - - T += T_len; - T_len = SHA256_DIGEST_SIZE; - count += 1; - OKM += block_size; - OKM_len -= block_size; - } - return 1; -} - -int DCRYPTO_hkdf(uint8_t *OKM, size_t OKM_len, - const uint8_t *salt, size_t salt_len, - const uint8_t *IKM, size_t IKM_len, - const uint8_t *info, size_t info_len) -{ - int result; - uint8_t PRK[SHA256_DIGEST_SIZE]; - - if (!hkdf_extract(PRK, salt, salt_len, IKM, IKM_len)) - return 0; - - result = hkdf_expand(OKM, OKM_len, PRK, info, info_len); - always_memset(PRK, 0, sizeof(PRK)); - return result; -} diff --git a/chip/g/dcrypto/hmac.c b/chip/g/dcrypto/hmac.c deleted file mode 100644 index 7cc45a03ba..0000000000 --- a/chip/g/dcrypto/hmac.c +++ /dev/null @@ -1,63 +0,0 @@ -/* 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 "internal.h" -#include "dcrypto.h" - -#include - -#include "cryptoc/sha256.h" -#include "cryptoc/util.h" - -/* TODO(sukhomlinov): add support for hardware hmac. */ -static void hmac_sha256_init(LITE_HMAC_CTX *ctx, const void *key, - unsigned int len) -{ - unsigned int i; - - BUILD_ASSERT(sizeof(ctx->opad) >= SHA256_BLOCK_SIZE); - - memset(&ctx->opad[0], 0, SHA256_BLOCK_SIZE); - - if (len > SHA256_BLOCK_SIZE) { - DCRYPTO_SHA256_init(&ctx->hash, 0); - HASH_update(&ctx->hash, key, len); - memcpy(&ctx->opad[0], HASH_final(&ctx->hash), - HASH_size(&ctx->hash)); - } else { - memcpy(&ctx->opad[0], key, len); - } - - for (i = 0; i < SHA256_BLOCK_SIZE; ++i) - ctx->opad[i] ^= 0x36; - - DCRYPTO_SHA256_init(&ctx->hash, 0); - /* hash ipad */ - HASH_update(&ctx->hash, ctx->opad, SHA256_BLOCK_SIZE); - - for (i = 0; i < SHA256_BLOCK_SIZE; ++i) - ctx->opad[i] ^= (0x36 ^ 0x5c); -} - -void DCRYPTO_HMAC_SHA256_init(LITE_HMAC_CTX *ctx, const void *key, - unsigned int len) -{ - hmac_sha256_init(ctx, key, len); -} - -const uint8_t *DCRYPTO_HMAC_final(LITE_HMAC_CTX *ctx) -{ - uint8_t digest[SHA256_DIGEST_SIZE]; /* up to SHA256 */ - - memcpy(digest, HASH_final(&ctx->hash), - (HASH_size(&ctx->hash) <= sizeof(digest) ? - HASH_size(&ctx->hash) : - sizeof(digest))); - DCRYPTO_SHA256_init(&ctx->hash, 0); - HASH_update(&ctx->hash, ctx->opad, SHA256_BLOCK_SIZE); - HASH_update(&ctx->hash, digest, HASH_size(&ctx->hash)); - always_memset(&ctx->opad[0], 0, SHA256_BLOCK_SIZE); /* wipe key */ - return HASH_final(&ctx->hash); -} diff --git a/chip/g/dcrypto/hmac_drbg.c b/chip/g/dcrypto/hmac_drbg.c deleted file mode 100644 index 2ca20e03ff..0000000000 --- a/chip/g/dcrypto/hmac_drbg.c +++ /dev/null @@ -1,478 +0,0 @@ -/* Copyright 2018 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 "console.h" -#include "cryptoc/util.h" -#include "dcrypto.h" -#include "extension.h" -#include "internal.h" -#include "trng.h" - -/* HMAC_DRBG flow in NIST SP 800-90Ar1, 10.2, RFC 6979 - */ -/* V = HMAC(K, V) */ -static void update_v(const uint32_t *k, uint32_t *v) -{ - LITE_HMAC_CTX ctx; - - DCRYPTO_HMAC_SHA256_init(&ctx, k, SHA256_DIGEST_SIZE); - HASH_update(&ctx.hash, v, SHA256_DIGEST_SIZE); - memcpy(v, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE); -} - -/* K = HMAC(K, V || tag || p0 || p1 || p2) */ -/* V = HMAC(K, V) */ -static void update_kv(uint32_t *k, uint32_t *v, uint8_t tag, - const void *p0, size_t p0_len, - const void *p1, size_t p1_len, - const void *p2, size_t p2_len) -{ - LITE_HMAC_CTX ctx; - - DCRYPTO_HMAC_SHA256_init(&ctx, k, SHA256_DIGEST_SIZE); - HASH_update(&ctx.hash, v, SHA256_DIGEST_SIZE); - HASH_update(&ctx.hash, &tag, 1); - HASH_update(&ctx.hash, p0, p0_len); - HASH_update(&ctx.hash, p1, p1_len); - HASH_update(&ctx.hash, p2, p2_len); - memcpy(k, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE); - - update_v(k, v); -} - -static void update(struct drbg_ctx *ctx, - const void *p0, size_t p0_len, - const void *p1, size_t p1_len, - const void *p2, size_t p2_len) -{ - /* K = HMAC(K, V || 0x00 || provided_data) */ - /* V = HMAC(K, V) */ - update_kv(ctx->k, ctx->v, 0x00, - p0, p0_len, p1, p1_len, p2, p2_len); - - /* If no provided_data, stop. */ - if (p0_len + p1_len + p2_len == 0) - return; - - /* K = HMAC(K, V || 0x01 || provided_data) */ - /* V = HMAC(K, V) */ - update_kv(ctx->k, ctx->v, - 0x01, - p0, p0_len, p1, p1_len, p2, p2_len); -} - -void hmac_drbg_init(struct drbg_ctx *ctx, - const void *p0, size_t p0_len, - const void *p1, size_t p1_len, - const void *p2, size_t p2_len) -{ - /* K = 0x00 0x00 0x00 ... 0x00 */ - always_memset(ctx->k, 0x00, sizeof(ctx->k)); - /* V = 0x01 0x01 0x01 ... 0x01 */ - always_memset(ctx->v, 0x01, sizeof(ctx->v)); - - update(ctx, p0, p0_len, p1, p1_len, p2, p2_len); - - ctx->reseed_counter = 1; -} - -void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx, const p256_int *key, - const p256_int *message) -{ - hmac_drbg_init(ctx, - key->a, sizeof(key->a), - message->a, sizeof(message->a), - NULL, 0); -} - -void hmac_drbg_init_rand(struct drbg_ctx *ctx, size_t nbits) -{ - int i; - uint32_t x[(nbits + 31) / 32]; - - for (i = 0; i < ARRAY_SIZE(x); ++i) - x[i] = rand(); - - hmac_drbg_init(ctx, &x, sizeof(x), NULL, 0, NULL, 0); -} - -void hmac_drbg_reseed(struct drbg_ctx *ctx, - const void *p0, size_t p0_len, - const void *p1, size_t p1_len, - const void *p2, size_t p2_len) -{ - update(ctx, p0, p0_len, p1, p1_len, p2, p2_len); - ctx->reseed_counter = 1; -} - -enum hmac_result hmac_drbg_generate(struct drbg_ctx *ctx, - void *out, size_t out_len, - const void *input, size_t input_len) -{ - /* According to NIST SP 800-90A rev 1 B.2 - * Maximum number of bits per request = 7500 bits - * Reseed_interval = 10 000 requests. - */ - if (out_len > 7500 / 8) - return HMAC_DRBG_INVALID_PARAM; - - if (ctx->reseed_counter++ >= 10000) - return HMAC_DRBG_RESEED_REQUIRED; - - if (input_len) - update(ctx, input, input_len, NULL, 0, NULL, 0); - - while (out_len) { - size_t n = out_len > sizeof(ctx->v) ? sizeof(ctx->v) : out_len; - - update_v(ctx->k, ctx->v); - - memcpy(out, ctx->v, n); - out += n; - out_len -= n; - } - - update(ctx, input, input_len, NULL, 0, NULL, 0); - - return HMAC_DRBG_SUCCESS; -} - -enum hmac_result hmac_drbg_generate_p256(struct drbg_ctx *ctx, p256_int *k_out) -{ - return hmac_drbg_generate(ctx, k_out->a, sizeof(k_out->a), NULL, 0); -} - -void drbg_exit(struct drbg_ctx *ctx) -{ - always_memset(ctx->k, 0x00, sizeof(ctx->k)); - always_memset(ctx->v, 0x00, sizeof(ctx->v)); -} - -#ifdef CRYPTO_TEST_SETUP - -/* - * from the RFC 6979 A.2.5 example: - * - * curve: NIST P-256 - * - * q = FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 - * (qlen = 256 bits) - * - * private key: - * x = C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721 - * - * public key: U = xG - * Ux = 60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6 - * Uy = 7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299 - * - * Signature: - * With SHA-256, message = "sample": - * k = A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60 - * r = EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716 - * s = F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8 - */ -static int cmd_rfc6979(int argc, char **argv) -{ - static p256_int h1; - static p256_int k; - static const char message[] = "sample"; - static struct drbg_ctx drbg; - - static HASH_CTX ctx; - int result; - static const uint8_t priv_from_rfc[] = { - 0xC9, 0xAF, 0xA9, 0xD8, 0x45, 0xBA, 0x75, 0x16, - 0x6B, 0x5C, 0x21, 0x57, 0x67, 0xB1, 0xD6, 0x93, - 0x4E, 0x50, 0xC3, 0xDB, 0x36, 0xE8, 0x9B, 0x12, - 0x7B, 0x8A, 0x62, 0x2B, 0x12, 0x0F, 0x67, 0x21 - }; - static const uint8_t k_from_rfc[] = { - 0xA6, 0xE3, 0xC5, 0x7D, 0xD0, 0x1A, 0xBE, 0x90, - 0x08, 0x65, 0x38, 0x39, 0x83, 0x55, 0xDD, 0x4C, - 0x3B, 0x17, 0xAA, 0x87, 0x33, 0x82, 0xB0, 0xF2, - 0x4D, 0x61, 0x29, 0x49, 0x3D, 0x8A, 0xAD, 0x60 - }; - p256_int *x = (p256_int *)priv_from_rfc; - p256_int *reference_k = (p256_int *)k_from_rfc; - - /* h1 = H(m) */ - DCRYPTO_SHA256_init(&ctx, 1); - HASH_update(&ctx, message, sizeof(message) - 1); - memcpy(&h1, HASH_final(&ctx), SHA256_DIGEST_SIZE); - - hmac_drbg_init_rfc6979(&drbg, x, &h1); - do { - hmac_drbg_generate_p256(&drbg, &k); - ccprintf("K = %ph\n", HEX_BUF(&k, 32)); - } while (p256_cmp(&SECP256r1_nMin2, &k) < 0); - drbg_exit(&drbg); - result = p256_cmp(&k, reference_k); - ccprintf("K generation: %s\n", result ? "FAIL" : "PASS"); - - return result ? EC_ERROR_INVAL : EC_SUCCESS; -} -DECLARE_SAFE_CONSOLE_COMMAND(rfc6979, cmd_rfc6979, NULL, NULL); - -/* - * Test vectors from the NIST Cryptographic Algorithm Validation Program. - * - * These are the first two examples from the SHA-256, without prediction - * resistance, and with reseed supported. - */ -#define HMAC_TEST_COUNT 2 -static int cmd_hmac_drbg(int argc, char **argv) -{ - static struct drbg_ctx ctx; - - static const uint8_t init_entropy[HMAC_TEST_COUNT][32] = { - { - 0x06, 0x03, 0x2C, 0xD5, 0xEE, 0xD3, 0x3F, 0x39, 0x26, - 0x5F, 0x49, 0xEC, 0xB1, 0x42, 0xC5, 0x11, 0xDA, 0x9A, - 0xFF, 0x2A, 0xF7, 0x12, 0x03, 0xBF, 0xFA, 0xF3, 0x4A, - 0x9C, 0xA5, 0xBD, 0x9C, 0x0D - }, - { - 0xAA, 0xDC, 0xF3, 0x37, 0x78, 0x8B, 0xB8, 0xAC, 0x01, - 0x97, 0x66, 0x40, 0x72, 0x6B, 0xC5, 0x16, 0x35, 0xD4, - 0x17, 0x77, 0x7F, 0xE6, 0x93, 0x9E, 0xDE, 0xD9, 0xCC, - 0xC8, 0xA3, 0x78, 0xC7, 0x6A - }, - }; - - static const uint8_t init_nonce[HMAC_TEST_COUNT][16] = { - { - 0x0E, 0x66, 0xF7, 0x1E, 0xDC, 0x43, 0xE4, 0x2A, 0x45, - 0xAD, 0x3C, 0x6F, 0xC6, 0xCD, 0xC4, 0xDF - }, - { - 0x9C, 0xCC, 0x9D, 0x80, 0xC8, 0x9A, 0xC5, 0x5A, 0x8C, - 0xFE, 0x0F, 0x99, 0x94, 0x2F, 0x5A, 0x4D - }, - }; - - static const uint8_t reseed_entropy[HMAC_TEST_COUNT][32] = { - { - 0x01, 0x92, 0x0A, 0x4E, 0x66, 0x9E, 0xD3, 0xA8, 0x5A, - 0xE8, 0xA3, 0x3B, 0x35, 0xA7, 0x4A, 0xD7, 0xFB, 0x2A, - 0x6B, 0xB4, 0xCF, 0x39, 0x5C, 0xE0, 0x03, 0x34, 0xA9, - 0xC9, 0xA5, 0xA5, 0xD5, 0x52 - }, - { - 0x03, 0xA5, 0x77, 0x92, 0x54, 0x7E, 0x0C, 0x98, 0xEA, - 0x17, 0x76, 0xE4, 0xBA, 0x80, 0xC0, 0x07, 0x34, 0x62, - 0x96, 0xA5, 0x6A, 0x27, 0x0A, 0x35, 0xFD, 0x9E, 0xA2, - 0x84, 0x5C, 0x7E, 0x81, 0xE2 - } - }; - - static const uint8_t expected_output[HMAC_TEST_COUNT][128] = { - { - 0x76, 0xFC, 0x79, 0xFE, 0x9B, 0x50, 0xBE, 0xCC, 0xC9, - 0x91, 0xA1, 0x1B, 0x56, 0x35, 0x78, 0x3A, 0x83, 0x53, - 0x6A, 0xDD, 0x03, 0xC1, 0x57, 0xFB, 0x30, 0x64, 0x5E, - 0x61, 0x1C, 0x28, 0x98, 0xBB, 0x2B, 0x1B, 0xC2, 0x15, - 0x00, 0x02, 0x09, 0x20, 0x8C, 0xD5, 0x06, 0xCB, 0x28, - 0xDA, 0x2A, 0x51, 0xBD, 0xB0, 0x38, 0x26, 0xAA, 0xF2, - 0xBD, 0x23, 0x35, 0xD5, 0x76, 0xD5, 0x19, 0x16, 0x08, - 0x42, 0xE7, 0x15, 0x8A, 0xD0, 0x94, 0x9D, 0x1A, 0x9E, - 0xC3, 0xE6, 0x6E, 0xA1, 0xB1, 0xA0, 0x64, 0xB0, 0x05, - 0xDE, 0x91, 0x4E, 0xAC, 0x2E, 0x9D, 0x4F, 0x2D, 0x72, - 0xA8, 0x61, 0x6A, 0x80, 0x22, 0x54, 0x22, 0x91, 0x82, - 0x50, 0xFF, 0x66, 0xA4, 0x1B, 0xD2, 0xF8, 0x64, 0xA6, - 0xA3, 0x8C, 0xC5, 0xB6, 0x49, 0x9D, 0xC4, 0x3F, 0x7F, - 0x2B, 0xD0, 0x9E, 0x1E, 0x0F, 0x8F, 0x58, 0x85, 0x93, - 0x51, 0x24 - }, - { - 0x17, 0xD0, 0x9F, 0x40, 0xA4, 0x37, 0x71, 0xF4, 0xA2, - 0xF0, 0xDB, 0x32, 0x7D, 0xF6, 0x37, 0xDE, 0xA9, 0x72, - 0xBF, 0xFF, 0x30, 0xC9, 0x8E, 0xBC, 0x88, 0x42, 0xDC, - 0x7A, 0x9E, 0x3D, 0x68, 0x1C, 0x61, 0x90, 0x2F, 0x71, - 0xBF, 0xFA, 0xF5, 0x09, 0x36, 0x07, 0xFB, 0xFB, 0xA9, - 0x67, 0x4A, 0x70, 0xD0, 0x48, 0xE5, 0x62, 0xEE, 0x88, - 0xF0, 0x27, 0xF6, 0x30, 0xA7, 0x85, 0x22, 0xEC, 0x6F, - 0x70, 0x6B, 0xB4, 0x4A, 0xE1, 0x30, 0xE0, 0x5C, 0x8D, - 0x7E, 0xAC, 0x66, 0x8B, 0xF6, 0x98, 0x0D, 0x99, 0xB4, - 0xC0, 0x24, 0x29, 0x46, 0x45, 0x23, 0x99, 0xCB, 0x03, - 0x2C, 0xC6, 0xF9, 0xFD, 0x96, 0x28, 0x47, 0x09, 0xBD, - 0x2F, 0xA5, 0x65, 0xB9, 0xEB, 0x9F, 0x20, 0x04, 0xBE, - 0x6C, 0x9E, 0xA9, 0xFF, 0x91, 0x28, 0xC3, 0xF9, 0x3B, - 0x60, 0xDC, 0x30, 0xC5, 0xFC, 0x85, 0x87, 0xA1, 0x0D, - 0xE6, 0x8C - } - }; - - static uint8_t output[128]; - - int i, cmp_result; - - for (i = 0; i < HMAC_TEST_COUNT; i++) { - hmac_drbg_init(&ctx, - init_entropy[i], sizeof(init_entropy[i]), - init_nonce[i], sizeof(init_nonce[i]), - NULL, 0); - - hmac_drbg_reseed(&ctx, - reseed_entropy[i], sizeof(reseed_entropy[i]), - NULL, 0, - NULL, 0); - - hmac_drbg_generate(&ctx, - output, sizeof(output), - NULL, 0); - - hmac_drbg_generate(&ctx, - output, sizeof(output), - NULL, 0); - - cmp_result = memcmp(output, expected_output[i], sizeof(output)); - ccprintf("HMAC DRBG generate test %d, %s\n", - i, cmp_result ? "failed" : "passed"); - } - - return 0; -} -DECLARE_SAFE_CONSOLE_COMMAND(hmac_drbg, cmd_hmac_drbg, NULL, NULL); - -/* - * Sanity check to exercise random initialization. - */ -static int cmd_hmac_drbg_rand(int argc, char **argv) -{ - static struct drbg_ctx ctx; - static uint8_t output[128]; - - int i; - - hmac_drbg_init_rand(&ctx, 256); - - hmac_drbg_generate(&ctx, output, sizeof(output), NULL, 0); - - ccprintf("Randomly initialized HMAC DRBG, 1024 bit output: "); - - for (i = 0; i < sizeof(output); i++) - ccprintf("%x", output[i]); - ccprintf("\n"); - - return 0; -} -DECLARE_SAFE_CONSOLE_COMMAND(hmac_drbg_rand, cmd_hmac_drbg_rand, NULL, NULL); - -enum drbg_command { - DRBG_INIT = 0, - DRBG_RESEED = 1, - DRBG_GENERATE = 2 -}; - -/* - * DRBG_TEST command structure: - * - * field | size | note - * ========================================================================== - * mode | 1 | 0 - DRBG_INIT, 1 - DRBG_RESEED, 2 - DRBG_GENERATE - * p0_len | 2 | size of first input in bytes - * p0 | p0_len | entropy for INIT & SEED, input for GENERATE - * p1_len | 2 | size of second input in bytes (for INIT & RESEED) - * | | or size of expected output for GENERATE - * p1 | p1_len | nonce for INIT & SEED - * p2_len | 2 | size of third input in bytes for DRBG_INIT - * p2 | p2_len | personalization for INIT & SEED - * - * DRBG_INIT (entropy, nonce, perso) - * DRBG_RESEED (entropy, additional input 1, additional input 2) - * DRBG_INIT and DRBG_RESEED returns empty response - * DRBG_GENERATE (p0_len, p0 - additional input 1, p1_len - size of output) - * DRBG_GENERATE returns p1_len bytes of generated data - * (up to a maximum of 128 bytes) - */ -static enum vendor_cmd_rc drbg_test(enum vendor_cmd_cc code, void *buf, - size_t input_size, size_t *response_size) -{ - static struct drbg_ctx drbg_ctx; - static uint8_t output[512]; - uint8_t *p0 = NULL, *p1 = NULL, *p2 = NULL; - uint16_t p0_len = 0, p1_len = 0, p2_len = 0; - uint8_t *cmd = (uint8_t *)buf; - size_t max_out_len = *response_size; - enum drbg_command drbg_op; - - *response_size = 0; - /* there is always op + first parameter, even if zero length */ - if (input_size < sizeof(p0_len) + 1) - return VENDOR_RC_BOGUS_ARGS; - drbg_op = *cmd++; - p0_len = *cmd++; - p0_len = p0_len * 256 + *cmd++; - input_size -= 3; - if (p0_len > input_size) - return VENDOR_RC_BOGUS_ARGS; - input_size -= p0_len; - if (p0_len) - p0 = cmd; - cmd += p0_len; - - /* there should be enough space for p1_len */ - if (input_size && input_size < sizeof(p1_len)) - return VENDOR_RC_BOGUS_ARGS; - - /* DRBG_GENERATE should just have p1_len defined */ - if (drbg_op == DRBG_GENERATE && input_size != sizeof(p1_len)) - return VENDOR_RC_BOGUS_ARGS; - - if (input_size) { - p1_len = *cmd++; - p1_len = p1_len * 256 + *cmd++; - input_size -= 2; - - if (drbg_op != DRBG_GENERATE) { - if (p1_len > input_size) - return VENDOR_RC_BOGUS_ARGS; - input_size -= p1_len; - if (p1_len) - p1 = cmd; - cmd += p1_len; - } - } - - if (input_size) { - if (drbg_op == DRBG_GENERATE) - return VENDOR_RC_BOGUS_ARGS; - p2_len = *cmd++; - p2_len = p2_len * 256 + *cmd++; - input_size -= 2; - if (p2_len > input_size) - return VENDOR_RC_BOGUS_ARGS; - if (p2_len) - p2 = cmd; - } - - switch (drbg_op) { - case DRBG_INIT: { - hmac_drbg_init(&drbg_ctx, p0, p0_len, p1, p1_len, p2, p2_len); - break; - } - case DRBG_RESEED: { - hmac_drbg_reseed(&drbg_ctx, p0, p0_len, p1, p1_len, p2, p2_len); - break; - } - case DRBG_GENERATE: { - if (p1_len > sizeof(output) || max_out_len < p1_len) - return VENDOR_RC_BOGUS_ARGS; - - hmac_drbg_generate(&drbg_ctx, output, p1_len, p0, p0_len); - - memcpy(buf, output, p1_len); - *response_size = p1_len; - break; - } - default: - return VENDOR_RC_BOGUS_ARGS; - } - - return VENDOR_RC_SUCCESS; -} -DECLARE_VENDOR_COMMAND(VENDOR_CC_DRBG_TEST, drbg_test); - -#endif /* CRYPTO_TEST_SETUP */ diff --git a/chip/g/dcrypto/internal.h b/chip/g/dcrypto/internal.h deleted file mode 100644 index 1811426f2a..0000000000 --- a/chip/g/dcrypto/internal.h +++ /dev/null @@ -1,219 +0,0 @@ -/* 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. - */ - -#ifndef __EC_CHIP_G_DCRYPTO_INTERNAL_H -#define __EC_CHIP_G_DCRYPTO_INTERNAL_H - -#include -#include - -#include "common.h" -#include "util.h" - -#include "cryptoc/p256.h" -#include "cryptoc/sha.h" -#include "cryptoc/sha256.h" -#include "cryptoc/sha384.h" -#include "cryptoc/sha512.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * SHA. - */ -#define CTRL_CTR_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#define CTRL_ENABLE 1 -#define CTRL_ENCRYPT 1 -#define CTRL_NO_SOFT_RESET 0 - -#define SHA_DIGEST_WORDS (SHA_DIGEST_SIZE / sizeof(uint32_t)) -#define SHA256_DIGEST_WORDS (SHA256_DIGEST_SIZE / sizeof(uint32_t)) - -#ifdef SHA512_SUPPORT -#define SHA_DIGEST_MAX_BYTES SHA512_DIGEST_SIZE -#else -#define SHA_DIGEST_MAX_BYTES SHA256_DIGEST_SIZE -#endif - -enum sha_mode { - SHA1_MODE = 0, - SHA256_MODE = 1 -}; - -/* - * Use this structure to avoid alignment problems with input and output - * pointers. - */ -struct access_helper { - uint32_t udata; -} __packed; - -#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 void *data, uint32_t n); -void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest); - -/* - * BIGNUM. - */ -#define LITE_BN_BITS2 32 -#define LITE_BN_BYTES 4 - -struct LITE_BIGNUM { - uint32_t dmax; /* Size of d, in 32-bit words. */ - struct access_helper *d; /* Word array, little endian format ... */ -}; - -#define BN_DIGIT(b, i) ((b)->d[(i)].udata) - -void bn_init(struct LITE_BIGNUM *bn, void *buf, size_t len); -#define bn_size(b) ((b)->dmax * LITE_BN_BYTES) -#define bn_words(b) ((b)->dmax) -#define bn_bits(b) ((b)->dmax * LITE_BN_BITS2) -int bn_eq(const struct LITE_BIGNUM *a, const struct LITE_BIGNUM *b); -int bn_check_topbit(const struct LITE_BIGNUM *N); -int bn_modexp(struct LITE_BIGNUM *output, - const struct LITE_BIGNUM *input, - const struct LITE_BIGNUM *exp, - const struct LITE_BIGNUM *N); -int bn_modexp_word(struct LITE_BIGNUM *output, - const struct LITE_BIGNUM *input, - uint32_t pubexp, - const struct LITE_BIGNUM *N); -int bn_modexp_blinded(struct LITE_BIGNUM *output, - const struct LITE_BIGNUM *input, - const struct LITE_BIGNUM *exp, - const struct LITE_BIGNUM *N, - uint32_t pubexp); -uint32_t bn_add(struct LITE_BIGNUM *c, - const struct LITE_BIGNUM *a); -uint32_t bn_sub(struct LITE_BIGNUM *c, - const struct LITE_BIGNUM *a); -int bn_modinv_vartime(struct LITE_BIGNUM *r, - const struct LITE_BIGNUM *e, - const struct LITE_BIGNUM *MOD); -int bn_is_bit_set(const struct LITE_BIGNUM *a, int n); - -/* - * Accelerated bn. - */ -int dcrypto_modexp(struct LITE_BIGNUM *output, - const struct LITE_BIGNUM *input, - const struct LITE_BIGNUM *exp, - const struct LITE_BIGNUM *N); -int dcrypto_modexp_word(struct LITE_BIGNUM *output, - const struct LITE_BIGNUM *input, - uint32_t pubexp, - const struct LITE_BIGNUM *N); -int dcrypto_modexp_blinded(struct LITE_BIGNUM *output, - const struct LITE_BIGNUM *input, - const struct LITE_BIGNUM *exp, - const struct LITE_BIGNUM *N, - uint32_t pubexp); - -struct drbg_ctx { - uint32_t k[SHA256_DIGEST_WORDS]; - uint32_t v[SHA256_DIGEST_WORDS]; - uint32_t reseed_counter; -}; - -/* - * NIST SP 800-90A HMAC DRBG. - */ -enum hmac_result { - HMAC_DRBG_SUCCESS = 0, - HMAC_DRBG_INVALID_PARAM = 1, - HMAC_DRBG_RESEED_REQUIRED = 2 -}; - -/* Standard initialization. */ -void hmac_drbg_init(struct drbg_ctx *ctx, - const void *p0, size_t p0_len, - const void *p1, size_t p1_len, - const void *p2, size_t p2_len); -/* Initialize for use as RFC6979 DRBG. */ -void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx, - const p256_int *key, - const p256_int *message); -/* Initialize with at least nbits of random entropy. */ -void hmac_drbg_init_rand(struct drbg_ctx *ctx, size_t nbits); -void hmac_drbg_reseed(struct drbg_ctx *ctx, - const void *p0, size_t p0_len, - const void *p1, size_t p1_len, - const void *p2, size_t p2_len); -enum hmac_result hmac_drbg_generate(struct drbg_ctx *ctx, void *out, - size_t out_len, const void *input, - size_t input_len); -/* Generate p256, with no additional input. */ -enum hmac_result hmac_drbg_generate_p256(struct drbg_ctx *ctx, p256_int *k_out); -void drbg_exit(struct drbg_ctx *ctx); - -/* - * Accelerated p256. FIPS PUB 186-4 - */ -int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key, - const p256_int *message, p256_int *r, p256_int *s) - __attribute__((warn_unused_result)); -int dcrypto_p256_base_point_mul(const p256_int *k, p256_int *x, p256_int *y) - __attribute__((warn_unused_result)); -int dcrypto_p256_point_mul(const p256_int *k, - const p256_int *in_x, const p256_int *in_y, - p256_int *x, p256_int *y) - __attribute__((warn_unused_result)); -int dcrypto_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y, - const p256_int *message, const p256_int *r, - const p256_int *s) - __attribute__((warn_unused_result)); -int dcrypto_p256_is_valid_point(const p256_int *x, const p256_int *y) - __attribute__((warn_unused_result)); - -/* Pick a p256 number between 1 < k < |p256| */ -int dcrypto_p256_pick(struct drbg_ctx *drbg, p256_int *output); - -/* Overwrite with random p256 value */ -void dcrypto_p256_rnd(p256_int *output); - -/* - * Accelerator runtime. - * - * Note dcrypto_init_and_lock grabs a mutex and dcrypto_unlock releases it. - * Do not use dcrypto_call, dcrypto_imem_load or dcrypto_dmem_load w/o holding - * the mutex. - */ -void dcrypto_init_and_lock(void); -void dcrypto_unlock(void); -uint32_t dcrypto_call(uint32_t adr) __attribute__((warn_unused_result)); -void dcrypto_imem_load(size_t offset, const uint32_t *opcodes, - size_t n_opcodes); -/* - * Returns 0 iff no difference was observed between existing and new content. - */ -uint32_t dcrypto_dmem_load(size_t offset, const void *words, size_t n_words); - -/* - * Key ladder. - */ -#ifndef __cplusplus -enum dcrypto_appid; /* Forward declaration. */ - -int dcrypto_ladder_compute_usr(enum dcrypto_appid id, - const uint32_t usr_salt[8]); -int dcrypto_ladder_derive(enum dcrypto_appid appid, const uint32_t salt[8], - const uint32_t input[8], uint32_t output[8]); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* ! __EC_CHIP_G_DCRYPTO_INTERNAL_H */ diff --git a/chip/g/dcrypto/key_ladder.c b/chip/g/dcrypto/key_ladder.c deleted file mode 100644 index 77055e4159..0000000000 --- a/chip/g/dcrypto/key_ladder.c +++ /dev/null @@ -1,300 +0,0 @@ -/* Copyright 2017 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 "endian.h" -#include "registers.h" -#include "trng.h" - -static void ladder_init(void) -{ - /* Do not reset keyladder engine here, as before. - * - * Should not be needed and if it is, it is indicative - * of sync error between this and sha engine usage. - * Reset will make this flow work, but will have broken - * the other pending sha flow. - * Hence leave as is and observe the error. - */ - - /* Enable random stalls for key-ladder usage. Note that - * the stall rate used for key-ladder operations is - * 25% (vs. 12% for generic SHA operations). This distinction - * is made so as to increase the difficulty in characterizng - * the key-ladder engine via random inputs provided over the - * generic SHA interface. - */ - /* Turn off random nops (which are enabled by default). */ - GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 0); - /* Configure random nop percentage at 25%. */ - GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, FREQ, 1); - /* Now turn on random nops. */ - GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 1); -} - -static int ladder_step(uint32_t cert, const uint32_t input[8]) -{ - GREG32(KEYMGR, SHA_ITOP) = 0; /* clear status */ - - GREG32(KEYMGR, SHA_USE_CERT_INDEX) = - (cert << GC_KEYMGR_SHA_USE_CERT_INDEX_LSB) | - GC_KEYMGR_SHA_USE_CERT_ENABLE_MASK; - - GREG32(KEYMGR, SHA_CFG_EN) = - GC_KEYMGR_SHA_CFG_EN_INT_EN_DONE_MASK; - GREG32(KEYMGR, SHA_TRIG) = - GC_KEYMGR_SHA_TRIG_TRIG_GO_MASK; - - if (input) { - GREG32(KEYMGR, SHA_INPUT_FIFO) = input[0]; - GREG32(KEYMGR, SHA_INPUT_FIFO) = input[1]; - GREG32(KEYMGR, SHA_INPUT_FIFO) = input[2]; - GREG32(KEYMGR, SHA_INPUT_FIFO) = input[3]; - GREG32(KEYMGR, SHA_INPUT_FIFO) = input[4]; - GREG32(KEYMGR, SHA_INPUT_FIFO) = input[5]; - GREG32(KEYMGR, SHA_INPUT_FIFO) = input[6]; - GREG32(KEYMGR, SHA_INPUT_FIFO) = input[7]; - - GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_STOP_MASK; - } - - while (!GREG32(KEYMGR, SHA_ITOP)) - ; - - GREG32(KEYMGR, SHA_ITOP) = 0; /* clear status */ - - return !!GREG32(KEYMGR, HKEY_ERR_FLAGS); -} - -static int compute_certs(const uint32_t *certs, size_t num_certs) -{ - int i; - - for (i = 0; i < num_certs; i++) { - if (ladder_step(certs[i], NULL)) - return 0; - } - - return 1; -} - -#define KEYMGR_CERT_0 0 -#define KEYMGR_CERT_3 3 -#define KEYMGR_CERT_4 4 -#define KEYMGR_CERT_5 5 -#define KEYMGR_CERT_7 7 -#define KEYMGR_CERT_15 15 -#define KEYMGR_CERT_20 20 -#define KEYMGR_CERT_25 25 -#define KEYMGR_CERT_26 26 -#define KEYMGR_CERT_27 27 -#define KEYMGR_CERT_28 28 -#define KEYMGR_CERT_34 34 -#define KEYMGR_CERT_35 35 -#define KEYMGR_CERT_38 38 - -static const uint32_t FRK2_CERTS_PREFIX[] = { - KEYMGR_CERT_0, - KEYMGR_CERT_3, - KEYMGR_CERT_4, - KEYMGR_CERT_5, - KEYMGR_CERT_7, - KEYMGR_CERT_15, - KEYMGR_CERT_20, -}; - -static const uint32_t FRK2_CERTS_POSTFIX[] = { - KEYMGR_CERT_26, -}; - -#define MAX_MAJOR_FW_VERSION 254 - -int DCRYPTO_ladder_compute_frk2(size_t fw_version, uint8_t *frk2) -{ - int result = 0; - - if (fw_version > MAX_MAJOR_FW_VERSION) - return 0; - - if (!dcrypto_grab_sha_hw()) - return 0; - - do { - int i; - - ladder_init(); - - if (!compute_certs(FRK2_CERTS_PREFIX, - ARRAY_SIZE(FRK2_CERTS_PREFIX))) - break; - - for (i = 0; i < MAX_MAJOR_FW_VERSION - fw_version; i++) { - if (ladder_step(KEYMGR_CERT_25, NULL)) - break; - } - - if (!compute_certs(FRK2_CERTS_POSTFIX, - ARRAY_SIZE(FRK2_CERTS_POSTFIX))) - break; - - memcpy(frk2, (void *) GREG32_ADDR(KEYMGR, HKEY_FRR0), - AES256_BLOCK_CIPHER_KEY_SIZE); - - result = 1; - } while (0); - - dcrypto_release_sha_hw(); - return result; -} - -/* ISR salt (SHA256("ISR_SALT")) to use for USR generation. */ -static const uint32_t ISR_SALT[8] = { - 0x6ba1b495, 0x4b7ca214, 0xfe07e922, 0x09735185, - 0xfcca43ca, 0xc6d4dfd9, 0x5fc2fcca, 0xaa45400b -}; - -/* Map of populated USR registers. */ -static int usr_ready[8] = {}; - -int dcrypto_ladder_compute_usr(enum dcrypto_appid id, - const uint32_t usr_salt[8]) -{ - int result = 0; - - /* Check for USR readiness. */ - if (usr_ready[id]) - return 1; - - if (!dcrypto_grab_sha_hw()) - return 0; - - do { - int i; - - /* The previous check performed without lock acquisition. */ - if (usr_ready[id]) { - result = 1; - break; - } - - ladder_init(); - - if (!compute_certs(FRK2_CERTS_PREFIX, - ARRAY_SIZE(FRK2_CERTS_PREFIX))) - break; - - /* USR generation requires running the key-ladder till - * the end (version 0), plus one additional iteration. - */ - for (i = 0; i < MAX_MAJOR_FW_VERSION - 0 + 1; i++) { - if (ladder_step(KEYMGR_CERT_25, NULL)) - break; - } - if (i != MAX_MAJOR_FW_VERSION - 0 + 1) - break; - - if (ladder_step(KEYMGR_CERT_34, ISR_SALT)) - break; - - /* Output goes to USR[appid] (the multiply by 2 is an - * artifact of slot addressing). - */ - GWRITE_FIELD(KEYMGR, SHA_CERT_OVERRIDE, DIGEST_PTR, 2 * id); - if (ladder_step(KEYMGR_CERT_35, usr_salt)) - break; - - /* Check for key-ladder errors. */ - if (GREG32(KEYMGR, HKEY_ERR_FLAGS)) - break; - - /* Key deposited in USR[id], and ready to use. */ - usr_ready[id] = 1; - - result = 1; - } while (0); - - dcrypto_release_sha_hw(); - return result; -} - -static void ladder_out(uint32_t output[8]) -{ - output[0] = GREG32(KEYMGR, SHA_STS_H0); - output[1] = GREG32(KEYMGR, SHA_STS_H1); - output[2] = GREG32(KEYMGR, SHA_STS_H2); - output[3] = GREG32(KEYMGR, SHA_STS_H3); - output[4] = GREG32(KEYMGR, SHA_STS_H4); - output[5] = GREG32(KEYMGR, SHA_STS_H5); - output[6] = GREG32(KEYMGR, SHA_STS_H6); - output[7] = GREG32(KEYMGR, SHA_STS_H7); -} - -/* - * Stir TRNG entropy into RSR and pull some out. - */ -int DCRYPTO_ladder_random(void *output) -{ - int error = 1; - uint32_t tmp[8]; - - if (!dcrypto_grab_sha_hw()) - goto fail; - - rand_bytes(tmp, sizeof(tmp)); - /* Mix TRNG bytes with RSR entropy */ - error = ladder_step(KEYMGR_CERT_27, tmp); - if (!error) - ladder_out(output); - -fail: - dcrypto_release_sha_hw(); - return !error; -} - -int dcrypto_ladder_derive(enum dcrypto_appid appid, const uint32_t salt[8], - const uint32_t input[8], uint32_t output[8]) -{ - int error; - - if (!dcrypto_grab_sha_hw()) - return 0; - - GWRITE_FIELD(KEYMGR, SHA_CERT_OVERRIDE, KEY_PTR, 2 * appid); - error = ladder_step(KEYMGR_CERT_38, input); /* HMAC */ - if (!error) - ladder_out(output); - - dcrypto_release_sha_hw(); - return !error; -} - -void DCRYPTO_ladder_revoke(void) -{ - /* Revoke certificates */ - GWRITE(KEYMGR, CERT_REVOKE_CTRL0, 0xffffffff); - GWRITE(KEYMGR, CERT_REVOKE_CTRL1, 0xffffffff); - - /* Wipe out the hidden keys cached in AES and SHA engines. */ - GWRITE_FIELD(KEYMGR, AES_USE_HIDDEN_KEY, ENABLE, 0); - GWRITE_FIELD(KEYMGR, SHA_USE_HIDDEN_KEY, ENABLE, 0); - - /* Clear usr_ready[] */ - memset(usr_ready, 0, sizeof(usr_ready)); -} - -#define KEYMGR_CERT_REVOKE_CTRL0_DEFAULT_VAL 0xa8028a82 -#define KEYMGR_CERT_REVOKE_CTRL1_DEFAULT_VAL 0xaaaaaaaa - -int DCRYPTO_ladder_is_enabled(void) -{ - uint32_t ctrl0; - uint32_t ctrl1; - - ctrl0 = GREAD(KEYMGR, CERT_REVOKE_CTRL0); - ctrl1 = GREAD(KEYMGR, CERT_REVOKE_CTRL1); - - return ctrl0 == KEYMGR_CERT_REVOKE_CTRL0_DEFAULT_VAL && - ctrl1 == KEYMGR_CERT_REVOKE_CTRL1_DEFAULT_VAL; -} diff --git a/chip/g/dcrypto/p256.c b/chip/g/dcrypto/p256.c deleted file mode 100644 index 665144e31b..0000000000 --- a/chip/g/dcrypto/p256.c +++ /dev/null @@ -1,30 +0,0 @@ -/* 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 "cryptoc/p256.h" -#include "cryptoc/util.h" - -static const p256_int p256_one = P256_ONE; - -/* - * Key selection based on FIPS-186-4, section B.4.2 (Key Pair - * Generation by Testing Candidates). - */ -int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d, - const uint8_t key_bytes[P256_NBYTES]) -{ - p256_int key; - - p256_from_bin(key_bytes, &key); - if (p256_cmp(&SECP256r1_nMin2, &key) < 0) - return 0; - p256_add(&key, &p256_one, d); - always_memset(&key, 0, sizeof(key)); - if (x == NULL || y == NULL) - return 1; - return dcrypto_p256_base_point_mul(d, x, y); -} diff --git a/chip/g/dcrypto/p256_ec.c b/chip/g/dcrypto/p256_ec.c deleted file mode 100644 index cb33a15774..0000000000 --- a/chip/g/dcrypto/p256_ec.c +++ /dev/null @@ -1,39 +0,0 @@ -/* 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 - -#include "cryptoc/p256.h" - -/* p256_base_point_mul sets {out_x,out_y} = nG, where n is < the - * order of the group. */ -int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y, - const p256_int *n) -{ - if (p256_is_zero(n) != 0) { - p256_clear(out_x); - p256_clear(out_y); - return 0; - } - - return dcrypto_p256_base_point_mul(n, out_x, out_y); -} - -/* DCRYPTO_p256_point_mul sets {out_x,out_y} = n*{in_x,in_y}, where n is < - * the order of the group. */ -int DCRYPTO_p256_point_mul(p256_int *out_x, p256_int *out_y, - const p256_int *n, const p256_int *in_x, - const p256_int *in_y) -{ - if (p256_is_zero(n) != 0) { - p256_clear(out_x); - p256_clear(out_y); - return 0; - } - - return dcrypto_p256_point_mul(n, in_x, in_y, out_x, out_y); -} diff --git a/chip/g/dcrypto/p256_ecies.c b/chip/g/dcrypto/p256_ecies.c deleted file mode 100644 index 30a410d828..0000000000 --- a/chip/g/dcrypto/p256_ecies.c +++ /dev/null @@ -1,175 +0,0 @@ -/* Copyright 2016 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 "internal.h" -#include "dcrypto.h" - -#include "trng.h" -#include "util.h" - -#include "cryptoc/p256.h" -#include "cryptoc/sha256.h" - -#define AES_KEY_BYTES 16 -#define HMAC_KEY_BYTES 32 - -#define AES_BLOCK_BYTES 16 - -/* P256 based hybrid encryption. The output format is: - * - * 0x04 || PUBKEY || AUTH_DATA || AES128_CTR(PLAINTEXT) || - * HMAC_SHA256(AUTH_DATA || CIPHERTEXT) - */ -size_t DCRYPTO_ecies_encrypt( - void *out, size_t out_len, const void *in, size_t in_len, - size_t auth_data_len, const uint8_t *iv, - const p256_int *pub_x, const p256_int *pub_y, - const uint8_t *salt, size_t salt_len, - const uint8_t *info, size_t info_len) -{ - p256_int eph_d; - p256_int eph_x; - p256_int eph_y; - uint8_t seed[P256_NBYTES]; - p256_int secret_x; - p256_int secret_y; - /* Key bytes to be extracted from HKDF. */ - uint8_t key[AES_KEY_BYTES + HMAC_KEY_BYTES]; - const uint8_t *aes_key; - const uint8_t *hmac_key; - LITE_HMAC_CTX ctx; - uint8_t *outp = out; - uint8_t *ciphertext; - - if (auth_data_len > in_len) - return 0; - if (out_len < 1 + P256_NBYTES + P256_NBYTES + - in_len + SHA256_DIGEST_SIZE) - return 0; - - /* Generate emphemeral EC key. */ - rand_bytes(seed, sizeof(seed)); - if (!DCRYPTO_p256_key_from_bytes(&eph_x, &eph_y, &eph_d, seed)) - return 0; - /* Compute DH point. */ - if (!DCRYPTO_p256_point_mul(&secret_x, &secret_y, - &eph_d, pub_x, pub_y)) - return 0; - /* Check for computational errors. */ - if (!dcrypto_p256_is_valid_point(&secret_x, &secret_y)) - return 0; - /* Convert secret to big-endian. */ - reverse(&secret_x, sizeof(secret_x)); - /* Derive shared secret. */ - if (!DCRYPTO_hkdf(key, sizeof(key), salt, salt_len, - (uint8_t *) &secret_x, sizeof(secret_x), - info, info_len)) - return 0; - - aes_key = &key[0]; - hmac_key = &key[AES_KEY_BYTES]; - - if (out == in) - ciphertext = out + auth_data_len; /* In place encrypt. */ - else - ciphertext = out + 1 + P256_NBYTES + P256_NBYTES + - auth_data_len; - - /* Compute ciphertext. */ - if (!DCRYPTO_aes_ctr(ciphertext, aes_key, AES_KEY_BYTES * 8, iv, - in + auth_data_len, in_len - auth_data_len)) - return 0; - - /* Write out auth_data / ciphertext. */ - outp = out + 1 + P256_NBYTES + P256_NBYTES; - if (out == in) - memmove(outp, in, in_len); - else - memcpy(outp, in, auth_data_len); - - /* Write out ephemeral pub key. */ - outp = out; - *outp++ = 0x04; /* uncompressed EC public key. */ - p256_to_bin(&eph_x, outp); - outp += P256_NBYTES; - p256_to_bin(&eph_y, outp); - outp += P256_NBYTES; - - /* Calculate HMAC(auth_data || ciphertext). */ - DCRYPTO_HMAC_SHA256_init(&ctx, hmac_key, HMAC_KEY_BYTES); - HASH_update(&ctx.hash, outp, in_len); - outp += in_len; - memcpy(outp, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE); - outp += SHA256_DIGEST_SIZE; - - return outp - (uint8_t *) out; -} - -size_t DCRYPTO_ecies_decrypt( - void *out, size_t out_len, const void *in, size_t in_len, - size_t auth_data_len, const uint8_t *iv, - const p256_int *d, - const uint8_t *salt, size_t salt_len, - const uint8_t *info, size_t info_len) -{ - p256_int eph_x; - p256_int eph_y; - p256_int secret_x; - p256_int secret_y; - uint8_t key[AES_KEY_BYTES + HMAC_KEY_BYTES]; - const uint8_t *aes_key; - const uint8_t *hmac_key; - LITE_HMAC_CTX ctx; - const uint8_t *inp = in; - uint8_t *outp = out; - - if (in_len < 1 + P256_NBYTES + P256_NBYTES + auth_data_len + - SHA256_DIGEST_SIZE) - return 0; - if (inp[0] != 0x04) - return 0; - - in_len -= 1 + P256_NBYTES + P256_NBYTES + SHA256_DIGEST_SIZE; - - inp++; - p256_from_bin(inp, &eph_x); - inp += P256_NBYTES; - p256_from_bin(inp, &eph_y); - inp += P256_NBYTES; - - /* Verify that the public point is on the curve. */ - if (!dcrypto_p256_is_valid_point(&eph_x, &eph_y)) - return 0; - /* Compute the DH point. */ - if (!DCRYPTO_p256_point_mul(&secret_x, &secret_y, - d, &eph_x, &eph_y)) - return 0; - /* Check for computational errors. */ - if (!dcrypto_p256_is_valid_point(&secret_x, &secret_y)) - return 0; - /* Convert secret to big-endian. */ - reverse(&secret_x, sizeof(secret_x)); - /* Derive shared secret. */ - if (!DCRYPTO_hkdf(key, sizeof(key), salt, salt_len, - (uint8_t *) &secret_x, sizeof(secret_x), - info, info_len)) - return 0; - - aes_key = &key[0]; - hmac_key = &key[AES_KEY_BYTES]; - DCRYPTO_HMAC_SHA256_init(&ctx, hmac_key, HMAC_KEY_BYTES); - HASH_update(&ctx.hash, inp, in_len); - if (!DCRYPTO_equals(inp + in_len, DCRYPTO_HMAC_final(&ctx), - SHA256_DIGEST_SIZE)) - return 0; - - memmove(outp, inp, auth_data_len); - inp += auth_data_len; - outp += auth_data_len; - if (!DCRYPTO_aes_ctr(outp, aes_key, AES_KEY_BYTES * 8, iv, - inp, in_len - auth_data_len)) - return 0; - return in_len; -} diff --git a/chip/g/dcrypto/proofs_p256.md b/chip/g/dcrypto/proofs_p256.md deleted file mode 100644 index c0fa7ef6ad..0000000000 --- a/chip/g/dcrypto/proofs_p256.md +++ /dev/null @@ -1,28 +0,0 @@ -Proving P256 dcrypto code -========================= - -In 2018, partial proofs of modular reduction were written in the Coq proof -assistant. -They can be used against the crypto accelerator code in [chip/g/dcrypto/dcrypto_p256.c](dcrypto_p256.c). - -The Coq code is in this file: -[github.com/mit-plv/fiat-crypto/.../Experiments/SimplyTypedArithmetic.v](https://github.com/mit-plv/fiat-crypto/blob/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Experiments/SimplyTypedArithmetic.v) - -Specific lines of interest: - -Instruction specifications: -[fiat-crypto/.../Experiments/SimplyTypedArithmetic.v#L10014](https://github.com/mit-plv/fiat-crypto/blob/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Experiments/SimplyTypedArithmetic.v#L10014) - -Printouts of verified code versions with explanatory comments are at the very -end of the same file (which GitHub cuts off, so here is the link to the raw -version): -https://raw.githubusercontent.com/mit-plv/fiat-crypto/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Experiments/SimplyTypedArithmetic.v - -Additionally, the MulMod procedure in p256 uses a non-standard Barrett -reduction optimization. In particular, it assumes that the quotient estimate is -off by no more than 1, while most resources say it can be off by 2. This -assumption was proven correct for most primes (including p256) here: - -[fiat-crypto/.../Arithmetic/BarrettReduction/Generalized.v#L140](https://github.com/mit-plv/fiat-crypto/blob/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Arithmetic/BarrettReduction/Generalized.v#L140) - -The proofs can be re-checked using Coq version 8.7 or 8.8 (or above, probably). diff --git a/chip/g/dcrypto/rsa.c b/chip/g/dcrypto/rsa.c deleted file mode 100644 index 8a4115398d..0000000000 --- a/chip/g/dcrypto/rsa.c +++ /dev/null @@ -1,743 +0,0 @@ -/* 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 "trng.h" -#include "util.h" - -#include - -#include "cryptoc/sha.h" -#include "cryptoc/sha256.h" -#include "cryptoc/sha384.h" -#include "cryptoc/sha512.h" -#include "cryptoc/util.h" - -/* Extend the MSB throughout the word. */ -static uint32_t msb_extend(uint32_t a) -{ - return 0u - (a >> 31); -} - -/* Return 0xFF..FF if a is zero, and zero otherwise. */ -static uint32_t is_zero(uint32_t a) -{ - return msb_extend(~a & (a - 1)); -} - -/* Select a or b based on mask. Mask expected to be 0xFF..FF or 0. */ -static uint32_t select(uint32_t mask, uint32_t a, uint32_t b) -{ - return (mask & a) | (~mask & b); -} - -static void MGF1_xor(uint8_t *dst, uint32_t dst_len, - const uint8_t *seed, uint32_t seed_len, - enum hashing_mode hashing) -{ - HASH_CTX ctx; - struct { - uint8_t b3; - uint8_t b2; - uint8_t b1; - uint8_t b0; - } cnt; - const uint8_t *digest; - const size_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE - : SHA256_DIGEST_SIZE; - - cnt.b0 = cnt.b1 = cnt.b2 = cnt.b3 = 0; - while (dst_len) { - int i; - - if (hashing == HASH_SHA1) - DCRYPTO_SHA1_init(&ctx, 0); - else - DCRYPTO_SHA256_init(&ctx, 0); - - HASH_update(&ctx, seed, seed_len); - HASH_update(&ctx, (uint8_t *) &cnt, sizeof(cnt)); - digest = HASH_final(&ctx); - for (i = 0; i < dst_len && i < hash_size; ++i) - *dst++ ^= *digest++; - dst_len -= i; - if (!++cnt.b0) - ++cnt.b1; - } -} - -/* - * struct OAEP { // MSB to LSB. - * uint8_t zero; - * uint8_t seed[HASH_SIZE]; - * uint8_t phash[HASH_SIZE]; - * uint8_t PS[]; // Variable length (optional) zero-pad. - * uint8_t one; // 0x01, message demarcator. - * uint8_t msg[]; // Input message. - * }; - */ -/* encrypt */ -static int oaep_pad(uint8_t *output, uint32_t output_len, - const uint8_t *msg, uint32_t msg_len, - enum hashing_mode hashing, const char *label) -{ - int i; - const size_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE - : SHA256_DIGEST_SIZE; - uint8_t *const seed = output + 1; - uint8_t *const phash = seed + hash_size; - uint8_t *const PS = phash + hash_size; - const uint32_t max_msg_len = output_len - 2 - 2 * hash_size; - const uint32_t ps_len = max_msg_len - msg_len; - uint8_t *const one = PS + ps_len; - struct HASH_CTX ctx; - - if (output_len < 2 + 2 * hash_size) - return 0; /* Key size too small for chosen hash. */ - if (msg_len > output_len - 2 - 2 * hash_size) - return 0; /* Input message too large for key size. */ - - always_memset(output, 0, output_len); - for (i = 0; i < hash_size;) { - uint32_t r = rand(); - - seed[i++] = r >> 0; - seed[i++] = r >> 8; - seed[i++] = r >> 16; - seed[i++] = r >> 24; - } - - if (hashing == HASH_SHA1) - DCRYPTO_SHA1_init(&ctx, 0); - else - DCRYPTO_SHA256_init(&ctx, 0); - - HASH_update(&ctx, label, label ? strlen(label) + 1 : 0); - memcpy(phash, HASH_final(&ctx), hash_size); - *one = 1; - memcpy(one + 1, msg, msg_len); - MGF1_xor(phash, hash_size + 1 + max_msg_len, - seed, hash_size, hashing); - MGF1_xor(seed, hash_size, phash, hash_size + 1 + max_msg_len, - hashing); - return 1; -} - -/* decrypt */ -static int check_oaep_pad(uint8_t *out, uint32_t *out_len, - uint8_t *padded, uint32_t padded_len, - enum hashing_mode hashing, const char *label) -{ - const size_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE - : SHA256_DIGEST_SIZE; - uint8_t *seed = padded + 1; - uint8_t *phash = seed + hash_size; - uint8_t *PS = phash + hash_size; - const uint32_t max_msg_len = padded_len - 2 - 2 * hash_size; - struct HASH_CTX ctx; - size_t one_index = 0; - uint32_t looking_for_one_byte = ~0; - int bad; - int i; - - if (padded_len < 2 + 2 * hash_size) - return 0; /* Invalid input size. */ - - /* Recover seed. */ - MGF1_xor(seed, hash_size, phash, hash_size + 1 + max_msg_len, hashing); - /* Recover db. */ - MGF1_xor(phash, hash_size + 1 + max_msg_len, seed, hash_size, hashing); - - if (hashing == HASH_SHA1) - DCRYPTO_SHA1_init(&ctx, 0); - else - DCRYPTO_SHA256_init(&ctx, 0); - HASH_update(&ctx, label, label ? strlen(label) + 1 : 0); - - bad = !DCRYPTO_equals(phash, HASH_final(&ctx), hash_size); - bad |= padded[0]; - - for (i = PS - padded; i < padded_len; i++) { - uint32_t equals0 = is_zero(padded[i]); - uint32_t equals1 = is_zero(padded[i] ^ 1); - - one_index = select(looking_for_one_byte & equals1, - i, one_index); - looking_for_one_byte = select(equals1, 0, looking_for_one_byte); - - /* Bad padding if padded[i] is neither 1 nor 0. */ - bad |= looking_for_one_byte & ~equals0; - } - - bad |= looking_for_one_byte; - - if (bad) - return 0; - - one_index++; - if (*out_len < padded_len - one_index) - return 0; - memcpy(out, padded + one_index, padded_len - one_index); - *out_len = padded_len - one_index; - return 1; -} - -/* Constants from RFC 3447. */ -#define RSA_PKCS1_PADDING_SIZE 11 - -/* encrypt */ -static int pkcs1_type2_pad(uint8_t *padded, uint32_t padded_len, - const uint8_t *in, uint32_t in_len) -{ - uint32_t PS_len; - - if (padded_len < RSA_PKCS1_PADDING_SIZE) - return 0; - if (in_len > padded_len - RSA_PKCS1_PADDING_SIZE) - return 0; - PS_len = padded_len - 3 - in_len; - - *(padded++) = 0; - *(padded++) = 2; - while (PS_len) { - int i; - uint32_t r = rand(); - - for (i = 0; i < 4 && PS_len; i++) { - uint8_t b = ((uint8_t *) &r)[i]; - - if (b) { - *padded++ = b; - PS_len--; - } - } - } - *(padded++) = 0; - memcpy(padded, in, in_len); - return 1; -} - -/* decrypt */ -static int check_pkcs1_type2_pad(uint8_t *out, uint32_t *out_len, - const uint8_t *padded, uint32_t padded_len) -{ - int i; - int valid; - uint32_t zero_index = 0; - uint32_t looking_for_index = ~0; - - if (padded_len < RSA_PKCS1_PADDING_SIZE) - return 0; - - valid = (padded[0] == 0); - valid &= (padded[1] == 2); - - for (i = 2; i < padded_len; i++) { - uint32_t found = is_zero(padded[i]); - - zero_index = select(looking_for_index & found, i, zero_index); - looking_for_index = select(found, 0, looking_for_index); - } - - zero_index++; - - valid &= ~looking_for_index; - valid &= (zero_index >= RSA_PKCS1_PADDING_SIZE); - if (!valid) - return 0; - - if (*out_len < padded_len - zero_index) - return 0; - memcpy(out, &padded[zero_index], padded_len - zero_index); - *out_len = padded_len - zero_index; - return 1; -} - -static const uint8_t SHA1_DER[] = { - 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, - 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 -}; -static const uint8_t SHA256_DER[] = { - 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, - 0x00, 0x04, 0x20 -}; -static const uint8_t SHA384_DER[] = { - 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, - 0x00, 0x04, 0x30 -}; -static const uint8_t SHA512_DER[] = { - 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, - 0x00, 0x04, 0x40 -}; - -static int pkcs1_get_der(enum hashing_mode hashing, const uint8_t **der, - uint32_t *der_size, uint32_t *hash_size) -{ - switch (hashing) { - case HASH_SHA1: - *der = &SHA1_DER[0]; - *der_size = sizeof(SHA1_DER); - *hash_size = SHA_DIGEST_SIZE; - break; - case HASH_SHA256: - *der = &SHA256_DER[0]; - *der_size = sizeof(SHA256_DER); - *hash_size = SHA256_DIGEST_SIZE; - break; - case HASH_SHA384: - *der = &SHA384_DER[0]; - *der_size = sizeof(SHA384_DER); - *hash_size = SHA384_DIGEST_SIZE; - break; - case HASH_SHA512: - *der = &SHA512_DER[0]; - *der_size = sizeof(SHA512_DER); - *hash_size = SHA512_DIGEST_SIZE; - break; - case HASH_NULL: - *der = NULL; - *der_size = 0; - *hash_size = 0; /* any size allowed */ - break; - default: - return 0; - } - - return 1; -} - -/* sign */ -static int pkcs1_type1_pad(uint8_t *padded, uint32_t padded_len, - const uint8_t *in, uint32_t in_len, - enum hashing_mode hashing) -{ - const uint8_t *der; - uint32_t der_size; - uint32_t hash_size; - uint32_t ps_len; - - if (!pkcs1_get_der(hashing, &der, &der_size, &hash_size)) - return 0; - if (padded_len < RSA_PKCS1_PADDING_SIZE + der_size) - return 0; - if (!in_len || (hash_size && in_len != hash_size)) - return 0; - if (in_len > padded_len - RSA_PKCS1_PADDING_SIZE - der_size) - return 0; - ps_len = padded_len - 3 - der_size - in_len; - - *(padded++) = 0; - *(padded++) = 1; - always_memset(padded, 0xFF, ps_len); - padded += ps_len; - *(padded++) = 0; - memcpy(padded, der, der_size); - padded += der_size; - memcpy(padded, in, in_len); - return 1; -} - -/* verify */ -static int check_pkcs1_type1_pad(const uint8_t *msg, uint32_t msg_len, - const uint8_t *padded, uint32_t padded_len, - enum hashing_mode hashing) -{ - int i; - const uint8_t *der; - uint32_t der_size; - uint32_t hash_size; - uint32_t ps_len; - - if (!pkcs1_get_der(hashing, &der, &der_size, &hash_size)) - return 0; - if (msg_len != hash_size) - return 0; - if (padded_len < RSA_PKCS1_PADDING_SIZE + der_size + hash_size) - return 0; - ps_len = padded_len - 3 - der_size - hash_size; - - if (padded[0] != 0 || padded[1] != 1) - return 0; - for (i = 2; i < ps_len + 2; i++) { - if (padded[i] != 0xFF) - return 0; - } - - if (padded[i++] != 0) - return 0; - if (!DCRYPTO_equals(&padded[i], der, der_size)) - return 0; - i += der_size; - return DCRYPTO_equals(msg, &padded[i], hash_size); -} - -/* sign */ -static int pkcs1_pss_pad(uint8_t *padded, uint32_t padded_len, - const uint8_t *in, uint32_t in_len, - enum hashing_mode hashing) -{ - const uint32_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE - : SHA256_DIGEST_SIZE; - const uint32_t salt_len = MIN(padded_len - hash_size - 2, hash_size); - uint32_t db_len; - uint32_t ps_len; - struct HASH_CTX ctx; - - if (in_len != hash_size) - return 0; - if (padded_len < hash_size + 2) - return 0; - db_len = padded_len - hash_size - 1; - - if (hashing == HASH_SHA1) - DCRYPTO_SHA1_init(&ctx, 0); - else - DCRYPTO_SHA256_init(&ctx, 0); - - /* Pilfer bits of output for temporary use. */ - memset(padded, 0, 8); - HASH_update(&ctx, padded, 8); - HASH_update(&ctx, in, in_len); - /* Pilfer bits of output for temporary use. */ - rand_bytes(padded, salt_len); - HASH_update(&ctx, padded, salt_len); - - /* Output hash. */ - memcpy(padded + db_len, HASH_final(&ctx), hash_size); - - /* Prepare DB. */ - ps_len = db_len - salt_len - 1; - memmove(padded + ps_len + 1, padded, salt_len); - memset(padded, 0, ps_len); - padded[ps_len] = 0x01; - MGF1_xor(padded, db_len, padded + db_len, hash_size, hashing); - - /* Clear most significant bit. */ - padded[0] &= 0x7F; - /* Set trailing byte. */ - padded[padded_len - 1] = 0xBC; - return 1; -} - -/* verify */ -static int check_pkcs1_pss_pad(const uint8_t *in, uint32_t in_len, - uint8_t *padded, uint32_t padded_len, - enum hashing_mode hashing) -{ - const uint32_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE - : SHA256_DIGEST_SIZE; - const uint8_t zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t db_len; - uint32_t max_ps_len; - uint32_t salt_len; - HASH_CTX ctx; - int bad = 0; - int i; - - if (in_len != hash_size) - return 0; - if (padded_len < hash_size + 2) - return 0; - db_len = padded_len - hash_size - 1; - - /* Top bit should be zero. */ - bad |= padded[0] & 0x80; - /* Check trailing byte. */ - bad |= padded[padded_len - 1] ^ 0xBC; - - /* Recover DB. */ - MGF1_xor(padded, db_len, padded + db_len, hash_size, hashing); - /* Clear top bit. */ - padded[0] &= 0x7F; - /* Verify padding2. */ - max_ps_len = db_len - 1; - for (i = 0; i < max_ps_len; i++) { - if (padded[i] == 0x01) - break; - else - bad |= padded[i]; - } - bad |= (padded[i] ^ 0x01); - /* Continue with zero-length salt if 0x01 was not found. */ - salt_len = max_ps_len - i; - - if (hashing == HASH_SHA1) - DCRYPTO_SHA1_init(&ctx, 0); - else - DCRYPTO_SHA256_init(&ctx, 0); - HASH_update(&ctx, zeros, sizeof(zeros)); - HASH_update(&ctx, in, in_len); - HASH_update(&ctx, padded + db_len - salt_len, salt_len); - bad |= !DCRYPTO_equals(padded + db_len, HASH_final(&ctx), hash_size); - return !bad; -} - -static int check_modulus_params( - const struct LITE_BIGNUM *N, size_t rsa_max_bytes, uint32_t *out_len) -{ - if (bn_size(N) > rsa_max_bytes) - return 0; /* Unsupported key size. */ - if (!bn_check_topbit(N)) /* Check that top bit is set. */ - return 0; - if (out_len && *out_len < bn_size(N)) - return 0; /* Output buffer too small. */ - return 1; -} - -int DCRYPTO_rsa_encrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len, - const uint8_t *in, uint32_t in_len, - enum padding_mode padding, enum hashing_mode hashing, - const char *label) -{ - uint8_t *p; - uint32_t padded_buf[RSA_MAX_WORDS]; - uint32_t e_buf[LITE_BN_BYTES / sizeof(uint32_t)]; - - struct LITE_BIGNUM padded; - struct LITE_BIGNUM encrypted; - int ret; - - if (!check_modulus_params(&rsa->N, sizeof(padded_buf), out_len)) - return 0; - - bn_init(&padded, padded_buf, bn_size(&rsa->N)); - bn_init(&encrypted, out, bn_size(&rsa->N)); - - switch (padding) { - case PADDING_MODE_OAEP: - if (!oaep_pad((uint8_t *) padded.d, bn_size(&padded), - (const uint8_t *) in, in_len, hashing, label)) - return 0; - break; - case PADDING_MODE_PKCS1: - if (!pkcs1_type2_pad((uint8_t *) padded.d, bn_size(&padded), - (const uint8_t *) in, in_len)) - return 0; - break; - case PADDING_MODE_NULL: - /* Input is allowed to have more bytes than N, in - * which case the excess must be zero. */ - for (; in_len > bn_size(&padded); in_len--) - if (*in++ != 0) - return 0; - p = (uint8_t *) padded.d; - /* If in_len < bn_size(&padded), padded will - * have leading zero bytes. */ - memcpy(&p[bn_size(&padded) - in_len], in, in_len); - /* TODO(ngm): in may be > N, bn_mod_exp() should - * handle this case. */ - break; - default: - return 0; /* Unsupported padding mode. */ - } - - /* Reverse from big-endian to little-endian notation. */ - reverse((uint8_t *) padded.d, bn_size(&padded)); - ret = bn_modexp_word(&encrypted, &padded, rsa->e, &rsa->N); - /* Back to big-endian notation. */ - reverse((uint8_t *) encrypted.d, bn_size(&encrypted)); - *out_len = bn_size(&encrypted); - - always_memset(padded_buf, 0, sizeof(padded_buf)); - always_memset(e_buf, 0, sizeof(e_buf)); - return ret; -} - -int DCRYPTO_rsa_decrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len, - const uint8_t *in, const uint32_t in_len, - enum padding_mode padding, enum hashing_mode hashing, - const char *label) -{ - uint32_t encrypted_buf[RSA_MAX_WORDS]; - uint32_t padded_buf[RSA_MAX_WORDS]; - - struct LITE_BIGNUM encrypted; - struct LITE_BIGNUM padded; - int ret; - - if (!check_modulus_params(&rsa->N, sizeof(padded_buf), NULL)) - return 0; - if (in_len != bn_size(&rsa->N)) - return 0; /* Invalid input length. */ - - /* TODO(ngm): this copy can be eliminated if input may be modified. */ - bn_init(&encrypted, encrypted_buf, in_len); - memcpy(encrypted_buf, in, in_len); - bn_init(&padded, padded_buf, in_len); - - /* Reverse from big-endian to little-endian notation. */ - reverse((uint8_t *) encrypted.d, encrypted.dmax * LITE_BN_BYTES); - ret = bn_modexp_blinded(&padded, &encrypted, &rsa->d, &rsa->N, rsa->e); - /* Back to big-endian notation. */ - reverse((uint8_t *) padded.d, padded.dmax * LITE_BN_BYTES); - - switch (padding) { - case PADDING_MODE_OAEP: - if (!check_oaep_pad(out, out_len, (uint8_t *) padded.d, - bn_size(&padded), hashing, label)) - ret = 0; - break; - case PADDING_MODE_PKCS1: - if (!check_pkcs1_type2_pad( - out, out_len, (const uint8_t *) padded.d, - bn_size(&padded))) - ret = 0; - break; - case PADDING_MODE_NULL: - if (*out_len < bn_size(&padded)) { - ret = 0; - } else { - *out_len = bn_size(&padded); - memcpy(out, padded.d, *out_len); - } - break; - default: - /* Unsupported padding mode. */ - ret = 0; - break; - } - - always_memset(encrypted_buf, 0, sizeof(encrypted_buf)); - always_memset(padded_buf, 0, sizeof(padded_buf)); - return ret; -} - -int DCRYPTO_rsa_sign(struct RSA *rsa, uint8_t *out, uint32_t *out_len, - const uint8_t *in, const uint32_t in_len, - enum padding_mode padding, enum hashing_mode hashing) -{ - uint32_t padded_buf[RSA_MAX_WORDS]; - - struct LITE_BIGNUM padded; - struct LITE_BIGNUM signature; - int ret; - - if (!check_modulus_params(&rsa->N, sizeof(padded_buf), out_len)) - return 0; - - bn_init(&padded, padded_buf, bn_size(&rsa->N)); - bn_init(&signature, out, bn_size(&rsa->N)); - - switch (padding) { - case PADDING_MODE_PKCS1: - if (!pkcs1_type1_pad((uint8_t *) padded.d, bn_size(&padded), - (const uint8_t *) in, in_len, hashing)) - return 0; - break; - case PADDING_MODE_PSS: - if (!pkcs1_pss_pad((uint8_t *) padded.d, bn_size(&padded), - (const uint8_t *) in, in_len, hashing)) - return 0; - break; - default: - return 0; - } - - /* Reverse from big-endian to little-endian notation. */ - reverse((uint8_t *) padded.d, bn_size(&padded)); - ret = bn_modexp_blinded(&signature, &padded, &rsa->d, &rsa->N, rsa->e); - /* Back to big-endian notation. */ - reverse((uint8_t *) signature.d, bn_size(&signature)); - *out_len = bn_size(&rsa->N); - - always_memset(padded_buf, 0, sizeof(padded_buf)); - return ret; -} - -int DCRYPTO_rsa_verify(const struct RSA *rsa, const uint8_t *digest, - uint32_t digest_len, const uint8_t *sig, - const uint32_t sig_len, enum padding_mode padding, - enum hashing_mode hashing) -{ - uint32_t padded_buf[RSA_WORDS_4K]; - uint32_t signature_buf[RSA_WORDS_4K]; - - struct LITE_BIGNUM padded; - struct LITE_BIGNUM signature; - int ret; - - if (!check_modulus_params(&rsa->N, sizeof(padded_buf), NULL)) - return 0; - if (sig_len != bn_size(&rsa->N)) - return 0; /* Invalid input length. */ - - bn_init(&signature, signature_buf, bn_size(&rsa->N)); - memcpy(signature_buf, sig, bn_size(&rsa->N)); - bn_init(&padded, padded_buf, bn_size(&rsa->N)); - - /* Reverse from big-endian to little-endian notation. */ - reverse((uint8_t *) signature.d, bn_size(&signature)); - ret = bn_modexp_word(&padded, &signature, rsa->e, &rsa->N); - /* Back to big-endian notation. */ - reverse((uint8_t *) padded.d, bn_size(&padded)); - - switch (padding) { - case PADDING_MODE_PKCS1: - if (!check_pkcs1_type1_pad( - digest, digest_len, (uint8_t *) padded.d, - bn_size(&padded), hashing)) - ret = 0; - break; - case PADDING_MODE_PSS: - if (!check_pkcs1_pss_pad( - digest, digest_len, (uint8_t *) padded.d, - bn_size(&padded), hashing)) - ret = 0; - break; - default: - /* Unsupported padding mode. */ - ret = 0; - break; - } - - always_memset(padded_buf, 0, sizeof(padded_buf)); - always_memset(signature_buf, 0, sizeof(signature_buf)); - return ret; -} - -int DCRYPTO_rsa_key_compute(struct LITE_BIGNUM *N, struct LITE_BIGNUM *d, - struct LITE_BIGNUM *p, struct LITE_BIGNUM *q, - uint32_t e_buf) -{ - uint32_t ONE_buf = 1; - uint32_t phi_buf[RSA_MAX_WORDS]; - uint32_t q_buf[RSA_MAX_WORDS / 2 + 1]; - - struct LITE_BIGNUM ONE; - struct LITE_BIGNUM e; - struct LITE_BIGNUM phi; - struct LITE_BIGNUM q_local; - - DCRYPTO_bn_wrap(&ONE, &ONE_buf, sizeof(ONE_buf)); - DCRYPTO_bn_wrap(&phi, phi_buf, bn_size(N)); - if (!q) { - /* q not provided, calculate it. */ - memcpy(phi_buf, N->d, bn_size(N)); - bn_init(&q_local, q_buf, bn_size(p)); - q = &q_local; - - if (!DCRYPTO_bn_div(q, NULL, &phi, p)) - return 0; - - /* Check that p * q == N */ - DCRYPTO_bn_mul(&phi, p, q); - if (!bn_eq(N, &phi)) - return 0; - } else { - DCRYPTO_bn_mul(N, p, q); - memcpy(phi_buf, N->d, bn_size(N)); - } - - bn_sub(&phi, p); - bn_sub(&phi, q); - bn_add(&phi, &ONE); - DCRYPTO_bn_wrap(&e, &e_buf, sizeof(e_buf)); - return bn_modinv_vartime(d, &e, &phi); -} diff --git a/chip/g/dcrypto/sha1.c b/chip/g/dcrypto/sha1.c deleted file mode 100644 index 07ef3a34ef..0000000000 --- a/chip/g/dcrypto/sha1.c +++ /dev/null @@ -1,65 +0,0 @@ -/* 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 "cryptoc/sha.h" - -static void dcrypto_sha1_init(SHA_CTX *ctx); -static const uint8_t *dcrypto_sha1_final(SHA_CTX *unused); - -/* - * Hardware SHA implementation. - */ -static const HASH_VTAB HW_SHA1_VTAB = { - dcrypto_sha1_init, - dcrypto_sha_update, - dcrypto_sha1_final, - DCRYPTO_SHA1_hash, - SHA_DIGEST_SIZE -}; - -/* Requires dcrypto_grab_sha_hw() to be called first. */ -static void dcrypto_sha1_init(SHA_CTX *ctx) -{ - ctx->f = &HW_SHA1_VTAB; - dcrypto_sha_init(SHA1_MODE); -} - -/* 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(SHA_CTX *ctx, uint32_t sw_required) -{ - if (!sw_required && dcrypto_grab_sha_hw()) - dcrypto_sha1_init(ctx); - else - SHA_init(ctx); -} - -static const uint8_t *dcrypto_sha1_final(SHA_CTX *ctx) -{ - dcrypto_sha_wait(SHA1_MODE, (uint32_t *) ctx->buf); - return ctx->buf; -} - -const uint8_t *DCRYPTO_SHA1_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(SHA1_MODE, data, n, digest); - else - SHA_hash(data, n, digest); - return digest; -} diff --git a/chip/g/dcrypto/sha256.c b/chip/g/dcrypto/sha256.c deleted file mode 100644 index f127ab445a..0000000000 --- a/chip/g/dcrypto/sha256.c +++ /dev/null @@ -1,195 +0,0 @@ -/* 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" - -#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) -{ - 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) ? - 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(); -} - -/* 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) -{ - 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 void *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) -{ - 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; -} - -static void dcrypto_sha256_init(LITE_SHA256_CTX *ctx) -{ - ctx->f = &HW_SHA256_VTAB; - dcrypto_sha_init(SHA256_MODE); -} - -/* 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 -} - -static const uint8_t *dcrypto_sha256_final(LITE_SHA256_CTX *ctx) -{ - dcrypto_sha_wait(SHA256_MODE, (uint32_t *) ctx->buf); - return ctx->buf; -} - -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 - return digest; -} diff --git a/chip/g/dcrypto/sha384.c b/chip/g/dcrypto/sha384.c deleted file mode 100644 index 6f3c6ca096..0000000000 --- a/chip/g/dcrypto/sha384.c +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright 2016 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 "cryptoc/sha384.h" - -void DCRYPTO_SHA384_init(LITE_SHA512_CTX *ctx) -{ - SHA384_init(ctx); -} - -const uint8_t *DCRYPTO_SHA384_hash(const void *data, uint32_t n, - uint8_t *digest) -{ - return SHA384_hash(data, n, digest); -} diff --git a/chip/g/dcrypto/sha512.c b/chip/g/dcrypto/sha512.c deleted file mode 100644 index 1446970174..0000000000 --- a/chip/g/dcrypto/sha512.c +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright 2016 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 "cryptoc/sha512.h" - -void DCRYPTO_SHA512_init(LITE_SHA512_CTX *ctx) -{ - SHA512_init(ctx); -} - -const uint8_t *DCRYPTO_SHA512_hash(const void *data, uint32_t n, - uint8_t *digest) -{ - return SHA512_hash(data, n, digest); -} diff --git a/chip/g/dcrypto/x509.c b/chip/g/dcrypto/x509.c deleted file mode 100644 index 81f1674db1..0000000000 --- a/chip/g/dcrypto/x509.c +++ /dev/null @@ -1,545 +0,0 @@ -/* Copyright 2016 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 - -/* Limit the size of long form encoded objects to < 64 kB. */ -#define MAX_ASN1_OBJ_LEN_BYTES 3 - -/* Reserve space for TLV encoding */ -#define SEQ_SMALL 2 /* < 128 bytes (1B type, 1B 7-bit length) */ -#define SEQ_MEDIUM 3 /* < 256 bytes (1B type, 1B length size, 1B length) */ -#define SEQ_LARGE 4 /* < 65536 bytes (1B type, 1B length size, 2B length) */ - -/* Tag related constants. */ -enum { - V_ASN1_INT = 0x02, - V_ASN1_BIT_STRING = 0x03, - V_ASN1_BYTES = 0x04, - V_ASN1_OBJ = 0x06, - V_ASN1_UTF8 = 0x0c, - V_ASN1_SEQUENCE = 0x10, - V_ASN1_SET = 0x11, - V_ASN1_ASCII = 0x13, - V_ASN1_TIME = 0x18, - V_ASN1_CONSTRUCTED = 0x20, - /* short helpers */ - V_BITS = V_ASN1_BIT_STRING, - V_SEQ = V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE, - V_SET = V_ASN1_CONSTRUCTED | V_ASN1_SET, -}; - -struct asn1 { - uint8_t *p; - size_t n; -}; - - -#define SEQ_START(X, T, L) \ - do { \ - int __old = (X).n; \ - uint8_t __t = (T); \ - int __l = (L); \ - (X).n += __l; -#define SEQ_END(X) \ - (X).n = asn1_seq((X).p + __old, __t, __l, (X).n - __old - __l) + __old;\ - } \ - while (0) - -/* The SHA256 OID, from https://tools.ietf.org/html/rfc5754#section-3.2 - * Only the object bytes below, the DER encoding header ([0x30 0x0d]) - * is verified by the parser. */ -static const uint8_t OID_SHA256_WITH_RSA_ENCRYPTION[13] = { - 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, - 0x01, 0x01, 0x0b, 0x05, 0x00 -}; -static const uint8_t OID_commonName[3] = {0x55, 0x04, 0x03}; -static const uint8_t OID_ecdsa_with_SHA256[8] = {0x2A, 0x86, 0x48, 0xCE, - 0x3D, 0x04, 0x03, 0x02}; -static const uint8_t OID_id_ecPublicKey[7] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, - 0x02, 0x01}; -static const uint8_t OID_prime256v1[8] = {0x2A, 0x86, 0x48, 0xCE, - 0x3D, 0x03, 0x01, 0x07}; -static const uint8_t OID_fido_u2f[11] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, - 0xE5, 0x1C, 0x02, 0x01, 0x01}; -#define OID(X) sizeof(OID_##X), OID_##X - -/* ---- ASN.1 Generation ---- */ - -/* start a tag and return write ptr */ -static uint8_t *asn1_tag(struct asn1 *ctx, uint8_t tag) -{ - ctx->p[(ctx->n)++] = tag; - return ctx->p + ctx->n; -} - -/* DER encode length and return encoded size thereof */ -static int asn1_len(uint8_t *p, size_t size) -{ - if (size < 128) { - p[0] = size; - return 1; - } else if (size < 256) { - p[0] = 0x81; - p[1] = size; - return 2; - } else { - p[0] = 0x82; - p[1] = size >> 8; - p[2] = size; - return 3; - } -} - -/* - * close sequence and move encapsulated data if needed - * return total length. - */ -static size_t asn1_seq(uint8_t *p, uint8_t tag, size_t l, size_t size) -{ - size_t tl; - - p[0] = tag; - tl = asn1_len(p + 1, size) + 1; - /* TODO: tl > l fail */ - if (tl < l) - memmove(p + tl, p + l, size); - - return tl + size; -} - -/* DER encode (small positive) integer */ -static void asn1_int(struct asn1 *ctx, uint32_t val) -{ - uint8_t *p = asn1_tag(ctx, V_ASN1_INT); - - if (!val) { - *p++ = 1; - *p++ = 0; - } else { - int nbits = 32 - __builtin_clz(val); - int nbytes = (nbits + 7) / 8; - - if ((nbits & 7) == 0) { - *p++ = nbytes + 1; - *p++ = 0; - } else { - *p++ = nbytes; - } - while (nbytes--) - *p++ = val >> (nbytes * 8); - } - - ctx->n = p - ctx->p; -} - -/* DER encode positive p256_int */ -static void asn1_p256_int(struct asn1 *ctx, const p256_int *n) -{ - uint8_t *p = asn1_tag(ctx, V_ASN1_INT); - uint8_t bn[P256_NBYTES]; - int i; - - p256_to_bin(n, bn); - for (i = 0; i < P256_NBYTES; ++i) { - if (bn[i] != 0) - break; - } - if (bn[i] & 0x80) { - *p++ = P256_NBYTES - i + 1; - *p++ = 0; - } else { - *p++ = P256_NBYTES - i; - } - for (; i < P256_NBYTES; ++i) - *p++ = bn[i]; - - ctx->n = p - ctx->p; -} - -/* DER encode p256 signature */ -static void asn1_sig(struct asn1 *ctx, const p256_int *r, const p256_int *s) -{ - SEQ_START(*ctx, V_SEQ, SEQ_SMALL) { - asn1_p256_int(ctx, r); - asn1_p256_int(ctx, s); - } - SEQ_END(*ctx); -} - -/* DER encode printable string */ -static void asn1_string(struct asn1 *ctx, uint8_t tag, const char *s) -{ - uint8_t *p = asn1_tag(ctx, tag); - size_t n = strlen(s); - - p += asn1_len(p, n); - while (n--) - *p++ = *s++; - - ctx->n = p - ctx->p; -} - -/* DER encode bytes */ -static void asn1_object(struct asn1 *ctx, size_t n, const uint8_t *b) -{ - uint8_t *p = asn1_tag(ctx, V_ASN1_OBJ); - - p += asn1_len(p, n); - while (n--) - *p++ = *b++; - - ctx->n = p - ctx->p; -} - -/* DER encode p256 pk */ -static void asn1_pub(struct asn1 *ctx, const p256_int *x, const p256_int *y) -{ - uint8_t *p = asn1_tag(ctx, 4); /* uncompressed format */ - - p256_to_bin(x, p); p += P256_NBYTES; - p256_to_bin(y, p); p += P256_NBYTES; - - ctx->n = p - ctx->p; -} - -size_t DCRYPTO_asn1_sigp(uint8_t *buf, const p256_int *r, const p256_int *s) -{ - struct asn1 asn1 = {buf, 0}; - - asn1_sig(&asn1, r, s); - return asn1.n; -} - -size_t DCRYPTO_asn1_pubp(uint8_t *buf, const p256_int *x, const p256_int *y) -{ - struct asn1 asn1 = {buf, 0}; - - asn1_pub(&asn1, x, y); - return asn1.n; -} - -/* ---- ASN.1 Parsing ---- */ - -/* - * An ASN.1 DER (Definite Encoding Rules) parser. - * Details about the format are available here: - * https://en.wikipedia.org/wiki/X.690#Definite_form - */ -static size_t asn1_parse(const uint8_t **p, size_t available, - uint8_t expected_type, const uint8_t **out, - size_t *out_len, size_t *remaining) -{ - const size_t tag_len = 1; - const uint8_t *in = *p; - size_t obj_len = 0; - size_t obj_len_bytes; - size_t consumed; - - if (available < 2) - return 0; - if (in[0] != expected_type) /* in[0] specifies the tag. */ - return 0; - - if ((in[1] & 128) == 0) { - /* Short-length encoding (i.e. obj_len <= 127). */ - obj_len = in[1]; - obj_len_bytes = 1; - } else { - int i; - - obj_len_bytes = 1 + (in[1] & 127); - if (obj_len_bytes > MAX_ASN1_OBJ_LEN_BYTES || - tag_len + obj_len_bytes > available) - return 0; - - if (in[2] == 0) - /* Definite form encoding requires minimal - * length encoding. */ - return 0; - for (i = 0; i < obj_len_bytes - 1; i++) { - obj_len <<= 8; - obj_len |= in[tag_len + 1 + i]; - } - } - - consumed = tag_len + obj_len_bytes + obj_len; - if (consumed > available) - return 0; /* Invalid object length.*/ - if (out) - *out = &in[tag_len + obj_len_bytes]; - if (out_len) - *out_len = obj_len; - - *p = in + consumed; - if (remaining) - *remaining = available - consumed; - return consumed; -} - -static size_t asn1_parse_certificate(const uint8_t **p, size_t *available) -{ - size_t consumed; - size_t obj_len; - const uint8_t *in = *p; - - consumed = asn1_parse(&in, *available, - V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE, - NULL, &obj_len, NULL); - if (consumed == 0 || consumed != *available) /* Invalid SEQUENCE. */ - return 0; - *p += consumed - obj_len; - *available -= consumed - obj_len; - return 1; -} - -static size_t asn1_parse_tbs(const uint8_t **p, size_t *available, - size_t *tbs_len) -{ - size_t consumed; - - consumed = asn1_parse(p, *available, - V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE, - NULL, NULL, available); - if (consumed == 0) - return 0; - *tbs_len = consumed; - return 1; -} - -static size_t asn1_parse_signature_algorithm(const uint8_t **p, - size_t *available) -{ - const uint8_t *alg_oid; - size_t alg_oid_len; - - if (!asn1_parse(p, *available, V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE, - &alg_oid, &alg_oid_len, available)) - return 0; - if (alg_oid_len != sizeof(OID_SHA256_WITH_RSA_ENCRYPTION)) - return 0; - if (memcmp(alg_oid, OID_SHA256_WITH_RSA_ENCRYPTION, - sizeof(OID_SHA256_WITH_RSA_ENCRYPTION)) != 0) - return 0; - return 1; -} - -static size_t asn1_parse_signature_value(const uint8_t **p, size_t *available, - const uint8_t **sig, size_t *sig_len) -{ - if (!asn1_parse(p, *available, V_ASN1_BIT_STRING, - sig, sig_len, available)) - return 0; - if (*available != 0) - return 0; /* Not all input bytes consumed. */ - return 1; -} - -/* This method verifies that the provided X509 certificate was issued - * by the specified certifcate authority. - * - * cert is a pointer to a DER encoded X509 certificate, as specified - * in https://tools.ietf.org/html/rfc5280#section-4.1. In ASN.1 - * notation, the certificate has the following structure: - * - * Certificate ::= SEQUENCE { - * tbsCertificate TBSCertificate, - * signatureAlgorithm AlgorithmIdentifier, - * signatureValue BIT STRING } - * - * TBSCertificate ::= SEQUENCE { } - * AlgorithmIdentifier ::= SEQUENCE { } - * - * where signatureValue = SIGN(HASH(tbsCertificate)), with SIGN and - * HASH specified by signatureAlgorithm. - */ -int DCRYPTO_x509_verify(const uint8_t *cert, size_t len, - const struct RSA *ca_pub_key) -{ - const uint8_t *p = cert; - const uint8_t *tbs; - size_t tbs_len; - const uint8_t *sig; - size_t sig_len; - - uint8_t digest[SHA256_DIGEST_SIZE]; - - /* Read Certificate SEQUENCE. */ - if (!asn1_parse_certificate(&p, &len)) - return 0; - - /* Read tbsCertificate SEQUENCE. */ - tbs = p; - if (!asn1_parse_tbs(&p, &len, &tbs_len)) - return 0; - - /* Read signatureAlgorithm SEQUENCE. */ - if (!asn1_parse_signature_algorithm(&p, &len)) - return 0; - - /* Read signatureValue BIT STRING. */ - if (!asn1_parse_signature_value(&p, &len, &sig, &sig_len)) - return 0; - - /* Check that the signature length corresponds to the issuer's - * public key size. */ - if (sig_len != bn_size(&ca_pub_key->N) && - sig_len != bn_size(&ca_pub_key->N) + 1) - return 0; - /* Check that leading signature bytes (if any) are zero. */ - if (sig_len == bn_size(&ca_pub_key->N) + 1) { - if (sig[0] != 0) - return 0; - sig++; - sig_len--; - } - - DCRYPTO_SHA256_hash(tbs, tbs_len, digest); - return DCRYPTO_rsa_verify(ca_pub_key, digest, sizeof(digest), - sig, sig_len, PADDING_MODE_PKCS1, HASH_SHA256); -} - -/* ---- Certificate generation ---- */ - -static void add_common_name(struct asn1 *ctx, const char *cname) -{ - SEQ_START(*ctx, V_SEQ, SEQ_SMALL) { - SEQ_START(*ctx, V_SET, SEQ_SMALL) { - SEQ_START(*ctx, V_SEQ, SEQ_SMALL) { - asn1_object(ctx, OID(commonName)); - asn1_string(ctx, V_ASN1_ASCII, cname); - } - SEQ_END(*ctx); - } - SEQ_END(*ctx); - } - SEQ_END(*ctx); -} - -int DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x, - const p256_int *pk_y, const p256_int *serial, - const char *name, uint8_t *cert, const int n) -{ - struct asn1 ctx = {cert, 0}; - HASH_CTX sha; - p256_int h, r, s; - struct drbg_ctx drbg; - - SEQ_START(ctx, V_SEQ, SEQ_LARGE) { /* outer seq */ - /* - * Grab current pointer to data to hash later. - * Note this will fail if cert body + cert sign is less - * than 256 bytes (SEQ_MEDIUM) -- not likely. - */ - uint8_t *body = ctx.p + ctx.n; - - /* Cert body seq */ - SEQ_START(ctx, V_SEQ, SEQ_MEDIUM) { - /* X509 v3 */ - SEQ_START(ctx, 0xa0, SEQ_SMALL) { - asn1_int(&ctx, 2); - } - SEQ_END(ctx); - - /* Serial number */ - if (serial) - asn1_p256_int(&ctx, serial); - else - asn1_int(&ctx, 1); - - /* Signature algo */ - SEQ_START(ctx, V_SEQ, SEQ_SMALL) { - asn1_object(&ctx, OID(ecdsa_with_SHA256)); - } - SEQ_END(ctx); - - /* Issuer */ - add_common_name(&ctx, name); - - /* Expiry */ - SEQ_START(ctx, V_SEQ, SEQ_SMALL) { - asn1_string(&ctx, V_ASN1_TIME, "20000101000000Z"); - asn1_string(&ctx, V_ASN1_TIME, "20991231235959Z"); - } - SEQ_END(ctx); - - /* Subject */ - add_common_name(&ctx, name); - - /* Subject pk */ - SEQ_START(ctx, V_SEQ, SEQ_SMALL) { - /* pk parameters */ - SEQ_START(ctx, V_SEQ, SEQ_SMALL) { - asn1_object(&ctx, OID(id_ecPublicKey)); - asn1_object(&ctx, OID(prime256v1)); - } - SEQ_END(ctx); - /* pk bits */ - SEQ_START(ctx, V_BITS, SEQ_SMALL) { - /* No unused bit at the end */ - asn1_tag(&ctx, 0); - asn1_pub(&ctx, pk_x, pk_y); - } - SEQ_END(ctx); - } - SEQ_END(ctx); - - /* U2F transports indicator extension */ - SEQ_START(ctx, 0xa3, SEQ_SMALL) { - SEQ_START(ctx, V_SEQ, SEQ_SMALL) { - SEQ_START(ctx, V_SEQ, SEQ_SMALL) { - asn1_object(&ctx, OID(fido_u2f)); - SEQ_START(ctx, V_ASN1_BYTES, SEQ_SMALL) { - SEQ_START(ctx, V_BITS, SEQ_SMALL) { - /* 3 zero bits */ - asn1_tag(&ctx, 3); - /* usb-internal transport */ - asn1_tag(&ctx, 0x08); - } - SEQ_END(ctx); - } - SEQ_END(ctx); - } - SEQ_END(ctx); - } - SEQ_END(ctx); - } - SEQ_END(ctx); - } - SEQ_END(ctx); /* Cert body */ - - /* Sign all of cert body */ - DCRYPTO_SHA256_init(&sha, 0); - HASH_update(&sha, body, (ctx.p + ctx.n) - body); - p256_from_bin(HASH_final(&sha), &h); - hmac_drbg_init_rfc6979(&drbg, d, &h); - if (!dcrypto_p256_ecdsa_sign(&drbg, d, &h, &r, &s)) - return 0; - - /* Append X509 signature */ - SEQ_START(ctx, V_SEQ, SEQ_SMALL); - asn1_object(&ctx, OID(ecdsa_with_SHA256)); - SEQ_END(ctx); - SEQ_START(ctx, V_BITS, SEQ_SMALL) { - /* no unused/zero bit at the end */ - asn1_tag(&ctx, 0); - asn1_sig(&ctx, &r, &s); - } SEQ_END(ctx); - - } SEQ_END(ctx); /* end of outer seq */ - - return ctx.n; -} - -int DCRYPTO_x509_gen_u2f_cert(const p256_int *d, const p256_int *pk_x, - const p256_int *pk_y, const p256_int *serial, - uint8_t *cert, const int n) -{ - return DCRYPTO_x509_gen_u2f_cert_name(d, pk_x, pk_y, serial, - serial ? STRINGIFY(BOARD) : "U2F", - cert, n); -} diff --git a/chip/g/trng.c b/chip/g/trng.c deleted file mode 100644 index 94363b29c4..0000000000 --- a/chip/g/trng.c +++ /dev/null @@ -1,236 +0,0 @@ -/* 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 "common.h" -#include "flash_log.h" -#include "init_chip.h" -#include "registers.h" -#include "trng.h" -#include "watchdog.h" -#include "console.h" - -/** - * The H1 TRNG uses the collapse time of a ring oscillator (RO) that is - * initialized in a 3x mode (three enable pulses) and eventually collapses - * to a stable 1x mode as a result of accumulated jitter (thermal noise). - * A Phase-Frequency Detector (PFD) compares the 3x RO to a reference - * RO (1.5x) and captures the state of a counter that is incremented - * from the reference RO. The resulting reference-cycles-to-collapse - * distribution is log-normal, and truncation of the counter bits results in - * a distribution that approaches uniform. - * - * TRNG_SAMPLE_BITS defines how many bits to use from the 16 bit counter - * output coming from the analog unit. Entropy is highest in least significant - * bits of counter. For FIPS-certified code use just Bit 0 - it provides - * highest entropy, allows better security settings for TRNG and simplifies - * implementation of continuous health tests. - */ -#ifndef TRNG_SAMPLE_BITS -#define TRNG_SAMPLE_BITS 1 -#endif - -/** - * Attempts to read TRNG_EMPTY before reporting a stall. Practically data should - * be available in less than 0x7ff cycles under normal conditions. 0x7ff was - * chosen to match the hardware TRNG TIMEOUT_COUNTER. Test on boards with slow - * TRNG before reducing this number. - */ -#define TRNG_EMPTY_COUNT 0x7ff - -void init_trng(void) -{ -#if (!(defined(CONFIG_CUSTOMIZED_RO) && defined(SECTION_IS_RO))) - /* - * Most of the trng initialization requires high permissions. If RO has - * dropped the permission level, dont try to read or write these high - * permission registers because it will cause rolling reboots. RO - * should do the TRNG initialization before dropping the level. - */ - if (!runlevel_is_high()) - return; -#endif - /** - * According to NIST SP 800-90B only vetted conditioning mechanism - * should be used for post-processing raw entropy. - * See SP 800-90B, 3.1.5.1 Using Vetted Conditioning Components. - * Use of non-vetted algorithms is governed in 3.1.5.2, but - * assumes conservative coefficient 0.85 for entropy estimate, - * which increase number of requests to TRNG to get desirable - * entropy and prevents from getting full entropy. - */ - GWRITE(TRNG, POST_PROCESSING_CTRL, 0); - - /** - * TRNG can return up to 16 bits at a time, but highest bits - * have lower entropy. Practically on Cr50 only 13 bits can be - * used - setting to higher value makes TRNG_EMPTY always set. - * Entropy assessed to be reasonable (one bit H > 0.85) - * for up to 8 bits [7..0]. - * Time to get 32bit random is roughly 160/TRNG_SAMPLE_BITS us. - */ - GWRITE(TRNG, SLICE_MAX_UPPER_LIMIT, TRNG_SAMPLE_BITS - 1); - - /* lowest bit have highest entropy, so always start from it */ - GWRITE(TRNG, SLICE_MIN_LOWER_LIMIT, 0); - - /** - * Analog logic cannot create a value < 8 under normal operating - * conditions, but there's a chance that an attacker could coax - * them out. - * Bit 0 - Enable rejection for values outside of range specified - * by TRNG_ALLOWED_VALUES register - */ - GWRITE(TRNG, SECURE_POST_PROCESSING_CTRL, 0x1); - - /** - * Since for FIPS settings we use TRNG_SAMPLE_BITS = 1, - * and take only bit 0 from internal 16 bit reading, no bias is - * created for bit 0 if allowed_min is set to 6, which - * actually means min accepted value is 8 (RTL adds +2). - * TRNG_ALLOWED_VALUES_MAX=0x04 (accept all values up to 2^16-1). - * So, range will be [8..65535], with probability for bit 0 and 1 - * remaining 50/50. - */ - GWRITE(TRNG, ALLOWED_VALUES_MIN, 0x26); - - GWRITE(TRNG, TIMEOUT_COUNTER, 0x7ff); - GWRITE(TRNG, TIMEOUT_MAX_TRY_NUM, 4); - GWRITE(TRNG, POWER_DOWN_B, 1); - GWRITE(TRNG, GO_EVENT, 1); -} - -uint32_t rand(void) -{ uint32_t empty_count = 0; - - while (GREAD(TRNG, EMPTY)) { - if (GREAD_FIELD(TRNG, FSM_STATE, FSM_IDLE) || - empty_count > TRNG_EMPTY_COUNT) { - /* TRNG timed out, restart */ - GWRITE(TRNG, STOP_WORK, 1); -#if !defined(SECTION_IS_RO) && defined(CONFIG_FLASH_LOG) - flash_log_add_event(FE_LOG_TRNG_STALL, 0, NULL); -#endif - GWRITE(TRNG, GO_EVENT, 1); - empty_count = 0; - } - empty_count++; - } - return GREAD(TRNG, READ_DATA); -} - -void rand_bytes(void *buffer, size_t len) -{ - int random_togo = 0; - int buffer_index = 0; - uint32_t random_value; - uint8_t *buf = (uint8_t *) buffer; - - /* - * Retrieve random numbers in 4 byte quantities and pack as many bytes - * as needed into 'buffer'. If len is not divisible by 4, the - * remaining random bytes get dropped. - */ - while (buffer_index < len) { - if (!random_togo) { - random_value = rand(); - random_togo = sizeof(random_value); - } - buf[buffer_index++] = random_value >> - ((random_togo-- - 1) * 8); - } -} - -#if !defined(SECTION_IS_RO) && defined(CRYPTO_TEST_SETUP) -#include "console.h" -#include "watchdog.h" - -static void print_rand_stat(uint32_t *histogram, size_t size) -{ - struct pair { - uint32_t value; - uint32_t count; - }; - struct pair min; - struct pair max; - size_t count; - - min.count = ~0; - max.count = 0; - max.value = ~0; - min.value = ~0; - - for (count = 0; count < size; count++) { - if (histogram[count] > max.count) { - max.count = histogram[count]; - max.value = count; - } - if (histogram[count] < min.count) { - min.count = histogram[count]; - min.value = count; - } - } - - ccprintf("min %d(%d), max %d(%d)", min.count, min.value, - max.count, max.value); - - for (count = 0; count < size; count++) { - if (!(count % 8)) { - ccprintf("\n"); - cflush(); - } - ccprintf(" %6d", histogram[count]); - } - ccprintf("\n"); -} - -/* histogram at byte level */ -static uint32_t histogram[256]; -/* histogram at level of TRNG samples */ -static uint32_t histogram_trng[1 << TRNG_SAMPLE_BITS]; - -static int command_rand(int argc, char **argv) -{ - int count = 1000; /* Default number of cycles. */ - uint32_t val = 0, bits = 0; - - if (argc == 2) - count = strtoi(argv[1], NULL, 10); - - memset(histogram, 0, sizeof(histogram)); - memset(histogram_trng, 0, sizeof(histogram_trng)); - ccprintf("Retrieving %d 32-bit random words.\n", count); - while (count-- > 0) { - uint32_t rvalue; - int size; - - rvalue = rand(); - /* update byte-level histogram */ - for (size = 0; size < sizeof(rvalue); size++) - histogram[((uint8_t *)&rvalue)[size]]++; - - /* update histogram on TRNG sample size level */ - val = (val | (rvalue << bits)) & ((1 << TRNG_SAMPLE_BITS) - 1); - rvalue >>= TRNG_SAMPLE_BITS - bits; - bits += 32; - while (bits >= TRNG_SAMPLE_BITS) { - histogram_trng[val]++; - val = rvalue & ((1 << TRNG_SAMPLE_BITS) - 1); - rvalue >>= TRNG_SAMPLE_BITS; - bits -= TRNG_SAMPLE_BITS; - }; - - if (!(count % 10000)) - watchdog_reload(); - } - ccprintf("Byte-level histogram:\n"); - print_rand_stat(histogram, ARRAY_SIZE(histogram)); - ccprintf("\nSample-level (%d bits) histogram:\n", TRNG_SAMPLE_BITS); - print_rand_stat(histogram_trng, ARRAY_SIZE(histogram_trng)); - - return EC_SUCCESS; -} -DECLARE_SAFE_CONSOLE_COMMAND(rand, command_rand, NULL, NULL); - -#endif /* CRYPTO_TEST_SETUP */ -- cgit v1.2.1 From 750140eb3c43026675216bb13ab0deed701af37c Mon Sep 17 00:00:00 2001 From: Josip Sokcevic Date: Thu, 17 Jun 2021 14:12:54 -0700 Subject: Restore chip/g/dcrypto Signed-off-by: Josip Sokcevic --- chip/g/dcrypto/aes.c | 160 ++++ chip/g/dcrypto/aes_cmac.c | 346 +++++++++ chip/g/dcrypto/app_cipher.c | 451 ++++++++++++ chip/g/dcrypto/app_key.c | 87 +++ chip/g/dcrypto/bn.c | 1244 +++++++++++++++++++++++++++++++ chip/g/dcrypto/compare.c | 20 + chip/g/dcrypto/dcrypto.h | 445 ++++++++++++ chip/g/dcrypto/dcrypto_bn.c | 1496 ++++++++++++++++++++++++++++++++++++++ chip/g/dcrypto/dcrypto_p256.c | 1018 ++++++++++++++++++++++++++ chip/g/dcrypto/dcrypto_runtime.c | 480 ++++++++++++ chip/g/dcrypto/dcrypto_sha512.c | 772 ++++++++++++++++++++ chip/g/dcrypto/gcm.c | 345 +++++++++ chip/g/dcrypto/hkdf.c | 83 +++ chip/g/dcrypto/hmac.c | 63 ++ chip/g/dcrypto/hmac_drbg.c | 478 ++++++++++++ chip/g/dcrypto/internal.h | 219 ++++++ chip/g/dcrypto/key_ladder.c | 300 ++++++++ chip/g/dcrypto/p256.c | 30 + chip/g/dcrypto/p256_ec.c | 39 + chip/g/dcrypto/p256_ecies.c | 175 +++++ chip/g/dcrypto/proofs_p256.md | 28 + chip/g/dcrypto/rsa.c | 743 +++++++++++++++++++ chip/g/dcrypto/sha1.c | 65 ++ chip/g/dcrypto/sha256.c | 195 +++++ chip/g/dcrypto/sha384.c | 20 + chip/g/dcrypto/sha512.c | 20 + chip/g/dcrypto/x509.c | 545 ++++++++++++++ chip/g/trng.c | 236 ++++++ 28 files changed, 10103 insertions(+) create mode 100644 chip/g/dcrypto/aes.c create mode 100644 chip/g/dcrypto/aes_cmac.c create mode 100644 chip/g/dcrypto/app_cipher.c create mode 100644 chip/g/dcrypto/app_key.c create mode 100644 chip/g/dcrypto/bn.c create mode 100644 chip/g/dcrypto/compare.c create mode 100644 chip/g/dcrypto/dcrypto.h create mode 100644 chip/g/dcrypto/dcrypto_bn.c create mode 100644 chip/g/dcrypto/dcrypto_p256.c create mode 100644 chip/g/dcrypto/dcrypto_runtime.c create mode 100644 chip/g/dcrypto/dcrypto_sha512.c create mode 100644 chip/g/dcrypto/gcm.c create mode 100644 chip/g/dcrypto/hkdf.c create mode 100644 chip/g/dcrypto/hmac.c create mode 100644 chip/g/dcrypto/hmac_drbg.c create mode 100644 chip/g/dcrypto/internal.h create mode 100644 chip/g/dcrypto/key_ladder.c create mode 100644 chip/g/dcrypto/p256.c create mode 100644 chip/g/dcrypto/p256_ec.c create mode 100644 chip/g/dcrypto/p256_ecies.c create mode 100644 chip/g/dcrypto/proofs_p256.md create mode 100644 chip/g/dcrypto/rsa.c create mode 100644 chip/g/dcrypto/sha1.c create mode 100644 chip/g/dcrypto/sha256.c create mode 100644 chip/g/dcrypto/sha384.c create mode 100644 chip/g/dcrypto/sha512.c create mode 100644 chip/g/dcrypto/x509.c create mode 100644 chip/g/trng.c diff --git a/chip/g/dcrypto/aes.c b/chip/g/dcrypto/aes.c new file mode 100644 index 0000000000..f5cc0e6d8f --- /dev/null +++ b/chip/g/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; +} diff --git a/chip/g/dcrypto/aes_cmac.c b/chip/g/dcrypto/aes_cmac.c new file mode 100644 index 0000000000..4f996f42b6 --- /dev/null +++ b/chip/g/dcrypto/aes_cmac.c @@ -0,0 +1,346 @@ +/* Copyright 2018 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. + */ + +/* AES-CMAC-128 implementation according to NIST SP 800-38B, RFC4493 */ +#include "console.h" +#include "dcrypto.h" + +#define BSIZE 16 /* 16 bytes per 128-bit block */ + +/* Given a 128-bit number in 32-bit chunks, shift to the left by one */ +static void shiftl_1(const uint8_t *in, uint8_t *out) +{ + int i; + uint8_t carry = 0; + + for (i = 15; i >= 0; i--) { + out[i] = in[i] << 1; + out[i] |= carry; + carry = (in[i] & 0x80) ? 1 : 0; + } +} + +static void xor128(const uint32_t in1[4], const uint32_t in2[4], + uint32_t out[4]) +{ + int i; + + for (i = 0; i < 4; i++) + out[i] = in1[i] ^ in2[i]; +} + +static void get_and_xor(const uint8_t *arr, const uint32_t nBytes, int i, + const uint8_t *xor_term, uint8_t *out) +{ + int j; + int k; + + for (j = 0; j < 16; j++) { + k = i*16 + j; /* index in arr */ + if (k < nBytes) + out[j] = arr[k]; + else if (k == nBytes) + out[j] = 0x80; + else + out[j] = 0; + out[j] = out[j] ^ xor_term[j]; + } +} + +/* Wrapper for initializing and calling AES-128 */ +static int aes128(const uint8_t *K, const uint32_t in[4], uint32_t out[4]) +{ + const uint32_t zero[4] = {0, 0, 0, 0}; + + if (!DCRYPTO_aes_init((const uint8_t *)K, 128, (const uint8_t *) zero, + CIPHER_MODE_ECB, ENCRYPT_MODE)) + return 0; + if (!DCRYPTO_aes_block((const uint8_t *) in, (uint8_t *) out)) + return 0; + return 1; +} + +static int gen_subkey(const uint8_t *K, uint32_t k1[4], uint32_t k2[4]) +{ + uint32_t L[4]; + uint32_t tmp[4]; + const uint32_t *xor_term; + static const uint32_t zero[4] = {0, 0, 0, 0}; + static const uint32_t Rb[4] = {0, 0, 0, 0x87000000}; + + if (!aes128(K, zero, L)) + return 0; + + xor_term = (L[0] & 0x00000080) ? Rb : zero; + shiftl_1((const uint8_t *)L, (uint8_t *)tmp); + xor128(tmp, xor_term, k1); + + xor_term = (k1[0] & 0x00000080) ? Rb : zero; + shiftl_1((const uint8_t *) k1, (uint8_t *) tmp); + xor128(tmp, xor_term, k2); + + return 1; +} + +int DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, const uint32_t len, + uint32_t T[4]) +{ + uint32_t n; + int i; + int flag; + uint32_t k1[4]; + uint32_t k2[4]; + uint32_t M_last[4]; + uint32_t Y[4]; + uint32_t X[4] = {0, 0, 0, 0}; + + /* Generate the subkeys K1 and K2 */ + if (!gen_subkey(K, k1, k2)) + return 0; + + /* Set n and flag. + * flag = 1 if the last block has a full 128 bits; 0 otherwise + * n = number of 128-bit blocks in input = ceil (len / BSIZE) + * + * Special case: if len = 0, then n = 1 and flag = 0. + */ + flag = (len % BSIZE == 0) ? 1 : 0; + n = len / BSIZE + (flag ? 0 : 1); // ceil (len / BSIZE) + if (len == 0) { + n = 1; + flag = 0; + } + + /* M_last = padded(last 128-bit block of M) ^ (flag ? k1 : k2) */ + get_and_xor(M, len, n-1, (uint8_t *) (flag ? k1 : k2), + (uint8_t *) M_last); + + for (i = 0; i < n - 1; i++) { + /* Y = padded(nth 128-bit block of M) ^ (flag ? k1 : k2) */ + get_and_xor(M, len, i, (uint8_t *)X, (uint8_t *)Y); + if (!aes128(K, Y, X)) + return 0; + } + + /* TODO: This block is separate from the main loop in the RFC. However, + * if we set M[n-1] = M_last, then it is equivalent to running the loop + * for one more step, which might be a nicer way to write it. + */ + xor128(X, M_last, Y); + if (!aes128(K, Y, T)) + return 0; + return 1; +} + +int DCRYPTO_aes_cmac_verify(const uint8_t *key, const uint8_t *M, const int len, + const uint32_t T[4]) +{ + int i; + uint32_t T2[4]; + int match = 1; + + if (!DCRYPTO_aes_cmac(key, M, len, T2)) + return -EC_ERROR_UNKNOWN; + + for (i = 0; i < 4; i++) { + if (T[i] != T2[i]) + match = 0; + } + return match; +} + +#ifdef CRYPTO_TEST_SETUP +static int check_answer(const uint32_t expected[4], uint32_t actual[4]) +{ + int i; + int success = 1; + + for (i = 0; i < 4; i++) { + if (actual[i] != expected[i]) + success = 0; + } + if (success) { + ccprintf("SUCCESS\n"); + } else { + ccprintf("FAILURE:\n"); + ccprintf("actual = 0x%08x 0x%08x 0x%08x 0x%08x\n", actual[0], + actual[1], actual[2], actual[3]); + ccprintf("expected = 0x%08x 0x%08x 0x%08x 0x%08x\n", + expected[0], expected[1], expected[2], expected[3]); + } + return success; +} + +static int command_test_aes_block(int argc, char **argv) +{ + uint32_t actual[4]; + const uint32_t zero[4] = {0, 0, 0, 0}; + const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09}; + const uint32_t expected[4] = {0x0c6bf77d, 0xb399b81a, 0x47f0423e, + 0x6f541bb9}; + + aes128((const uint8_t *) K, zero, actual); + check_answer(expected, actual); + + return 0; +} + +DECLARE_SAFE_CONSOLE_COMMAND(test_aesbk, command_test_aes_block, NULL, + "Test AES block in AES-CMAC subkey generation"); + +static int command_test_subkey_gen(int argc, char **argv) +{ + uint32_t k1[4]; + uint32_t k2[4]; + /* K: 2b7e1516 28aed2a6 abf71588 09cf4f3c + * k1: fbeed618 35713366 7c85e08f 7236a8de + * k2: f7ddac30 6ae266cc f90bc11e e46d513b + */ + const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09}; + const uint32_t k1e[4] = {0x18d6eefb, 0x66337135, 0x8fe0857c, + 0xdea83672}; + const uint32_t k2e[4] = {0x30acddf7, 0xcc66e26a, 0x1ec10bf9, + 0x3b516de4}; + + gen_subkey((const uint8_t *) K, k1, k2); + + ccprintf("Checking K1: "); + check_answer(k1e, k1); + + ccprintf("Checking K2: "); + check_answer(k2e, k2); + + return 0; +} + +DECLARE_SAFE_CONSOLE_COMMAND(test_skgen, command_test_subkey_gen, NULL, + "Test AES-CMAC subkey generation"); + +struct cmac_test_param { + uint32_t len; + uint8_t *M; + uint32_t Te[4]; +}; + +/* N.B. The order of bytes in each 32-bit block is reversed from the form in + * which they are written in the RFC. + */ +const struct cmac_test_param rfctests[4] = { + /* -------------------------------------------------- + * Example 1: len = 0 + * M + * AES-CMAC bb1d6929 e9593728 7fa37d12 9b756746 + * -------------------------------------------------- + */ + { .len = 0, + .M = (uint8_t *) "", + .Te = {0x29691dbb, 0x283759e9, 0x127da37f, 0x4667759b}, + }, + /* -------------------------------------------------- + * Example 2: len = 16 + * M 6bc1bee2 2e409f96 e93d7e11 7393172a + * AES-CMAC 070a16b4 6b4d4144 f79bdd9d d04a287c + * -------------------------------------------------- + */ + { .len = 16, + .M = (uint8_t *) (uint32_t[]) { + 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373 + }, + .Te = {0xb4160a07, 0x44414d6b, 0x9ddd9bf7, 0x7c284ad0}, + }, + /* -------------------------------------------------- + * Example 3: len = 40 + * M 6bc1bee2 2e409f96 e93d7e11 7393172a + * ae2d8a57 1e03ac9c 9eb76fac 45af8e51 + * 30c81c46 a35ce411 + * AES-CMAC dfa66747 de9ae630 30ca3261 1497c827 + * -------------------------------------------------- + */ + { .len = 40, + .M = (uint8_t *) (uint32_t[]) { + 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373, + 0x578a2dae, 0x9cac031e, 0xac6fb79e, 0x518eaf45, + 0x461cc830, 0x11e45ca3 + }, + .Te = {0x4767a6df, 0x30e69ade, 0x6132ca30, 0x27c89714}, + }, + /* -------------------------------------------------- + * Example 4: len = 64 + * M 6bc1bee2 2e409f96 e93d7e11 7393172a + * ae2d8a57 1e03ac9c 9eb76fac 45af8e51 + * 30c81c46 a35ce411 e5fbc119 1a0a52ef + * f69f2445 df4f9b17 ad2b417b e66c3710 + * AES-CMAC 51f0bebf 7e3b9d92 fc497417 79363cfe + * -------------------------------------------------- + */ + { .len = 64, + .M = (uint8_t *) (uint32_t[]) { + 0xe2bec16b, 0x969f402e, 0x117e3de9, 0x2a179373, + 0x578a2dae, 0x9cac031e, 0xac6fb79e, 0x518eaf45, + 0x461cc830, 0x11e45ca3, 0x19c1fbe5, 0xef520a1a, + 0x45249ff6, 0x179b4fdf, 0x7b412bad, 0x10376ce6 + }, + .Te = {0xbfbef051, 0x929d3b7e, 0x177449fc, 0xfe3c3679}, + }, +}; + +static int command_test_aes_cmac(int argc, char **argv) +{ + int i; + uint32_t T[4]; + int testN; + struct cmac_test_param param; + const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09}; + + for (i = 1; i < argc; i++) { + testN = strtoi(argv[i], NULL, 10); + param = rfctests[testN - 1]; + + ccprintf("Testing RFC Example #%d (%d-byte message)...", testN, + param.len); + + DCRYPTO_aes_cmac((const uint8_t *)K, param.M, param.len, T); + check_answer(param.Te, T); + } + + return 0; +} + +DECLARE_SAFE_CONSOLE_COMMAND(test_cmac, command_test_aes_cmac, + "[test cases (1-4)]", + "Test AES-CMAC with RFC examples"); + +static int command_test_verify(int argc, char **argv) +{ + int i; + int testN; + int result; + struct cmac_test_param param; + const uint32_t K[4] = {0x16157e2b, 0xa6d2ae28, 0x8815f7ab, 0x3c4fcf09}; + + for (i = 1; i < argc; i++) { + testN = strtoi(argv[i], NULL, 10); + param = rfctests[testN-1]; + + ccprintf("Testing RFC Example #%d (%d-byte message)...", testN, + param.len); + + result = DCRYPTO_aes_cmac_verify((const uint8_t *)K, param.M, + param.len, param.Te); + if (result == 1) + ccprintf("SUCCESS\n"); + else if (result == 0) + ccprintf("FAILURE: verify returned INVALID\n"); + else if (result == -EC_ERROR_UNKNOWN) + ccprintf("FAILURE: verify returned ERROR\n"); + } + + return 0; +} + +DECLARE_SAFE_CONSOLE_COMMAND(test_cmac_ver, command_test_verify, + "[test cases (1-4)]", + "Test AES-CMAC-verify with RFC examples"); +#endif /* CRYPTO_TEST_SETUP */ diff --git a/chip/g/dcrypto/app_cipher.c b/chip/g/dcrypto/app_cipher.c new file mode 100644 index 0000000000..125b443ee6 --- /dev/null +++ b/chip/g/dcrypto/app_cipher.c @@ -0,0 +1,451 @@ +/* + * Copyright 2017 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 "registers.h" + +/* The default build options compile for size (-Os); instruct the + * compiler to optimize for speed here. Incidentally -O produces + * faster code than -O2! + */ +static int __attribute__((optimize("O"))) +inner_loop(uint32_t **out, const uint32_t **in, size_t len) +{ + uint32_t *outw = *out; + const uint32_t *inw = *in; + + while (len >= 16) { + uint32_t w0, w1, w2, w3; + + w0 = inw[0]; + w1 = inw[1]; + w2 = inw[2]; + w3 = inw[3]; + GREG32(KEYMGR, AES_WFIFO_DATA) = w0; + GREG32(KEYMGR, AES_WFIFO_DATA) = w1; + GREG32(KEYMGR, AES_WFIFO_DATA) = w2; + GREG32(KEYMGR, AES_WFIFO_DATA) = w3; + + while (GREG32(KEYMGR, AES_RFIFO_EMPTY)) + ; + + w0 = GREG32(KEYMGR, AES_RFIFO_DATA); + w1 = GREG32(KEYMGR, AES_RFIFO_DATA); + w2 = GREG32(KEYMGR, AES_RFIFO_DATA); + w3 = GREG32(KEYMGR, AES_RFIFO_DATA); + outw[0] = w0; + outw[1] = w1; + outw[2] = w2; + outw[3] = w3; + + inw += 4; + outw += 4; + len -= 16; + } + + *in = inw; + *out = outw; + return len; +} + +static int outer_loop(uint32_t **out, const uint32_t **in, size_t len) +{ + uint32_t *outw = *out; + const uint32_t *inw = *in; + + if (len >= 16) { + GREG32(KEYMGR, AES_WFIFO_DATA) = inw[0]; + GREG32(KEYMGR, AES_WFIFO_DATA) = inw[1]; + GREG32(KEYMGR, AES_WFIFO_DATA) = inw[2]; + GREG32(KEYMGR, AES_WFIFO_DATA) = inw[3]; + inw += 4; + len -= 16; + + len = inner_loop(&outw, &inw, len); + + while (GREG32(KEYMGR, AES_RFIFO_EMPTY)) + ; + + outw[0] = GREG32(KEYMGR, AES_RFIFO_DATA); + outw[1] = GREG32(KEYMGR, AES_RFIFO_DATA); + outw[2] = GREG32(KEYMGR, AES_RFIFO_DATA); + outw[3] = GREG32(KEYMGR, AES_RFIFO_DATA); + outw += 4; + } + + *in = inw; + *out = outw; + return len; +} + +static int aes_init(struct APPKEY_CTX *ctx, enum dcrypto_appid appid, + const uint32_t iv[4]) +{ + /* Setup USR-based application key. */ + if (!DCRYPTO_appkey_init(appid, ctx)) + return 0; + + /* Configure AES engine. */ + GWRITE_FIELD(KEYMGR, AES_CTRL, RESET, CTRL_NO_SOFT_RESET); + GWRITE_FIELD(KEYMGR, AES_CTRL, KEYSIZE, 2 /* AES-256 */); + GWRITE_FIELD(KEYMGR, AES_CTRL, CIPHER_MODE, CIPHER_MODE_CTR); + GWRITE_FIELD(KEYMGR, AES_CTRL, ENC_MODE, ENCRYPT_MODE); + GWRITE_FIELD(KEYMGR, AES_CTRL, CTR_ENDIAN, CTRL_CTR_BIG_ENDIAN); + + /* + * For fixed-key, bulk ciphering, turn off random nops (which + * are enabled by default). + */ + GWRITE_FIELD(KEYMGR, AES_RAND_STALL_CTL, STALL_EN, 0); + + /* Enable hidden key usage, each appid gets its own + * USR, with USR0 starting at 0x2a0. + */ + GWRITE_FIELD(KEYMGR, AES_USE_HIDDEN_KEY, INDEX, + 0x2a0 + (appid * 2)); + GWRITE_FIELD(KEYMGR, AES_USE_HIDDEN_KEY, ENABLE, 1); + GWRITE_FIELD(KEYMGR, AES_CTRL, ENABLE, CTRL_ENABLE); + + /* Wait for key-expansion. */ + GREG32(KEYMGR, AES_KEY_START) = 1; + while (GREG32(KEYMGR, AES_KEY_START)) + ; + + /* Check for errors (e.g. USR not correctly setup. */ + if (GREG32(KEYMGR, HKEY_ERR_FLAGS)) + return 0; + + /* Set IV. */ + GR_KEYMGR_AES_CTR(0) = iv[0]; + GR_KEYMGR_AES_CTR(1) = iv[1]; + GR_KEYMGR_AES_CTR(2) = iv[2]; + GR_KEYMGR_AES_CTR(3) = iv[3]; + + return 1; +} + +int DCRYPTO_app_cipher(enum dcrypto_appid appid, const void *salt, + void *out, const void *in, size_t len) +{ + struct APPKEY_CTX ctx; + const uint32_t *inw = in; + uint32_t *outw = out; + + /* Test pointers for word alignment. */ + if (((uintptr_t) in & 0x03) || ((uintptr_t) out & 0x03)) + return 0; + + { + /* Initialize key, and AES engine. */ + uint32_t iv[4]; + + memcpy(iv, salt, sizeof(iv)); + if (!aes_init(&ctx, appid, iv)) + return 0; + } + + len = outer_loop(&outw, &inw, len); + + if (len) { + /* Cipher the final partial block */ + uint32_t tmpin[4]; + uint32_t tmpout[4]; + const uint32_t *tmpinw; + uint32_t *tmpoutw; + + tmpinw = tmpin; + tmpoutw = tmpout; + + memcpy(tmpin, inw, len); + outer_loop(&tmpoutw, &tmpinw, 16); + memcpy(outw, tmpout, len); + } + + DCRYPTO_appkey_finish(&ctx); + return 1; +} + +#ifdef CRYPTO_TEST_SETUP + +#include "common.h" +#include "console.h" +#include "hooks.h" +#include "shared_mem.h" +#include "task.h" +#include "timer.h" +#include "watchdog.h" + +#define HEAP_HEAD_ROOM 0x400 +static uint32_t number_of_iterations; +static uint8_t result; + +/* Staticstics for ecrypt and decryp passes. */ +struct ciph_stats { + uint16_t min_time; + uint16_t max_time; + uint32_t total_time; +} __packed; /* Just in case. */ + +/* A common structure to contain information about the test run. */ +struct test_info { + size_t test_blob_size; + struct ciph_stats enc_stats; + struct ciph_stats dec_stats; + char *p; /* Pointer to an allcoated buffer of test_blob_size bytes. */ +}; + +static void init_stats(struct ciph_stats *stats) +{ + stats->min_time = ~0; + stats->max_time = 0; + stats->total_time = 0; +} + +static void update_stats(struct ciph_stats *stats, uint32_t time) +{ + if (time < stats->min_time) + stats->min_time = time; + + if (time > stats->max_time) + stats->max_time = time; + + stats->total_time += time; +} + +static void report_stats(const char *direction, struct ciph_stats *stats) +{ + ccprintf("%s results: min %d us, max %d us, average %d us\n", + direction, stats->min_time, stats->max_time, + stats->total_time / number_of_iterations); +} + +/* + * Prepare to run the test: allocate memory, initialize stats structures. + * + * Returns EC_SUCCESS if everything is fine, EC_ERROR_OVERFLOW on malloc + * failures. + */ +static int prepare_running(struct test_info *pinfo) +{ + memset(pinfo, 0, sizeof(*pinfo)); + + + pinfo->test_blob_size = shared_mem_size(); + /* + * Leave some room for crypto functions if they need to allocate + * something, just in case. 0x20 extra bytes are needed to be able to + * modify size alignment of the allocated buffer. + */ + if (pinfo->test_blob_size < (HEAP_HEAD_ROOM + 0x20)) { + ccprintf("Not enough memory to run the test\n"); + return EC_ERROR_OVERFLOW; + } + pinfo->test_blob_size = (pinfo->test_blob_size - HEAP_HEAD_ROOM); + + if (shared_mem_acquire(pinfo->test_blob_size, + (char **)&(pinfo->p)) != EC_SUCCESS) { + ccprintf("Failed to allocate %d bytes\n", + pinfo->test_blob_size); + return EC_ERROR_OVERFLOW; + } + + /* + * Use odd block size to make sure unaligned length blocks are handled + * properly. This leaves room in the end of the buffer to check if the + * decryption routine scratches it. + */ + pinfo->test_blob_size &= ~0x1f; + pinfo->test_blob_size |= 7; + + ccprintf("running %d iterations\n", number_of_iterations); + ccprintf("blob size %d at %pP\n", pinfo->test_blob_size, pinfo->p); + + init_stats(&(pinfo->enc_stats)); + init_stats(&(pinfo->dec_stats)); + + return EC_SUCCESS; +} + +/* + * Let's split the buffer in two equal halves, encrypt the lower half into the + * upper half and compare them word by word. There should be no repetitions. + * + * The side effect of this is starting the test with random clear text data. + * + * The first 16 bytes of the allocated buffer are used as the encryption IV. + */ +static int basic_check(struct test_info *pinfo) +{ + size_t half; + int i; + uint32_t *p; + + ccprintf("original data %ph\n", HEX_BUF(pinfo->p, 16)); + + half = (pinfo->test_blob_size/2) & ~3; + if (!DCRYPTO_app_cipher(NVMEM, pinfo->p, pinfo->p, + pinfo->p + half, half)) { + ccprintf("first ecnryption run failed\n"); + return EC_ERROR_UNKNOWN; + } + + p = (uint32_t *)pinfo->p; + half /= sizeof(*p); + + for (i = 0; i < half; i++) + if (p[i] == p[i + half]) { + ccprintf("repeating 32 bit word detected" + " at offset 0x%x!\n", i * 4); + return EC_ERROR_UNKNOWN; + } + + ccprintf("hashed data %ph\n", HEX_BUF(pinfo->p, 16)); + + return EC_SUCCESS; +} + +/* + * Main iteration of the console command, runs ecnryption/decryption cycles, + * vefifying that decrypted text's hash matches the original, and accumulating + * timing statistics. + */ +static int command_loop(struct test_info *pinfo) +{ + uint8_t sha[SHA_DIGEST_SIZE]; + uint8_t sha_after[SHA_DIGEST_SIZE]; + uint32_t iteration; + uint8_t *p_last_byte; + int rv; + + /* + * Prepare the hash of the original data to be able to verify + * results. + */ + DCRYPTO_SHA1_hash(pinfo->p, pinfo->test_blob_size, sha); + + /* Use the hash as an IV for the cipher. */ + memcpy(sha_after, sha, sizeof(sha_after)); + + iteration = number_of_iterations; + p_last_byte = pinfo->p + pinfo->test_blob_size; + + while (iteration--) { + char last_byte = (char) iteration; + uint32_t tstamp; + + *p_last_byte = last_byte; + + if (!(iteration % 500)) + watchdog_reload(); + + tstamp = get_time().val; + rv = DCRYPTO_app_cipher(NVMEM, sha_after, pinfo->p, + pinfo->p, pinfo->test_blob_size); + tstamp = get_time().val - tstamp; + + if (!rv) { + ccprintf("encryption failed\n"); + return EC_ERROR_UNKNOWN; + } + if (*p_last_byte != last_byte) { + ccprintf("encryption overflowed\n"); + return EC_ERROR_UNKNOWN; + } + update_stats(&pinfo->enc_stats, tstamp); + + tstamp = get_time().val; + rv = DCRYPTO_app_cipher(NVMEM, sha_after, pinfo->p, + pinfo->p, pinfo->test_blob_size); + tstamp = get_time().val - tstamp; + + if (!rv) { + ccprintf("decryption failed\n"); + return EC_ERROR_UNKNOWN; + } + if (*p_last_byte != last_byte) { + ccprintf("decryption overflowed\n"); + return EC_ERROR_UNKNOWN; + } + + DCRYPTO_SHA1_hash(pinfo->p, pinfo->test_blob_size, sha_after); + if (memcmp(sha, sha_after, sizeof(sha))) { + ccprintf("\n" + "sha1 before and after mismatch, %d to go!\n", + iteration); + return EC_ERROR_UNKNOWN; + } + + update_stats(&pinfo->dec_stats, tstamp); + + /* get a new IV */ + DCRYPTO_SHA1_hash(sha_after, sizeof(sha), sha_after); + } + + return EC_SUCCESS; +} + +/* + * Run cipher command on the hooks task context, as dcrypto's stack + * requirements exceed console tasks' allowance. + */ +static void run_cipher_cmd(void) +{ + struct test_info info; + + result = prepare_running(&info); + + if (result == EC_SUCCESS) + result = basic_check(&info); + + if (result == EC_SUCCESS) + result = command_loop(&info); + + if (result == EC_SUCCESS) { + report_stats("Encryption", &info.enc_stats); + report_stats("Decryption", &info.dec_stats); + } else if (info.p) { + ccprintf("current data %ph\n", HEX_BUF(info.p, 16)); + } + + if (info.p) + shared_mem_release(info.p); + + task_set_event(TASK_ID_CONSOLE, TASK_EVENT_CUSTOM_BIT(0), 0); +} +DECLARE_DEFERRED(run_cipher_cmd); + +static int cmd_cipher(int argc, char **argv) +{ + uint32_t events; + uint32_t max_time; + + /* Ignore potential input errors, let the user handle them. */ + if (argc > 1) + number_of_iterations = strtoi(argv[1], NULL, 0); + else + number_of_iterations = 1000; + + if (!number_of_iterations) { + ccprintf("not running zero iterations\n"); + return EC_ERROR_PARAM1; + } + + hook_call_deferred(&run_cipher_cmd_data, 0); + + /* Roughly, .5 us per byte should be more than enough. */ + max_time = number_of_iterations * shared_mem_size() / 2; + + ccprintf("Will wait up to %d ms\n", (max_time + 500)/1000); + + events = task_wait_event_mask(TASK_EVENT_CUSTOM_BIT(0), max_time); + if (!(events & TASK_EVENT_CUSTOM_BIT(0))) { + ccprintf("Timed out, you might want to reboot...\n"); + return EC_ERROR_TIMEOUT; + } + + return result; +} +DECLARE_SAFE_CONSOLE_COMMAND(cipher, cmd_cipher, NULL, NULL); +#endif diff --git a/chip/g/dcrypto/app_key.c b/chip/g/dcrypto/app_key.c new file mode 100644 index 0000000000..1fafab9d2e --- /dev/null +++ b/chip/g/dcrypto/app_key.c @@ -0,0 +1,87 @@ +/* Copyright 2016 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 "endian.h" +#include "registers.h" + +#include "cryptoc/util.h" + +#include "console.h" + +const char *const dcrypto_app_names[] = { + "RESERVED", + "NVMEM", + "U2F_ATTEST", + "U2F_ORIGIN", + "U2F_WRAP", + /* This key signs data from H1's configured by mn50/scribe. */ + "PERSO_AUTH", + "PINWEAVER", +}; + +static void name_hash(enum dcrypto_appid appid, + uint32_t digest[SHA256_DIGEST_WORDS]) +{ + LITE_SHA256_CTX ctx; + const char *name = dcrypto_app_names[appid]; + size_t x; + + /* The PERSO_AUTH digest was improperly defined, so now this exception + * exists to prevent data loss. + */ + if (appid == PERSO_AUTH) { + digest[0] = 0x2019da34; + digest[1] = 0xf1a01a13; + digest[2] = 0x0fb9f73f; + digest[3] = 0xf2e85f76; + digest[4] = 0x5ecb7690; + digest[5] = 0x09f732c9; + digest[6] = 0xe540bf14; + digest[7] = 0xcc46799a; + return; + } + + DCRYPTO_SHA256_init(&ctx, 0); + HASH_update(&ctx, name, strlen(name)); + memcpy(digest, HASH_final(&ctx), SHA256_DIGEST_SIZE); + + /* The digests were originally endian swapped because xxd was used to + * print them so this operation is needed to keep the derived keys the + * same. Any changes to they key derivation process must result in the + * same keys being produced given the same inputs, or devices will + * effectively be reset and user data will be lost by the key change. + */ + for (x = 0; x < SHA256_DIGEST_WORDS; ++x) + digest[x] = __builtin_bswap32(digest[x]); +} + +int DCRYPTO_appkey_init(enum dcrypto_appid appid, struct APPKEY_CTX *ctx) +{ + uint32_t digest[SHA256_DIGEST_WORDS]; + + memset(ctx, 0, sizeof(*ctx)); + name_hash(appid, digest); + + if (!dcrypto_ladder_compute_usr(appid, digest)) + return 0; + + return 1; +} + +void DCRYPTO_appkey_finish(struct APPKEY_CTX *ctx) +{ + always_memset(ctx, 0, sizeof(struct APPKEY_CTX)); + GREG32(KEYMGR, AES_WIPE_SECRETS) = 1; +} + +int DCRYPTO_appkey_derive(enum dcrypto_appid appid, const uint32_t input[8], + uint32_t output[8]) +{ + uint32_t digest[SHA256_DIGEST_WORDS]; + + name_hash(appid, digest); + return !!dcrypto_ladder_derive(appid, digest, input, output); +} diff --git a/chip/g/dcrypto/bn.c b/chip/g/dcrypto/bn.c new file mode 100644 index 0000000000..94aafa1799 --- /dev/null +++ b/chip/g/dcrypto/bn.c @@ -0,0 +1,1244 @@ +/* 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. + */ + +#ifdef PRINT_PRIMES +#include "console.h" +#endif + +#include "dcrypto.h" +#include "internal.h" + +#include "trng.h" + +#include "cryptoc/util.h" + +#include + +#ifdef CONFIG_WATCHDOG +extern void watchdog_reload(void); +#else +static inline void watchdog_reload(void) { } +#endif + +void bn_init(struct LITE_BIGNUM *b, void *buf, size_t len) +{ + DCRYPTO_bn_wrap(b, buf, len); + always_memset(buf, 0x00, len); +} + +void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len) +{ + /* Only word-multiple sized buffers accepted. */ + assert((len & 0x3) == 0); + b->dmax = len / LITE_BN_BYTES; + b->d = (struct access_helper *) buf; +} + +int bn_eq(const struct LITE_BIGNUM *a, const struct LITE_BIGNUM *b) +{ + int i; + uint32_t top = 0; + + for (i = a->dmax - 1; i > b->dmax - 1; --i) + top |= BN_DIGIT(a, i); + if (top) + return 0; + + for (i = b->dmax - 1; i > a->dmax - 1; --i) + top |= BN_DIGIT(b, i); + if (top) + return 0; + + for (i = MIN(a->dmax, b->dmax) - 1; i >= 0; --i) + if (BN_DIGIT(a, i) != BN_DIGIT(b, i)) + return 0; + + return 1; +} + +static void bn_copy(struct LITE_BIGNUM *dst, const struct LITE_BIGNUM *src) +{ + dst->dmax = src->dmax; + memcpy(dst->d, src->d, bn_size(dst)); +} + +int bn_check_topbit(const struct LITE_BIGNUM *N) +{ + return BN_DIGIT(N, N->dmax - 1) >> 31; +} + +/* a[n]. */ +int bn_is_bit_set(const struct LITE_BIGNUM *a, int n) +{ + int i, j; + + if (n < 0) + return 0; + + i = n / LITE_BN_BITS2; + j = n % LITE_BN_BITS2; + if (a->dmax <= i) + return 0; + + return (BN_DIGIT(a, i) >> j) & 1; +} + +static int bn_set_bit(const struct LITE_BIGNUM *a, int n) +{ + int i, j; + + if (n < 0) + return 0; + + i = n / LITE_BN_BITS2; + j = n % LITE_BN_BITS2; + if (a->dmax <= i) + return 0; + + BN_DIGIT(a, i) |= 1 << j; + return 1; +} + +/* a[] >= b[]. */ +/* TODO(ngm): constant time. */ +static int bn_gte(const struct LITE_BIGNUM *a, const struct LITE_BIGNUM *b) +{ + int i; + uint32_t top = 0; + + for (i = a->dmax - 1; i > b->dmax - 1; --i) + top |= BN_DIGIT(a, i); + if (top) + return 1; + + for (i = b->dmax - 1; i > a->dmax - 1; --i) + top |= BN_DIGIT(b, i); + if (top) + return 0; + + for (i = MIN(a->dmax, b->dmax) - 1; + BN_DIGIT(a, i) == BN_DIGIT(b, i) && i > 0; --i) + ; + return BN_DIGIT(a, i) >= BN_DIGIT(b, i); +} + +/* c[] = c[] - a[], assumes c > a. */ +uint32_t bn_sub(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a) +{ + int64_t A = 0; + int i; + + for (i = 0; i < a->dmax; i++) { + A += (uint64_t) BN_DIGIT(c, i) - BN_DIGIT(a, i); + BN_DIGIT(c, i) = (uint32_t) A; + A >>= 32; + } + + for (; A && i < c->dmax; i++) { + A += (uint64_t) BN_DIGIT(c, i); + BN_DIGIT(c, i) = (uint32_t) A; + A >>= 32; + } + + return (uint32_t) A; /* 0 or -1. */ +} + +/* c[] = c[] - a[], negative numbers in 2's complement representation. */ +/* Returns borrow bit. */ +static uint32_t bn_signed_sub(struct LITE_BIGNUM *c, int *c_neg, + const struct LITE_BIGNUM *a, int a_neg) +{ + uint32_t carry = 0; + uint64_t A = 1; + int i; + + for (i = 0; i < a->dmax; ++i) { + A += (uint64_t) BN_DIGIT(c, i) + ~BN_DIGIT(a, i); + BN_DIGIT(c, i) = (uint32_t) A; + A >>= 32; + } + + for (; i < c->dmax; ++i) { + A += (uint64_t) BN_DIGIT(c, i) + 0xFFFFFFFF; + BN_DIGIT(c, i) = (uint32_t) A; + A >>= 32; + } + + A &= 0x01; + carry = (!*c_neg && a_neg && A) || (*c_neg && !a_neg && !A); + *c_neg = carry ? *c_neg : (*c_neg + !a_neg + A) & 0x01; + return carry; +} + +/* c[] = c[] + a[]. */ +uint32_t bn_add(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a) +{ + uint64_t A = 0; + int i; + + for (i = 0; i < a->dmax; ++i) { + A += (uint64_t) BN_DIGIT(c, i) + BN_DIGIT(a, i); + BN_DIGIT(c, i) = (uint32_t) A; + A >>= 32; + } + + for (; A && i < c->dmax; ++i) { + A += (uint64_t) BN_DIGIT(c, i); + BN_DIGIT(c, i) = (uint32_t) A; + A >>= 32; + } + + return (uint32_t) A; /* 0 or 1. */ +} + +/* c[] = c[] + a[], negative numbers in 2's complement representation. */ +/* Returns carry bit. */ +static uint32_t bn_signed_add(struct LITE_BIGNUM *c, int *c_neg, + const struct LITE_BIGNUM *a, int a_neg) +{ + uint32_t A = bn_add(c, a); + uint32_t carry; + + carry = (!*c_neg && !a_neg && A) || (*c_neg && a_neg && !A); + *c_neg = carry ? *c_neg : (*c_neg + a_neg + A) & 0x01; + return carry; +} + +/* r[] <<= 1. */ +static uint32_t bn_lshift(struct LITE_BIGNUM *r) +{ + int i; + uint32_t w; + uint32_t carry = 0; + + for (i = 0; i < r->dmax; i++) { + w = (BN_DIGIT(r, i) << 1) | carry; + carry = BN_DIGIT(r, i) >> 31; + BN_DIGIT(r, i) = w; + } + return carry; +} + +/* r[] >>= 1. Handles 2's complement negative numbers. */ +static void bn_rshift(struct LITE_BIGNUM *r, uint32_t carry, uint32_t neg) +{ + int i; + uint32_t ones = ~0; + uint32_t highbit = (!carry && neg) || (carry && !neg); + + for (i = 0; i < r->dmax - 1; ++i) { + uint32_t accu; + + ones &= BN_DIGIT(r, i); + accu = (BN_DIGIT(r, i) >> 1); + accu |= (BN_DIGIT(r, i + 1) << (LITE_BN_BITS2 - 1)); + BN_DIGIT(r, i) = accu; + } + ones &= BN_DIGIT(r, i); + BN_DIGIT(r, i) = (BN_DIGIT(r, i) >> 1) | + (highbit << (LITE_BN_BITS2 - 1)); + + if (ones == ~0 && highbit && neg) + memset(r->d, 0x00, bn_size(r)); /* -1 >> 1 = 0. */ +} + +/* Montgomery c[] += a * b[] / R % N. */ +/* TODO(ngm): constant time. */ +static void bn_mont_mul_add(struct LITE_BIGNUM *c, const uint32_t a, + const struct LITE_BIGNUM *b, const uint32_t nprime, + const struct LITE_BIGNUM *N) +{ + uint32_t A, B, d0; + int i; + + { + register uint64_t tmp; + + tmp = BN_DIGIT(c, 0) + (uint64_t) a * BN_DIGIT(b, 0); + A = tmp >> 32; + d0 = (uint32_t) tmp * (uint32_t) nprime; + tmp = (uint32_t)tmp + (uint64_t) d0 * BN_DIGIT(N, 0); + B = tmp >> 32; + } + + for (i = 0; i < N->dmax - 1;) { + register uint64_t tmp; + + tmp = A + (uint64_t) a * BN_DIGIT(b, i + 1) + + BN_DIGIT(c, i + 1); + A = tmp >> 32; + tmp = B + (uint64_t) d0 * BN_DIGIT(N, i + 1) + (uint32_t) tmp; + BN_DIGIT(c, i) = (uint32_t) tmp; + B = tmp >> 32; + ++i; + } + + { + uint64_t tmp = (uint64_t) A + B; + + BN_DIGIT(c, i) = (uint32_t) tmp; + A = tmp >> 32; /* 0 or 1. */ + if (A) + bn_sub(c, N); + } +} + +/* Montgomery c[] = a[] * b[] / R % N. */ +static void bn_mont_mul(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a, + const struct LITE_BIGNUM *b, const uint32_t nprime, + const struct LITE_BIGNUM *N) +{ + int i; + + for (i = 0; i < N->dmax; i++) + BN_DIGIT(c, i) = 0; + + bn_mont_mul_add(c, a ? BN_DIGIT(a, 0) : 1, b, nprime, N); + for (i = 1; i < N->dmax; i++) + bn_mont_mul_add(c, a ? BN_DIGIT(a, i) : 0, b, nprime, N); +} + +/* Mongomery R * R % N, R = 1 << (1 + log2N). */ +/* TODO(ngm): constant time. */ +static void bn_compute_RR(struct LITE_BIGNUM *RR, const struct LITE_BIGNUM *N) +{ + int i; + + bn_sub(RR, N); /* R - N = R % N since R < 2N */ + + /* Repeat 2 * R % N, log2(R) times. */ + for (i = 0; i < N->dmax * LITE_BN_BITS2; i++) { + if (bn_lshift(RR)) + assert(bn_sub(RR, N) == -1); + if (bn_gte(RR, N)) + bn_sub(RR, N); + } +} + +/* Montgomery nprime = -1 / n0 % (2 ^ 32). */ +static uint32_t bn_compute_nprime(const uint32_t n0) +{ + int i; + uint32_t ninv = 1; + + /* Repeated Hensel lifting. */ + for (i = 0; i < 5; i++) + ninv *= 2 - (n0 * ninv); + + return ~ninv + 1; /* Two's complement. */ +} + +/* TODO(ngm): this implementation not timing or side-channel safe by + * any measure. */ +static void bn_modexp_internal(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, + const struct LITE_BIGNUM *N) +{ + int i; + uint32_t nprime; + uint32_t RR_buf[RSA_MAX_WORDS]; + uint32_t acc_buf[RSA_MAX_WORDS]; + uint32_t aR_buf[RSA_MAX_WORDS]; + + struct LITE_BIGNUM RR; + struct LITE_BIGNUM acc; + struct LITE_BIGNUM aR; + + bn_init(&RR, RR_buf, bn_size(N)); + bn_init(&acc, acc_buf, bn_size(N)); + bn_init(&aR, aR_buf, bn_size(N)); + + nprime = bn_compute_nprime(BN_DIGIT(N, 0)); + bn_compute_RR(&RR, N); + bn_mont_mul(&acc, NULL, &RR, nprime, N); /* R = 1 * RR / R % N */ + bn_mont_mul(&aR, input, &RR, nprime, N); /* aR = a * RR / R % N */ + + /* TODO(ngm): burn stack space and use windowing. */ + for (i = exp->dmax * LITE_BN_BITS2 - 1; i >= 0; i--) { + bn_mont_mul(output, &acc, &acc, nprime, N); + if (bn_is_bit_set(exp, i)) { + bn_mont_mul(&acc, output, &aR, nprime, N); + } else { + struct LITE_BIGNUM tmp = *output; + + *output = acc; + acc = tmp; + } + /* Poke the watchdog. + * TODO(ngm): may be unnecessary with + * a faster implementation. + */ + watchdog_reload(); + } + + bn_mont_mul(output, NULL, &acc, nprime, N); /* Convert out. */ + /* Copy to output buffer if necessary. */ + if (acc.d != (struct access_helper *) acc_buf) { + memcpy(acc.d, acc_buf, bn_size(output)); + *output = acc; + } + + /* TODO(ngm): constant time. */ + if (bn_sub(output, N)) + bn_add(output, N); /* Final reduce. */ + output->dmax = N->dmax; + + always_memset(RR_buf, 0, sizeof(RR_buf)); + always_memset(acc_buf, 0, sizeof(acc_buf)); + always_memset(aR_buf, 0, sizeof(aR_buf)); +} + +/* output = input ^ exp % N */ +int bn_modexp(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, const struct LITE_BIGNUM *N) +{ +#ifndef CR50_NO_BN_ASM + if ((bn_bits(N) & 255) == 0) { + /* Use hardware support for standard key sizes. */ + return dcrypto_modexp(output, input, exp, N); + } +#endif + bn_modexp_internal(output, input, exp, N); + return 1; +} + +/* output = input ^ exp % N */ +int bn_modexp_word(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, + uint32_t exp, const struct LITE_BIGNUM *N) +{ +#ifndef CR50_NO_BN_ASM + if ((bn_bits(N) & 255) == 0) { + /* Use hardware support for standard key sizes. */ + return dcrypto_modexp_word(output, input, exp, N); + } +#endif + { + struct LITE_BIGNUM pubexp; + + DCRYPTO_bn_wrap(&pubexp, &exp, sizeof(exp)); + bn_modexp_internal(output, input, &pubexp, N); + return 1; + } +} + +/* output = input ^ exp % N */ +int bn_modexp_blinded(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, + const struct LITE_BIGNUM *N, + uint32_t pubexp) +{ +#ifndef CR50_NO_BN_ASM + if ((bn_bits(N) & 255) == 0) { + /* Use hardware support for standard key sizes. */ + return dcrypto_modexp_blinded(output, input, exp, N, pubexp); + } +#endif + bn_modexp_internal(output, input, exp, N); + return 1; +} + +/* c[] += a * b[] */ +static uint32_t bn_mul_add(struct LITE_BIGNUM *c, uint32_t a, + const struct LITE_BIGNUM *b, uint32_t offset) +{ + int i; + uint64_t carry = 0; + + for (i = 0; i < b->dmax; i++) { + carry += BN_DIGIT(c, offset + i) + + (uint64_t) BN_DIGIT(b, i) * a; + BN_DIGIT(c, offset + i) = (uint32_t) carry; + carry >>= 32; + } + + return carry; +} + +/* c[] = a[] * b[] */ +void DCRYPTO_bn_mul(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a, + const struct LITE_BIGNUM *b) +{ + int i; + uint32_t carry = 0; + + memset(c->d, 0, bn_size(c)); + for (i = 0; i < a->dmax; i++) { + BN_DIGIT(c, i + b->dmax - 1) = carry; + carry = bn_mul_add(c, BN_DIGIT(a, i), b, i); + } + + BN_DIGIT(c, i + b->dmax - 1) = carry; +} + +/* c[] = a[] * b[] */ +static void bn_mul_ex(struct LITE_BIGNUM *c, + const struct LITE_BIGNUM *a, int a_len, + const struct LITE_BIGNUM *b) +{ + int i; + uint32_t carry = 0; + + memset(c->d, 0, bn_size(c)); + for (i = 0; i < a_len; i++) { + BN_DIGIT(c, i + b->dmax - 1) = carry; + carry = bn_mul_add(c, BN_DIGIT(a, i), b, i); + } + + BN_DIGIT(c, i + b->dmax - 1) = carry; +} + +static int bn_div_word_ex(struct LITE_BIGNUM *q, + struct LITE_BIGNUM *r, + const struct LITE_BIGNUM *u, int m, + uint32_t div) +{ + uint32_t rem = 0; + int i; + + for (i = m - 1; i >= 0; --i) { + uint64_t tmp = ((uint64_t)rem << 32) + BN_DIGIT(u, i); + uint32_t qd = tmp / div; + + BN_DIGIT(q, i) = qd; + rem = tmp - (uint64_t)qd * div; + } + + if (r != NULL) + BN_DIGIT(r, 0) = rem; + + return 1; +} + +/* + * Knuth's long division. + * + * Returns 0 on error. + * |u| >= |v| + * v[n-1] must not be 0 + * r gets |v| digits written to. + * q gets |u| - |v| + 1 digits written to. + */ +static int bn_div_ex(struct LITE_BIGNUM *q, + struct LITE_BIGNUM *r, + const struct LITE_BIGNUM *u, int m, + const struct LITE_BIGNUM *v, int n) +{ + uint32_t vtop; + int s, i, j; + uint32_t vn[RSA_MAX_WORDS]; /* Normalized v */ + uint32_t un[RSA_MAX_WORDS + 1]; /* Normalized u */ + + if (m < n || n <= 0) + return 0; + + vtop = BN_DIGIT(v, n - 1); + + if (vtop == 0) + return 0; + + if (n == 1) + return bn_div_word_ex(q, r, u, m, vtop); + + /* Compute shift factor to make v have high bit set */ + s = 0; + while ((vtop & 0x80000000) == 0) { + s = s + 1; + vtop = vtop << 1; + } + + /* Normalize u and v into un and vn. + * Note un always gains a leading digit + */ + if (s != 0) { + for (i = n - 1; i > 0; i--) + vn[i] = (BN_DIGIT(v, i) << s) | + (BN_DIGIT(v, i - 1) >> (32 - s)); + vn[0] = BN_DIGIT(v, 0) << s; + + un[m] = BN_DIGIT(u, m - 1) >> (32 - s); + for (i = m - 1; i > 0; i--) + un[i] = (BN_DIGIT(u, i) << s) | + (BN_DIGIT(u, i - 1) >> (32 - s)); + un[0] = BN_DIGIT(u, 0) << s; + } else { + for (i = 0; i < n; ++i) + vn[i] = BN_DIGIT(v, i); + for (i = 0; i < m; ++i) + un[i] = BN_DIGIT(u, i); + un[m] = 0; + } + + /* Main loop, reducing un digit by digit */ + for (j = m - n; j >= 0; j--) { + uint32_t qd; + int64_t t, k; + + /* Estimate quotient digit */ + if (un[j + n] == vn[n - 1]) { + /* Maxed out */ + qd = 0xFFFFFFFF; + } else { + /* Fine tune estimate */ + uint64_t rhat = ((uint64_t)un[j + n] << 32) + + un[j + n - 1]; + + qd = rhat / vn[n - 1]; + rhat = rhat - (uint64_t)qd * vn[n - 1]; + while ((rhat >> 32) == 0 && + (uint64_t)qd * vn[n - 2] > + (rhat << 32) + un[j + n - 2]) { + qd = qd - 1; + rhat = rhat + vn[n - 1]; + } + } + + /* Multiply and subtract */ + k = 0; + for (i = 0; i < n; i++) { + uint64_t p = (uint64_t)qd * vn[i]; + + t = un[i + j] - k - (p & 0xFFFFFFFF); + un[i + j] = t; + k = (p >> 32) - (t >> 32); + } + t = un[j + n] - k; + un[j + n] = t; + + /* If borrowed, add one back and adjust estimate */ + if (t < 0) { + k = 0; + qd = qd - 1; + for (i = 0; i < n; i++) { + t = (uint64_t)un[i + j] + vn[i] + k; + un[i + j] = t; + k = t >> 32; + } + un[j + n] = un[j + n] + k; + } + + BN_DIGIT(q, j) = qd; + } + + if (r != NULL) { + /* Denormalize un into r */ + if (s != 0) { + for (i = 0; i < n - 1; i++) + BN_DIGIT(r, i) = (un[i] >> s) | + (un[i + 1] << (32 - s)); + BN_DIGIT(r, n - 1) = un[n - 1] >> s; + } else { + for (i = 0; i < n; i++) + BN_DIGIT(r, i) = un[i]; + } + } + + return 1; +} + +static void bn_set_bn(struct LITE_BIGNUM *d, const struct LITE_BIGNUM *src, + size_t n) +{ + size_t i = 0; + + for (; i < n && i < d->dmax; ++i) + BN_DIGIT(d, i) = BN_DIGIT(src, i); + for (; i < d->dmax; ++i) + BN_DIGIT(d, i) = 0; +} + +static size_t bn_digits(const struct LITE_BIGNUM *a) +{ + size_t n = a->dmax - 1; + + while (BN_DIGIT(a, n) == 0 && n) + --n; + return n + 1; +} + +int DCRYPTO_bn_div(struct LITE_BIGNUM *quotient, + struct LITE_BIGNUM *remainder, + const struct LITE_BIGNUM *src, + const struct LITE_BIGNUM *divisor) +{ + int src_len = bn_digits(src); + int div_len = bn_digits(divisor); + int i, result; + + if (src_len < div_len) + return 0; + + result = bn_div_ex(quotient, remainder, + src, src_len, + divisor, div_len); + + if (!result) + return 0; + + /* 0-pad the destinations. */ + for (i = src_len - div_len + 1; i < quotient->dmax; ++i) + BN_DIGIT(quotient, i) = 0; + if (remainder) { + for (i = div_len; i < remainder->dmax; ++i) + BN_DIGIT(remainder, i) = 0; + } + + return result; +} + +/* + * Extended Euclid modular inverse. + * + * https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm + * #Computing_multiplicative_inverses_in_modular_structures: + + * function inverse(a, n) + * t := 0; newt := 1; + * r := n; newr := a; + * while newr ≠ 0 + * quotient := r div newr + * (t, newt) := (newt, t - quotient * newt) + * (r, newr) := (newr, r - quotient * newr) + * if r > 1 then return "a is not invertible" + * if t < 0 then t := t + n + * return t + */ +int bn_modinv_vartime(struct LITE_BIGNUM *dst, const struct LITE_BIGNUM *src, + const struct LITE_BIGNUM *mod) +{ + uint32_t R_buf[RSA_MAX_WORDS]; + uint32_t nR_buf[RSA_MAX_WORDS]; + uint32_t Q_buf[RSA_MAX_WORDS]; + + uint32_t nT_buf[RSA_MAX_WORDS + 1]; /* Can go negative, hence +1 */ + uint32_t T_buf[RSA_MAX_WORDS + 1]; /* Can go negative */ + uint32_t tmp_buf[2 * RSA_MAX_WORDS + 1]; /* needs to hold Q*nT */ + + struct LITE_BIGNUM R; + struct LITE_BIGNUM nR; + struct LITE_BIGNUM Q; + struct LITE_BIGNUM T; + struct LITE_BIGNUM nT; + struct LITE_BIGNUM tmp; + + struct LITE_BIGNUM *pT = &T; + struct LITE_BIGNUM *pnT = &nT; + struct LITE_BIGNUM *pR = &R; + struct LITE_BIGNUM *pnR = &nR; + struct LITE_BIGNUM *bnswap; + + int t_neg = 0; + int nt_neg = 0; + int iswap; + + size_t r_len, nr_len; + + bn_init(&R, R_buf, bn_size(mod)); + bn_init(&nR, nR_buf, bn_size(mod)); + bn_init(&Q, Q_buf, bn_size(mod)); + bn_init(&T, T_buf, bn_size(mod) + sizeof(uint32_t)); + bn_init(&nT, nT_buf, bn_size(mod) + sizeof(uint32_t)); + bn_init(&tmp, tmp_buf, bn_size(mod) + sizeof(uint32_t)); + + r_len = bn_digits(mod); + nr_len = bn_digits(src); + + BN_DIGIT(&nT, 0) = 1; /* T = 0, nT = 1 */ + bn_set_bn(&R, mod, r_len); /* R = n */ + bn_set_bn(&nR, src, nr_len); /* nR = input */ + + /* Trim nR */ + while (nr_len && BN_DIGIT(&nR, nr_len - 1) == 0) + --nr_len; + + while (nr_len) { + size_t q_len = r_len - nr_len + 1; + + /* (r, nr) = (nr, r % nr), q = r / nr */ + if (!bn_div_ex(&Q, pR, pR, r_len, pnR, nr_len)) + return 0; + + /* swap R and nR */ + r_len = nr_len; + bnswap = pR; pR = pnR; pnR = bnswap; + + /* trim nR and Q */ + while (nr_len && BN_DIGIT(pnR, nr_len - 1) == 0) + --nr_len; + while (q_len && BN_DIGIT(&Q, q_len - 1) == 0) + --q_len; + + Q.dmax = q_len; + + /* compute t - q*nt */ + if (q_len == 1 && BN_DIGIT(&Q, 0) <= 2) { + /* Doing few direct subs is faster than mul + sub */ + uint32_t n = BN_DIGIT(&Q, 0); + + while (n--) + bn_signed_sub(pT, &t_neg, pnT, nt_neg); + } else { + /* Call bn_mul_ex with smallest operand first */ + if (nt_neg) { + /* Negative numbers use all digits, + * thus pnT is large + */ + bn_mul_ex(&tmp, &Q, q_len, pnT); + } else { + int nt_len = bn_digits(pnT); + + if (q_len < nt_len) + bn_mul_ex(&tmp, &Q, q_len, pnT); + else + bn_mul_ex(&tmp, pnT, nt_len, &Q); + } + bn_signed_sub(pT, &t_neg, &tmp, nt_neg); + } + + /* swap T and nT */ + bnswap = pT; pT = pnT; pnT = bnswap; + iswap = t_neg; t_neg = nt_neg; nt_neg = iswap; + } + + if (r_len != 1 || BN_DIGIT(pR, 0) != 1) { + /* gcd not 1; no direct inverse */ + return 0; + } + + if (t_neg) + bn_signed_add(pT, &t_neg, mod, 0); + + bn_set_bn(dst, pT, bn_digits(pT)); + + return 1; +} + +#define PRIME1 3 + +/* + * The array below is an encoding of the first 4096 primes, starting with + * PRIME1. Using 4096 of the first primes results in at least 5% improvement + * in running time over using the first 2048. + * + * Most byte entries in the array contain two sequential differentials between + * two adjacent prime numbers, each differential halved (as the difference is + * always even) and packed into 4 bits. + * + * If a halved differential value exceeds 0xf (and as such does not fit into 4 + * bits), a zero is placed in the array followed by the value literal (no + * halving). + * + * If out of two consecutive differencials only the second one exceeds 0xf, + * the first one still is put into the array in its own byte prepended by a + * zero. + */ +const uint8_t PRIME_DELTAS[] = { + 1, 18, 18, 18, 49, 50, 18, 51, 19, 33, 50, 52, + 33, 33, 39, 35, 21, 19, 50, 51, 21, 18, 22, 98, + 18, 49, 83, 51, 19, 33, 87, 33, 39, 53, 18, 52, + 51, 35, 66, 69, 21, 19, 35, 66, 18, 100, 36, 35, + 97, 147, 83, 49, 53, 51, 19, 50, 22, 81, 35, 49, + 98, 52, 84, 84, 51, 36, 50, 66, 117, 97, 81, 33, + 87, 33, 39, 33, 42, 36, 84, 35, 55, 35, 52, 54, + 35, 21, 19, 81, 81, 57, 33, 35, 52, 51, 177, 84, + 83, 52, 98, 51, 19, 101, 145, 35, 19, 33, 38, 19, + 0, 34, 51, 73, 87, 33, 35, 66, 19, 101, 18, 18, + 54, 100, 99, 35, 66, 66, 114, 49, 35, 19, 90, 50, + 28, 33, 86, 21, 67, 51, 147, 33, 101, 100, 135, 50, + 18, 21, 99, 57, 24, 27, 52, 50, 18, 67, 81, 87, + 83, 97, 33, 86, 24, 19, 33, 84, 156, 35, 72, 18, + 72, 18, 67, 50, 97, 179, 19, 35, 115, 33, 50, 54, + 51, 114, 54, 67, 45, 149, 66, 49, 59, 97, 132, 38, + 117, 18, 67, 50, 18, 52, 33, 53, 21, 66, 117, 97, + 50, 24, 114, 52, 50, 148, 83, 52, 86, 114, 51, 30, + 21, 66, 114, 70, 54, 35, 165, 24, 210, 22, 50, 99, + 66, 75, 18, 22, 225, 51, 50, 49, 98, 97, 81, 129, + 131, 168, 66, 18, 27, 70, 53, 18, 49, 53, 22, 81, + 87, 50, 52, 51, 134, 18, 115, 36, 84, 51, 179, 21, + 114, 57, 21, 114, 21, 114, 73, 35, 18, 49, 98, 171, + 97, 35, 49, 59, 19, 131, 97, 54, 129, 35, 114, 25, + 197, 49, 81, 81, 83, 21, 21, 52, 245, 21, 67, 89, + 54, 97, 147, 35, 57, 21, 115, 33, 44, 22, 56, 67, + 57, 129, 35, 19, 53, 54, 105, 19, 41, 76, 33, 35, + 22, 39, 245, 54, 115, 86, 18, 52, 53, 18, 115, 50, + 49, 81, 134, 73, 35, 97, 51, 62, 55, 36, 84, 105, + 33, 44, 99, 24, 51, 117, 114, 243, 51, 67, 33, 99, + 33, 59, 49, 41, 18, 97, 50, 211, 50, 69, 0, 32, + 129, 50, 18, 21, 115, 36, 83, 162, 19, 242, 69, 51, + 67, 98, 49, 50, 49, 81, 131, 162, 103, 227, 162, 148, + 50, 55, 51, 81, 86, 69, 21, 70, 92, 18, 67, 36, + 149, 51, 19, 86, 21, 51, 52, 53, 49, 51, 53, 76, + 59, 25, 36, 95, 73, 33, 83, 19, 41, 70, 152, 49, + 99, 81, 81, 53, 114, 193, 129, 81, 90, 33, 36, 131, + 49, 104, 66, 63, 21, 19, 35, 52, 50, 99, 70, 39, + 101, 195, 99, 27, 73, 83, 114, 19, 84, 50, 63, 117, + 22, 81, 129, 156, 147, 137, 49, 146, 49, 84, 83, 52, + 35, 21, 22, 35, 49, 98, 121, 35, 162, 67, 36, 39, + 50, 118, 33, 242, 195, 54, 103, 50, 18, 147, 100, 50, + 97, 111, 129, 59, 115, 86, 49, 36, 83, 60, 115, 36, + 105, 81, 81, 35, 163, 39, 33, 39, 54, 197, 52, 81, + 242, 49, 98, 115, 0, 34, 100, 53, 18, 165, 72, 21, + 114, 22, 56, 52, 36, 35, 67, 54, 50, 51, 73, 42, + 38, 21, 49, 86, 18, 163, 243, 36, 86, 49, 225, 50, + 24, 97, 53, 76, 99, 147, 39, 50, 100, 54, 35, 99, + 97, 138, 33, 89, 66, 114, 19, 179, 115, 53, 49, 81, + 33, 177, 35, 54, 55, 86, 52, 0, 4, 0, 36, 118, + 50, 49, 99, 104, 21, 75, 22, 50, 57, 22, 50, 100, + 54, 35, 99, 22, 98, 115, 131, 21, 73, 0, 6, 0, + 34, 30, 27, 49, 86, 19, 36, 179, 21, 66, 52, 38, + 150, 162, 51, 66, 24, 97, 84, 81, 35, 118, 180, 225, + 42, 33, 39, 86, 22, 129, 228, 180, 35, 55, 36, 99, + 50, 162, 145, 99, 35, 121, 84, 0, 10, 0, 32, 53, + 51, 19, 131, 22, 62, 21, 72, 52, 53, 202, 81, 81, + 98, 58, 33, 105, 81, 81, 42, 141, 36, 50, 99, 70, + 99, 36, 177, 135, 83, 102, 115, 42, 38, 49, 51, 132, + 177, 228, 50, 162, 108, 162, 69, 24, 22, 0, 12, 0, + 34, 18, 54, 51, 67, 33, 60, 42, 83, 55, 35, 49, + 99, 81, 83, 162, 210, 19, 177, 194, 49, 35, 195, 66, + 0, 2, 0, 34, 52, 134, 21, 21, 52, 36, 107, 55, + 45, 33, 101, 66, 70, 39, 56, 52, 35, 52, 53, 97, + 51, 132, 51, 101, 19, 146, 51, 54, 148, 53, 73, 39, + 57, 84, 86, 19, 102, 0, 36, 35, 66, 49, 41, 99, + 67, 50, 145, 33, 194, 51, 127, 50, 54, 58, 36, 36, + 51, 47, 21, 100, 84, 195, 98, 114, 49, 231, 129, 99, + 42, 83, 51, 69, 103, 87, 135, 87, 56, 52, 56, 165, + 19, 33, 38, 21, 19, 179, 18, 148, 84, 177, 89, 114, + 18, 145, 35, 69, 31, 47, 21, 25, 41, 55, 81, 42, + 0, 36, 50, 55, 42, 87, 179, 31, 101, 145, 39, 59, + 145, 99, 36, 36, 53, 22, 149, 120, 114, 51, 19, 33, + 225, 227, 18, 55, 38, 120, 114, 52, 50, 51, 52, 36, + 39, 132, 50, 100, 129, 84, 35, 211, 84, 35, 103, 242, + 123, 70, 35, 69, 55, 83, 21, 102, 115, 57, 83, 73, + 35, 19, 81, 84, 51, 81, 149, 22, 35, 69, 103, 98, + 69, 51, 162, 120, 117, 69, 97, 147, 101, 97, 33, 99, + 36, 0, 4, 0, 44, 33, 33, 86, 51, 114, 51, 52, + 0, 6, 0, 36, 146, 49, 99, 51, 39, 182, 25, 83, + 220, 33, 33, 39, 35, 52, 134, 0, 2, 0, 42, 33, + 44, 51, 25, 39, 62, 151, 53, 97, 54, 243, 35, 55, + 33, 194, 51, 213, 147, 67, 63, 38, 97, 129, 50, 105, + 19, 45, 99, 98, 204, 99, 22, 228, 35, 97, 147, 35, + 58, 129, 51, 149, 49, 36, 51, 200, 52, 83, 123, 72, + 49, 98, 27, 73, 0, 34, 19, 146, 51, 69, 73, 50, + 18, 72, 22, 99, 146, 51, 49, 54, 90, 105, 35, 24, + 21, 114, 241, 86, 28, 56, 69, 22, 179, 24, 165, 22, + 105, 86, 49, 81, 53, 145, 99, 35, 28, 225, 33, 81, + 134, 75, 19, 33, 83, 166, 84, 99, 51, 41, 18, 105, + 22, 50, 24, 102, 114, 73, 38, 115, 50, 67, 42, 101, + 114, 24, 22, 242, 60, 172, 84, 101, 99, 102, 52, 135, + 50, 0, 6, 0, 36, 165, 246, 18, 30, 103, 59, 66, + 147, 121, 35, 19, 0, 34, 145, 131, 145, 194, 19, 99, + 101, 67, 134, 69, 0, 14, 0, 40, 49, 50, 103, 33, + 33, 36, 53, 51, 19, 51, 99, 197, 21, 54, 51, 115, + 0, 6, 0, 52, 163, 81, 84, 86, 97, 50, 120, 70, + 59, 21, 67, 177, 179, 69, 102, 21, 54, 18, 117, 19, + 146, 100, 150, 51, 35, 55, 33, 102, 35, 153, 97, 134, + 73, 93, 35, 67, 50, 21, 162, 52, 42, 81, 0, 34, + 18, 193, 102, 83, 22, 243, 104, 97, 185, 103, 81, 102, + 33, 35, 97, 137, 0, 2, 0, 40, 72, 52, 81, 41, + 69, 70, 41, 25, 81, 33, 36, 225, 59, 99, 121, 35, + 67, 53, 66, 25, 83, 171, 67, 242, 18, 147, 241, 36, + 50, 54, 0, 14, 0, 34, 115, 33, 50, 114, 19, 225, + 35, 69, 21, 21, 18, 241, 102, 89, 103, 81, 99, 83, + 118, 39, 41, 21, 66, 69, 105, 148, 57, 135, 51, 87, + 35, 22, 98, 51, 97, 129, 99, 39, 50, 22, 146, 0, + 36, 150, 97, 33, 36, 98, 0, 36, 57, 22, 83, 108, + 67, 56, 97, 149, 165, 19, 146, 0, 2, 0, 40, 49, + 129, 36, 149, 99, 21, 66, 54, 21, 148, 50, 162, 0, + 6, 0, 36, 49, 83, 195, 120, 57, 21, 165, 67, 35, + 21, 22, 33, 36, 83, 105, 118, 132, 56, 66, 19, 156, + 149, 97, 39, 83, 51, 150, 30, 151, 134, 124, 107, 49, + 84, 33, 39, 99, 35, 114, 18, 243, 19, 81, 251, 18, + 52, 51, 134, 99, 66, 28, 98, 52, 51, 81, 54, 231, + 50, 100, 54, 35, 115, 101, 51, 67, 50, 18, 70, 39, + 149, 24, 58, 53, 66, 0, 30, 0, 36, 100, 182, 19, + 104, 51, 25, 45, 36, 149, 69, 55, 42, 185, 100, 230, + 51, 67, 108, 135, 39, 99, 86, 163, 36, 150, 149, 18, + 165, 114, 49, 92, 145, 42, 135, 87, 50, 58, 53, 49, + 99, 245, 67, 35, 0, 8, 0, 40, 18, 22, 146, 52, + 83, 153, 22, 132, 50, 51, 0, 2, 0, 52, 114, 168, + 18, 54, 19, 102, 50, 117, 51, 117, 120, 67, 98, 75, + 49, 155, 49, 147, 135, 83, 97, 50, 73, 104, 18, 114, + 70, 111, 132, 33, 59, 100, 83, 51, 115, 149, 97, 81, + 45, 38, 66, 148, 87, 131, 52, 83, 67, 101, 165, 66, + 109, 146, 105, 63, 52, 59, 97, 35, 49, 81, 35, 49, + 59, 147, 150, 70, 53, 97, 129, 81, 89, 58, 33, 59, + 51, 147, 118, 129, 51, 39, 98, 25, 0, 16, 0, 36, + 99, 126, 22, 54, 50, 24, 244, 195, 245, 25, 35, 100, + 177, 59, 145, 81, 95, 30, 55, 131, 168, 19, 0, 4, + 0, 32, 33, 35, 22, 35, 54, 19, 35, 67, 42, 0, + 4, 0, 32, 84, 129, 177, 35, 67, 135, 41, 66, 163, + 102, 53, 21, 22, 230, 145, 149, 69, 0, 48, 18, 52, + 81, 95, 0, 2, 0, 36, 53, 49, 146, 52, 135, 131, + 114, 162, 49, 86, 19, 99, 50, 97, 50, 99, 66, 19, + 149, 52, 99, 177, 54, 146, 115, 42, 56, 66, 75, 70, + 51, 134, 159, 66, 18, 61, 39, 203, 49, 53, 55, 51, + 101, 49, 101, 100, 153, 83, 72, 51, 72, 162, 21, 21, + 99, 67, 90, 89, 210, 63, 18, 67, 102, 146, 75, 49, + 0, 12, 0, 34, 57, 99, 30, 120, 114, 118, 35, 49, + 0, 36, 35, 166, 195, 177, 137, 102, 145, 51, 50, 55, + 33, 180, 99, 83, 70, 150, 53, 27, 115, 50, 147, 171, + 22, 194, 153, 27, 18, 100, 101, 114, 25, 0, 16, 0, + 38, 51, 54, 83, 100, 50, 55, 243, 84, 179, 70, 81, + 81, 53, 21, 105, 163, 36, 179, 63, 55, 54, 99, 81, + 95, 24, 66, 19, 146, 19, 45, 36, 53, 18, 52, 35, + 246, 19, 50, 171, 66, 18, 0, 72, 66, 75, 18, 117, + 18, 163, 89, 58, 131, 67, 42, 107, 18, 22, 89, 27, + 57, 241, 87, 84, 0, 16, 0, 50, 53, 69, 99, 145, + 179, 18, 52, 51, 89, 27, 24, 117, 49, 101, 162, 115, + 0, 4, 0, 36, 18, 54, 18, 118, 50, 49, 50, 165, + 21, 54, 28, 102, 51, 44, 18, 193, 50, 52, 131, 21, + 103, 0, 6, 0, 34, 55, 50, 31, 180, 35, 66, 30, + 19, 45, 155, 19, 131, 24, 97, 98, 51, 117, 52, 98, + 145, 84, 131, 63, 21, 145, 84, 36, 108, 0, 40, 22, + 83, 97, 98, 18, 57, 118, 50, 127, 36, 84, 53, 148, + 39, 131, 66, 49, 81, 98, 18, 52, 35, 0, 32, 197, + 73, 81, 53, 18, 147, 97, 129, 179, 52, 146, 150, 67, + 42, 63, 182, 19, 146, 0, 62, 33, 99, 81, 102, 225, + 39, 179, 19, 53, 114, 21, 52, 87, 83, 22, 185, 69, + 150, 22, 38, 21, 19, 147, 0, 6, 0, 34, 49, 98, + 57, 145, 131, 52, 53, 148, 84, 81, 41, 214, 177, 33, + 179, 55, 131, 165, 97, 0, 18, 0, 42, 44, 19, 86, + 19, 84, 35, 102, 66, 54, 250, 60, 53, 97, 90, 51, + 38, 117, 150, 67, 98, 117, 22, 248, 22, 50, 18, 61, + 41, 18, 55, 0, 54, 0, 6, 0, 52, 24, 51, 109, + 33, 59, 49, 102, 53, 145, 102, 89, 99, 67, 83, 66, + 18, 172, 51, 87, 81, 179, 117, 210, 148, 102, 86, 52, + 131, 67, 59, 21, 165, 0, 6, 0, 44, 147, 81, 35, + 114, 210, 22, 84, 36, 98, 100, 180, 53, 147, 52, 54, + 36, 149, 99, 97, 50, 24, 102, 117, 115, 86, 22, 50, + 49, 98, 211, 147, 83, 25, 84, 45, 90, 56, 166, 84, + 81, 131, 165, 162, 241, 36, 129, 146, 19, 89, 103, 147, + 138, 50, 67, 35, 100, 81, 99, 33, 53, 24, 103, 83, + 67, 225, 57, 0, 30, 0, 34, 24, 97, 152, 52, 84, + 84, 0, 10, 0, 44, 51, 42, 33, 39, 228, 56, 127, + 63, 39, 83, 52, 41, 99, 27, 100, 54, 39, 35, 18, + 154, 56, 0, 38, 129, 35, 0, 2, 0, 40, 0, 42, + 114, 49, 197, 49, 149, 97, 129, 56, 52, 33, 83, 69, + 25, 132, 105, 99, 101, 51, +}; + +static uint32_t bn_mod_word16(const struct LITE_BIGNUM *p, uint16_t word) +{ + int i; + uint32_t rem = 0; + + for (i = p->dmax - 1; i >= 0; i--) { + rem = ((rem << 16) | + ((BN_DIGIT(p, i) >> 16) & 0xFFFFUL)) % word; + rem = ((rem << 16) | (BN_DIGIT(p, i) & 0xFFFFUL)) % word; + } + + return rem; +} + +static uint32_t bn_mod_f4(const struct LITE_BIGNUM *d) +{ + int i = bn_size(d) - 1; + const uint8_t *p = (const uint8_t *) (d->d); + uint32_t rem = 0; + + for (; i >= 0; --i) { + uint32_t q = RSA_F4 * (rem >> 8); + + if (rem < q) + q -= RSA_F4; + rem <<= 8; + rem |= p[i]; + rem -= q; + } + + if (rem >= RSA_F4) + rem -= RSA_F4; + + return rem; +} + +#define bn_is_even(b) !bn_is_bit_set((b), 0) +/* From HAC Fact 4.48 (ii), the following number of + * rounds suffice for ~2^145 confidence. Each additional + * round provides about another k/100 bits of confidence. */ +#define ROUNDS_1024 7 +#define ROUNDS_512 15 +#define ROUNDS_384 22 + +/* Miller-Rabin from HAC, algorithm 4.24. */ +static int bn_probable_prime(const struct LITE_BIGNUM *p) +{ + int j; + int s = 0; + + uint32_t ONE_buf = 1; + uint8_t r_buf[RSA_MAX_BYTES / 2]; + uint8_t A_buf[RSA_MAX_BYTES / 2]; + uint8_t y_buf[RSA_MAX_BYTES / 2]; + + struct LITE_BIGNUM ONE; + struct LITE_BIGNUM r; + struct LITE_BIGNUM A; + struct LITE_BIGNUM y; + + const int rounds = bn_bits(p) >= 1024 ? ROUNDS_1024 : + bn_bits(p) >= 512 ? ROUNDS_512 : + ROUNDS_384; + + /* Failsafe: update rounds table above to support smaller primes. */ + if (bn_bits(p) < 384) + return 0; + + if (bn_size(p) > sizeof(r_buf)) + return 0; + + DCRYPTO_bn_wrap(&ONE, &ONE_buf, sizeof(ONE_buf)); + DCRYPTO_bn_wrap(&r, r_buf, bn_size(p)); + bn_copy(&r, p); + + /* r * (2 ^ s) = p - 1 */ + bn_sub(&r, &ONE); + while (bn_is_even(&r)) { + bn_rshift(&r, 0, 0); + s++; + } + + DCRYPTO_bn_wrap(&A, A_buf, bn_size(p)); + DCRYPTO_bn_wrap(&y, y_buf, bn_size(p)); + for (j = 0; j < rounds; j++) { + int i; + + /* pick random A, such that A < p */ + rand_bytes(A_buf, bn_size(&A)); + for (i = A.dmax - 1; i >= 0; i--) { + while (BN_DIGIT(&A, i) > BN_DIGIT(p, i)) + BN_DIGIT(&A, i) = rand(); + if (BN_DIGIT(&A, i) < BN_DIGIT(p, i)) + break; + } + + /* y = a ^ r mod p */ + bn_modexp(&y, &A, &r, p); + if (bn_eq(&y, &ONE)) + continue; + bn_add(&y, &ONE); + if (bn_eq(&y, p)) + continue; + bn_sub(&y, &ONE); + + /* y = y ^ 2 mod p */ + for (i = 0; i < s - 1; i++) { + bn_copy(&A, &y); + bn_modexp_word(&y, &A, 2, p); + + if (bn_eq(&y, &ONE)) + return 0; + + bn_add(&y, &ONE); + if (bn_eq(&y, p)) { + bn_sub(&y, &ONE); + break; + } + bn_sub(&y, &ONE); + } + bn_add(&y, &ONE); + if (!bn_eq(&y, p)) + return 0; + } + + return 1; +} + +/* #define PRINT_PRIMES to enable printing predefined prime numbers' set. */ +static void print_primes(uint16_t prime) +{ +#ifdef PRINT_PRIMES + static uint16_t num_per_line; + static uint16_t max_printed; + + if (prime <= max_printed) + return; + + if (!(num_per_line++ % 8)) { + if (num_per_line == 1) + ccprintf("Prime numbers:"); + ccprintf("\n"); + cflush(); + } + max_printed = prime; + ccprintf(" %6d", prime); +#endif +} + +int DCRYPTO_bn_generate_prime(struct LITE_BIGNUM *p) +{ + int i; + int j; + /* Using a sieve size of 2048-bits results in a failure rate + * of ~0.5% @ 1024-bit candidates. The failure rate rises to ~6% + * if the sieve size is halved. */ + uint8_t composites_buf[256]; + struct LITE_BIGNUM composites; + uint16_t prime = PRIME1; + + /* Set top two bits, as well as LSB. */ + bn_set_bit(p, 0); + bn_set_bit(p, bn_bits(p) - 1); + bn_set_bit(p, bn_bits(p) - 2); + + /* Save on trial division by marking known composites. */ + bn_init(&composites, composites_buf, sizeof(composites_buf)); + for (i = 0; i < ARRAY_SIZE(PRIME_DELTAS); i++) { + uint16_t rem; + uint8_t unpacked_deltas[2]; + uint8_t packed_deltas = PRIME_DELTAS[i]; + int k; + int m; + + if (packed_deltas) { + unpacked_deltas[0] = (packed_deltas >> 4) << 1; + unpacked_deltas[1] = (packed_deltas & 0xf) << 1; + m = 2; + } else { + i += 1; + unpacked_deltas[0] = PRIME_DELTAS[i]; + m = 1; + } + + for (k = 0; k < m; k++) { + prime += unpacked_deltas[k]; + print_primes(prime); + rem = bn_mod_word16(p, prime); + /* Skip marking odd offsets (i.e. even candidates). */ + for (j = (rem == 0) ? 0 : prime - rem; + j < bn_bits(&composites) << 1; + j += prime) { + if ((j & 1) == 0) + bn_set_bit(&composites, j >> 1); + } + } + } + + /* composites now marked, apply Miller-Rabin to prime candidates. */ + j = 0; + for (i = 0; i < bn_bits(&composites); i++) { + uint32_t diff_buf; + struct LITE_BIGNUM diff; + + if (bn_is_bit_set(&composites, i)) + continue; + + /* Recover increment from the composites sieve. */ + diff_buf = (i << 1) - j; + j = (i << 1); + DCRYPTO_bn_wrap(&diff, &diff_buf, sizeof(diff_buf)); + bn_add(p, &diff); + /* Make sure prime will work with F4 public exponent. */ + if (bn_mod_f4(p) >= 2) { + if (bn_probable_prime(p)) + return 1; + } + } + + always_memset(composites_buf, 0, sizeof(composites_buf)); + return 0; +} diff --git a/chip/g/dcrypto/compare.c b/chip/g/dcrypto/compare.c new file mode 100644 index 0000000000..db6193752b --- /dev/null +++ b/chip/g/dcrypto/compare.c @@ -0,0 +1,20 @@ +/* Copyright 2016 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" + +/* Constant time comparator. */ +int DCRYPTO_equals(const void *a, const void *b, size_t len) +{ + size_t i; + const uint8_t *pa = a; + const uint8_t *pb = b; + uint8_t diff = 0; + + for (i = 0; i < len; i++) + diff |= pa[i] ^ pb[i]; + + return !diff; +} diff --git a/chip/g/dcrypto/dcrypto.h b/chip/g/dcrypto/dcrypto.h new file mode 100644 index 0000000000..8cf1071090 --- /dev/null +++ b/chip/g/dcrypto/dcrypto.h @@ -0,0 +1,445 @@ +/* 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. + */ + +/* + * Crypto wrapper library for the g chip. + */ +#ifndef __EC_CHIP_G_DCRYPTO_DCRYPTO_H +#define __EC_CHIP_G_DCRYPTO_DCRYPTO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(TEST_FUZZ) || !defined(TEST_BUILD) + +#include "internal.h" + +#include "crypto_api.h" + +#include + +#include "cryptoc/hmac.h" + +enum cipher_mode { + CIPHER_MODE_ECB = 0, /* NIST SP 800-38A */ + CIPHER_MODE_CTR = 1, /* NIST SP 800-38A */ + CIPHER_MODE_CBC = 2, /* NIST SP 800-38A */ + CIPHER_MODE_GCM = 3 /* NIST SP 800-38D */ +}; + +enum encrypt_mode { + DECRYPT_MODE = 0, + ENCRYPT_MODE = 1 +}; + +enum hashing_mode { + HASH_SHA1 = 0, + HASH_SHA256 = 1, + HASH_SHA384 = 2, /* Only supported for PKCS#1 signing */ + HASH_SHA512 = 3, /* Only supported for PKCS#1 signing */ + HASH_NULL = 4 /* Only supported for PKCS#1 signing */ +}; + +/* + * AES implementation, based on a hardware AES block. + * FIPS Publication 197, The Advanced Encryption Standard (AES) + */ +#define AES256_BLOCK_CIPHER_KEY_SIZE 32 + +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); + +void DCRYPTO_aes_write_iv(const uint8_t *iv); +void DCRYPTO_aes_read_iv(uint8_t *iv); + +/* AES-CTR-128/192/256 + * NIST Special Publication 800-38A + */ +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); + +/* AES-GCM-128/192/256 + * NIST Special Publication 800-38D, IV is provided externally + * Caller should use IV length according to section 8.2 of SP 800-38D + * And choose appropriate IV construction method, constrain number + * of invocations according to section 8.3 of SP 800-38D + */ +struct GCM_CTX { + union { + uint32_t d[4]; + uint8_t c[16]; + } block, Ej0; + + uint64_t aad_len; + uint64_t count; + size_t remainder; +}; + +/* Initialize the GCM context structure. */ +void DCRYPTO_gcm_init(struct GCM_CTX *ctx, uint32_t key_bits, + const uint8_t *key, const uint8_t *iv, size_t iv_len); +/* Additional authentication data to include in the tag calculation. */ +void DCRYPTO_gcm_aad(struct GCM_CTX *ctx, const uint8_t *aad_data, size_t len); +/* Encrypt & decrypt return the number of bytes written to out + * (always an integral multiple of 16), or -1 on error. These functions + * may be called repeatedly with incremental data. + * + * NOTE: if in_len is not a integral multiple of 16, then out_len must + * be atleast in_len - (in_len % 16) + 16 bytes. + */ +int DCRYPTO_gcm_encrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len, + const uint8_t *in, size_t in_len); +int DCRYPTO_gcm_decrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len, + const uint8_t *in, size_t in_len); +/* Encrypt & decrypt a partial final block, if any. These functions + * return the number of bytes written to out (<= 15), or -1 on error. + */ +int DCRYPTO_gcm_encrypt_final(struct GCM_CTX *ctx, + uint8_t *out, size_t out_len); +int DCRYPTO_gcm_decrypt_final(struct GCM_CTX *ctx, + uint8_t *out, size_t out_len); +/* Compute the tag over AAD + encrypt or decrypt data, and return the + * number of bytes written to tag. Returns -1 on error. + */ +int DCRYPTO_gcm_tag(struct GCM_CTX *ctx, uint8_t *tag, size_t tag_len); +/* Cleanup secrets. */ +void DCRYPTO_gcm_finish(struct GCM_CTX *ctx); + +/* AES-CMAC-128 + * NIST Special Publication 800-38B, RFC 4493 + * K: 128-bit key, M: message, len: number of bytes in M + * Writes 128-bit tag to T; returns 0 if an error is encountered and 1 + * otherwise. + */ +int DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, const uint32_t len, + uint32_t T[4]); +/* key: 128-bit key, M: message, len: number of bytes in M, + * T: tag to be verified + * Returns 1 if the tag is correct and 0 otherwise. + */ +int DCRYPTO_aes_cmac_verify(const uint8_t *key, const uint8_t *M, const int len, + const uint32_t T[4]); + +/* + * 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(SHA_CTX *ctx, uint32_t sw_required); +/* SHA256/384/512 FIPS 180-4 + */ +void DCRYPTO_SHA256_init(LITE_SHA256_CTX *ctx, uint32_t sw_required); +void DCRYPTO_SHA384_init(LITE_SHA384_CTX *ctx); +void DCRYPTO_SHA512_init(LITE_SHA512_CTX *ctx); +const uint8_t *DCRYPTO_SHA1_hash(const void *data, uint32_t n, + uint8_t *digest); +const uint8_t *DCRYPTO_SHA256_hash(const void *data, uint32_t n, + uint8_t *digest); +const uint8_t *DCRYPTO_SHA384_hash(const void *data, uint32_t n, + uint8_t *digest); +const uint8_t *DCRYPTO_SHA512_hash(const void *data, uint32_t n, + uint8_t *digest); +/* + * HMAC. FIPS 198-1 + */ +void DCRYPTO_HMAC_SHA256_init(LITE_HMAC_CTX *ctx, const void *key, + unsigned int len); +/* DCRYPTO HMAC-SHA256 final */ +const uint8_t *DCRYPTO_HMAC_final(LITE_HMAC_CTX *ctx); + +/* + * BIGNUM utility methods. + */ +void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len); + +/* + * RSA. + */ + +/* Largest supported key size for signing / encryption: 2048-bits. + * Verification is a special case and supports 4096-bits (signing / + * decryption could also support 4k-RSA, but is disabled since support + * is not required, and enabling support would result in increased + * stack usage for all key sizes.) + */ +#define RSA_BYTES_2K 256 +#define RSA_BYTES_4K 512 +#define RSA_WORDS_2K (RSA_BYTES_2K / sizeof(uint32_t)) +#define RSA_WORDS_4K (RSA_BYTES_4K / sizeof(uint32_t)) +#ifndef RSA_MAX_BYTES +#define RSA_MAX_BYTES RSA_BYTES_2K +#endif +#define RSA_MAX_WORDS (RSA_MAX_BYTES / sizeof(uint32_t)) +#define RSA_F4 65537 + +struct RSA { + uint32_t e; + struct LITE_BIGNUM N; + struct LITE_BIGNUM d; +}; + +enum padding_mode { + PADDING_MODE_PKCS1 = 0, + PADDING_MODE_OAEP = 1, + PADDING_MODE_PSS = 2, + /* USE OF NULL PADDING IS NOT RECOMMENDED. + * SUPPORT EXISTS AS A REQUIREMENT FOR TPM2 OPERATION. */ + PADDING_MODE_NULL = 3 +}; + +/* RSA support, FIPS PUB 186-4 * + * Calculate r = m ^ e mod N + */ +int DCRYPTO_rsa_encrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len, + const uint8_t *in, uint32_t in_len, + enum padding_mode padding, enum hashing_mode hashing, + const char *label); + +/* Calculate r = m ^ d mod N + * return 0 if error + */ +int DCRYPTO_rsa_decrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len, + const uint8_t *in, const uint32_t in_len, + enum padding_mode padding, enum hashing_mode hashing, + const char *label); + +/* Calculate r = m ^ d mod N + * return 0 if error + */ +int DCRYPTO_rsa_sign(struct RSA *rsa, uint8_t *out, uint32_t *out_len, + const uint8_t *in, const uint32_t in_len, + enum padding_mode padding, enum hashing_mode hashing); + +/* Calculate r = m ^ e mod N + * return 0 if error + */ +int DCRYPTO_rsa_verify(const struct RSA *rsa, const uint8_t *digest, + uint32_t digest_len, const uint8_t *sig, + const uint32_t sig_len, enum padding_mode padding, + enum hashing_mode hashing); + +/* Calculate n = p * q, d = e ^ -1 mod phi. */ +int DCRYPTO_rsa_key_compute(struct LITE_BIGNUM *N, struct LITE_BIGNUM *d, + struct LITE_BIGNUM *p, struct LITE_BIGNUM *q, + uint32_t e); + +/* + * EC. + */ + +/* DCRYPTO_p256_base_point_mul sets {out_x,out_y} = nG, where n is < the + * order of the group. + */ +int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y, + const p256_int *n); + +/* DCRYPTO_p256_point_mul sets {out_x,out_y} = n*{in_x,in_y}, where n is < + * the order of the group. + */ +int DCRYPTO_p256_point_mul(p256_int *out_x, p256_int *out_y, + const p256_int *n, const p256_int *in_x, + const p256_int *in_y); +/* + * Key selection based on FIPS-186-4, section B.4.2 (Key Pair + * Generation by Testing Candidates). + * Produce uniform private key from seed. + * If x or y is NULL, the public key part is not computed. + * Returns !0 on success. + */ +int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d, + const uint8_t bytes[P256_NBYTES]); + + +/* P256 based integration encryption (DH+AES128+SHA256). + * Not FIPS 140-2 compliant, not used other than for tests + * Authenticated data may be provided, where the first auth_data_len + * bytes of in will be authenticated but not encrypted. * + * Supports in-place encryption / decryption. * + * The output format is: + * 0x04 || PUBKEY || AUTH_DATA || AES128_CTR(PLAINTEXT) || + * HMAC_SHA256(AUTH_DATA || CIPHERTEXT) + */ +size_t DCRYPTO_ecies_encrypt( + void *out, size_t out_len, const void *in, size_t in_len, + size_t auth_data_len, const uint8_t *iv, + const p256_int *pub_x, const p256_int *pub_y, + const uint8_t *salt, size_t salt_len, + const uint8_t *info, size_t info_len); +size_t DCRYPTO_ecies_decrypt( + void *out, size_t out_len, const void *in, size_t in_len, + size_t auth_data_len, const uint8_t *iv, + const p256_int *d, + const uint8_t *salt, size_t salt_len, + const uint8_t *info, size_t info_len); + +/* + * HKDF as per RFC 5869. Mentioned as conforming NIST SP 800-56C Rev.1 + * [RFC 5869] specifies a version of the above extraction-then-expansion + * key-derivation procedure using HMAC for both the extraction and expansion + * steps. + */ +int DCRYPTO_hkdf(uint8_t *OKM, size_t OKM_len, + const uint8_t *salt, size_t salt_len, + const uint8_t *IKM, size_t IKM_len, + const uint8_t *info, size_t info_len); + +/* + * BN. + */ + +/* Apply Miller-Rabin test for prime candidate p. + * Returns 1 if test passed, 0 otherwise + */ +int DCRYPTO_bn_generate_prime(struct LITE_BIGNUM *p); +void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len); +void DCRYPTO_bn_mul(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a, + const struct LITE_BIGNUM *b); +int DCRYPTO_bn_div(struct LITE_BIGNUM *quotient, struct LITE_BIGNUM *remainder, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *divisor); + +/* + * ASN.1 DER + */ +size_t DCRYPTO_asn1_sigp(uint8_t *buf, const p256_int *r, const p256_int *s); +size_t DCRYPTO_asn1_pubp(uint8_t *buf, const p256_int *x, const p256_int *y); + +/* + * X509. + */ +/* DCRYPTO_x509_verify verifies that the provided X509 certificate was issued + * by the specified certifcate authority. + * + * cert is a pointer to a DER encoded X509 certificate, as specified + * in https://tools.ietf.org/html/rfc5280#section-4.1. In ASN.1 + * notation, the certificate has the following structure: + * + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + * + * TBSCertificate ::= SEQUENCE { } + * AlgorithmIdentifier ::= SEQUENCE { } + * + * where signatureValue = SIGN(HASH(tbsCertificate)), with SIGN and + * HASH specified by signatureAlgorithm. + * Accepts only certs with OID: sha256WithRSAEncryption: + * 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 + */ +int DCRYPTO_x509_verify(const uint8_t *cert, size_t len, + const struct RSA *ca_pub_key); + +/* Generate U2F Certificate and sign it + * Use ECDSA with NIST P-256 curve, and SHA2-256 digest + * @param d: key handle, used for NIST SP 800-90A HMAC DRBG + * @param pk_x, pk_y: public key + * @param serial: serial number for certificate + * @param name: certificate issuer and subject + * @param cert: output buffer for certificate + * @param n: max size of cert + */ +int DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x, + const p256_int *pk_y, const p256_int *serial, + const char *name, uint8_t *cert, + const int n); + +/* Generate U2F Certificate with DCRYPTO_x509_gen_u2f_cert_name + * Providing certificate issuer as BOARD or U2F + * @param d: key handle, used for NIST SP 800-90A HMAC DRBG + * @param pk_x, pk_y: public key + * @param serial: serial number for certificate + * @param name: certificate issuer and subject + * @param cert: output buffer for certificate + * @param n: max size of cert + */ +int DCRYPTO_x509_gen_u2f_cert(const p256_int *d, const p256_int *pk_x, + const p256_int *pk_y, const p256_int *serial, + uint8_t *cert, const int n); + +/* + * Memory related functions. + */ +int DCRYPTO_equals(const void *a, const void *b, size_t len); + +/* + * Key-ladder and application key related functions. + */ +enum dcrypto_appid { + RESERVED = 0, + NVMEM = 1, + U2F_ATTEST = 2, + U2F_ORIGIN = 3, + U2F_WRAP = 4, + PERSO_AUTH = 5, + PINWEAVER = 6, + /* This enum value should not exceed 7. */ +}; + +struct APPKEY_CTX { +#ifdef TEST_FUZZ + uint8_t unused_for_cxx_compatibility; +#endif +}; + +int DCRYPTO_ladder_compute_frk2(size_t major_fw_version, uint8_t *frk2); +int DCRYPTO_ladder_random(void *output); +void DCRYPTO_ladder_revoke(void); + +int DCRYPTO_appkey_init(enum dcrypto_appid id, struct APPKEY_CTX *ctx); +void DCRYPTO_appkey_finish(struct APPKEY_CTX *ctx); +int DCRYPTO_appkey_derive(enum dcrypto_appid appid, const uint32_t input[8], + uint32_t output[8]); + +/* Number of bytes in the salt object. */ +#define DCRYPTO_CIPHER_SALT_SIZE 16 +BUILD_ASSERT(DCRYPTO_CIPHER_SALT_SIZE == CIPHER_SALT_SIZE); + +/* + * Encrypt/decrypt a flat blob. + * + * Encrypt or decrypt the input buffer, and write the correspondingly + * ciphered output to out. The number of bytes produced is equal to + * the number of input bytes. Note that the input and output pointers + * MUST be word-aligned. + * + * This API is expected to be applied to a single contiguous region. + + * WARNING: A given salt/"in" pair MUST be unique, i.e. re-using a + * salt with a logically different input buffer is catastrophic. An + * example of a suitable salt is one that is derived from "in", e.g. a + * digest of the input data. + * + * @param appid the application-id of the calling context. + * @param salt pointer to a unique value to be associated with this blob, + * used for derivation of the proper IV, the size of the value + * is as defined by DCRYPTO_CIPHER_SALT_SIZE above. + * @param out Destination pointer where to write plaintext / ciphertext. + * @param in Source pointer where to read ciphertext / plaintext. + * @param len Number of bytes to read from in / write to out. + * @return non-zero on success, and zero otherwise. + */ +int DCRYPTO_app_cipher(enum dcrypto_appid appid, const void *salt, + void *out, const void *in, size_t len); + +#endif /* ^^^^^^^^^^^^^^^^^^^^^ !TEST_BUILD */ +/* + * Query whether Key Ladder is enabled. + * + * @return 1 if Key Ladder is enabled, and 0 otherwise. + */ +int DCRYPTO_ladder_is_enabled(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ! __EC_CHIP_G_DCRYPTO_DCRYPTO_H */ diff --git a/chip/g/dcrypto/dcrypto_bn.c b/chip/g/dcrypto/dcrypto_bn.c new file mode 100644 index 0000000000..b8f8fef4f4 --- /dev/null +++ b/chip/g/dcrypto/dcrypto_bn.c @@ -0,0 +1,1496 @@ +/* Copyright 2016 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 "trng.h" + +/* Firmware blob for crypto accelerator */ + +/* AUTO-GENERATED. DO NOT MODIFY. */ +/* clang-format off */ +static const uint32_t IMEM_dcrypto_bn[] = { +/* @0x0: function tag[1] { */ +#define CF_tag_adr 0 +0xf8000001, /* sigini #1 */ +/* } */ +/* @0x1: function d0inv[14] { */ +#define CF_d0inv_adr 1 +0x4c000000, /* xor r0, r0, r0 */ +0x80000001, /* movi r0.0l, #1 */ +0x7c740000, /* mov r29, r0 */ +0x05100008, /* loop #256 ( */ +0x5807bc00, /* mul128 r1, r28l, r29l */ +0x588bbc00, /* mul128 r2, r28u, r29l */ +0x50044110, /* add r1, r1, r2 << 128 */ +0x590bbc00, /* mul128 r2, r28l, r29u */ +0x50044110, /* add r1, r1, r2 << 128 */ +0x40040100, /* and r1, r1, r0 */ +0x44743d00, /* or r29, r29, r1 */ +0x50000000, /* add r0, r0, r0 */ +/* ) */ +0x5477bf00, /* sub r29, r31, r29 */ +0x0c000000, /* ret */ +/* } */ +/* @0xf: function selcxSub[25] { */ +#define CF_selcxSub_adr 15 +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x99100000, /* strnd r4 */ +0x5013e400, /* add r4, r4, r31 */ +0x1000101e, /* bl selcxSub_invsel */ +0x528c8402, /* addcx r3, r4, r4 << 16 */ +0x0600c007, /* loop *6 ( */ +0x8c081800, /* ld *2, *0++ */ +0x7c8c0000, /* ldr *3, *0 */ +0x7c800400, /* ldr *0, *4 */ +0x54906200, /* subb r4, r2, r3 */ +0x990c0000, /* strnd r3 */ +0x660c4401, /* sellx r3, r4, r2 */ +0x7ca00200, /* ldr *0++, *2 */ +/* ) */ +0x0c000000, /* ret */ +/*selcxSub_invsel: */ +0x528c8402, /* addcx r3, r4, r4 << 16 */ +0x0600c007, /* loop *6 ( */ +0x8c081800, /* ld *2, *0++ */ +0x7c8c0000, /* ldr *3, *0 */ +0x7c800400, /* ldr *0, *4 */ +0x54906200, /* subb r4, r2, r3 */ +0x990c0000, /* strnd r3 */ +0x660c8201, /* sellx r3, r2, r4 */ +0x7ca00200, /* ldr *0++, *2 */ +/* ) */ +0x0c000000, /* ret */ +/* } */ +/* @0x28: function computeRR[41] { */ +#define CF_computeRR_adr 40 +0x4c7fff00, /* xor r31, r31, r31 */ +0x84004000, /* ldi r0, [#0] */ +0x95800000, /* lddmp r0 */ +0x4c0c6300, /* xor r3, r3, r3 */ +0x800cffff, /* movi r3.0l, #65535 */ +0x40040398, /* and r1, r3, r0 >> 192 */ +0x480c6000, /* not r3, r3 */ +0x400c0300, /* and r3, r3, r0 */ +0x500c2301, /* add r3, r3, r1 << 8 */ +0x94800300, /* ldlc r3 */ +0x80040005, /* movi r1.0l, #5 */ +0x81040003, /* movi r1.2l, #3 */ +0x81840002, /* movi r1.3l, #2 */ +0x82040004, /* movi r1.4l, #4 */ +0x97800100, /* ldrfp r1 */ +0x4c0c6300, /* xor r3, r3, r3 */ +0x0600c001, /* loop *6 ( */ +0x7ca00200, /* ldr *0++, *2 */ +/* ) */ +0x560c1f00, /* subx r3, r31, r0 */ +0x0800000f, /* call &selcxSub */ +0x06000010, /* loop *0 ( */ +0x97800100, /* ldrfp r1 */ +0x560c6300, /* subx r3, r3, r3 */ +0x0600c003, /* loop *6 ( */ +0x7c8c0000, /* ldr *3, *0 */ +0x52884200, /* addcx r2, r2, r2 */ +0x7ca00300, /* ldr *0++, *3 */ +/* ) */ +0x0800000f, /* call &selcxSub */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x560c6300, /* subx r3, r3, r3 */ +0x0600c003, /* loop *6 ( */ +0x8c081800, /* ld *2, *0++ */ +0x7c8c0800, /* ldr *3, *0++ */ +0x5e804300, /* cmpbx r3, r2 */ +/* ) */ +0x0800000f, /* call &selcxSub */ +0xfc000000, /* nop */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x0600c001, /* loop *6 ( */ +0x90680800, /* st *0++, *2++ */ +/* ) */ +0x0c000000, /* ret */ +/* } */ +/* @0x51: function dmXd0[9] { */ +#define CF_dmXd0_adr 81 +0x586f3e00, /* mul128 r27, r30l, r25l */ +0x59eb3e00, /* mul128 r26, r30u, r25u */ +0x58df3e00, /* mul128 r23, r30u, r25l */ +0x506efb10, /* add r27, r27, r23 << 128 */ +0x50eafa90, /* addc r26, r26, r23 >> 128 */ +0x595f3e00, /* mul128 r23, r30l, r25u */ +0x506efb10, /* add r27, r27, r23 << 128 */ +0x50eafa90, /* addc r26, r26, r23 >> 128 */ +0x0c000000, /* ret */ +/* } */ +/* @0x5a: function dmXa[9] { */ +#define CF_dmXa_adr 90 +0x586c5e00, /* mul128 r27, r30l, r2l */ +0x59e85e00, /* mul128 r26, r30u, r2u */ +0x58dc5e00, /* mul128 r23, r30u, r2l */ +0x506efb10, /* add r27, r27, r23 << 128 */ +0x50eafa90, /* addc r26, r26, r23 >> 128 */ +0x595c5e00, /* mul128 r23, r30l, r2u */ +0x506efb10, /* add r27, r27, r23 << 128 */ +0x50eafa90, /* addc r26, r26, r23 >> 128 */ +0x0c000000, /* ret */ +/* } */ +/* @0x63: function mma_sub_cx[23] { */ +#define CF_mma_sub_cx_adr 99 +0x99700000, /* strnd r28 */ +0x5073fc00, /* add r28, r28, r31 */ +0x10001070, /* bl mma_invsel */ +0x52f39c02, /* addcx r28, r28, r28 << 16 */ +0x0600c007, /* loop *6 ( */ +0x8c141800, /* ld *5, *0++ */ +0x7c900000, /* ldr *4, *0 */ +0x54f71e00, /* subb r29, r30, r24 */ +0x99600000, /* strnd r24 */ +0x7c800500, /* ldr *0, *5 */ +0x6663dd01, /* sellx r24, r29, r30 */ +0x7ca00500, /* ldr *0++, *5 */ +/* ) */ +0x0c000000, /* ret */ +/*mma_invsel: */ +0x52f39c02, /* addcx r28, r28, r28 << 16 */ +0x0600c007, /* loop *6 ( */ +0x8c141800, /* ld *5, *0++ */ +0x7c900000, /* ldr *4, *0 */ +0x54f71e00, /* subb r29, r30, r24 */ +0x99600000, /* strnd r24 */ +0x7c800500, /* ldr *0, *5 */ +0x6663be01, /* sellx r24, r30, r29 */ +0x7ca00500, /* ldr *0++, *5 */ +/* ) */ +0x0c000000, /* ret */ +/* } */ +/* @0x7a: function mma[39] { */ +#define CF_mma_adr 122 +0x8204001e, /* movi r1.4l, #30 */ +0x82840018, /* movi r1.5l, #24 */ +0x97800100, /* ldrfp r1 */ +0x8c101b00, /* ld *4, *3++ */ +0x0800005a, /* call &dmXa */ +0x7c940800, /* ldr *5, *0++ */ +0x507b1b00, /* add r30, r27, r24 */ +0x50f7fa00, /* addc r29, r26, r31 */ +0x7c640300, /* mov r25, r3 */ +0x08000051, /* call &dmXd0 */ +0x7c641b00, /* mov r25, r27 */ +0x7c701a00, /* mov r28, r26 */ +0x7c601e00, /* mov r24, r30 */ +0x8c101800, /* ld *4, *0++ */ +0x08000051, /* call &dmXd0 */ +0x506f1b00, /* add r27, r27, r24 */ +0x50f3fa00, /* addc r28, r26, r31 */ +0x0600e00e, /* loop *7 ( */ +0x8c101b00, /* ld *4, *3++ */ +0x0800005a, /* call &dmXa */ +0x7c940800, /* ldr *5, *0++ */ +0x506f1b00, /* add r27, r27, r24 */ +0x50ebfa00, /* addc r26, r26, r31 */ +0x5063bb00, /* add r24, r27, r29 */ +0x50f7fa00, /* addc r29, r26, r31 */ +0x8c101800, /* ld *4, *0++ */ +0x08000051, /* call &dmXd0 */ +0x506f1b00, /* add r27, r27, r24 */ +0x50ebfa00, /* addc r26, r26, r31 */ +0x52639b00, /* addx r24, r27, r28 */ +0x7ca80500, /* ldr *2++, *5 */ +0x52f3fa00, /* addcx r28, r26, r31 */ +/* ) */ +0x52e39d00, /* addcx r24, r29, r28 */ +0x7ca80500, /* ldr *2++, *5 */ +0x95800000, /* lddmp r0 */ +0x97800100, /* ldrfp r1 */ +0x08000063, /* call &mma_sub_cx */ +0xfc000000, /* nop */ +0x0c000000, /* ret */ +/* } */ +/* @0xa1: function setupPtrs[11] { */ +#define CF_setupPtrs_adr 161 +0x847c4000, /* ldi r31, [#0] */ +0x4c7fff00, /* xor r31, r31, r31 */ +0x95800000, /* lddmp r0 */ +0x94800000, /* ldlc r0 */ +0x7c041f00, /* mov r1, r31 */ +0x80040004, /* movi r1.0l, #4 */ +0x80840003, /* movi r1.1l, #3 */ +0x81040004, /* movi r1.2l, #4 */ +0x81840002, /* movi r1.3l, #2 */ +0x97800100, /* ldrfp r1 */ +0x0c000000, /* ret */ +/* } */ +/* @0xac: function mulx[19] { */ +#define CF_mulx_adr 172 +0x84004000, /* ldi r0, [#0] */ +0x080000a1, /* call &setupPtrs */ +0x8c041100, /* ld *1, *1 */ +0x7c081f00, /* mov r2, r31 */ +0x0600c001, /* loop *6 ( */ +0x7ca80300, /* ldr *2++, *3 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x0600c004, /* loop *6 ( */ +0x8c0c1c00, /* ld *3, *4++ */ +0x95000000, /* stdmp r0 */ +0x0800007a, /* call &mma */ +0x95800000, /* lddmp r0 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x0600c001, /* loop *6 ( */ +0x90740800, /* st *0++, *5++ */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x0c000000, /* ret */ +/* } */ +/* @0xbf: function mm1_sub_cx[22] { */ +#define CF_mm1_sub_cx_adr 191 +0x990c0000, /* strnd r3 */ +0x500fe300, /* add r3, r3, r31 */ +0x100010cc, /* bl mm1_invsel */ +0x528c6302, /* addcx r3, r3, r3 << 16 */ +0x0600c006, /* loop *6 ( */ +0x8c041800, /* ld *1, *0++ */ +0x7c8c0800, /* ldr *3, *0++ */ +0x548c6200, /* subb r3, r2, r3 */ +0x66084301, /* sellx r2, r3, r2 */ +0x90740300, /* st *3, *5++ */ +0xfc000000, /* nop */ +/* ) */ +0x0c000000, /* ret */ +0xfc000000, /* nop */ +/*mm1_invsel: */ +0x528c6302, /* addcx r3, r3, r3 << 16 */ +0x0600c006, /* loop *6 ( */ +0x8c041800, /* ld *1, *0++ */ +0x7c8c0800, /* ldr *3, *0++ */ +0x548c6200, /* subb r3, r2, r3 */ +0x66086201, /* sellx r2, r2, r3 */ +0x90740300, /* st *3, *5++ */ +0xfc000000, /* nop */ +/* ) */ +0x0c000000, /* ret */ +/* } */ +/* @0xd5: function mul1_exp[23] { */ +#define CF_mul1_exp_adr 213 +0x8c041100, /* ld *1, *1 */ +0x7c081f00, /* mov r2, r31 */ +0x0600c001, /* loop *6 ( */ +0x7ca80300, /* ldr *2++, *3 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x80080001, /* movi r2.0l, #1 */ +0x0600c003, /* loop *6 ( */ +0x95800000, /* lddmp r0 */ +0x0800007a, /* call &mma */ +0x7c081f00, /* mov r2, r31 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x56084200, /* subx r2, r2, r2 */ +0x0600c003, /* loop *6 ( */ +0x8c041800, /* ld *1, *0++ */ +0x7c8c0800, /* ldr *3, *0++ */ +0x5e804300, /* cmpbx r3, r2 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x080000bf, /* call &mm1_sub_cx */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x0c000000, /* ret */ +/* } */ +/* @0xec: function mul1[4] { */ +#define CF_mul1_adr 236 +0x84004000, /* ldi r0, [#0] */ +0x080000a1, /* call &setupPtrs */ +0x080000d5, /* call &mul1_exp */ +0x0c000000, /* ret */ +/* } */ +/* @0xf0: function sqrx_exp[19] { */ +#define CF_sqrx_exp_adr 240 +0x84004020, /* ldi r0, [#1] */ +0x95800000, /* lddmp r0 */ +0x8c041100, /* ld *1, *1 */ +0x7c081f00, /* mov r2, r31 */ +0x0600c001, /* loop *6 ( */ +0x7ca80300, /* ldr *2++, *3 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x0600c004, /* loop *6 ( */ +0x8c0c1c00, /* ld *3, *4++ */ +0x95000000, /* stdmp r0 */ +0x0800007a, /* call &mma */ +0x95800000, /* lddmp r0 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x0600c001, /* loop *6 ( */ +0x90740800, /* st *0++, *5++ */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x95800000, /* lddmp r0 */ +0x0c000000, /* ret */ +/* } */ +/* @0x103: function mulx_exp[14] { */ +#define CF_mulx_exp_adr 259 +0x84004040, /* ldi r0, [#2] */ +0x95800000, /* lddmp r0 */ +0x8c041100, /* ld *1, *1 */ +0x7c081f00, /* mov r2, r31 */ +0x0600c001, /* loop *6 ( */ +0x7ca80300, /* ldr *2++, *3 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x0600c004, /* loop *6 ( */ +0x8c0c1c00, /* ld *3, *4++ */ +0x95000000, /* stdmp r0 */ +0x0800007a, /* call &mma */ +0x95800000, /* lddmp r0 */ +/* ) */ +0x97800100, /* ldrfp r1 */ +0x0c000000, /* ret */ +/* } */ +/* @0x111: function selOutOrC[30] { */ +#define CF_selOutOrC_adr 273 +0x990c0000, /* strnd r3 */ +0x440c6300, /* or r3, r3, r3 */ +0x10001122, /* bl selOutOrC_invsel */ +0x508c6302, /* addc r3, r3, r3 << 16 */ +0x0600c00a, /* loop *6 ( */ +0x990c0000, /* strnd r3 */ +0x99080000, /* strnd r2 */ +0x8c041500, /* ld *1, *5 */ +0x90540300, /* st *3, *5 */ +0x7c8c0800, /* ldr *3, *0++ */ +0x99000000, /* strnd r0 */ +0x7c000200, /* mov r0, r2 */ +0x99080000, /* strnd r2 */ +0x64086001, /* sell r2, r0, r3 */ +0x90740300, /* st *3, *5++ */ +/* ) */ +0x0c000000, /* ret */ +0xfc000000, /* nop */ +/*selOutOrC_invsel: */ +0x508c6302, /* addc r3, r3, r3 << 16 */ +0x0600c00a, /* loop *6 ( */ +0x990c0000, /* strnd r3 */ +0x99080000, /* strnd r2 */ +0x8c041500, /* ld *1, *5 */ +0x90540300, /* st *3, *5 */ +0x7c8c0800, /* ldr *3, *0++ */ +0x99000000, /* strnd r0 */ +0x7c000200, /* mov r0, r2 */ +0x99080000, /* strnd r2 */ +0x64080301, /* sell r2, r3, r0 */ +0x90740300, /* st *3, *5++ */ +/* ) */ +0x0c000000, /* ret */ +/* } */ +/* @0x12f: function modexp[35] { */ +#define CF_modexp_adr 303 +0x080000ac, /* call &mulx */ +0x84004060, /* ldi r0, [#3] */ +0x95800000, /* lddmp r0 */ +0x54084200, /* sub r2, r2, r2 */ +0x0600c004, /* loop *6 ( */ +0xfc000000, /* nop */ +0x8c0c1800, /* ld *3, *0++ */ +0x54885f00, /* subb r2, r31, r2 */ +0x90740300, /* st *3, *5++ */ +/* ) */ +0xfc000000, /* nop */ +0x7c081f00, /* mov r2, r31 */ +0x8008ffff, /* movi r2.0l, #65535 */ +0x400c0298, /* and r3, r2, r0 >> 192 */ +0x48084000, /* not r2, r2 */ +0x40080200, /* and r2, r2, r0 */ +0x50086201, /* add r2, r2, r3 << 8 */ +0x94800200, /* ldlc r2 */ +0x0600000d, /* loop *0 ( */ +0x080000f0, /* call &sqrx_exp */ +0x08000103, /* call &mulx_exp */ +0x84004060, /* ldi r0, [#3] */ +0x95800000, /* lddmp r0 */ +0x99080000, /* strnd r2 */ +0x50084200, /* add r2, r2, r2 */ +0x0600c004, /* loop *6 ( */ +0x99080000, /* strnd r2 */ +0x8c0c1400, /* ld *3, *4 */ +0x50884200, /* addc r2, r2, r2 */ +0x90700300, /* st *3, *4++ */ +/* ) */ +0x08000111, /* call &selOutOrC */ +0xfc000000, /* nop */ +/* ) */ +0x84004060, /* ldi r0, [#3] */ +0x95800000, /* lddmp r0 */ +0x080000d5, /* call &mul1_exp */ +0x0c000000, /* ret */ +/* } */ +/* @0x152: function modexp_blinded[76] { */ +#define CF_modexp_blinded_adr 338 +0x080000ac, /* call &mulx */ +0x84004060, /* ldi r0, [#3] */ +0x95800000, /* lddmp r0 */ +0x54084200, /* sub r2, r2, r2 */ +0x0600c004, /* loop *6 ( */ +0xfc000000, /* nop */ +0x8c0c1800, /* ld *3, *0++ */ +0x54885f00, /* subb r2, r31, r2 */ +0x90740300, /* st *3, *5++ */ +/* ) */ +0xfc000000, /* nop */ +0x8c0c1900, /* ld *3, *1++ */ +0x8c0c1100, /* ld *3, *1 */ +0x521c5f90, /* addx r7, r31, r2 >> 128 */ +0x590c4200, /* mul128 r3, r2l, r2u */ +0x7c181f00, /* mov r6, r31 */ +0x0600c011, /* loop *6 ( */ +0x99080000, /* strnd r2 */ +0x8c0c1400, /* ld *3, *4 */ +0x58106200, /* mul128 r4, r2l, r3l */ +0x59946200, /* mul128 r5, r2u, r3u */ +0x58806200, /* mul128 r0, r2u, r3l */ +0x50100410, /* add r4, r4, r0 << 128 */ +0x50940590, /* addc r5, r5, r0 >> 128 */ +0x59006200, /* mul128 r0, r2l, r3u */ +0x50100410, /* add r4, r4, r0 << 128 */ +0x50940590, /* addc r5, r5, r0 >> 128 */ +0x5010c400, /* add r4, r4, r6 */ +0x5097e500, /* addc r5, r5, r31 */ +0x50088200, /* add r2, r2, r4 */ +0x509be500, /* addc r6, r5, r31 */ +0x5688e200, /* subbx r2, r2, r7 */ +0x90700300, /* st *3, *4++ */ +0x541ce700, /* sub r7, r7, r7 */ +/* ) */ +0x7c080600, /* mov r2, r6 */ +0x5688e200, /* subbx r2, r2, r7 */ +0x90500300, /* st *3, *4 */ +0xfc000000, /* nop */ +0x84004060, /* ldi r0, [#3] */ +0x7c081f00, /* mov r2, r31 */ +0x8008ffff, /* movi r2.0l, #65535 */ +0x400c0298, /* and r3, r2, r0 >> 192 */ +0x48084000, /* not r2, r2 */ +0x40080200, /* and r2, r2, r0 */ +0x510c0301, /* addi r3, r3, #1 */ +0x50086201, /* add r2, r2, r3 << 8 */ +0x94800200, /* ldlc r2 */ +0x06000019, /* loop *0 ( */ +0x080000f0, /* call &sqrx_exp */ +0x08000103, /* call &mulx_exp */ +0x84004060, /* ldi r0, [#3] */ +0x95800000, /* lddmp r0 */ +0x99080000, /* strnd r2 */ +0x54084200, /* sub r2, r2, r2 */ +0x0600c004, /* loop *6 ( */ +0x99080000, /* strnd r2 */ +0x8c0c1400, /* ld *3, *4 */ +0x50884200, /* addc r2, r2, r2 */ +0x90700300, /* st *3, *4++ */ +/* ) */ +0x99080000, /* strnd r2 */ +0x8c0c1400, /* ld *3, *4 */ +0x50884200, /* addc r2, r2, r2 */ +0x90700300, /* st *3, *4++ */ +0x0600c008, /* loop *6 ( */ +0x99080000, /* strnd r2 */ +0x8c041500, /* ld *1, *5 */ +0x90540300, /* st *3, *5 */ +0x7c8c0800, /* ldr *3, *0++ */ +0x7c000200, /* mov r0, r2 */ +0x99080000, /* strnd r2 */ +0x64086008, /* selc r2, r0, r3 */ +0x90740300, /* st *3, *5++ */ +/* ) */ +0xfc000000, /* nop */ +/* ) */ +0x84004060, /* ldi r0, [#3] */ +0x95800000, /* lddmp r0 */ +0x080000d5, /* call &mul1_exp */ +0x0c000000, /* ret */ +/* } */ +/* @0x19e: function modload[12] { */ +#define CF_modload_adr 414 +0x4c7fff00, /* xor r31, r31, r31 */ +0x84004000, /* ldi r0, [#0] */ +0x95800000, /* lddmp r0 */ +0x94800000, /* ldlc r0 */ +0x8000001c, /* movi r0.0l, #28 */ +0x8080001d, /* movi r0.1l, #29 */ +0x97800000, /* ldrfp r0 */ +0x8c001000, /* ld *0, *0 */ +0x08000001, /* call &d0inv */ +0x90440100, /* st *1, *1 */ +0x08000028, /* call &computeRR */ +0x0c000000, /* ret */ +/* } */ +#ifdef CONFIG_DCRYPTO_RSA_SPEEDUP +/* @0x1aa: function selA0orC4[16] { */ +#define CF_selA0orC4_adr 426 +0x99000000, /* strnd r0 */ +0x44000000, /* or r0, r0, r0 */ +0x100011b4, /* bl selA0orC4_invsel */ +0x50840002, /* addc r1, r0, r0 << 16 */ +0x6458da01, /* sell r22, r26, r6 */ +0x645cfb01, /* sell r23, r27, r7 */ +0x64611c01, /* sell r24, r28, r8 */ +0x64653d01, /* sell r25, r29, r9 */ +0x0c000000, /* ret */ +0xfc000000, /* nop */ +/*selA0orC4_invsel: */ +0x50840002, /* addc r1, r0, r0 << 16 */ +0x645b4601, /* sell r22, r6, r26 */ +0x645f6701, /* sell r23, r7, r27 */ +0x64638801, /* sell r24, r8, r28 */ +0x6467a901, /* sell r25, r9, r29 */ +0x0c000000, /* ret */ +/* } */ +/* @0x1ba: function mul4[169] { */ +#define CF_mul4_adr 442 +0x58594600, /* mul128 r22, r6l, r10l */ +0x59dd4600, /* mul128 r23, r6u, r10u */ +0x58894600, /* mul128 r2, r6u, r10l */ +0x50585610, /* add r22, r22, r2 << 128 */ +0x50dc5790, /* addc r23, r23, r2 >> 128 */ +0x59094600, /* mul128 r2, r6l, r10u */ +0x50585610, /* add r22, r22, r2 << 128 */ +0x50dc5790, /* addc r23, r23, r2 >> 128 */ +0x58616700, /* mul128 r24, r7l, r11l */ +0x59e56700, /* mul128 r25, r7u, r11u */ +0x58896700, /* mul128 r2, r7u, r11l */ +0x50605810, /* add r24, r24, r2 << 128 */ +0x50e45990, /* addc r25, r25, r2 >> 128 */ +0x59096700, /* mul128 r2, r7l, r11u */ +0x50605810, /* add r24, r24, r2 << 128 */ +0x50e45990, /* addc r25, r25, r2 >> 128 */ +0x58698800, /* mul128 r26, r8l, r12l */ +0x59ed8800, /* mul128 r27, r8u, r12u */ +0x58898800, /* mul128 r2, r8u, r12l */ +0x50685a10, /* add r26, r26, r2 << 128 */ +0x50ec5b90, /* addc r27, r27, r2 >> 128 */ +0x59098800, /* mul128 r2, r8l, r12u */ +0x50685a10, /* add r26, r26, r2 << 128 */ +0x50ec5b90, /* addc r27, r27, r2 >> 128 */ +0x5871a900, /* mul128 r28, r9l, r13l */ +0x59f5a900, /* mul128 r29, r9u, r13u */ +0x5889a900, /* mul128 r2, r9u, r13l */ +0x50705c10, /* add r28, r28, r2 << 128 */ +0x50f45d90, /* addc r29, r29, r2 >> 128 */ +0x5909a900, /* mul128 r2, r9l, r13u */ +0x50705c10, /* add r28, r28, r2 << 128 */ +0x50f45d90, /* addc r29, r29, r2 >> 128 */ +0x58016600, /* mul128 r0, r6l, r11l */ +0x59856600, /* mul128 r1, r6u, r11u */ +0x58896600, /* mul128 r2, r6u, r11l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59096600, /* mul128 r2, r6l, r11u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x505c1700, /* add r23, r23, r0 */ +0x50e03800, /* addc r24, r24, r1 */ +0x508fff00, /* addc r3, r31, r31 */ +0x58014700, /* mul128 r0, r7l, r10l */ +0x59854700, /* mul128 r1, r7u, r10u */ +0x58894700, /* mul128 r2, r7u, r10l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59094700, /* mul128 r2, r7l, r10u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x505c1700, /* add r23, r23, r0 */ +0x50e03800, /* addc r24, r24, r1 */ +0x50e47900, /* addc r25, r25, r3 */ +0x508fff00, /* addc r3, r31, r31 */ +0x58018600, /* mul128 r0, r6l, r12l */ +0x59858600, /* mul128 r1, r6u, r12u */ +0x58898600, /* mul128 r2, r6u, r12l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59098600, /* mul128 r2, r6l, r12u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x58014800, /* mul128 r0, r8l, r10l */ +0x59854800, /* mul128 r1, r8u, r10u */ +0x58894800, /* mul128 r2, r8u, r10l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59094800, /* mul128 r2, r8l, r10u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x50e87a00, /* addc r26, r26, r3 */ +0x508fff00, /* addc r3, r31, r31 */ +0x5801a600, /* mul128 r0, r6l, r13l */ +0x5985a600, /* mul128 r1, r6u, r13u */ +0x5889a600, /* mul128 r2, r6u, r13l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x5909a600, /* mul128 r2, r6l, r13u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x58018700, /* mul128 r0, r7l, r12l */ +0x59858700, /* mul128 r1, r7u, r12u */ +0x58898700, /* mul128 r2, r7u, r12l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59098700, /* mul128 r2, r7l, r12u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x58014900, /* mul128 r0, r9l, r10l */ +0x59854900, /* mul128 r1, r9u, r10u */ +0x58894900, /* mul128 r2, r9u, r10l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59094900, /* mul128 r2, r9l, r10u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x58016800, /* mul128 r0, r8l, r11l */ +0x59856800, /* mul128 r1, r8u, r11u */ +0x58896800, /* mul128 r2, r8u, r11l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59096800, /* mul128 r2, r8l, r11u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x50ec7b00, /* addc r27, r27, r3 */ +0x508fff00, /* addc r3, r31, r31 */ +0x5801a700, /* mul128 r0, r7l, r13l */ +0x5985a700, /* mul128 r1, r7u, r13u */ +0x5889a700, /* mul128 r2, r7u, r13l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x5909a700, /* mul128 r2, r7l, r13u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50681a00, /* add r26, r26, r0 */ +0x50ec3b00, /* addc r27, r27, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x58016900, /* mul128 r0, r9l, r11l */ +0x59856900, /* mul128 r1, r9u, r11u */ +0x58896900, /* mul128 r2, r9u, r11l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59096900, /* mul128 r2, r9l, r11u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50681a00, /* add r26, r26, r0 */ +0x50ec3b00, /* addc r27, r27, r1 */ +0x50f07c00, /* addc r28, r28, r3 */ +0x50f7fd00, /* addc r29, r29, r31 */ +0x5801a800, /* mul128 r0, r8l, r13l */ +0x5985a800, /* mul128 r1, r8u, r13u */ +0x5889a800, /* mul128 r2, r8u, r13l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x5909a800, /* mul128 r2, r8l, r13u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x506c1b00, /* add r27, r27, r0 */ +0x50f03c00, /* addc r28, r28, r1 */ +0x50f7fd00, /* addc r29, r29, r31 */ +0x58018900, /* mul128 r0, r9l, r12l */ +0x59858900, /* mul128 r1, r9u, r12u */ +0x58898900, /* mul128 r2, r9u, r12l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59098900, /* mul128 r2, r9l, r12u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x506c1b00, /* add r27, r27, r0 */ +0x50f03c00, /* addc r28, r28, r1 */ +0x50f7fd00, /* addc r29, r29, r31 */ +0x0c000000, /* ret */ +/* } */ +/* @0x263: function sqr4[117] { */ +#define CF_sqr4_adr 611 +0x5858c600, /* mul128 r22, r6l, r6l */ +0x59dcc600, /* mul128 r23, r6u, r6u */ +0x5888c600, /* mul128 r2, r6u, r6l */ +0x50585610, /* add r22, r22, r2 << 128 */ +0x50dc5790, /* addc r23, r23, r2 >> 128 */ +0x50585610, /* add r22, r22, r2 << 128 */ +0x50dc5790, /* addc r23, r23, r2 >> 128 */ +0x5860e700, /* mul128 r24, r7l, r7l */ +0x59e4e700, /* mul128 r25, r7u, r7u */ +0x5888e700, /* mul128 r2, r7u, r7l */ +0x50605810, /* add r24, r24, r2 << 128 */ +0x50e45990, /* addc r25, r25, r2 >> 128 */ +0x50605810, /* add r24, r24, r2 << 128 */ +0x50e45990, /* addc r25, r25, r2 >> 128 */ +0x58690800, /* mul128 r26, r8l, r8l */ +0x59ed0800, /* mul128 r27, r8u, r8u */ +0x58890800, /* mul128 r2, r8u, r8l */ +0x50685a10, /* add r26, r26, r2 << 128 */ +0x50ec5b90, /* addc r27, r27, r2 >> 128 */ +0x50685a10, /* add r26, r26, r2 << 128 */ +0x50ec5b90, /* addc r27, r27, r2 >> 128 */ +0x58712900, /* mul128 r28, r9l, r9l */ +0x59f52900, /* mul128 r29, r9u, r9u */ +0x58892900, /* mul128 r2, r9u, r9l */ +0x50705c10, /* add r28, r28, r2 << 128 */ +0x50f45d90, /* addc r29, r29, r2 >> 128 */ +0x50705c10, /* add r28, r28, r2 << 128 */ +0x50f45d90, /* addc r29, r29, r2 >> 128 */ +0x5800e600, /* mul128 r0, r6l, r7l */ +0x5984e600, /* mul128 r1, r6u, r7u */ +0x5888e600, /* mul128 r2, r6u, r7l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x5908e600, /* mul128 r2, r6l, r7u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x505c1700, /* add r23, r23, r0 */ +0x50e03800, /* addc r24, r24, r1 */ +0x508fff00, /* addc r3, r31, r31 */ +0x505c1700, /* add r23, r23, r0 */ +0x50e03800, /* addc r24, r24, r1 */ +0x50e47900, /* addc r25, r25, r3 */ +0x508fff00, /* addc r3, r31, r31 */ +0x58010600, /* mul128 r0, r6l, r8l */ +0x59850600, /* mul128 r1, r6u, r8u */ +0x58890600, /* mul128 r2, r6u, r8l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59090600, /* mul128 r2, r6l, r8u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x50e87a00, /* addc r26, r26, r3 */ +0x508fff00, /* addc r3, r31, r31 */ +0x58012600, /* mul128 r0, r6l, r9l */ +0x59852600, /* mul128 r1, r6u, r9u */ +0x58892600, /* mul128 r2, r6u, r9l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59092600, /* mul128 r2, r6l, r9u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x58010700, /* mul128 r0, r7l, r8l */ +0x59850700, /* mul128 r1, r7u, r8u */ +0x58890700, /* mul128 r2, r7u, r8l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59090700, /* mul128 r2, r7l, r8u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x50ec7b00, /* addc r27, r27, r3 */ +0x508fff00, /* addc r3, r31, r31 */ +0x58012700, /* mul128 r0, r7l, r9l */ +0x59852700, /* mul128 r1, r7u, r9u */ +0x58892700, /* mul128 r2, r7u, r9l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59092700, /* mul128 r2, r7l, r9u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x50681a00, /* add r26, r26, r0 */ +0x50ec3b00, /* addc r27, r27, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x50681a00, /* add r26, r26, r0 */ +0x50ec3b00, /* addc r27, r27, r1 */ +0x50f07c00, /* addc r28, r28, r3 */ +0x50f7fd00, /* addc r29, r29, r31 */ +0x58012800, /* mul128 r0, r8l, r9l */ +0x59852800, /* mul128 r1, r8u, r9u */ +0x58892800, /* mul128 r2, r8u, r9l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x59092800, /* mul128 r2, r8l, r9u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x506c1b00, /* add r27, r27, r0 */ +0x50f03c00, /* addc r28, r28, r1 */ +0x50f7fd00, /* addc r29, r29, r31 */ +0x506c1b00, /* add r27, r27, r0 */ +0x50f03c00, /* addc r28, r28, r1 */ +0x50f7fd00, /* addc r29, r29, r31 */ +0x0c000000, /* ret */ +/* } */ +/* @0x2d8: function dod0[15] { */ +#define CF_dod0_adr 728 +0x8c0c1100, /* ld *3, *1 */ +0x58140100, /* mul128 r5, r1l, r0l */ +0x58880100, /* mul128 r2, r1u, r0l */ +0x50144510, /* add r5, r5, r2 << 128 */ +0x59080100, /* mul128 r2, r1l, r0u */ +0x50144510, /* add r5, r5, r2 << 128 */ +0x5801c500, /* mul128 r0, r5l, r14l */ +0x5985c500, /* mul128 r1, r5u, r14u */ +0x5889c500, /* mul128 r2, r5u, r14l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x5909c500, /* mul128 r2, r5l, r14u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x0c000000, /* ret */ +/* } */ +/* @0x2e7: function dod1[9] { */ +#define CF_dod1_adr 743 +0x5801e500, /* mul128 r0, r5l, r15l */ +0x5985e500, /* mul128 r1, r5u, r15u */ +0x5889e500, /* mul128 r2, r5u, r15l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x5909e500, /* mul128 r2, r5l, r15u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x0c000000, /* ret */ +/* } */ +/* @0x2f0: function dod2[9] { */ +#define CF_dod2_adr 752 +0x58020500, /* mul128 r0, r5l, r16l */ +0x59860500, /* mul128 r1, r5u, r16u */ +0x588a0500, /* mul128 r2, r5u, r16l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x590a0500, /* mul128 r2, r5l, r16u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x0c000000, /* ret */ +/* } */ +/* @0x2f9: function dod3[9] { */ +#define CF_dod3_adr 761 +0x58022500, /* mul128 r0, r5l, r17l */ +0x59862500, /* mul128 r1, r5u, r17u */ +0x588a2500, /* mul128 r2, r5u, r17l */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x590a2500, /* mul128 r2, r5l, r17u */ +0x50004010, /* add r0, r0, r2 << 128 */ +0x50844190, /* addc r1, r1, r2 >> 128 */ +0x0c000000, /* ret */ +/* } */ +/* @0x302: function redc4[97] { */ +#define CF_redc4_adr 770 +0x7c001600, /* mov r0, r22 */ +0x080002d8, /* call &dod0 */ +0x50581600, /* add r22, r22, r0 */ +0x50dc3700, /* addc r23, r23, r1 */ +0x50e3f800, /* addc r24, r24, r31 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002e7, /* call &dod1 */ +0x505c1700, /* add r23, r23, r0 */ +0x50e03800, /* addc r24, r24, r1 */ +0x50e49900, /* addc r25, r25, r4 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002f0, /* call &dod2 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x50e89a00, /* addc r26, r26, r4 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002f9, /* call &dod3 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x50ec9b00, /* addc r27, r27, r4 */ +0x508fff00, /* addc r3, r31, r31 */ +0x7c001700, /* mov r0, r23 */ +0x080002d8, /* call &dod0 */ +0x505c1700, /* add r23, r23, r0 */ +0x50e03800, /* addc r24, r24, r1 */ +0x50e7f900, /* addc r25, r25, r31 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002e7, /* call &dod1 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x50e89a00, /* addc r26, r26, r4 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002f0, /* call &dod2 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x50ec9b00, /* addc r27, r27, r4 */ +0x508fff00, /* addc r3, r31, r31 */ +0x080002f9, /* call &dod3 */ +0x50681a00, /* add r26, r26, r0 */ +0x50ec3b00, /* addc r27, r27, r1 */ +0x50f07c00, /* addc r28, r28, r3 */ +0x508fff00, /* addc r3, r31, r31 */ +0x7c001800, /* mov r0, r24 */ +0x080002d8, /* call &dod0 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x50ebfa00, /* addc r26, r26, r31 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002e7, /* call &dod1 */ +0x50641900, /* add r25, r25, r0 */ +0x50e83a00, /* addc r26, r26, r1 */ +0x50ec9b00, /* addc r27, r27, r4 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002f0, /* call &dod2 */ +0x50681a00, /* add r26, r26, r0 */ +0x50ec3b00, /* addc r27, r27, r1 */ +0x50f09c00, /* addc r28, r28, r4 */ +0x5093e300, /* addc r4, r3, r31 */ +0x080002f9, /* call &dod3 */ +0x506c1b00, /* add r27, r27, r0 */ +0x50f03c00, /* addc r28, r28, r1 */ +0x50f49d00, /* addc r29, r29, r4 */ +0x508fff00, /* addc r3, r31, r31 */ +0x7c001900, /* mov r0, r25 */ +0x080002d8, /* call &dod0 */ +0x50641900, /* add r25, r25, r0 */ +0x50d83a00, /* addc r22, r26, r1 */ +0x50dffb00, /* addc r23, r27, r31 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002e7, /* call &dod1 */ +0x50581600, /* add r22, r22, r0 */ +0x50dc3700, /* addc r23, r23, r1 */ +0x50e09c00, /* addc r24, r28, r4 */ +0x5093ff00, /* addc r4, r31, r31 */ +0x080002f0, /* call &dod2 */ +0x505c1700, /* add r23, r23, r0 */ +0x50e03800, /* addc r24, r24, r1 */ +0x50e49d00, /* addc r25, r29, r4 */ +0x508fe300, /* addc r3, r3, r31 */ +0x080002f9, /* call &dod3 */ +0x50601800, /* add r24, r24, r0 */ +0x50e43900, /* addc r25, r25, r1 */ +0x508fe300, /* addc r3, r3, r31 */ +0x56007f00, /* subx r0, r31, r3 */ +0x99680000, /* strnd r26 */ +0x996c0000, /* strnd r27 */ +0x99700000, /* strnd r28 */ +0x99740000, /* strnd r29 */ +0x5409d600, /* sub r2, r22, r14 */ +0x54e9f700, /* subb r26, r23, r15 */ +0x54ee1800, /* subb r27, r24, r16 */ +0x54f23900, /* subb r28, r25, r17 */ +0x66773c08, /* selcx r29, r28, r25 */ +0x66731b08, /* selcx r28, r27, r24 */ +0x666efa08, /* selcx r27, r26, r23 */ +0x666ac208, /* selcx r26, r2, r22 */ +0x0c000000, /* ret */ +/* } */ +/* @0x363: function modexp_1024[101] { */ +#define CF_modexp_1024_adr 867 +0x7c081f00, /* mov r2, r31 */ +0x80080006, /* movi r2.0l, #6 */ +0x8088000a, /* movi r2.1l, #10 */ +0x81880001, /* movi r2.3l, #1 */ +0x8208000e, /* movi r2.4l, #14 */ +0x82880016, /* movi r2.5l, #22 */ +0x83080012, /* movi r2.6l, #18 */ +0x97800200, /* ldrfp r2 */ +0x7c001f00, /* mov r0, r31 */ +0x8180ffff, /* movi r0.3l, #65535 */ +0x84044000, /* ldi r1, [#0] */ +0x40040100, /* and r1, r1, r0 */ +0x48000000, /* not r0, r0 */ +0x84084060, /* ldi r2, [#3] */ +0x40080200, /* and r2, r2, r0 */ +0x44082200, /* or r2, r2, r1 */ +0x95800200, /* lddmp r2 */ +0x05004004, /* loop #4 ( */ +0x8c201b00, /* ld *0++, *3++ */ +0x8c241a00, /* ld *1++, *2++ */ +0x8c301800, /* ld *4++, *0++ */ +0x8c381c00, /* ld *6++, *4++ */ +/* ) */ +0x99780000, /* strnd r30 */ +0x507bde00, /* add r30, r30, r30 */ +0x080001ba, /* call &mul4 */ +0x08000302, /* call &redc4 */ +0x7c281a00, /* mov r10, r26 */ +0x7c2c1b00, /* mov r11, r27 */ +0x7c301c00, /* mov r12, r28 */ +0x7c341d00, /* mov r13, r29 */ +0x99180000, /* strnd r6 */ +0x991c0000, /* strnd r7 */ +0x99200000, /* strnd r8 */ +0x99240000, /* strnd r9 */ +0x05400033, /* loop #1024 ( */ +0x08000263, /* call &sqr4 */ +0x08000302, /* call &redc4 */ +0x99180000, /* strnd r6 */ +0x991c0000, /* strnd r7 */ +0x99200000, /* strnd r8 */ +0x99240000, /* strnd r9 */ +0x7c181a00, /* mov r6, r26 */ +0x7c1c1b00, /* mov r7, r27 */ +0x7c201c00, /* mov r8, r28 */ +0x7c241d00, /* mov r9, r29 */ +0x080001ba, /* call &mul4 */ +0x08000302, /* call &redc4 */ +0x99000000, /* strnd r0 */ +0x5002b500, /* add r0, r21, r21 */ +0x99000000, /* strnd r0 */ +0x50825200, /* addc r0, r18, r18 */ +0x99480000, /* strnd r18 */ +0x7c480000, /* mov r18, r0 */ +0x99000000, /* strnd r0 */ +0x50827300, /* addc r0, r19, r19 */ +0x994c0000, /* strnd r19 */ +0x7c4c0000, /* mov r19, r0 */ +0x99000000, /* strnd r0 */ +0x50829400, /* addc r0, r20, r20 */ +0x99500000, /* strnd r20 */ +0x7c500000, /* mov r20, r0 */ +0x99000000, /* strnd r0 */ +0x5082b500, /* addc r0, r21, r21 */ +0x99540000, /* strnd r21 */ +0x7c540000, /* mov r21, r0 */ +0x99580000, /* strnd r22 */ +0x995c0000, /* strnd r23 */ +0x99600000, /* strnd r24 */ +0x99640000, /* strnd r25 */ +0x080001aa, /* call &selA0orC4 */ +0x99180000, /* strnd r6 */ +0x991c0000, /* strnd r7 */ +0x99200000, /* strnd r8 */ +0x99240000, /* strnd r9 */ +0x99000000, /* strnd r0 */ +0x50000000, /* add r0, r0, r0 */ +0x4c001e00, /* xor r0, r30, r0 */ +0x99780000, /* strnd r30 */ +0x507bde00, /* add r30, r30, r30 */ +0x4c781e00, /* xor r30, r30, r0 */ +0x447a5e00, /* or r30, r30, r18 */ +0x4c03c000, /* xor r0, r0, r30 */ +0x641aca01, /* sell r6, r10, r22 */ +0x641eeb01, /* sell r7, r11, r23 */ +0x64230c01, /* sell r8, r12, r24 */ +0x64272d01, /* sell r9, r13, r25 */ +/* ) */ +0x7c281f00, /* mov r10, r31 */ +0x80280001, /* movi r10.0l, #1 */ +0x7c2c1f00, /* mov r11, r31 */ +0x7c301f00, /* mov r12, r31 */ +0x7c341f00, /* mov r13, r31 */ +0x080001ba, /* call &mul4 */ +0x08000302, /* call &redc4 */ +0x5419da00, /* sub r6, r26, r14 */ +0x549dfb00, /* subb r7, r27, r15 */ +0x54a21c00, /* subb r8, r28, r16 */ +0x54a63d00, /* subb r9, r29, r17 */ +0x080001aa, /* call &selA0orC4 */ +0x05004001, /* loop #4 ( */ +0x90740d00, /* st *5++, *5++ */ +/* ) */ +0x0c000000, /* ret */ +/* } */ +#endif // CONFIG_DCRYPTO_RSA_SPEEDUP +}; +/* clang-format on */ + +struct DMEM_ctx_ptrs { + uint32_t pMod; + uint32_t pDinv; + uint32_t pRR; + uint32_t pA; + uint32_t pB; + uint32_t pC; + uint32_t n; + uint32_t n1; +}; + +/* + * This struct is "calling convention" for passing parameters into the + * code block above for RSA operations. Parameters start at &DMEM[0]. + */ +struct DMEM_ctx { + struct DMEM_ctx_ptrs in_ptrs; + struct DMEM_ctx_ptrs sqr_ptrs; + struct DMEM_ctx_ptrs mul_ptrs; + struct DMEM_ctx_ptrs out_ptrs; + uint32_t mod[RSA_WORDS_4K]; + uint32_t dInv[8]; + uint32_t pubexp; + uint32_t _pad1[3]; + uint32_t rnd[2]; + uint32_t _pad2[2]; + uint32_t RR[RSA_WORDS_4K]; + uint32_t in[RSA_WORDS_4K]; + uint32_t exp[RSA_WORDS_4K + 8]; /* extra word for randomization */ + uint32_t out[RSA_WORDS_4K]; + uint32_t bin[RSA_WORDS_4K]; + uint32_t bout[RSA_WORDS_4K]; +}; + +#define DMEM_CELL_SIZE 32 +#define DMEM_INDEX(p, f) \ + (((const uint8_t *)&(p)->f - (const uint8_t *)(p)) / DMEM_CELL_SIZE) + +/* Get non-0 64 bit random */ +static void rand64(uint32_t dst[2]) +{ + do { + dst[0] = rand(); + dst[1] = rand(); + } while ((dst[0] | dst[1]) == 0); +} + +/* Grab dcrypto lock and set things up for modulus and input */ +static int setup_and_lock(const struct LITE_BIGNUM *N, + const struct LITE_BIGNUM *input) +{ + struct DMEM_ctx *ctx = + (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); + + /* Initialize hardware; load code page. */ + dcrypto_init_and_lock(); + dcrypto_imem_load(0, IMEM_dcrypto_bn, ARRAY_SIZE(IMEM_dcrypto_bn)); + + /* Setup DMEM pointers (as indices into DMEM which are 256-bit cells). + */ + ctx->in_ptrs.pMod = DMEM_INDEX(ctx, mod); + ctx->in_ptrs.pDinv = DMEM_INDEX(ctx, dInv); + ctx->in_ptrs.pRR = DMEM_INDEX(ctx, RR); + ctx->in_ptrs.pA = DMEM_INDEX(ctx, in); + ctx->in_ptrs.pB = DMEM_INDEX(ctx, exp); + ctx->in_ptrs.pC = DMEM_INDEX(ctx, out); + ctx->in_ptrs.n = bn_bits(N) / (DMEM_CELL_SIZE * 8); + ctx->in_ptrs.n1 = ctx->in_ptrs.n - 1; + + ctx->sqr_ptrs = ctx->in_ptrs; + ctx->mul_ptrs = ctx->in_ptrs; + ctx->out_ptrs = ctx->in_ptrs; + + dcrypto_dmem_load(DMEM_INDEX(ctx, in), input->d, bn_words(input)); + if (dcrypto_dmem_load(DMEM_INDEX(ctx, mod), N->d, bn_words(N)) == 0) { + /* + * No change detected; assume modulus precomputation is cached. + */ + return 0; + } + + /* Calculate RR and d0inv. */ + return dcrypto_call(CF_modload_adr); +} + +#define MONTMUL(ctx, a, b, c) \ + montmul(ctx, DMEM_INDEX(ctx, a), DMEM_INDEX(ctx, b), DMEM_INDEX(ctx, c)) + +static int montmul(struct DMEM_ctx *ctx, uint32_t pA, uint32_t pB, + uint32_t pOut) +{ + + ctx->in_ptrs.pA = pA; + ctx->in_ptrs.pB = pB; + ctx->in_ptrs.pC = pOut; + + return dcrypto_call(CF_mulx_adr); +} + +#define MONTOUT(ctx, a, b) montout(ctx, DMEM_INDEX(ctx, a), DMEM_INDEX(ctx, b)) + +static int montout(struct DMEM_ctx *ctx, uint32_t pA, uint32_t pOut) +{ + + ctx->in_ptrs.pA = pA; + ctx->in_ptrs.pB = 0; + ctx->in_ptrs.pC = pOut; + + return dcrypto_call(CF_mul1_adr); +} + +#define MODEXP(ctx, in, exp, out) \ + modexp(ctx, CF_modexp_adr, DMEM_INDEX(ctx, RR), DMEM_INDEX(ctx, in), \ + DMEM_INDEX(ctx, exp), DMEM_INDEX(ctx, out)) + +#define MODEXP1024(ctx, in, exp, out) \ + modexp(ctx, CF_modexp_1024_adr, DMEM_INDEX(ctx, RR), \ + DMEM_INDEX(ctx, in), DMEM_INDEX(ctx, exp), \ + DMEM_INDEX(ctx, out)) + +#define MODEXP_BLINDED(ctx, in, exp, out) \ + modexp(ctx, CF_modexp_blinded_adr, DMEM_INDEX(ctx, RR), \ + DMEM_INDEX(ctx, in), DMEM_INDEX(ctx, exp), \ + DMEM_INDEX(ctx, out)) + +static int modexp(struct DMEM_ctx *ctx, uint32_t adr, uint32_t rr, uint32_t pIn, + uint32_t pExp, uint32_t pOut) +{ + /* in = in * RR */ + ctx->in_ptrs.pA = pIn; + ctx->in_ptrs.pB = rr; + ctx->in_ptrs.pC = pIn; + + /* out = out * out */ + ctx->sqr_ptrs.pA = pOut; + ctx->sqr_ptrs.pB = pOut; + ctx->sqr_ptrs.pC = pOut; + + /* out = out * in */ + ctx->mul_ptrs.pA = pIn; + ctx->mul_ptrs.pB = pOut; + ctx->mul_ptrs.pC = pOut; + + /* out = out / R */ + ctx->out_ptrs.pA = pOut; + ctx->out_ptrs.pB = pExp; + ctx->out_ptrs.pC = pOut; + + return dcrypto_call(adr); +} + +/* output = input ** exp % N. */ +int dcrypto_modexp_blinded(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, + const struct LITE_BIGNUM *N, uint32_t pubexp) +{ + int i, result; + struct DMEM_ctx *ctx = + (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); + + uint32_t r_buf[RSA_MAX_WORDS]; + uint32_t rinv_buf[RSA_MAX_WORDS]; + + struct LITE_BIGNUM r; + struct LITE_BIGNUM rinv; + + bn_init(&r, r_buf, bn_size(N)); + bn_init(&rinv, rinv_buf, bn_size(N)); + + /* + * pick 64 bit r != 0 + * We cannot tolerate risk of 0 since 0 breaks computation. + */ + rand64(r_buf); + + /* + * compute 1/r mod N + * Note this cannot fail since N is product of two large primes + * and r != 0, so we can ignore return value. + */ + bn_modinv_vartime(&rinv, &r, N); + + /* + * compute r^pubexp mod N + */ + dcrypto_modexp_word(&r, &r, pubexp, N); + + result = setup_and_lock(N, input); + + /* Pick !0 64-bit random for exponent blinding */ + rand64(ctx->rnd); + ctx->pubexp = pubexp; + + ctx->_pad1[0] = ctx->_pad1[1] = ctx->_pad1[2] = 0; + ctx->_pad2[0] = ctx->_pad2[1] = 0; + + dcrypto_dmem_load(DMEM_INDEX(ctx, bin), r.d, bn_words(&r)); + dcrypto_dmem_load(DMEM_INDEX(ctx, bout), rinv.d, bn_words(&rinv)); + dcrypto_dmem_load(DMEM_INDEX(ctx, exp), exp->d, bn_words(exp)); + + /* 0 pad the exponent to full size + 8 */ + for (i = bn_words(exp); i < bn_words(N) + 8; ++i) + ctx->exp[i] = 0; + + /* Blind input */ + result |= MONTMUL(ctx, in, RR, in); + result |= MONTMUL(ctx, in, bin, in); + + result |= MODEXP_BLINDED(ctx, in, exp, out); + + /* remove blinding factor */ + result |= MONTMUL(ctx, out, RR, out); + result |= MONTMUL(ctx, out, bout, out); + /* fully reduce out */ + result |= MONTMUL(ctx, out, RR, out); + result |= MONTOUT(ctx, out, out); + + memcpy(output->d, ctx->out, bn_size(output)); + + dcrypto_unlock(); + return result == 0; +} + +/* output = input ** exp % N. */ +int dcrypto_modexp(struct LITE_BIGNUM *output, const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, const struct LITE_BIGNUM *N) +{ + int i, result; + struct DMEM_ctx *ctx = + (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); + + result = setup_and_lock(N, input); + + dcrypto_dmem_load(DMEM_INDEX(ctx, exp), exp->d, bn_words(exp)); + + /* 0 pad the exponent to full size */ + for (i = bn_words(exp); i < bn_words(N); ++i) + ctx->exp[i] = 0; + +#ifdef CONFIG_DCRYPTO_RSA_SPEEDUP + if (bn_bits(N) == 1024) { /* special code for 1024 bits */ + result |= MODEXP1024(ctx, in, exp, out); + } else { + result |= MODEXP(ctx, in, exp, out); + } +#else + result |= MODEXP(ctx, in, exp, out); +#endif + + memcpy(output->d, ctx->out, bn_size(output)); + + dcrypto_unlock(); + return result == 0; +} + +/* output = input ** exp % N. */ +int dcrypto_modexp_word(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, uint32_t exp, + const struct LITE_BIGNUM *N) +{ + int result; + uint32_t e = exp; + uint32_t b = 0x80000000; + struct DMEM_ctx *ctx = + (struct DMEM_ctx *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); + + result = setup_and_lock(N, input); + + /* Find top bit */ + while (b != 0 && !(b & e)) + b >>= 1; + + /* out = in * RR */ + result |= MONTMUL(ctx, in, RR, out); + /* in = in * RR */ + result |= MONTMUL(ctx, in, RR, in); + + while (b > 1) { + b >>= 1; + + /* out = out * out */ + result |= MONTMUL(ctx, out, out, out); + + if ((b & e) != 0) { + /* out = out * in */ + result |= MONTMUL(ctx, in, out, out); + } + } + + /* out = out / R */ + result |= MONTOUT(ctx, out, out); + + memcpy(output->d, ctx->out, bn_size(output)); + + dcrypto_unlock(); + return result == 0; +} + +#ifdef CRYPTO_TEST_SETUP +#include "console.h" +#include "shared_mem.h" +#include "timer.h" + +static uint8_t genp_seed[32]; +static uint32_t prime_buf[32]; +static timestamp_t genp_start; +static timestamp_t genp_end; + +static int genp_core(void) +{ + struct LITE_BIGNUM prime; + int result; + + // Spin seed out into prng candidate prime. + DCRYPTO_hkdf((uint8_t *)prime_buf, sizeof(prime_buf), genp_seed, + sizeof(genp_seed), 0, 0, 0, 0); + DCRYPTO_bn_wrap(&prime, &prime_buf, sizeof(prime_buf)); + + genp_start = get_time(); + result = (DCRYPTO_bn_generate_prime(&prime) != 0) ? EC_SUCCESS + : EC_ERROR_UNKNOWN; + genp_end = get_time(); + + return result; +} + +static int call_on_bigger_stack(int (*func)(void)) +{ + int result, i; + char *new_stack; + const int new_stack_size = 4 * 1024; + + result = shared_mem_acquire(new_stack_size, &new_stack); + if (result == EC_SUCCESS) { + // Paint stack arena + memset(new_stack, 0x01, new_stack_size); + + // Call whilst switching stacks + __asm__ volatile("mov r4, sp\n" // save sp + "mov sp, %[new_stack]\n" + "blx %[func]\n" + "mov sp, r4\n" // restore sp + "mov %[result], r0\n" + : [result] "=r"(result) + : [new_stack] "r"(new_stack + new_stack_size), + [func] "r"(func) + : "r0", "r1", "r2", "r3", "r4", + "lr" // clobbers + ); + + // Take guess at amount of stack that got used + for (i = 0; i < new_stack_size && new_stack[i] == 0x01; ++i) + ; + ccprintf("stack: %u/%u\n", new_stack_size - i, new_stack_size); + + shared_mem_release(new_stack); + } + + return result; +} + +static int command_genp(int argc, char **argv) +{ + int result; + + memset(genp_seed, 0, sizeof(genp_seed)); + if (argc > 1) + memcpy(genp_seed, argv[1], strlen(argv[1])); + + result = call_on_bigger_stack(genp_core); + + if (result == EC_SUCCESS) { + ccprintf("prime: %ph (lsb first)\n", + HEX_BUF(prime_buf, sizeof(prime_buf))); + ccprintf("μs : %llu\n", + (long long)(genp_end.val - genp_start.val)); + } + + return result; +} +DECLARE_CONSOLE_COMMAND(genp, command_genp, "[seed]", "Generate prng prime"); +#endif diff --git a/chip/g/dcrypto/dcrypto_p256.c b/chip/g/dcrypto/dcrypto_p256.c new file mode 100644 index 0000000000..4de8d22f9a --- /dev/null +++ b/chip/g/dcrypto/dcrypto_p256.c @@ -0,0 +1,1018 @@ +/* Copyright 2016 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 "trng.h" + +/* Firmware blob for crypto accelerator */ + +/* AUTO-GENERATED. DO NOT MODIFY. */ +/* clang-format off */ +static const uint32_t IMEM_dcrypto[] = { +/* @0x0: function tag[1] { */ +#define CF_tag_adr 0 + 0xf8000002, /* sigini #2 */ +/* } */ +/* @0x1: function SetupP256PandMuLow[21] { */ +#define CF_SetupP256PandMuLow_adr 1 + 0x55741f01, /* subi r29, r31, #1 */ + 0x83750000, /* movi r29.6h, #0 */ + 0x83740001, /* movi r29.6l, #1 */ + 0x82f50000, /* movi r29.5h, #0 */ + 0x82f40000, /* movi r29.5l, #0 */ + 0x82750000, /* movi r29.4h, #0 */ + 0x82740000, /* movi r29.4l, #0 */ + 0x81f50000, /* movi r29.3h, #0 */ + 0x81f40000, /* movi r29.3l, #0 */ + 0x98801d00, /* ldmod r29 */ + 0x55701f01, /* subi r28, r31, #1 */ + 0x83f10000, /* movi r28.7h, #0 */ + 0x83f00000, /* movi r28.7l, #0 */ + 0x82f0fffe, /* movi r28.5l, #65534 */ + 0x8270fffe, /* movi r28.4l, #65534 */ + 0x81f0fffe, /* movi r28.3l, #65534 */ + 0x80f10000, /* movi r28.1h, #0 */ + 0x80f00000, /* movi r28.1l, #0 */ + 0x80710000, /* movi r28.0h, #0 */ + 0x80700003, /* movi r28.0l, #3 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x16: function p256init[22] { */ +#define CF_p256init_adr 22 + 0x847c4000, /* ldi r31, [#0] */ + 0x4c7fff00, /* xor r31, r31, r31 */ + 0x51781f01, /* addi r30, r31, #1 */ + 0x08000001, /* call &SetupP256PandMuLow */ + 0x7c6c1f00, /* mov r27, r31 */ + 0x83ed5ac6, /* movi r27.7h, #23238 */ + 0x83ec35d8, /* movi r27.7l, #13784 */ + 0x836daa3a, /* movi r27.6h, #43578 */ + 0x836c93e7, /* movi r27.6l, #37863 */ + 0x82edb3eb, /* movi r27.5h, #46059 */ + 0x82ecbd55, /* movi r27.5l, #48469 */ + 0x826d7698, /* movi r27.4h, #30360 */ + 0x826c86bc, /* movi r27.4l, #34492 */ + 0x81ed651d, /* movi r27.3h, #25885 */ + 0x81ec06b0, /* movi r27.3l, #1712 */ + 0x816dcc53, /* movi r27.2h, #52307 */ + 0x816cb0f6, /* movi r27.2l, #45302 */ + 0x80ed3bce, /* movi r27.1h, #15310 */ + 0x80ec3c3e, /* movi r27.1l, #15422 */ + 0x806d27d2, /* movi r27.0h, #10194 */ + 0x806c604b, /* movi r27.0l, #24651 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x2c: function MulMod[38] { */ +#define CF_MulMod_adr 44 + 0x584f3800, /* mul128 r19, r24l, r25l */ + 0x59d33800, /* mul128 r20, r24u, r25u */ + 0x58d73800, /* mul128 r21, r24u, r25l */ + 0x504eb310, /* add r19, r19, r21 << 128 */ + 0x50d2b490, /* addc r20, r20, r21 >> 128 */ + 0x59573800, /* mul128 r21, r24l, r25u */ + 0x504eb310, /* add r19, r19, r21 << 128 */ + 0x50d2b490, /* addc r20, r20, r21 >> 128 */ + 0x645bfc02, /* selm r22, r28, r31 */ + 0x685693ff, /* rshi r21, r19, r20 >> 255 */ + 0x585f9500, /* mul128 r23, r21l, r28l */ + 0x59e39500, /* mul128 r24, r21u, r28u */ + 0x58e79500, /* mul128 r25, r21u, r28l */ + 0x505f3710, /* add r23, r23, r25 << 128 */ + 0x50e33890, /* addc r24, r24, r25 >> 128 */ + 0x59679500, /* mul128 r25, r21l, r28u */ + 0x505f3710, /* add r23, r23, r25 << 128 */ + 0x50e33890, /* addc r24, r24, r25 >> 128 */ + 0x6867f4ff, /* rshi r25, r20, r31 >> 255 */ + 0x5062b800, /* add r24, r24, r21 */ + 0x50e7f900, /* addc r25, r25, r31 */ + 0x5062d800, /* add r24, r24, r22 */ + 0x50e7f900, /* addc r25, r25, r31 */ + 0x68573801, /* rshi r21, r24, r25 >> 1 */ + 0x585abd00, /* mul128 r22, r29l, r21l */ + 0x59debd00, /* mul128 r23, r29u, r21u */ + 0x58e2bd00, /* mul128 r24, r29u, r21l */ + 0x505b1610, /* add r22, r22, r24 << 128 */ + 0x50df1790, /* addc r23, r23, r24 >> 128 */ + 0x5962bd00, /* mul128 r24, r29l, r21u */ + 0x505b1610, /* add r22, r22, r24 << 128 */ + 0x50df1790, /* addc r23, r23, r24 >> 128 */ + 0x545ad300, /* sub r22, r19, r22 */ + 0x54d2f400, /* subb r20, r20, r23 */ + 0x6457fd01, /* sell r21, r29, r31 */ + 0x5456b600, /* sub r21, r22, r21 */ + 0x9c4ff500, /* addm r19, r21, r31 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x52: function p256isoncurve[24] { */ +#define CF_p256isoncurve_adr 82 + 0x84004000, /* ldi r0, [#0] */ + 0x95800000, /* lddmp r0 */ + 0x82800018, /* movi r0.5l, #24 */ + 0x83000018, /* movi r0.6l, #24 */ + 0x80000000, /* movi r0.0l, #0 */ + 0x97800000, /* ldrfp r0 */ + 0x8c181600, /* ld *6, *6 */ + 0x7c641800, /* mov r25, r24 */ + 0x0800002c, /* call &MulMod */ + 0x7c001300, /* mov r0, r19 */ + 0x8c141500, /* ld *5, *5 */ + 0x7c641800, /* mov r25, r24 */ + 0x0800002c, /* call &MulMod */ + 0x8c141500, /* ld *5, *5 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x8c141500, /* ld *5, *5 */ + 0xa04f1300, /* subm r19, r19, r24 */ + 0xa04f1300, /* subm r19, r19, r24 */ + 0xa04f1300, /* subm r19, r19, r24 */ + 0x9c637300, /* addm r24, r19, r27 */ + 0x904c0500, /* st *5, *3 */ + 0x90500000, /* st *0, *4 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x6a: function ProjAdd[80] { */ +#define CF_ProjAdd_adr 106 + 0x7c600b00, /* mov r24, r11 */ + 0x7c640800, /* mov r25, r8 */ + 0x0800002c, /* call &MulMod */ + 0x7c381300, /* mov r14, r19 */ + 0x7c600c00, /* mov r24, r12 */ + 0x7c640900, /* mov r25, r9 */ + 0x0800002c, /* call &MulMod */ + 0x7c3c1300, /* mov r15, r19 */ + 0x7c600d00, /* mov r24, r13 */ + 0x7c640a00, /* mov r25, r10 */ + 0x0800002c, /* call &MulMod */ + 0x7c401300, /* mov r16, r19 */ + 0x9c458b00, /* addm r17, r11, r12 */ + 0x9c492800, /* addm r18, r8, r9 */ + 0x7c601100, /* mov r24, r17 */ + 0x7c641200, /* mov r25, r18 */ + 0x0800002c, /* call &MulMod */ + 0x9c49ee00, /* addm r18, r14, r15 */ + 0xa0465300, /* subm r17, r19, r18 */ + 0x9c49ac00, /* addm r18, r12, r13 */ + 0x9c4d4900, /* addm r19, r9, r10 */ + 0x7c601200, /* mov r24, r18 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x7c481300, /* mov r18, r19 */ + 0x9c4e0f00, /* addm r19, r15, r16 */ + 0xa04a7200, /* subm r18, r18, r19 */ + 0x9c4dab00, /* addm r19, r11, r13 */ + 0x9c314800, /* addm r12, r8, r10 */ + 0x7c601300, /* mov r24, r19 */ + 0x7c640c00, /* mov r25, r12 */ + 0x0800002c, /* call &MulMod */ + 0x7c2c1300, /* mov r11, r19 */ + 0x9c320e00, /* addm r12, r14, r16 */ + 0xa0318b00, /* subm r12, r11, r12 */ + 0x7c601b00, /* mov r24, r27 */ + 0x7c641000, /* mov r25, r16 */ + 0x0800002c, /* call &MulMod */ + 0xa02e6c00, /* subm r11, r12, r19 */ + 0x9c356b00, /* addm r13, r11, r11 */ + 0x9c2dab00, /* addm r11, r11, r13 */ + 0xa0356f00, /* subm r13, r15, r11 */ + 0x9c2d6f00, /* addm r11, r15, r11 */ + 0x7c601b00, /* mov r24, r27 */ + 0x7c640c00, /* mov r25, r12 */ + 0x0800002c, /* call &MulMod */ + 0x9c3e1000, /* addm r15, r16, r16 */ + 0x9c420f00, /* addm r16, r15, r16 */ + 0xa0321300, /* subm r12, r19, r16 */ + 0xa031cc00, /* subm r12, r12, r14 */ + 0x9c3d8c00, /* addm r15, r12, r12 */ + 0x9c318f00, /* addm r12, r15, r12 */ + 0x9c3dce00, /* addm r15, r14, r14 */ + 0x9c39cf00, /* addm r14, r15, r14 */ + 0xa03a0e00, /* subm r14, r14, r16 */ + 0x7c601200, /* mov r24, r18 */ + 0x7c640c00, /* mov r25, r12 */ + 0x0800002c, /* call &MulMod */ + 0x7c3c1300, /* mov r15, r19 */ + 0x7c600e00, /* mov r24, r14 */ + 0x7c640c00, /* mov r25, r12 */ + 0x0800002c, /* call &MulMod */ + 0x7c401300, /* mov r16, r19 */ + 0x7c600b00, /* mov r24, r11 */ + 0x7c640d00, /* mov r25, r13 */ + 0x0800002c, /* call &MulMod */ + 0x9c321300, /* addm r12, r19, r16 */ + 0x7c601100, /* mov r24, r17 */ + 0x7c640b00, /* mov r25, r11 */ + 0x0800002c, /* call &MulMod */ + 0xa02df300, /* subm r11, r19, r15 */ + 0x7c601200, /* mov r24, r18 */ + 0x7c640d00, /* mov r25, r13 */ + 0x0800002c, /* call &MulMod */ + 0x7c341300, /* mov r13, r19 */ + 0x7c601100, /* mov r24, r17 */ + 0x7c640e00, /* mov r25, r14 */ + 0x0800002c, /* call &MulMod */ + 0x9c366d00, /* addm r13, r13, r19 */ + 0x0c000000, /* ret */ +/* } */ +/* @0xba: function ProjToAffine[116] { */ +#define CF_ProjToAffine_adr 186 + 0x9c2bea00, /* addm r10, r10, r31 */ + 0x7c600a00, /* mov r24, r10 */ + 0x7c640a00, /* mov r25, r10 */ + 0x0800002c, /* call &MulMod */ + 0x7c601300, /* mov r24, r19 */ + 0x7c640a00, /* mov r25, r10 */ + 0x0800002c, /* call &MulMod */ + 0x7c301300, /* mov r12, r19 */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x7c601300, /* mov r24, r19 */ + 0x7c640c00, /* mov r25, r12 */ + 0x0800002c, /* call &MulMod */ + 0x7c341300, /* mov r13, r19 */ + 0x05004004, /* loop #4 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c601300, /* mov r24, r19 */ + 0x7c640d00, /* mov r25, r13 */ + 0x0800002c, /* call &MulMod */ + 0x7c381300, /* mov r14, r19 */ + 0x05008004, /* loop #8 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c601300, /* mov r24, r19 */ + 0x7c640e00, /* mov r25, r14 */ + 0x0800002c, /* call &MulMod */ + 0x7c3c1300, /* mov r15, r19 */ + 0x05010004, /* loop #16 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c601300, /* mov r24, r19 */ + 0x7c640f00, /* mov r25, r15 */ + 0x0800002c, /* call &MulMod */ + 0x7c401300, /* mov r16, r19 */ + 0x05020004, /* loop #32 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c441300, /* mov r17, r19 */ + 0x7c600a00, /* mov r24, r10 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x050c0004, /* loop #192 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c481300, /* mov r18, r19 */ + 0x7c601100, /* mov r24, r17 */ + 0x7c641000, /* mov r25, r16 */ + 0x0800002c, /* call &MulMod */ + 0x05010004, /* loop #16 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c600f00, /* mov r24, r15 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x05008004, /* loop #8 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c600e00, /* mov r24, r14 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x05004004, /* loop #4 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c600d00, /* mov r24, r13 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x05002004, /* loop #2 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c600c00, /* mov r24, r12 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x05002004, /* loop #2 ( */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0xfc000000, /* nop */ + /* ) */ + 0x7c600a00, /* mov r24, r10 */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x7c601300, /* mov r24, r19 */ + 0x7c641200, /* mov r25, r18 */ + 0x0800002c, /* call &MulMod */ + 0x7c381300, /* mov r14, r19 */ + 0x7c600800, /* mov r24, r8 */ + 0x7c640e00, /* mov r25, r14 */ + 0x0800002c, /* call &MulMod */ + 0x7c2c1300, /* mov r11, r19 */ + 0x7c600900, /* mov r24, r9 */ + 0x7c640e00, /* mov r25, r14 */ + 0x0800002c, /* call &MulMod */ + 0x7c301300, /* mov r12, r19 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x12e: function ModInv[17] { */ +#define CF_ModInv_adr 302 + 0x98080000, /* stmod r2 */ + 0x55080202, /* subi r2, r2, #2 */ + 0x7c041e00, /* mov r1, r30 */ + 0x0510000c, /* loop #256 ( */ + 0x7c600100, /* mov r24, r1 */ + 0x7c640100, /* mov r25, r1 */ + 0x0800002c, /* call &MulMod */ + 0x7c0c1300, /* mov r3, r19 */ + 0x50084200, /* add r2, r2, r2 */ + 0x64046108, /* selc r1, r1, r3 */ + 0x1008813d, /* bnc nomul */ + 0x7c600300, /* mov r24, r3 */ + 0x7c640000, /* mov r25, r0 */ + 0x0800002c, /* call &MulMod */ + 0x7c041300, /* mov r1, r19 */ + /*nomul: */ + 0xfc000000, /* nop */ + /* ) */ + 0x0c000000, /* ret */ +/* } */ +/* @0x13f: function FetchBandRandomize[11] { */ +#define CF_FetchBandRandomize_adr 319 + 0x99080000, /* strnd r2 */ + 0x9c6be200, /* addm r26, r2, r31 */ + 0x8c081500, /* ld *2, *5 */ + 0x7c641a00, /* mov r25, r26 */ + 0x0800002c, /* call &MulMod */ + 0x7c181300, /* mov r6, r19 */ + 0x8c081600, /* ld *2, *6 */ + 0x7c641a00, /* mov r25, r26 */ + 0x0800002c, /* call &MulMod */ + 0x7c1c1300, /* mov r7, r19 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x14a: function ProjDouble[5] { */ +#define CF_ProjDouble_adr 330 + 0x7c2c0800, /* mov r11, r8 */ + 0x7c300900, /* mov r12, r9 */ + 0x7c340a00, /* mov r13, r10 */ + 0x0800006a, /* call &ProjAdd */ + 0x0c000000, /* ret */ +/* } */ +/* @0x14f: function SetupP256NandMuLow[25] { */ +#define CF_SetupP256NandMuLow_adr 335 + 0x55741f01, /* subi r29, r31, #1 */ + 0x83750000, /* movi r29.6h, #0 */ + 0x83740000, /* movi r29.6l, #0 */ + 0x81f5bce6, /* movi r29.3h, #48358 */ + 0x81f4faad, /* movi r29.3l, #64173 */ + 0x8175a717, /* movi r29.2h, #42775 */ + 0x81749e84, /* movi r29.2l, #40580 */ + 0x80f5f3b9, /* movi r29.1h, #62393 */ + 0x80f4cac2, /* movi r29.1l, #51906 */ + 0x8075fc63, /* movi r29.0h, #64611 */ + 0x80742551, /* movi r29.0l, #9553 */ + 0x55701f01, /* subi r28, r31, #1 */ + 0x83f10000, /* movi r28.7h, #0 */ + 0x83f00000, /* movi r28.7l, #0 */ + 0x82f0fffe, /* movi r28.5l, #65534 */ + 0x81f14319, /* movi r28.3h, #17177 */ + 0x81f00552, /* movi r28.3l, #1362 */ + 0x8171df1a, /* movi r28.2h, #57114 */ + 0x81706c21, /* movi r28.2l, #27681 */ + 0x80f1012f, /* movi r28.1h, #303 */ + 0x80f0fd85, /* movi r28.1l, #64901 */ + 0x8071eedf, /* movi r28.0h, #61151 */ + 0x80709bfe, /* movi r28.0l, #39934 */ + 0x98801d00, /* ldmod r29 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x168: function ScalarMult_internal[51] { */ +#define CF_ScalarMult_internal_adr 360 + 0x0800014f, /* call &SetupP256NandMuLow */ + 0x8c041100, /* ld *1, *1 */ + 0x9c07e100, /* addm r1, r1, r31 */ + 0xa0002000, /* subm r0, r0, r1 */ + 0x08000001, /* call &SetupP256PandMuLow */ + 0x0800013f, /* call &FetchBandRandomize */ + 0x7c200600, /* mov r8, r6 */ + 0x7c240700, /* mov r9, r7 */ + 0x7c281a00, /* mov r10, r26 */ + 0x0800014a, /* call &ProjDouble */ + 0x7c0c0b00, /* mov r3, r11 */ + 0x7c100c00, /* mov r4, r12 */ + 0x7c140d00, /* mov r5, r13 */ + 0x7c201f00, /* mov r8, r31 */ + 0x7c241e00, /* mov r9, r30 */ + 0x7c281f00, /* mov r10, r31 */ + 0x05100020, /* loop #256 ( */ + 0x0800014a, /* call &ProjDouble */ + 0x0800013f, /* call &FetchBandRandomize */ + 0x4c202000, /* xor r8, r0, r1 */ + 0x64206602, /* selm r8, r6, r3 */ + 0x64248702, /* selm r9, r7, r4 */ + 0x6428ba02, /* selm r10, r26, r5 */ + 0x7c080b00, /* mov r2, r11 */ + 0x7c180c00, /* mov r6, r12 */ + 0x7c1c0d00, /* mov r7, r13 */ + 0x0800006a, /* call &ProjAdd */ + 0x44202000, /* or r8, r0, r1 */ + 0x64204b02, /* selm r8, r11, r2 */ + 0x6424cc02, /* selm r9, r12, r6 */ + 0x6428ed02, /* selm r10, r13, r7 */ + 0x680000ff, /* rshi r0, r0, r0 >> 255 */ + 0x680421ff, /* rshi r1, r1, r1 >> 255 */ + 0x992c0000, /* strnd r11 */ + 0x99300000, /* strnd r12 */ + 0x99340000, /* strnd r13 */ + 0x99080000, /* strnd r2 */ + 0x7c600300, /* mov r24, r3 */ + 0x7c640200, /* mov r25, r2 */ + 0x0800002c, /* call &MulMod */ + 0x7c0c1300, /* mov r3, r19 */ + 0x7c600400, /* mov r24, r4 */ + 0x7c640200, /* mov r25, r2 */ + 0x0800002c, /* call &MulMod */ + 0x7c101300, /* mov r4, r19 */ + 0x7c600500, /* mov r24, r5 */ + 0x7c640200, /* mov r25, r2 */ + 0x0800002c, /* call &MulMod */ + 0x7c141300, /* mov r5, r19 */ + /* ) */ + 0x080000ba, /* call &ProjToAffine */ + 0x0c000000, /* ret */ +/* } */ +/* @0x19b: function get_P256B[35] { */ +#define CF_get_P256B_adr 411 + 0x7c201f00, /* mov r8, r31 */ + 0x83a16b17, /* movi r8.7h, #27415 */ + 0x83a0d1f2, /* movi r8.7l, #53746 */ + 0x8321e12c, /* movi r8.6h, #57644 */ + 0x83204247, /* movi r8.6l, #16967 */ + 0x82a1f8bc, /* movi r8.5h, #63676 */ + 0x82a0e6e5, /* movi r8.5l, #59109 */ + 0x822163a4, /* movi r8.4h, #25508 */ + 0x822040f2, /* movi r8.4l, #16626 */ + 0x81a17703, /* movi r8.3h, #30467 */ + 0x81a07d81, /* movi r8.3l, #32129 */ + 0x81212deb, /* movi r8.2h, #11755 */ + 0x812033a0, /* movi r8.2l, #13216 */ + 0x80a1f4a1, /* movi r8.1h, #62625 */ + 0x80a03945, /* movi r8.1l, #14661 */ + 0x8021d898, /* movi r8.0h, #55448 */ + 0x8020c296, /* movi r8.0l, #49814 */ + 0x7c241f00, /* mov r9, r31 */ + 0x83a54fe3, /* movi r9.7h, #20451 */ + 0x83a442e2, /* movi r9.7l, #17122 */ + 0x8325fe1a, /* movi r9.6h, #65050 */ + 0x83247f9b, /* movi r9.6l, #32667 */ + 0x82a58ee7, /* movi r9.5h, #36583 */ + 0x82a4eb4a, /* movi r9.5l, #60234 */ + 0x82257c0f, /* movi r9.4h, #31759 */ + 0x82249e16, /* movi r9.4l, #40470 */ + 0x81a52bce, /* movi r9.3h, #11214 */ + 0x81a43357, /* movi r9.3l, #13143 */ + 0x81256b31, /* movi r9.2h, #27441 */ + 0x81245ece, /* movi r9.2l, #24270 */ + 0x80a5cbb6, /* movi r9.1h, #52150 */ + 0x80a44068, /* movi r9.1l, #16488 */ + 0x802537bf, /* movi r9.0h, #14271 */ + 0x802451f5, /* movi r9.0l, #20981 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1be: function p256sign[34] { */ +#define CF_p256sign_adr 446 + 0xfc000000, /* nop */ + 0x84004000, /* ldi r0, [#0] */ + 0x95800000, /* lddmp r0 */ + 0x80000000, /* movi r0.0l, #0 */ + 0x80800001, /* movi r0.1l, #1 */ + 0x81000018, /* movi r0.2l, #24 */ + 0x82000008, /* movi r0.4l, #8 */ + 0x82800009, /* movi r0.5l, #9 */ + 0x97800000, /* ldrfp r0 */ + 0x0800019b, /* call &get_P256B */ + 0x90540400, /* st *4, *5 */ + 0x90580500, /* st *5, *6 */ + 0xfc000000, /* nop */ + 0x8c001000, /* ld *0, *0 */ + 0x08000168, /* call &ScalarMult_internal */ + 0x0800014f, /* call &SetupP256NandMuLow */ + 0x8c001000, /* ld *0, *0 */ + 0x0800012e, /* call &ModInv */ + 0x8c081700, /* ld *2, *7 */ + 0x7c640100, /* mov r25, r1 */ + 0x0800002c, /* call &MulMod */ + 0x9c63eb00, /* addm r24, r11, r31 */ + 0x904c0200, /* st *2, *3 */ + 0xfc000000, /* nop */ + 0x7c641300, /* mov r25, r19 */ + 0x0800002c, /* call &MulMod */ + 0x7c001300, /* mov r0, r19 */ + 0x8c081200, /* ld *2, *2 */ + 0x7c640100, /* mov r25, r1 */ + 0x0800002c, /* call &MulMod */ + 0x9c001300, /* addm r0, r19, r0 */ + 0x90500000, /* st *0, *4 */ + 0x08000001, /* call &SetupP256PandMuLow */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1e0: function p256scalarbasemult[21] { */ +#define CF_p256scalarbasemult_adr 480 + 0xfc000000, /* nop */ + 0x84004000, /* ldi r0, [#0] */ + 0x95800000, /* lddmp r0 */ + 0x80000000, /* movi r0.0l, #0 */ + 0x80800001, /* movi r0.1l, #1 */ + 0x81000018, /* movi r0.2l, #24 */ + 0x8180000b, /* movi r0.3l, #11 */ + 0x82000008, /* movi r0.4l, #8 */ + 0x82800009, /* movi r0.5l, #9 */ + 0x97800000, /* ldrfp r0 */ + 0x8c001100, /* ld *0, *1 */ + 0x99800000, /* ldrnd r0 */ + 0x0800019b, /* call &get_P256B */ + 0x90540400, /* st *4, *5 */ + 0x90580500, /* st *5, *6 */ + 0xfc000000, /* nop */ + 0x8c001700, /* ld *0, *7 */ + 0x08000168, /* call &ScalarMult_internal */ + 0x90540b00, /* st *3++, *5 */ + 0x90580b00, /* st *3++, *6 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1f5: function ModInvVar[37] { */ +#define CF_ModInvVar_adr 501 + 0x7c081f00, /* mov r2, r31 */ + 0x7c0c1e00, /* mov r3, r30 */ + 0x98100000, /* stmod r4 */ + 0x981c0000, /* stmod r7 */ + 0x7c140000, /* mov r5, r0 */ + /*impvt_Loop: */ + 0x44108400, /* or r4, r4, r4 */ + 0x10001205, /* bl impvt_Uodd */ + 0x6813e401, /* rshi r4, r4, r31 >> 1 */ + 0x44084200, /* or r2, r2, r2 */ + 0x10001201, /* bl impvt_Rodd */ + 0x680be201, /* rshi r2, r2, r31 >> 1 */ + 0x100801fa, /* b impvt_Loop */ + /*impvt_Rodd: */ + 0x50084700, /* add r2, r7, r2 */ + 0x509bff00, /* addc r6, r31, r31 */ + 0x6808c201, /* rshi r2, r2, r6 >> 1 */ + 0x100801fa, /* b impvt_Loop */ + /*impvt_Uodd: */ + 0x4414a500, /* or r5, r5, r5 */ + 0x10001210, /* bl impvt_UVodd */ + 0x6817e501, /* rshi r5, r5, r31 >> 1 */ + 0x440c6300, /* or r3, r3, r3 */ + 0x1000120c, /* bl impvt_Sodd */ + 0x680fe301, /* rshi r3, r3, r31 >> 1 */ + 0x100801fa, /* b impvt_Loop */ + /*impvt_Sodd: */ + 0x500c6700, /* add r3, r7, r3 */ + 0x509bff00, /* addc r6, r31, r31 */ + 0x680cc301, /* rshi r3, r3, r6 >> 1 */ + 0x100801fa, /* b impvt_Loop */ + /*impvt_UVodd: */ + 0x5c008500, /* cmp r5, r4 */ + 0x10088215, /* bnc impvt_V>=U */ + 0xa0086200, /* subm r2, r2, r3 */ + 0x5410a400, /* sub r4, r4, r5 */ + 0x100801fa, /* b impvt_Loop */ + /*impvt_V>=U: */ + 0xa00c4300, /* subm r3, r3, r2 */ + 0x54148500, /* sub r5, r5, r4 */ + 0x100841fa, /* bnz impvt_Loop */ + 0x9c07e200, /* addm r1, r2, r31 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x21a: function p256verify[80] { */ +#define CF_p256verify_adr 538 + 0x84184000, /* ldi r6, [#0] */ + 0x95800600, /* lddmp r6 */ + 0x81980018, /* movi r6.3l, #24 */ + 0x82180000, /* movi r6.4l, #0 */ + 0x82980008, /* movi r6.5l, #8 */ + 0x83180009, /* movi r6.6l, #9 */ + 0x8018000b, /* movi r6.0l, #11 */ + 0x8398000c, /* movi r6.7l, #12 */ + 0x81180018, /* movi r6.2l, #24 */ + 0x97800600, /* ldrfp r6 */ + 0x8c0c1300, /* ld *3, *3 */ + 0x7c600600, /* mov r24, r6 */ + 0x48630000, /* not r24, r24 */ + 0x0800014f, /* call &SetupP256NandMuLow */ + 0x5c03e600, /* cmp r6, r31 */ + 0x10004268, /* bz fail */ + 0x5c03a600, /* cmp r6, r29 */ + 0x10088268, /* bnc fail */ + 0x8c101400, /* ld *4, *4 */ + 0x5c03e000, /* cmp r0, r31 */ + 0x10004268, /* bz fail */ + 0x5c03a000, /* cmp r0, r29 */ + 0x10088268, /* bnc fail */ + 0x080001f5, /* call &ModInvVar */ + 0x8c0c1300, /* ld *3, *3 */ + 0x7c640100, /* mov r25, r1 */ + 0x0800002c, /* call &MulMod */ + 0x7c001300, /* mov r0, r19 */ + 0x8c081200, /* ld *2, *2 */ + 0x7c640100, /* mov r25, r1 */ + 0x0800002c, /* call &MulMod */ + 0x7c041300, /* mov r1, r19 */ + 0x08000001, /* call &SetupP256PandMuLow */ + 0x8c001500, /* ld *0, *5 */ + 0x8c1c1600, /* ld *7, *6 */ + 0x7c341e00, /* mov r13, r30 */ + 0x0800019b, /* call &get_P256B */ + 0x7c281e00, /* mov r10, r30 */ + 0x0800006a, /* call &ProjAdd */ + 0x7c0c0b00, /* mov r3, r11 */ + 0x7c100c00, /* mov r4, r12 */ + 0x7c140d00, /* mov r5, r13 */ + 0x40082000, /* and r2, r0, r1 */ + 0x7c2c1f00, /* mov r11, r31 */ + 0x7c301e00, /* mov r12, r30 */ + 0x7c341f00, /* mov r13, r31 */ + 0x05100018, /* loop #256 ( */ + 0x7c200b00, /* mov r8, r11 */ + 0x7c240c00, /* mov r9, r12 */ + 0x7c280d00, /* mov r10, r13 */ + 0x0800006a, /* call &ProjAdd */ + 0x50084200, /* add r2, r2, r2 */ + 0x10088254, /* bnc noBoth */ + 0x7c200300, /* mov r8, r3 */ + 0x7c240400, /* mov r9, r4 */ + 0x7c280500, /* mov r10, r5 */ + 0x0800006a, /* call &ProjAdd */ + 0x1008025f, /* b noY */ + /*noBoth: */ + 0x50180000, /* add r6, r0, r0 */ + 0x1008825a, /* bnc noG */ + 0x8c141500, /* ld *5, *5 */ + 0x8c181600, /* ld *6, *6 */ + 0x7c281e00, /* mov r10, r30 */ + 0x0800006a, /* call &ProjAdd */ + /*noG: */ + 0x50182100, /* add r6, r1, r1 */ + 0x1008825f, /* bnc noY */ + 0x0800019b, /* call &get_P256B */ + 0x7c281e00, /* mov r10, r30 */ + 0x0800006a, /* call &ProjAdd */ + /*noY: */ + 0x50000000, /* add r0, r0, r0 */ + 0x50042100, /* add r1, r1, r1 */ + /* ) */ + 0x7c000d00, /* mov r0, r13 */ + 0x080001f5, /* call &ModInvVar */ + 0x7c600100, /* mov r24, r1 */ + 0x7c640b00, /* mov r25, r11 */ + 0x0800002c, /* call &MulMod */ + 0x0800014f, /* call &SetupP256NandMuLow */ + 0xa063f300, /* subm r24, r19, r31 */ + /*fail: */ + 0x90440300, /* st *3, *1 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x26a: function p256scalarmult[12] { */ +#define CF_p256scalarmult_adr 618 + 0x84004000, /* ldi r0, [#0] */ + 0x95800000, /* lddmp r0 */ + 0x80000000, /* movi r0.0l, #0 */ + 0x80800001, /* movi r0.1l, #1 */ + 0x81000018, /* movi r0.2l, #24 */ + 0x8180000b, /* movi r0.3l, #11 */ + 0x97800000, /* ldrfp r0 */ + 0x8c001000, /* ld *0, *0 */ + 0x08000168, /* call &ScalarMult_internal */ + 0x90540b00, /* st *3++, *5 */ + 0x90580b00, /* st *3++, *6 */ + 0x0c000000, /* ret */ + /* } */ +}; +/* clang-format on */ + +/* + * This struct is "calling convention" for passing parameters into the + * code block above for ecc operations. Writes to this struct should be done + * via the cp1w() and cp8w() functions to guarantee that word writes are used, + * as the dcrypto peripheral does not support byte writes. + */ +struct DMEM_ecc { + uint32_t pK; + uint32_t pRnd; + uint32_t pMsg; + uint32_t pR; + uint32_t pS; + uint32_t pX; + uint32_t pY; + uint32_t pD; + p256_int k; + p256_int rnd; + p256_int msg; + p256_int r; + p256_int s; + p256_int x; + p256_int y; + p256_int d; +}; + +#define DMEM_CELL_SIZE 32 +#define DMEM_OFFSET(p) (offsetof(struct DMEM_ecc, p)) +#define DMEM_INDEX(p) (DMEM_OFFSET(p) / DMEM_CELL_SIZE) + +/* p256 elliptic curve characteristics */ +static const p256_int SECP256r1_nMin1 = { + { + 0xfc632551 - 1, + 0xf3b9cac2, + 0xa7179e84, + 0xbce6faad, + -1, + -1, + 0, + -1, + }, +}; + +/* + * Read-only pointer to read-only DMEM_ecc struct, use cp*w() + * functions for writes. + */ +static const volatile struct DMEM_ecc *dmem_ecc = + (const volatile struct DMEM_ecc *)GREG32_ADDR(CRYPTO, DMEM_DUMMY); + +/* + * Writes one word to DMEM, at the address derived from the base + * offset and number of words. These parameters can be used for example + * by specifying the offset of a p256_int, and the index of a word within + * that p256_int. + */ +static void cp1w(size_t base_offset, int word, const uint32_t src) +{ + /* Destination address, always 32-bit aligned. */ + volatile uint32_t *dst = + REG32_ADDR((uint8_t *)GREG32_ADDR(CRYPTO, DMEM_DUMMY) + + base_offset + (word * sizeof(uint32_t))); + + *dst = src; +} + +/* + * Copies the contents of the src p256_int to the specified offset in DMEM. + * The src argument does not need to be aligned. + */ +static void cp8w(size_t offset, const volatile p256_int *src) +{ + int i; + + /* + * If p256_int is packed (as it is on cr50), the compiler + * cannot assume src will be aligned, and so performs + * byte reads into a register before calling cp1w (which + * is typically inlined). + * + * Note that the dcrypto peripheral supports byte reads, + * so it is safe to specify a pointer based on dmem_ecc + * as the src argument. + */ + for (i = 0; i < P256_NDIGITS; i++) + cp1w(offset, i, P256_DIGIT(src, i)); +} + +/* Convenience macros for above copy functions. */ +#define CP1W(a, b, c) cp1w(DMEM_OFFSET(a), b, c) +#define CP8W(a, b) cp8w(DMEM_OFFSET(a), b) + +static void dcrypto_ecc_init(void) +{ + dcrypto_imem_load(0, IMEM_dcrypto, ARRAY_SIZE(IMEM_dcrypto)); + + CP1W(pK, 0, DMEM_INDEX(k)); + CP1W(pRnd, 0, DMEM_INDEX(rnd)); + CP1W(pMsg, 0, DMEM_INDEX(msg)); + CP1W(pR, 0, DMEM_INDEX(r)); + CP1W(pS, 0, DMEM_INDEX(s)); + CP1W(pX, 0, DMEM_INDEX(x)); + CP1W(pY, 0, DMEM_INDEX(y)); + CP1W(pD, 0, DMEM_INDEX(d)); + + /* (over)write first words to ensure pairwise mismatch. */ + CP1W(k, 0, 1); + CP1W(rnd, 0, 2); + CP1W(msg, 0, 3); + CP1W(r, 0, 4); + CP1W(s, 0, 5); + CP1W(x, 0, 6); + CP1W(y, 0, 7); + CP1W(d, 0, 8); +} + +/* Return -1 if a < b */ +static int p256_lt(const p256_int *a, const p256_int *b) +{ + p256_sddigit borrow = 0; + + for (int i = 0; i < P256_NDIGITS; ++i) { + volatile uint32_t blinder = rand(); + + borrow += ((p256_sddigit)P256_DIGIT(a, i) - blinder); + borrow -= P256_DIGIT(b, i); + borrow += blinder; + borrow >>= P256_BITSPERDIGIT; + } + return (int)borrow; +} + +int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key, + const p256_int *message, p256_int *r, p256_int *s) +{ + int i, result; + p256_int rnd, k; + + dcrypto_init_and_lock(); + dcrypto_ecc_init(); + result = dcrypto_call(CF_p256init_adr); + + /* Pick uniform 0 < k < R */ + do { + hmac_drbg_generate_p256(drbg, &rnd); + } while (p256_cmp(&SECP256r1_nMin2, &rnd) < 0); + drbg_exit(drbg); + + p256_add_d(&rnd, 1, &k); + + CP8W(k, &k); + + for (i = 0; i < 8; ++i) + CP1W(rnd, i, rand()); + + /* Wipe temp rnd,k */ + rnd = dmem_ecc->rnd; + k = dmem_ecc->rnd; + + CP8W(msg, message); + CP8W(d, key); + + result |= dcrypto_call(CF_p256sign_adr); + + *r = dmem_ecc->r; + *s = dmem_ecc->s; + + /* Wipe d,k */ + CP8W(d, &rnd); + CP8W(k, &rnd); + + dcrypto_unlock(); + return result == 0; +} + +int dcrypto_p256_base_point_mul(const p256_int *k, p256_int *x, p256_int *y) +{ + int i, result; + + dcrypto_init_and_lock(); + dcrypto_ecc_init(); + result = dcrypto_call(CF_p256init_adr); + + for (i = 0; i < 8; ++i) + CP1W(rnd, i, dmem_ecc->rnd.a[i] ^ rand()); + + CP8W(d, k); + + result |= dcrypto_call(CF_p256scalarbasemult_adr); + + *x = dmem_ecc->x; + *y = dmem_ecc->y; + + /* Wipe d */ + CP8W(d, &dmem_ecc->rnd); + + dcrypto_unlock(); + return result == 0; +} + +int dcrypto_p256_point_mul(const p256_int *k, const p256_int *in_x, + const p256_int *in_y, p256_int *x, p256_int *y) +{ + int i, result; + + dcrypto_init_and_lock(); + dcrypto_ecc_init(); + result = dcrypto_call(CF_p256init_adr); + + for (i = 0; i < 8; ++i) + CP1W(rnd, i, dmem_ecc->rnd.a[i] ^ rand()); + + CP8W(k, k); + CP8W(x, in_x); + CP8W(y, in_y); + + result |= dcrypto_call(CF_p256scalarmult_adr); + + *x = dmem_ecc->x; + *y = dmem_ecc->y; + + /* Wipe k,x,y */ + CP8W(k, &dmem_ecc->rnd); + CP8W(x, &dmem_ecc->rnd); + CP8W(y, &dmem_ecc->rnd); + + dcrypto_unlock(); + return result == 0; +} + +int dcrypto_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y, + const p256_int *message, const p256_int *r, + const p256_int *s) +{ + int i, result; + + dcrypto_init_and_lock(); + dcrypto_ecc_init(); + result = dcrypto_call(CF_p256init_adr); + + CP8W(msg, message); + CP8W(r, r); + CP8W(s, s); + CP8W(x, key_x); + CP8W(y, key_y); + + result |= dcrypto_call(CF_p256verify_adr); + + for (i = 0; i < 8; ++i) + result |= (dmem_ecc->rnd.a[i] ^ r->a[i]); + + dcrypto_unlock(); + return result == 0; +} + +int dcrypto_p256_is_valid_point(const p256_int *x, const p256_int *y) +{ + int i, result; + + dcrypto_init_and_lock(); + dcrypto_ecc_init(); + result = dcrypto_call(CF_p256init_adr); + + CP8W(x, x); + CP8W(y, y); + + result |= dcrypto_call(CF_p256isoncurve_adr); + + for (i = 0; i < 8; ++i) + result |= (dmem_ecc->r.a[i] ^ dmem_ecc->s.a[i]); + + dcrypto_unlock(); + return result == 0; +} + +int dcrypto_p256_pick(struct drbg_ctx *drbg, p256_int *output) +{ + int result = 0; + + /* make sure to return stirred output even if drbg fails */ + dcrypto_p256_rnd(output); + + do { + result = hmac_drbg_generate_p256(drbg, output); + } while ((result == 0) && (p256_lt(output, &SECP256r1_nMin1) >= 0)); + return result; +} + +void dcrypto_p256_rnd(p256_int *output) +{ + for (int i = 0; i < 8; ++i) + output->a[i] = rand(); +} diff --git a/chip/g/dcrypto/dcrypto_runtime.c b/chip/g/dcrypto/dcrypto_runtime.c new file mode 100644 index 0000000000..394293ab83 --- /dev/null +++ b/chip/g/dcrypto/dcrypto_runtime.c @@ -0,0 +1,480 @@ +/* Copyright 2016 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 "flash_log.h" +#include "internal.h" +#include "registers.h" +#include "task.h" + +#define DMEM_NUM_WORDS 1024 +#define IMEM_NUM_WORDS 1024 + +static struct mutex dcrypto_mutex; +static volatile task_id_t my_task_id; +static uint8_t dcrypto_is_initialized; + +static const uint32_t wiped_value = 0xdddddddd; + +static void dcrypto_reset_and_wipe(void) +{ + int i; + volatile uint32_t *ptr; + + /* Reset. */ + GREG32(CRYPTO, CONTROL) = GC_CRYPTO_CONTROL_RESET_MASK; + GREG32(CRYPTO, CONTROL) = 0; + + /* Reset all the status bits. */ + GREG32(CRYPTO, INT_STATE) = -1; + + /* Wipe state. */ + GREG32(CRYPTO, WIPE_SECRETS) = 1; + + /* Wipe DMEM. */ + ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY); + for (i = 0; i < DMEM_NUM_WORDS; ++i) + *ptr++ = wiped_value; +} + +static void dcrypto_wipe_imem(void) +{ + int i; + volatile uint32_t *ptr; + + /* Wipe IMEM. */ + ptr = GREG32_ADDR(CRYPTO, IMEM_DUMMY); + for (i = 0; i < IMEM_NUM_WORDS; ++i) + *ptr++ = wiped_value; +} + +void dcrypto_init_and_lock(void) +{ + mutex_lock(&dcrypto_mutex); + my_task_id = task_get_current(); + + if (dcrypto_is_initialized) + return; + + /* Enable PMU. */ + REG_WRITE_MLV(GR_PMU_PERICLKSET0, GC_PMU_PERICLKSET0_DCRYPTO0_CLK_MASK, + GC_PMU_PERICLKSET0_DCRYPTO0_CLK_LSB, 1); + + dcrypto_reset_and_wipe(); + dcrypto_wipe_imem(); + + /* Turn off random nops (which are enabled by default). */ + GWRITE_FIELD(CRYPTO, RAND_STALL_CTL, STALL_EN, 0); + /* Configure random nop percentage at 6%. */ + GWRITE_FIELD(CRYPTO, RAND_STALL_CTL, FREQ, 3); + /* Now turn on random nops. */ + GWRITE_FIELD(CRYPTO, RAND_STALL_CTL, STALL_EN, 1); + + GREG32(CRYPTO, INT_STATE) = -1; /* Reset all the status bits. */ + GREG32(CRYPTO, INT_ENABLE) = -1; /* Enable all status bits. */ + + task_enable_irq(GC_IRQNUM_CRYPTO0_HOST_CMD_DONE_INT); + + dcrypto_is_initialized = 1; +} + +void dcrypto_unlock(void) +{ + mutex_unlock(&dcrypto_mutex); +} + +#ifndef DCRYPTO_CALL_TIMEOUT_US +#define DCRYPTO_CALL_TIMEOUT_US (700 * 1000) +#endif +/* + * When running on Cr50 this event belongs in the TPM task event space. Make + * sure there is no collision with events defined in ./common/tpm_registers.c. + */ +#define TASK_EVENT_DCRYPTO_DONE TASK_EVENT_CUSTOM_BIT(0) + +uint32_t dcrypto_call(uint32_t adr) +{ + uint32_t event; + uint32_t state = 0; + + do { + /* Reset all the status bits. */ + GREG32(CRYPTO, INT_STATE) = -1; + } while (GREG32(CRYPTO, INT_STATE) & 3); + + GREG32(CRYPTO, HOST_CMD) = 0x08000000 + adr; /* Call imem:adr. */ + + event = task_wait_event_mask(TASK_EVENT_DCRYPTO_DONE, + DCRYPTO_CALL_TIMEOUT_US); + /* TODO(ngm): switch return value to an enum. */ + switch (event) { + case TASK_EVENT_DCRYPTO_DONE: + /* + * We expect only the CMD_RECV status bit to be set at this + * point. CMD_DONE got cleared in the interrupt handler. Any and + * all other bits are indicative of error. + * Except for MOD_OPERAND_OUT_OF_RANGE, which is noise. + */ + state = GREG32(CRYPTO, INT_STATE); + if ((state & + ~(GC_CRYPTO_INT_STATE_MOD_OPERAND_OUT_OF_RANGE_MASK | + GC_CRYPTO_INT_STATE_HOST_CMD_RECV_MASK)) == 0) + return 0; + /* fall through */ + default: + dcrypto_reset_and_wipe(); +#ifdef CONFIG_FLASH_LOG + /* State value of zero indicates event timeout. */ + flash_log_add_event(FE_LOG_DCRYPTO_FAILURE, + sizeof(state), &state); +#endif + return 1; + } +} + +void __keep dcrypto_done_interrupt(void) +{ + GREG32(CRYPTO, INT_STATE) = GC_CRYPTO_INT_STATE_HOST_CMD_DONE_MASK; + task_set_event(my_task_id, TASK_EVENT_DCRYPTO_DONE, 0); +} +DECLARE_IRQ(GC_IRQNUM_CRYPTO0_HOST_CMD_DONE_INT, dcrypto_done_interrupt, 1); + +void dcrypto_imem_load(size_t offset, const uint32_t *opcodes, + size_t n_opcodes) +{ + size_t i; + volatile uint32_t *ptr = GREG32_ADDR(CRYPTO, IMEM_DUMMY); + + ptr += offset; + /* Check first word and copy all only if different. */ + if (ptr[0] != opcodes[0]) { + for (i = 0; i < n_opcodes; ++i) + ptr[i] = opcodes[i]; + } +} + +uint32_t dcrypto_dmem_load(size_t offset, const void *words, size_t n_words) +{ + size_t i; + volatile uint32_t *ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY); + const uint32_t *src = (const uint32_t *) words; + struct access_helper *word_accessor = (struct access_helper *) src; + uint32_t diff = 0; + + ptr += offset * 8; /* Offset is in 256 bit addresses. */ + for (i = 0; i < n_words; ++i) { + /* + * The implementation of memcpy makes unaligned writes if src + * is unaligned. DMEM on the other hand requires writes to be + * aligned, so do a word-by-word copy manually here. + */ + uint32_t v = word_accessor[i].udata; + + diff |= (ptr[i] ^ v); + ptr[i] = v; + } + return diff; +} + +#ifdef CRYPTO_TEST_SETUP + +#include "console.h" +#include "dcrypto.h" +#include "trng.h" +#include "shared_mem.h" +#include "system.h" +#include "watchdog.h" + +/* AUTO-GENERATED. DO NOT MODIFY. */ +/* clang-format off */ +static const uint32_t IMEM_test_hang[] = { +/* @0x0: function forever[2] { */ +#define CF_forever_adr 0 +/*forever: */ + 0x10080000, /* b forever */ + 0x0c000000, /* ret */ +/* } */ +/* @0x2: function func17[2] { */ +#define CF_func17_adr 2 + 0x08000000, /* call &forever */ + 0x0c000000, /* ret */ +/* } */ +/* @0x4: function func16[2] { */ +#define CF_func16_adr 4 + 0x08000002, /* call &func17 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x6: function func15[2] { */ +#define CF_func15_adr 6 + 0x08000004, /* call &func16 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x8: function func14[2] { */ +#define CF_func14_adr 8 + 0x08000006, /* call &func15 */ + 0x0c000000, /* ret */ +/* } */ +/* @0xa: function func13[2] { */ +#define CF_func13_adr 10 + 0x08000008, /* call &func14 */ + 0x0c000000, /* ret */ +/* } */ +/* @0xc: function func12[2] { */ +#define CF_func12_adr 12 + 0x0800000a, /* call &func13 */ + 0x0c000000, /* ret */ +/* } */ +/* @0xe: function func11[2] { */ +#define CF_func11_adr 14 + 0x0800000c, /* call &func12 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x10: function func10[2] { */ +#define CF_func10_adr 16 + 0x0800000e, /* call &func11 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x12: function func9[2] { */ +#define CF_func9_adr 18 + 0x08000010, /* call &func10 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x14: function func8[2] { */ +#define CF_func8_adr 20 + 0x08000012, /* call &func9 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x16: function func7[2] { */ +#define CF_func7_adr 22 + 0x08000014, /* call &func8 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x18: function func6[2] { */ +#define CF_func6_adr 24 + 0x08000016, /* call &func7 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1a: function func5[2] { */ +#define CF_func5_adr 26 + 0x08000018, /* call &func6 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1c: function func4[2] { */ +#define CF_func4_adr 28 + 0x0800001a, /* call &func5 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x1e: function func3[2] { */ +#define CF_func3_adr 30 + 0x0800001c, /* call &func4 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x20: function func2[2] { */ +#define CF_func2_adr 32 + 0x0800001e, /* call &func3 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x22: function func1[2] { */ +#define CF_func1_adr 34 + 0x08000020, /* call &func2 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x24: function test[2] { */ +#define CF_test_adr 36 + 0x08000022, /* call &func1 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x26: function sigchk[2] { */ +#define CF_sigchk_adr 38 + 0xf8000004, /* sigini #4 */ + 0xf9ccc3c2, /* sigchk #13419458 */ +/* } */ +}; +/* clang-format on */ + +/* + * Add console command "dcrypto_test" that runs a couple of engine failure + * scenarios and checks for adequate handling thereof: + * - error return code + * - dmem erasure on error + * - dmem preservation on success + */ +static int command_dcrypto_test(int argc, char *argv[]) +{ + volatile uint32_t *ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY); + uint32_t not_wiped = ~wiped_value; + int result; + + dcrypto_init_and_lock(); + dcrypto_imem_load(0, IMEM_test_hang, ARRAY_SIZE(IMEM_test_hang)); + + *ptr = not_wiped; + result = dcrypto_call(CF_func2_adr); /* max legal stack, into hang */ + if (result != 1 || *ptr != wiped_value) + ccprintf("dcrypto_test: fail1 %d,%08x\n", result, *ptr); + + *ptr = not_wiped; + result = dcrypto_call(CF_test_adr); /* stack overflow */ + if (result != 1 || *ptr != wiped_value) + ccprintf("dcrypto_test: fail2 %d,%08x\n", result, *ptr); + + *ptr = not_wiped; + result = dcrypto_call(CF_sigchk_adr); /* cfi trap */ + if (result != 1 || *ptr != wiped_value) + ccprintf("dcrypto_test: fail3 %d,%08x\n", result, *ptr); + + *ptr = not_wiped; + result = dcrypto_call(CF_test_adr + 1); /* simple ret should succeed */ + if (result != 0 || *ptr != not_wiped) + ccprintf("dcrypto_test: fail4 %d,%08x\n", result, *ptr); + + dcrypto_unlock(); + + return EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(dcrypto_test, command_dcrypto_test, "", + "dcrypto test"); + +#define ECDSA_TEST_ITERATIONS 1000 + +#define ECDSA_TEST_SLEEP_DELAY_IN_US 1000000 + +static const p256_int r_golden = { + .a = { 0xebc04580, 0x996c8634, 0xeaff3cd6, 0x4af33b39, 0xa17da3fb, + 0x2c9054f4, 0x3b4dfb95, 0xb3bf339c }, +}; +static const p256_int s_golden = { + .a = { 0xac457a6d, 0x8ca854ea, 0xa5877cc1, 0x17bd44f2, 0x77c4c11a, + 0xd55d07a0, 0x1efb1274, 0x94afb5c9 }, +}; + +static int call_on_bigger_stack(uint32_t stack, + int (*func)(p256_int *, p256_int *), + p256_int *r, p256_int *s) +{ + int result = 0; + + /* Move to new stack and call the function */ + __asm__ volatile("mov r4, sp\n" + "mov sp, %[new_stack]\n" + "mov r0, %[r]\n" + "mov r1, %[s]\n" + "blx %[func]\n" + "mov sp, r4\n" + "mov %[result], r0\n" + : [result] "=r"(result) /* output */ + : [new_stack] "r"(stack), [r] "r"(r), [s] "r"(s), + [func] "r"(func) /* input */ + : "r0", "r1", "r2", "r3", "r4", + "lr" /* clobbered registers */ + ); + + return result; +} + +/* Sets up the ecdsa_sign function with proper input conditions to mimic the + * ecdsa_verisign execution flow. + * in: r - ptr to entropy, s - ptr to message. + * out: r,s - generated signature. + */ +static int ecdsa_sign_go(p256_int *r, p256_int *s) +{ + struct drbg_ctx drbg; + p256_int d, tmp; + int ret = 0; + p256_int message = *s; + + /* drbg init with same entropy */ + hmac_drbg_init(&drbg, r->a, sizeof(r->a), NULL, 0, NULL, 0); + + /* pick a key */ + ret = dcrypto_p256_pick(&drbg, &tmp); + if (ret) { + /* to be consistent with ecdsa_sign error return */ + ret = 0; + goto exit; + } + + /* add 1 */ + p256_add_d(&tmp, 1, &d); + + /* drbg_reseed with entropy and message */ + hmac_drbg_reseed(&drbg, r->a, sizeof(r->a), s->a, sizeof(s->a), NULL, + 0); + + ret = dcrypto_p256_ecdsa_sign(&drbg, &d, &message, r, s); + +exit: + drbg_exit(&drbg); + return ret; +} + +static int command_dcrypto_ecdsa_test(int argc, char *argv[]) +{ + p256_int entropy, message, r, s; + LITE_SHA256_CTX hsh; + int result = 0; + char *new_stack; + const uint32_t new_stack_size = 2 * 1024; + + /* start with some known value for a message */ + const uint8_t ten = 0x0A; + + for (uint8_t i = 0; i < 8; i++) + entropy.a[i] = i; + + DCRYPTO_SHA256_init(&hsh, 0); + HASH_update(&hsh, &ten, sizeof(ten)); + p256_from_bin(HASH_final(&hsh), &message); + + r = entropy; + s = message; + + result = shared_mem_acquire(new_stack_size, &new_stack); + + if (result != EC_SUCCESS) { + ccprintf("Failed to acquire stack memory: %d\n", result); + return result; + } + + for (uint32_t i = 0; i < ECDSA_TEST_ITERATIONS; i++) { + result = call_on_bigger_stack((uint32_t)new_stack + + new_stack_size, + ecdsa_sign_go, &r, &s); + + if (!result) { + ccprintf("ECDSA TEST fail: %d\n", result); + return EC_ERROR_INVAL; + } + + watchdog_reload(); + delay_sleep_by(ECDSA_TEST_SLEEP_DELAY_IN_US); + } + + shared_mem_release(new_stack); + + /* compare to the golden r and s values */ + for (uint8_t i = 0; i < 8; i++) { + if (r.a[i] != r_golden.a[i]) { + ccprintf("ECDSA TEST r does not match with golden at " + "%d: %08x != %08x\n", + i, r.a[i], r_golden.a[i]); + return EC_ERROR_INVAL; + } + if (s.a[i] != s_golden.a[i]) { + ccprintf("ECDSA TEST s does not match with golden at " + "%d: %08x != %08x\n", + i, s.a[i], s_golden.a[i]); + return EC_ERROR_INVAL; + } + } + + ccprintf("ECDSA TEST success!!!\n"); + + return EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(dcrypto_ecdsa, command_dcrypto_ecdsa_test, "", + "dcrypto ecdsa test"); + +#endif diff --git a/chip/g/dcrypto/dcrypto_sha512.c b/chip/g/dcrypto/dcrypto_sha512.c new file mode 100644 index 0000000000..bb404b28d7 --- /dev/null +++ b/chip/g/dcrypto/dcrypto_sha512.c @@ -0,0 +1,772 @@ +/* Copyright 2016 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 "cryptoc/sha512.h" + +#ifdef CRYPTO_TEST_SETUP + +/* test and benchmark */ +#include "common.h" +#include "console.h" +#include "hooks.h" +#include "task.h" + +#define cyclecounter() GREG32(M3, DWT_CYCCNT) +#define START_PROFILE(x) \ + { \ + x -= cyclecounter(); \ + } +#define END_PROFILE(x) \ + { \ + x += cyclecounter(); \ + } +static uint32_t t_sw; +static uint32_t t_hw; +static uint32_t t_transform; +static uint32_t t_dcrypto; + +#else /* CRYPTO_TEST_SETUP */ + +#define START_PROFILE(x) +#define END_PROFILE(x) + +#endif /* CRYPTO_TEST_SETUP */ + +/* auto-generated from go test haven -test.run=TestSha512 -test.v */ +/* clang-format off */ +static const uint32_t IMEM_dcrypto[] = { +/* @0x0: function tag[1] { */ +#define CF_tag_adr 0 + 0xf8000003, /* sigini #3 */ +/* } */ +/* @0x1: function expandw[84] { */ +#define CF_expandw_adr 1 + 0x4c3def00, /* xor r15, r15, r15 */ + 0x803c0013, /* movi r15.0l, #19 */ + 0x80bc0016, /* movi r15.1l, #22 */ + 0x97800f00, /* ldrfp r15 */ + 0x05004003, /* loop #4 ( */ + 0x8c001800, /* ld *0, *0++ */ + 0x906c0800, /* st *0++, *3++ */ + 0xfc000000, /* nop */ + /* ) */ + 0x0501004a, /* loop #16 ( */ + 0x684a6080, /* rshi r18, r0, r19 >> 128 */ + 0x68443340, /* rshi r17, r19, r1 >> 64 */ + 0x683e3201, /* rshi r15, r18, r17 >> 1 */ + 0x68423208, /* rshi r16, r18, r17 >> 8 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f207, /* rshi r16, r18, r31 >> 7 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x505df398, /* add r23, r19, r15 >> 192 */ + 0x505eb788, /* add r23, r23, r21 >> 64 */ + 0x684ac0c0, /* rshi r18, r0, r22 >> 192 */ + 0x68443680, /* rshi r17, r22, r1 >> 128 */ + 0x683e3213, /* rshi r15, r18, r17 >> 19 */ + 0x6842323d, /* rshi r16, r18, r17 >> 61 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f206, /* rshi r16, r18, r31 >> 6 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x505df798, /* add r23, r23, r15 >> 192 */ + 0x684a60c0, /* rshi r18, r0, r19 >> 192 */ + 0x68443380, /* rshi r17, r19, r1 >> 128 */ + 0x683e3201, /* rshi r15, r18, r17 >> 1 */ + 0x68423208, /* rshi r16, r18, r17 >> 8 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f207, /* rshi r16, r18, r31 >> 7 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x50627f88, /* add r24, r31, r19 >> 64 */ + 0x5061f898, /* add r24, r24, r15 >> 192 */ + 0x5062b890, /* add r24, r24, r21 >> 128 */ + 0x684416c0, /* rshi r17, r22, r0 >> 192 */ + 0x683e3613, /* rshi r15, r22, r17 >> 19 */ + 0x6842363d, /* rshi r16, r22, r17 >> 61 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f606, /* rshi r16, r22, r31 >> 6 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x5061f898, /* add r24, r24, r15 >> 192 */ + 0x684433c0, /* rshi r17, r19, r1 >> 192 */ + 0x683e3301, /* rshi r15, r19, r17 >> 1 */ + 0x68423308, /* rshi r16, r19, r17 >> 8 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f307, /* rshi r16, r19, r31 >> 7 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x50667f90, /* add r25, r31, r19 >> 128 */ + 0x5065f998, /* add r25, r25, r15 >> 192 */ + 0x5066b998, /* add r25, r25, r21 >> 192 */ + 0x684ae040, /* rshi r18, r0, r23 >> 64 */ + 0x683ef213, /* rshi r15, r18, r23 >> 19 */ + 0x6842f23d, /* rshi r16, r18, r23 >> 61 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f206, /* rshi r16, r18, r31 >> 6 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x5065f998, /* add r25, r25, r15 >> 192 */ + 0x684a8040, /* rshi r18, r0, r20 >> 64 */ + 0x683e9201, /* rshi r15, r18, r20 >> 1 */ + 0x68429208, /* rshi r16, r18, r20 >> 8 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f207, /* rshi r16, r18, r31 >> 7 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x506a7f98, /* add r26, r31, r19 >> 192 */ + 0x5069fa98, /* add r26, r26, r15 >> 192 */ + 0x506ada00, /* add r26, r26, r22 */ + 0x684b0040, /* rshi r18, r0, r24 >> 64 */ + 0x683f1213, /* rshi r15, r18, r24 >> 19 */ + 0x6843123d, /* rshi r16, r18, r24 >> 61 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x6843f206, /* rshi r16, r18, r31 >> 6 */ + 0x4c3e0f00, /* xor r15, r15, r16 */ + 0x5069fa98, /* add r26, r26, r15 >> 192 */ + 0x7c4c1400, /* mov r19, r20 */ + 0x7c501500, /* mov r20, r21 */ + 0x7c541600, /* mov r21, r22 */ + 0x685af640, /* rshi r22, r22, r23 >> 64 */ + 0x685b1640, /* rshi r22, r22, r24 >> 64 */ + 0x685b3640, /* rshi r22, r22, r25 >> 64 */ + 0x685b5640, /* rshi r22, r22, r26 >> 64 */ + 0x906c0100, /* st *1, *3++ */ + /* ) */ + 0x0c000000, /* ret */ +/* } */ +/* @0x55: function Sha512_a[125] { */ +#define CF_Sha512_a_adr 85 + 0x68580c40, /* rshi r22, r12, r0 >> 64 */ + 0x683c161c, /* rshi r15, r22, r0 >> 28 */ + 0x68541622, /* rshi r21, r22, r0 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x68541627, /* rshi r21, r22, r0 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x40402000, /* and r16, r0, r1 */ + 0x40544000, /* and r21, r0, r2 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x40544100, /* and r21, r1, r2 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x68458fc0, /* rshi r17, r15, r12 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x68588d40, /* rshi r22, r13, r4 >> 64 */ + 0x6848960e, /* rshi r18, r22, r4 >> 14 */ + 0x68549612, /* rshi r21, r22, r4 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684c9629, /* rshi r19, r22, r4 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404ca400, /* and r19, r4, r5 */ + 0x48548000, /* not r21, r4 */ + 0x4054d500, /* and r21, r21, r6 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */ + 0x5050f400, /* add r20, r20, r7 */ + 0x50515480, /* add r20, r20, r10 >> 0 */ + 0x68558b00, /* rshi r21, r11, r12 >> 0 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x500e8300, /* add r3, r3, r20 */ + 0x501e3400, /* add r7, r20, r17 */ + 0x6858ec40, /* rshi r22, r12, r7 >> 64 */ + 0x683cf61c, /* rshi r15, r22, r7 >> 28 */ + 0x6854f622, /* rshi r21, r22, r7 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x6854f627, /* rshi r21, r22, r7 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x40400700, /* and r16, r7, r0 */ + 0x40542700, /* and r21, r7, r1 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x40542000, /* and r21, r0, r1 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x68458fc0, /* rshi r17, r15, r12 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x68586d40, /* rshi r22, r13, r3 >> 64 */ + 0x6848760e, /* rshi r18, r22, r3 >> 14 */ + 0x68547612, /* rshi r21, r22, r3 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684c7629, /* rshi r19, r22, r3 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404c8300, /* and r19, r3, r4 */ + 0x48546000, /* not r21, r3 */ + 0x4054b500, /* and r21, r21, r5 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */ + 0x5050d400, /* add r20, r20, r6 */ + 0x50515488, /* add r20, r20, r10 >> 64 */ + 0x68558b40, /* rshi r21, r11, r12 >> 64 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x500a8200, /* add r2, r2, r20 */ + 0x501a3400, /* add r6, r20, r17 */ + 0x6858cc40, /* rshi r22, r12, r6 >> 64 */ + 0x683cd61c, /* rshi r15, r22, r6 >> 28 */ + 0x6854d622, /* rshi r21, r22, r6 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x6854d627, /* rshi r21, r22, r6 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x4040e600, /* and r16, r6, r7 */ + 0x40540600, /* and r21, r6, r0 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x40540700, /* and r21, r7, r0 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x68458fc0, /* rshi r17, r15, r12 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x68584d40, /* rshi r22, r13, r2 >> 64 */ + 0x6848560e, /* rshi r18, r22, r2 >> 14 */ + 0x68545612, /* rshi r21, r22, r2 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684c5629, /* rshi r19, r22, r2 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404c6200, /* and r19, r2, r3 */ + 0x48544000, /* not r21, r2 */ + 0x40549500, /* and r21, r21, r4 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */ + 0x5050b400, /* add r20, r20, r5 */ + 0x50515490, /* add r20, r20, r10 >> 128 */ + 0x68558b80, /* rshi r21, r11, r12 >> 128 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x50068100, /* add r1, r1, r20 */ + 0x50163400, /* add r5, r20, r17 */ + 0x6858ac40, /* rshi r22, r12, r5 >> 64 */ + 0x683cb61c, /* rshi r15, r22, r5 >> 28 */ + 0x6854b622, /* rshi r21, r22, r5 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x6854b627, /* rshi r21, r22, r5 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x4040c500, /* and r16, r5, r6 */ + 0x4054e500, /* and r21, r5, r7 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x4054e600, /* and r21, r6, r7 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x68458fc0, /* rshi r17, r15, r12 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x68582d40, /* rshi r22, r13, r1 >> 64 */ + 0x6848360e, /* rshi r18, r22, r1 >> 14 */ + 0x68543612, /* rshi r21, r22, r1 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684c3629, /* rshi r19, r22, r1 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404c4100, /* and r19, r1, r2 */ + 0x48542000, /* not r21, r1 */ + 0x40547500, /* and r21, r21, r3 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x6851b2c0, /* rshi r20, r18, r13 >> 192 */ + 0x50509400, /* add r20, r20, r4 */ + 0x50515498, /* add r20, r20, r10 >> 192 */ + 0x68558bc0, /* rshi r21, r11, r12 >> 192 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x50028000, /* add r0, r0, r20 */ + 0x50123400, /* add r4, r20, r17 */ + 0x0c000000, /* ret */ +/* } */ +/* @0xd2: function Sha512_b[125] { */ +#define CF_Sha512_b_adr 210 + 0x68588d40, /* rshi r22, r13, r4 >> 64 */ + 0x683c961c, /* rshi r15, r22, r4 >> 28 */ + 0x68549622, /* rshi r21, r22, r4 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x68549627, /* rshi r21, r22, r4 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x4040a400, /* and r16, r4, r5 */ + 0x4054c400, /* and r21, r4, r6 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x4054c500, /* and r21, r5, r6 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x6845afc0, /* rshi r17, r15, r13 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x68580c40, /* rshi r22, r12, r0 >> 64 */ + 0x6848160e, /* rshi r18, r22, r0 >> 14 */ + 0x68541612, /* rshi r21, r22, r0 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684c1629, /* rshi r19, r22, r0 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404c2000, /* and r19, r0, r1 */ + 0x48540000, /* not r21, r0 */ + 0x40545500, /* and r21, r21, r2 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x685192c0, /* rshi r20, r18, r12 >> 192 */ + 0x50507400, /* add r20, r20, r3 */ + 0x50515480, /* add r20, r20, r10 >> 0 */ + 0x6855ab00, /* rshi r21, r11, r13 >> 0 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x501e8700, /* add r7, r7, r20 */ + 0x500e3400, /* add r3, r20, r17 */ + 0x68586d40, /* rshi r22, r13, r3 >> 64 */ + 0x683c761c, /* rshi r15, r22, r3 >> 28 */ + 0x68547622, /* rshi r21, r22, r3 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x68547627, /* rshi r21, r22, r3 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x40408300, /* and r16, r3, r4 */ + 0x4054a300, /* and r21, r3, r5 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x4054a400, /* and r21, r4, r5 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x6845afc0, /* rshi r17, r15, r13 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x6858ec40, /* rshi r22, r12, r7 >> 64 */ + 0x6848f60e, /* rshi r18, r22, r7 >> 14 */ + 0x6854f612, /* rshi r21, r22, r7 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684cf629, /* rshi r19, r22, r7 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404c0700, /* and r19, r7, r0 */ + 0x4854e000, /* not r21, r7 */ + 0x40543500, /* and r21, r21, r1 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x685192c0, /* rshi r20, r18, r12 >> 192 */ + 0x50505400, /* add r20, r20, r2 */ + 0x50515488, /* add r20, r20, r10 >> 64 */ + 0x6855ab40, /* rshi r21, r11, r13 >> 64 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x501a8600, /* add r6, r6, r20 */ + 0x500a3400, /* add r2, r20, r17 */ + 0x68584d40, /* rshi r22, r13, r2 >> 64 */ + 0x683c561c, /* rshi r15, r22, r2 >> 28 */ + 0x68545622, /* rshi r21, r22, r2 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x68545627, /* rshi r21, r22, r2 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x40406200, /* and r16, r2, r3 */ + 0x40548200, /* and r21, r2, r4 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x40548300, /* and r21, r3, r4 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x6845afc0, /* rshi r17, r15, r13 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x6858cc40, /* rshi r22, r12, r6 >> 64 */ + 0x6848d60e, /* rshi r18, r22, r6 >> 14 */ + 0x6854d612, /* rshi r21, r22, r6 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684cd629, /* rshi r19, r22, r6 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404ce600, /* and r19, r6, r7 */ + 0x4854c000, /* not r21, r6 */ + 0x40541500, /* and r21, r21, r0 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x685192c0, /* rshi r20, r18, r12 >> 192 */ + 0x50503400, /* add r20, r20, r1 */ + 0x50515490, /* add r20, r20, r10 >> 128 */ + 0x6855ab80, /* rshi r21, r11, r13 >> 128 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x50168500, /* add r5, r5, r20 */ + 0x50063400, /* add r1, r20, r17 */ + 0x68582d40, /* rshi r22, r13, r1 >> 64 */ + 0x683c361c, /* rshi r15, r22, r1 >> 28 */ + 0x68543622, /* rshi r21, r22, r1 >> 34 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x68543627, /* rshi r21, r22, r1 >> 39 */ + 0x4c3eaf00, /* xor r15, r15, r21 */ + 0x40404100, /* and r16, r1, r2 */ + 0x40546100, /* and r21, r1, r3 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x40546200, /* and r21, r2, r3 */ + 0x4c42b000, /* xor r16, r16, r21 */ + 0x6845afc0, /* rshi r17, r15, r13 >> 192 */ + 0x50461100, /* add r17, r17, r16 */ + 0x6858ac40, /* rshi r22, r12, r5 >> 64 */ + 0x6848b60e, /* rshi r18, r22, r5 >> 14 */ + 0x6854b612, /* rshi r21, r22, r5 >> 18 */ + 0x4c4ab200, /* xor r18, r18, r21 */ + 0x684cb629, /* rshi r19, r22, r5 >> 41 */ + 0x4c4a7200, /* xor r18, r18, r19 */ + 0x404cc500, /* and r19, r5, r6 */ + 0x4854a000, /* not r21, r5 */ + 0x4054f500, /* and r21, r21, r7 */ + 0x4c4eb300, /* xor r19, r19, r21 */ + 0x685192c0, /* rshi r20, r18, r12 >> 192 */ + 0x50501400, /* add r20, r20, r0 */ + 0x50515498, /* add r20, r20, r10 >> 192 */ + 0x6855abc0, /* rshi r21, r11, r13 >> 192 */ + 0x50567500, /* add r21, r21, r19 */ + 0x5052b400, /* add r20, r20, r21 */ + 0x50128400, /* add r4, r4, r20 */ + 0x50023400, /* add r0, r20, r17 */ + 0x0c000000, /* ret */ +/* } */ +/* @0x14f: function compress[70] { */ +#define CF_compress_adr 335 + 0xfc000000, /* nop */ + 0x4c7fff00, /* xor r31, r31, r31 */ + 0x4c000000, /* xor r0, r0, r0 */ + 0x4c042100, /* xor r1, r1, r1 */ + 0x55000001, /* subi r0, r0, #1 */ + 0x55040101, /* subi r1, r1, #1 */ + 0x84204100, /* ldi r8, [#8] */ + 0x94800800, /* ldlc r8 */ + 0x4c3def00, /* xor r15, r15, r15 */ + 0x803c000a, /* movi r15.0l, #10 */ + 0x95800f00, /* lddmp r15 */ + 0x06000039, /* loop *0 ( */ + 0x953c0000, /* stdmp r15 */ + 0x81bc002a, /* movi r15.3l, #42 */ + 0x95800f00, /* lddmp r15 */ + 0x08000001, /* call &expandw */ + 0x84004000, /* ldi r0, [#0] */ + 0x84044020, /* ldi r1, [#1] */ + 0x84084040, /* ldi r2, [#2] */ + 0x840c4060, /* ldi r3, [#3] */ + 0x84104080, /* ldi r4, [#4] */ + 0x841440a0, /* ldi r5, [#5] */ + 0x841840c0, /* ldi r6, [#6] */ + 0x841c40e0, /* ldi r7, [#7] */ + 0x4c3def00, /* xor r15, r15, r15 */ + 0x803c0060, /* movi r15.0l, #96 */ + 0x80bc000a, /* movi r15.1l, #10 */ + 0x813c000b, /* movi r15.2l, #11 */ + 0x96800f00, /* lddrp r15 */ + 0x97800f00, /* ldrfp r15 */ + 0x953c0000, /* stdmp r15 */ + 0x81bc002a, /* movi r15.3l, #42 */ + 0x95800f00, /* lddmp r15 */ + 0x4c318c00, /* xor r12, r12, r12 */ + 0x4c35ad00, /* xor r13, r13, r13 */ + 0x55300c01, /* subi r12, r12, #1 */ + 0x55340d01, /* subi r13, r13, #1 */ + 0x0500a007, /* loop #10 ( */ + 0x8c440800, /* ldc *1, *0++ */ + 0x8c081b00, /* ld *2, *3++ */ + 0x08000055, /* call &Sha512_a */ + 0x8c440800, /* ldc *1, *0++ */ + 0x8c081b00, /* ld *2, *3++ */ + 0x080000d2, /* call &Sha512_b */ + 0xfc000000, /* nop */ + /* ) */ + 0x843c4000, /* ldi r15, [#0] */ + 0x5001e000, /* add r0, r0, r15 */ + 0x843c4020, /* ldi r15, [#1] */ + 0x5005e100, /* add r1, r1, r15 */ + 0x843c4040, /* ldi r15, [#2] */ + 0x5009e200, /* add r2, r2, r15 */ + 0x843c4060, /* ldi r15, [#3] */ + 0x500de300, /* add r3, r3, r15 */ + 0x843c4080, /* ldi r15, [#4] */ + 0x5011e400, /* add r4, r4, r15 */ + 0x843c40a0, /* ldi r15, [#5] */ + 0x5015e500, /* add r5, r5, r15 */ + 0x843c40c0, /* ldi r15, [#6] */ + 0x5019e600, /* add r6, r6, r15 */ + 0x843c40e0, /* ldi r15, [#7] */ + 0x501de700, /* add r7, r7, r15 */ + 0x88004000, /* sti r0, [#0] */ + 0x88044020, /* sti r1, [#1] */ + 0x88084040, /* sti r2, [#2] */ + 0x880c4060, /* sti r3, [#3] */ + 0x88104080, /* sti r4, [#4] */ + 0x881440a0, /* sti r5, [#5] */ + 0x881840c0, /* sti r6, [#6] */ + 0x881c40e0, /* sti r7, [#7] */ + /* ) */ + 0x0c000000, /* ret */ + /* } */ +}; +/* clang-format on */ + +struct DMEM_sha512 { + uint64_t H0[4]; + uint64_t H1[4]; + uint64_t H2[4]; + uint64_t H3[4]; + uint64_t H4[4]; + uint64_t H5[4]; + uint64_t H6[4]; + uint64_t H7[4]; + uint32_t nblocks; + uint32_t unused[2 * 8 - 1]; + uint32_t input[4 * 8 * 8]; // dmem[10..41] +}; + +static void copy_words(const void *in, uint32_t *dst, size_t nwords) +{ + const uint32_t *src = (const uint32_t *) in; + + do { + uint32_t w1 = __builtin_bswap32(*src++); + uint32_t w2 = __builtin_bswap32(*src++); + *dst++ = w2; + *dst++ = w1; + } while (nwords -= 2); +} + +static void dcrypto_SHA512_setup(void) +{ + dcrypto_imem_load(0, IMEM_dcrypto, ARRAY_SIZE(IMEM_dcrypto)); +} + +static void dcrypto_SHA512_Transform(LITE_SHA512_CTX *ctx, const uint32_t *buf, + size_t nwords) +{ + int result = 0; + struct DMEM_sha512 *p512 = + (struct DMEM_sha512 *) GREG32_ADDR(CRYPTO, DMEM_DUMMY); + + START_PROFILE(t_transform) + + /* Pass in H[] */ + p512->H0[0] = ctx->state[0]; + p512->H1[0] = ctx->state[1]; + p512->H2[0] = ctx->state[2]; + p512->H3[0] = ctx->state[3]; + p512->H4[0] = ctx->state[4]; + p512->H5[0] = ctx->state[5]; + p512->H6[0] = ctx->state[6]; + p512->H7[0] = ctx->state[7]; + + p512->nblocks = nwords / 32; + + /* Pass in buf[] */ + copy_words(buf, p512->input, nwords); + + START_PROFILE(t_dcrypto) + result |= dcrypto_call(CF_compress_adr); + END_PROFILE(t_dcrypto) + + /* Retrieve new H[] */ + ctx->state[0] = p512->H0[0]; + ctx->state[1] = p512->H1[0]; + ctx->state[2] = p512->H2[0]; + ctx->state[3] = p512->H3[0]; + ctx->state[4] = p512->H4[0]; + ctx->state[5] = p512->H5[0]; + ctx->state[6] = p512->H6[0]; + ctx->state[7] = p512->H7[0]; + + /* TODO: errno or such to capture errors */ + (void) (result == 0); + + END_PROFILE(t_transform) +} + +static void dcrypto_SHA512_update(LITE_SHA512_CTX *ctx, const void *data, + size_t len) +{ + int i = (int) (ctx->count & (sizeof(ctx->buf) - 1)); + const uint8_t *p = (const uint8_t *) data; + uint8_t *d = &ctx->buf[i]; + + ctx->count += len; + + dcrypto_init_and_lock(); + dcrypto_SHA512_setup(); + + /* Take fast path for 32-bit aligned 1KB inputs */ + if (i == 0 && len == 1024 && (((intptr_t) data) & 3) == 0) { + dcrypto_SHA512_Transform(ctx, (const uint32_t *) data, 8 * 32); + } else { + if (len <= sizeof(ctx->buf) - i) { + memcpy(d, p, len); + if (len == sizeof(ctx->buf) - i) { + dcrypto_SHA512_Transform( + ctx, (uint32_t *) (ctx->buf), 32); + } + } else { + memcpy(d, p, sizeof(ctx->buf) - i); + dcrypto_SHA512_Transform(ctx, (uint32_t *) (ctx->buf), + 32); + d = ctx->buf; + len -= (sizeof(ctx->buf) - i); + p += (sizeof(ctx->buf) - i); + while (len >= sizeof(ctx->buf)) { + memcpy(d, p, sizeof(ctx->buf)); + p += sizeof(ctx->buf); + len -= sizeof(ctx->buf); + dcrypto_SHA512_Transform( + ctx, (uint32_t *) (ctx->buf), 32); + } + /* Leave remainder in ctx->buf */ + memcpy(d, p, len); + } + } + dcrypto_unlock(); +} + +static const uint8_t *dcrypto_SHA512_final(LITE_SHA512_CTX *ctx) +{ + uint64_t cnt = ctx->count * 8; + int i = (int) (ctx->count & (sizeof(ctx->buf) - 1)); + uint8_t *p = &ctx->buf[i]; + + *p++ = 0x80; + i++; + + dcrypto_init_and_lock(); + dcrypto_SHA512_setup(); + + if (i > sizeof(ctx->buf) - 16) { + memset(p, 0, sizeof(ctx->buf) - i); + dcrypto_SHA512_Transform(ctx, (uint32_t *) (ctx->buf), 32); + i = 0; + p = ctx->buf; + } + + memset(p, 0, sizeof(ctx->buf) - 8 - i); + p += sizeof(ctx->buf) - 8 - i; + + for (i = 0; i < 8; ++i) { + uint8_t tmp = (uint8_t)(cnt >> 56); + cnt <<= 8; + *p++ = tmp; + } + + dcrypto_SHA512_Transform(ctx, (uint32_t *) (ctx->buf), 32); + + p = ctx->buf; + for (i = 0; i < 8; i++) { + uint64_t tmp = ctx->state[i]; + *p++ = (uint8_t)(tmp >> 56); + *p++ = (uint8_t)(tmp >> 48); + *p++ = (uint8_t)(tmp >> 40); + *p++ = (uint8_t)(tmp >> 32); + *p++ = (uint8_t)(tmp >> 24); + *p++ = (uint8_t)(tmp >> 16); + *p++ = (uint8_t)(tmp >> 8); + *p++ = (uint8_t)(tmp >> 0); + } + + dcrypto_unlock(); + return ctx->buf; +} + +const uint8_t *DCRYPTO_SHA512_hash(const void *data, size_t len, + uint8_t *digest) +{ + LITE_SHA512_CTX ctx; + + DCRYPTO_SHA512_init(&ctx); + dcrypto_SHA512_update(&ctx, data, len); + memcpy(digest, dcrypto_SHA512_final(&ctx), SHA512_DIGEST_SIZE); + + return digest; +} + +static const HASH_VTAB dcrypto_SHA512_VTAB = { + DCRYPTO_SHA512_init, dcrypto_SHA512_update, dcrypto_SHA512_final, + DCRYPTO_SHA512_hash, SHA512_DIGEST_SIZE}; + +void DCRYPTO_SHA512_init(LITE_SHA512_CTX *ctx) +{ + SHA512_init(ctx); + ctx->f = &dcrypto_SHA512_VTAB; +} + +#ifdef CRYPTO_TEST_SETUP + +static uint32_t msg[256]; // 1KB +static int msg_len; +static int msg_loops; +static LITE_SHA512_CTX sw; +static LITE_SHA512_CTX hw; +static const uint8_t *sw_digest; +static const uint8_t *hw_digest; +static uint32_t t_sw; +static uint32_t t_hw; + +static void run_sha512_cmd(void) +{ + int i; + + t_transform = 0; + t_dcrypto = 0; + t_sw = 0; + t_hw = 0; + + START_PROFILE(t_sw) + SHA512_init(&sw); + for (i = 0; i < msg_loops; ++i) { + HASH_update(&sw, msg, msg_len); + } + sw_digest = HASH_final(&sw); + END_PROFILE(t_sw) + + START_PROFILE(t_hw) + DCRYPTO_SHA512_init(&hw); + for (i = 0; i < msg_loops; ++i) { + HASH_update(&hw, msg, msg_len); + } + hw_digest = HASH_final(&hw); + END_PROFILE(t_hw) + + ccprintf("sw(%u):\n", t_sw); + for (i = 0; i < 64; ++i) + ccprintf("%02x", sw_digest[i]); + ccprintf("\n"); + + ccprintf("hw(%u/%u/%u):\n", t_hw, t_transform, t_dcrypto); + for (i = 0; i < 64; ++i) + ccprintf("%02x", hw_digest[i]); + ccprintf("\n"); + + task_set_event(TASK_ID_CONSOLE, TASK_EVENT_CUSTOM_BIT(0), 0); +} +DECLARE_DEFERRED(run_sha512_cmd); + +static int cmd_sha512_bench(int argc, char *argv[]) +{ + const int max_time = 1000000; + uint32_t events; + + memset(msg, '!', sizeof(msg)); + + if (argc > 1) { + msg_loops = 1; + msg_len = strlen(argv[1]); + memcpy(msg, argv[1], msg_len); + } else { + msg_loops = 64; // benchmark 64K + msg_len = sizeof(msg); + } + + hook_call_deferred(&run_sha512_cmd_data, 0); + ccprintf("Will wait up to %d ms\n", (max_time + 500) / 1000); + + events = task_wait_event_mask(TASK_EVENT_CUSTOM_BIT(0), max_time); + if (!(events & TASK_EVENT_CUSTOM_BIT(0))) { + ccprintf("Timed out, you might want to reboot...\n"); + return EC_ERROR_TIMEOUT; + } + + return EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(sha512_bench, cmd_sha512_bench, NULL, NULL); + +static void run_sha512_test(void) +{ + int i; + + for (i = 0; i < 129; ++i) { + memset(msg, i, i); + + SHA512_init(&sw); + HASH_update(&sw, msg, i); + sw_digest = HASH_final(&sw); + + DCRYPTO_SHA512_init(&hw); + HASH_update(&hw, msg, i); + hw_digest = HASH_final(&hw); + + if (memcmp(sw_digest, hw_digest, SHA512_DIGEST_SIZE) != 0) { + ccprintf("sha512 self-test fail at %d!\n", i); + cflush(); + } + } + + ccprintf("sha512 self-test PASS!\n"); + task_set_event(TASK_ID_CONSOLE, TASK_EVENT_CUSTOM_BIT(0), 0); +} +DECLARE_DEFERRED(run_sha512_test); + +static int cmd_sha512_test(int argc, char *argv[]) +{ + hook_call_deferred(&run_sha512_test_data, 0); + task_wait_event_mask(TASK_EVENT_CUSTOM_BIT(0), 1000000); + return EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(sha512_test, cmd_sha512_test, NULL, NULL); + +#endif /* CRYPTO_TEST_SETUP */ diff --git a/chip/g/dcrypto/gcm.c b/chip/g/dcrypto/gcm.c new file mode 100644 index 0000000000..cd035bbd54 --- /dev/null +++ b/chip/g/dcrypto/gcm.c @@ -0,0 +1,345 @@ +/* Copyright 2017 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 "endian.h" + +#include "cryptoc/util.h" + +static void gcm_mul(uint32_t *counter) +{ + int i; + volatile uint32_t *p; + + /* Set HASH to zero. */ + p = GREG32_ADDR(KEYMGR, GCM_HASH_IN0); + for (i = 0; i < 4; i++) + *p++ = 0; + + /* Initialize GMAC. */ + p = GREG32_ADDR(KEYMGR, GCM_MAC0); + for (i = 0; i < 4; i++) + *p++ = counter[i]; + + /* Crank GMAC. */ + GREG32(KEYMGR, GCM_DO_ACC) = 1; + + /* Read GMAC. */ + p = GREG32_ADDR(KEYMGR, GCM_MAC0); + for (i = 0; i < 4; i++) + counter[i] = *p++; + + /* Reset GMAC. */ + p = GREG32_ADDR(KEYMGR, GCM_MAC0); + for (i = 0; i < 4; ++i) + *p++ = 0; +} + +static void gcm_init_iv( + const uint8_t *iv, uint32_t iv_len, uint32_t *counter) +{ + + if (iv_len == 12) { + memcpy(counter, iv, 12); + counter[3] = BIT(24); + } else { + size_t i; + uint32_t len = iv_len; + uint64_t len0 = len; + uint8_t *ctr = (uint8_t *) counter; + + memset(ctr, 0, 16); + while (len >= 16) { + for (i = 0; i < 16; ++i) + ctr[i] ^= iv[i]; + + gcm_mul(counter); + iv += 16; + len -= 16; + } + if (len) { + for (i = 0; i < len; ++i) + ctr[i] ^= iv[i]; + + gcm_mul(counter); + } + len0 <<= 3; + ctr[8] ^= (uint8_t)(len0 >> 56); + ctr[9] ^= (uint8_t)(len0 >> 48); + ctr[10] ^= (uint8_t)(len0 >> 40); + ctr[11] ^= (uint8_t)(len0 >> 32); + ctr[12] ^= (uint8_t)(len0 >> 24); + ctr[13] ^= (uint8_t)(len0 >> 16); + ctr[14] ^= (uint8_t)(len0 >> 8); + ctr[15] ^= (uint8_t)(len0); + + gcm_mul(counter); + } +} + +void DCRYPTO_gcm_init(struct GCM_CTX *ctx, uint32_t key_bits, + const uint8_t *key, const uint8_t *iv, size_t iv_len) +{ + int i; + const uint32_t zero[4] = {0, 0, 0, 0}; + uint32_t H[4]; + uint32_t counter[4]; + + memset(ctx, 0, sizeof(struct GCM_CTX)); + + /* Initialize AES engine in CTR mode, and set the counter to 0. */ + DCRYPTO_aes_init(key, key_bits, (const uint8_t *) zero, + CIPHER_MODE_CTR, ENCRYPT_MODE); + /* Set H to AES(ZERO). */ + DCRYPTO_aes_block((const uint8_t *) zero, (uint8_t *) H); + + /* Initialize the GMAC accumulator to ZERO. */ + for (i = 0; i < 4; i++) + GR_KEYMGR_GCM_MAC(i) = zero[i]; + + /* Initialize H. */ + for (i = 0; i < 4; i++) + GR_KEYMGR_GCM_H(i) = H[i]; + + /* Map the IV to a 128-bit counter. */ + gcm_init_iv(iv, iv_len, counter); + + /* Re-initialize the IV counter. */ + for (i = 0; i < 4; i++) + GR_KEYMGR_AES_CTR(i) = counter[i]; + + /* Calculate Ej0: encrypt IV counter XOR ZERO. */ + DCRYPTO_aes_block((const uint8_t *) zero, ctx->Ej0.c); +} + +static void gcm_aad_block(const struct GCM_CTX *ctx, const uint32_t *block) +{ + int i; + const struct access_helper *p = (struct access_helper *) block; + + if (ctx->aad_len == 0 && ctx->count <= 16) { + /* Update GMAC. */ + for (i = 0; i < 4; i++) + GR_KEYMGR_GCM_MAC(i) = p[i].udata; + } else { + for (i = 0; i < 4; i++) + GR_KEYMGR_GCM_HASH_IN(i) = p[i].udata; + + /* Crank GMAC. */ + GREG32(KEYMGR, GCM_DO_ACC) = 1; + } +} + +void DCRYPTO_gcm_aad(struct GCM_CTX *ctx, const uint8_t *aad_data, size_t len) +{ + uint32_t block[4]; + + while (len) { + size_t count; + + memset(block, 0, sizeof(block)); + count = MIN(16, len); + memcpy(block, aad_data, count); + + gcm_aad_block(ctx, block); + ctx->aad_len += count; + + len -= count; + aad_data += count; + } + + always_memset(block, 0, sizeof(block)); +} + +int DCRYPTO_gcm_encrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len, + const uint8_t *in, size_t in_len) +{ + uint8_t *outp = out; + + if (out_len < (in_len & ~0x0F) + ((in_len & 0x0F) ? 16 : 0)) + return -1; + + /* Process a previous partial block, if any. */ + if (ctx->remainder) { + size_t count = MIN(in_len, 16 - ctx->remainder); + + memcpy(ctx->block.c + ctx->remainder, in, count); + ctx->remainder += count; + if (ctx->remainder < 16) + return 0; + + DCRYPTO_aes_block(ctx->block.c, outp); + ctx->count += 16; + gcm_aad_block(ctx, (uint32_t *) outp); + ctx->remainder = 0; + in += count; + in_len -= count; + outp += 16; + } + + while (in_len >= 16) { + DCRYPTO_aes_block(in, outp); + ctx->count += 16; + + gcm_aad_block(ctx, (uint32_t *) outp); + + in_len -= 16; + in += 16; + outp += 16; + } + + if (in_len) { + memcpy(ctx->block.c, in, in_len); + ctx->remainder = in_len; + } + + return outp - out; +} + +int DCRYPTO_gcm_encrypt_final(struct GCM_CTX *ctx, uint8_t *out, size_t out_len) +{ + if (out_len < ctx->remainder) + return -1; + + if (ctx->remainder) { + size_t remainder = ctx->remainder; + uint8_t out_block[16]; + + DCRYPTO_aes_block(ctx->block.c, out_block); + ctx->count += ctx->remainder; + memcpy(out, out_block, ctx->remainder); + + memset(out_block + ctx->remainder, 0, 16 - ctx->remainder); + gcm_aad_block(ctx, (uint32_t *) out_block); + ctx->remainder = 0; + return remainder; + } + + return 0; +} + +int DCRYPTO_gcm_decrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len, + const uint8_t *in, size_t in_len) +{ + uint8_t *outp = out; + + if (out_len < (in_len & ~0x0F) + ((in_len & 0x0F) ? 16 : 0)) + return -1; + + if (ctx->remainder) { + size_t count = MIN(in_len, 16 - ctx->remainder); + + memcpy(ctx->block.c + ctx->remainder, in, count); + ctx->remainder += count; + + if (ctx->remainder < 16) + return 0; + + DCRYPTO_aes_block(ctx->block.c, outp); + ctx->remainder = 0; + ctx->count += 16; + gcm_aad_block(ctx, ctx->block.d); + in += count; + in_len -= count; + outp += count; + } + + while (in_len >= 16) { + DCRYPTO_aes_block(in, outp); + ctx->count += 16; + gcm_aad_block(ctx, (uint32_t *) in); + in += 16; + in_len -= 16; + outp += 16; + } + + if (in_len) { + memcpy(ctx->block.c, in, in_len); + ctx->remainder = in_len; + } + + return outp - out; +} + +int DCRYPTO_gcm_decrypt_final(struct GCM_CTX *ctx, + uint8_t *out, size_t out_len) +{ + if (out_len < ctx->remainder) + return -1; + + if (ctx->remainder) { + size_t remainder = ctx->remainder; + uint8_t out_block[16]; + + DCRYPTO_aes_block(ctx->block.c, out_block); + ctx->count += ctx->remainder; + memcpy(out, out_block, ctx->remainder); + + memset(ctx->block.c + ctx->remainder, 0, 16 - ctx->remainder); + gcm_aad_block(ctx, ctx->block.d); + ctx->remainder = 0; + return remainder; + } + + return 0; +} + +static void dcrypto_gcm_len_vector( + const struct GCM_CTX *ctx, void *len_vector) { + uint64_t aad_be; + uint64_t count_be; + + /* Serialize counters to bit-count (big-endian). */ + aad_be = ctx->aad_len * 8; + aad_be = htobe64(aad_be); + count_be = ctx->count * 8; + count_be = htobe64(count_be); + + memcpy(len_vector, &aad_be, 8); + memcpy(((uint8_t *)len_vector) + 8, &count_be, 8); +} + +static void dcrypto_gcm_tag(const struct GCM_CTX *ctx, + const uint32_t *len_vector, uint32_t *tag) { + int i; + + for (i = 0; i < 4; i++) + GR_KEYMGR_GCM_HASH_IN(i) = len_vector[i]; + + /* Crank GMAC. */ + GREG32(KEYMGR, GCM_DO_ACC) = 1; + + for (i = 0; i < 4; i++) + GR_KEYMGR_GCM_HASH_IN(i) = ctx->Ej0.d[i]; + + /* Crank GMAC. */ + GREG32(KEYMGR, GCM_DO_ACC) = 1; + + /* Read tag. */ + for (i = 0; i < 4; i++) + tag[i] = GR_KEYMGR_GCM_MAC(i); +} + +int DCRYPTO_gcm_tag(struct GCM_CTX *ctx, uint8_t *tag, size_t tag_len) +{ + uint32_t len_vector[4]; + uint32_t local_tag[4]; + size_t count = MIN(tag_len, sizeof(local_tag)); + + dcrypto_gcm_len_vector(ctx, len_vector); + dcrypto_gcm_tag(ctx, len_vector, local_tag); + + memcpy(tag, local_tag, count); + return count; +} + +void DCRYPTO_gcm_finish(struct GCM_CTX *ctx) +{ + always_memset(ctx, 0, sizeof(struct GCM_CTX)); + GREG32(KEYMGR, AES_WIPE_SECRETS) = 1; +} diff --git a/chip/g/dcrypto/hkdf.c b/chip/g/dcrypto/hkdf.c new file mode 100644 index 0000000000..3afdc6b2eb --- /dev/null +++ b/chip/g/dcrypto/hkdf.c @@ -0,0 +1,83 @@ +/* Copyright 2016 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. + */ +/* An implementation of HKDF as per RFC 5869. */ + +#include "dcrypto.h" +#include "internal.h" + +#include "cryptoc/sha256.h" +#include "cryptoc/util.h" + +static int hkdf_extract(uint8_t *PRK, const uint8_t *salt, size_t salt_len, + const uint8_t *IKM, size_t IKM_len) +{ + LITE_HMAC_CTX ctx; + + if (PRK == NULL) + return 0; + if (salt == NULL && salt_len > 0) + return 0; + if (IKM == NULL && IKM_len > 0) + return 0; + + DCRYPTO_HMAC_SHA256_init(&ctx, salt, salt_len); + HASH_update(&ctx.hash, IKM, IKM_len); + memcpy(PRK, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE); + return 1; +} + +static int hkdf_expand(uint8_t *OKM, size_t OKM_len, const uint8_t *PRK, + const uint8_t *info, size_t info_len) +{ + uint8_t count = 1; + const uint8_t *T = OKM; + size_t T_len = 0; + uint32_t num_blocks = (OKM_len / SHA256_DIGEST_SIZE) + + (OKM_len % SHA256_DIGEST_SIZE ? 1 : 0); + + if (OKM == NULL || OKM_len == 0) + return 0; + if (PRK == NULL) + return 0; + if (info == NULL && info_len > 0) + return 0; + if (num_blocks > 255) + return 0; + + while (OKM_len > 0) { + LITE_HMAC_CTX ctx; + const size_t block_size = OKM_len < SHA256_DIGEST_SIZE ? + OKM_len : SHA256_DIGEST_SIZE; + + DCRYPTO_HMAC_SHA256_init(&ctx, PRK, SHA256_DIGEST_SIZE); + HASH_update(&ctx.hash, T, T_len); + HASH_update(&ctx.hash, info, info_len); + HASH_update(&ctx.hash, &count, sizeof(count)); + memcpy(OKM, DCRYPTO_HMAC_final(&ctx), block_size); + + T += T_len; + T_len = SHA256_DIGEST_SIZE; + count += 1; + OKM += block_size; + OKM_len -= block_size; + } + return 1; +} + +int DCRYPTO_hkdf(uint8_t *OKM, size_t OKM_len, + const uint8_t *salt, size_t salt_len, + const uint8_t *IKM, size_t IKM_len, + const uint8_t *info, size_t info_len) +{ + int result; + uint8_t PRK[SHA256_DIGEST_SIZE]; + + if (!hkdf_extract(PRK, salt, salt_len, IKM, IKM_len)) + return 0; + + result = hkdf_expand(OKM, OKM_len, PRK, info, info_len); + always_memset(PRK, 0, sizeof(PRK)); + return result; +} diff --git a/chip/g/dcrypto/hmac.c b/chip/g/dcrypto/hmac.c new file mode 100644 index 0000000000..7cc45a03ba --- /dev/null +++ b/chip/g/dcrypto/hmac.c @@ -0,0 +1,63 @@ +/* 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 "internal.h" +#include "dcrypto.h" + +#include + +#include "cryptoc/sha256.h" +#include "cryptoc/util.h" + +/* TODO(sukhomlinov): add support for hardware hmac. */ +static void hmac_sha256_init(LITE_HMAC_CTX *ctx, const void *key, + unsigned int len) +{ + unsigned int i; + + BUILD_ASSERT(sizeof(ctx->opad) >= SHA256_BLOCK_SIZE); + + memset(&ctx->opad[0], 0, SHA256_BLOCK_SIZE); + + if (len > SHA256_BLOCK_SIZE) { + DCRYPTO_SHA256_init(&ctx->hash, 0); + HASH_update(&ctx->hash, key, len); + memcpy(&ctx->opad[0], HASH_final(&ctx->hash), + HASH_size(&ctx->hash)); + } else { + memcpy(&ctx->opad[0], key, len); + } + + for (i = 0; i < SHA256_BLOCK_SIZE; ++i) + ctx->opad[i] ^= 0x36; + + DCRYPTO_SHA256_init(&ctx->hash, 0); + /* hash ipad */ + HASH_update(&ctx->hash, ctx->opad, SHA256_BLOCK_SIZE); + + for (i = 0; i < SHA256_BLOCK_SIZE; ++i) + ctx->opad[i] ^= (0x36 ^ 0x5c); +} + +void DCRYPTO_HMAC_SHA256_init(LITE_HMAC_CTX *ctx, const void *key, + unsigned int len) +{ + hmac_sha256_init(ctx, key, len); +} + +const uint8_t *DCRYPTO_HMAC_final(LITE_HMAC_CTX *ctx) +{ + uint8_t digest[SHA256_DIGEST_SIZE]; /* up to SHA256 */ + + memcpy(digest, HASH_final(&ctx->hash), + (HASH_size(&ctx->hash) <= sizeof(digest) ? + HASH_size(&ctx->hash) : + sizeof(digest))); + DCRYPTO_SHA256_init(&ctx->hash, 0); + HASH_update(&ctx->hash, ctx->opad, SHA256_BLOCK_SIZE); + HASH_update(&ctx->hash, digest, HASH_size(&ctx->hash)); + always_memset(&ctx->opad[0], 0, SHA256_BLOCK_SIZE); /* wipe key */ + return HASH_final(&ctx->hash); +} diff --git a/chip/g/dcrypto/hmac_drbg.c b/chip/g/dcrypto/hmac_drbg.c new file mode 100644 index 0000000000..2ca20e03ff --- /dev/null +++ b/chip/g/dcrypto/hmac_drbg.c @@ -0,0 +1,478 @@ +/* Copyright 2018 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 "console.h" +#include "cryptoc/util.h" +#include "dcrypto.h" +#include "extension.h" +#include "internal.h" +#include "trng.h" + +/* HMAC_DRBG flow in NIST SP 800-90Ar1, 10.2, RFC 6979 + */ +/* V = HMAC(K, V) */ +static void update_v(const uint32_t *k, uint32_t *v) +{ + LITE_HMAC_CTX ctx; + + DCRYPTO_HMAC_SHA256_init(&ctx, k, SHA256_DIGEST_SIZE); + HASH_update(&ctx.hash, v, SHA256_DIGEST_SIZE); + memcpy(v, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE); +} + +/* K = HMAC(K, V || tag || p0 || p1 || p2) */ +/* V = HMAC(K, V) */ +static void update_kv(uint32_t *k, uint32_t *v, uint8_t tag, + const void *p0, size_t p0_len, + const void *p1, size_t p1_len, + const void *p2, size_t p2_len) +{ + LITE_HMAC_CTX ctx; + + DCRYPTO_HMAC_SHA256_init(&ctx, k, SHA256_DIGEST_SIZE); + HASH_update(&ctx.hash, v, SHA256_DIGEST_SIZE); + HASH_update(&ctx.hash, &tag, 1); + HASH_update(&ctx.hash, p0, p0_len); + HASH_update(&ctx.hash, p1, p1_len); + HASH_update(&ctx.hash, p2, p2_len); + memcpy(k, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE); + + update_v(k, v); +} + +static void update(struct drbg_ctx *ctx, + const void *p0, size_t p0_len, + const void *p1, size_t p1_len, + const void *p2, size_t p2_len) +{ + /* K = HMAC(K, V || 0x00 || provided_data) */ + /* V = HMAC(K, V) */ + update_kv(ctx->k, ctx->v, 0x00, + p0, p0_len, p1, p1_len, p2, p2_len); + + /* If no provided_data, stop. */ + if (p0_len + p1_len + p2_len == 0) + return; + + /* K = HMAC(K, V || 0x01 || provided_data) */ + /* V = HMAC(K, V) */ + update_kv(ctx->k, ctx->v, + 0x01, + p0, p0_len, p1, p1_len, p2, p2_len); +} + +void hmac_drbg_init(struct drbg_ctx *ctx, + const void *p0, size_t p0_len, + const void *p1, size_t p1_len, + const void *p2, size_t p2_len) +{ + /* K = 0x00 0x00 0x00 ... 0x00 */ + always_memset(ctx->k, 0x00, sizeof(ctx->k)); + /* V = 0x01 0x01 0x01 ... 0x01 */ + always_memset(ctx->v, 0x01, sizeof(ctx->v)); + + update(ctx, p0, p0_len, p1, p1_len, p2, p2_len); + + ctx->reseed_counter = 1; +} + +void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx, const p256_int *key, + const p256_int *message) +{ + hmac_drbg_init(ctx, + key->a, sizeof(key->a), + message->a, sizeof(message->a), + NULL, 0); +} + +void hmac_drbg_init_rand(struct drbg_ctx *ctx, size_t nbits) +{ + int i; + uint32_t x[(nbits + 31) / 32]; + + for (i = 0; i < ARRAY_SIZE(x); ++i) + x[i] = rand(); + + hmac_drbg_init(ctx, &x, sizeof(x), NULL, 0, NULL, 0); +} + +void hmac_drbg_reseed(struct drbg_ctx *ctx, + const void *p0, size_t p0_len, + const void *p1, size_t p1_len, + const void *p2, size_t p2_len) +{ + update(ctx, p0, p0_len, p1, p1_len, p2, p2_len); + ctx->reseed_counter = 1; +} + +enum hmac_result hmac_drbg_generate(struct drbg_ctx *ctx, + void *out, size_t out_len, + const void *input, size_t input_len) +{ + /* According to NIST SP 800-90A rev 1 B.2 + * Maximum number of bits per request = 7500 bits + * Reseed_interval = 10 000 requests. + */ + if (out_len > 7500 / 8) + return HMAC_DRBG_INVALID_PARAM; + + if (ctx->reseed_counter++ >= 10000) + return HMAC_DRBG_RESEED_REQUIRED; + + if (input_len) + update(ctx, input, input_len, NULL, 0, NULL, 0); + + while (out_len) { + size_t n = out_len > sizeof(ctx->v) ? sizeof(ctx->v) : out_len; + + update_v(ctx->k, ctx->v); + + memcpy(out, ctx->v, n); + out += n; + out_len -= n; + } + + update(ctx, input, input_len, NULL, 0, NULL, 0); + + return HMAC_DRBG_SUCCESS; +} + +enum hmac_result hmac_drbg_generate_p256(struct drbg_ctx *ctx, p256_int *k_out) +{ + return hmac_drbg_generate(ctx, k_out->a, sizeof(k_out->a), NULL, 0); +} + +void drbg_exit(struct drbg_ctx *ctx) +{ + always_memset(ctx->k, 0x00, sizeof(ctx->k)); + always_memset(ctx->v, 0x00, sizeof(ctx->v)); +} + +#ifdef CRYPTO_TEST_SETUP + +/* + * from the RFC 6979 A.2.5 example: + * + * curve: NIST P-256 + * + * q = FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 + * (qlen = 256 bits) + * + * private key: + * x = C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721 + * + * public key: U = xG + * Ux = 60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6 + * Uy = 7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299 + * + * Signature: + * With SHA-256, message = "sample": + * k = A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60 + * r = EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716 + * s = F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8 + */ +static int cmd_rfc6979(int argc, char **argv) +{ + static p256_int h1; + static p256_int k; + static const char message[] = "sample"; + static struct drbg_ctx drbg; + + static HASH_CTX ctx; + int result; + static const uint8_t priv_from_rfc[] = { + 0xC9, 0xAF, 0xA9, 0xD8, 0x45, 0xBA, 0x75, 0x16, + 0x6B, 0x5C, 0x21, 0x57, 0x67, 0xB1, 0xD6, 0x93, + 0x4E, 0x50, 0xC3, 0xDB, 0x36, 0xE8, 0x9B, 0x12, + 0x7B, 0x8A, 0x62, 0x2B, 0x12, 0x0F, 0x67, 0x21 + }; + static const uint8_t k_from_rfc[] = { + 0xA6, 0xE3, 0xC5, 0x7D, 0xD0, 0x1A, 0xBE, 0x90, + 0x08, 0x65, 0x38, 0x39, 0x83, 0x55, 0xDD, 0x4C, + 0x3B, 0x17, 0xAA, 0x87, 0x33, 0x82, 0xB0, 0xF2, + 0x4D, 0x61, 0x29, 0x49, 0x3D, 0x8A, 0xAD, 0x60 + }; + p256_int *x = (p256_int *)priv_from_rfc; + p256_int *reference_k = (p256_int *)k_from_rfc; + + /* h1 = H(m) */ + DCRYPTO_SHA256_init(&ctx, 1); + HASH_update(&ctx, message, sizeof(message) - 1); + memcpy(&h1, HASH_final(&ctx), SHA256_DIGEST_SIZE); + + hmac_drbg_init_rfc6979(&drbg, x, &h1); + do { + hmac_drbg_generate_p256(&drbg, &k); + ccprintf("K = %ph\n", HEX_BUF(&k, 32)); + } while (p256_cmp(&SECP256r1_nMin2, &k) < 0); + drbg_exit(&drbg); + result = p256_cmp(&k, reference_k); + ccprintf("K generation: %s\n", result ? "FAIL" : "PASS"); + + return result ? EC_ERROR_INVAL : EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(rfc6979, cmd_rfc6979, NULL, NULL); + +/* + * Test vectors from the NIST Cryptographic Algorithm Validation Program. + * + * These are the first two examples from the SHA-256, without prediction + * resistance, and with reseed supported. + */ +#define HMAC_TEST_COUNT 2 +static int cmd_hmac_drbg(int argc, char **argv) +{ + static struct drbg_ctx ctx; + + static const uint8_t init_entropy[HMAC_TEST_COUNT][32] = { + { + 0x06, 0x03, 0x2C, 0xD5, 0xEE, 0xD3, 0x3F, 0x39, 0x26, + 0x5F, 0x49, 0xEC, 0xB1, 0x42, 0xC5, 0x11, 0xDA, 0x9A, + 0xFF, 0x2A, 0xF7, 0x12, 0x03, 0xBF, 0xFA, 0xF3, 0x4A, + 0x9C, 0xA5, 0xBD, 0x9C, 0x0D + }, + { + 0xAA, 0xDC, 0xF3, 0x37, 0x78, 0x8B, 0xB8, 0xAC, 0x01, + 0x97, 0x66, 0x40, 0x72, 0x6B, 0xC5, 0x16, 0x35, 0xD4, + 0x17, 0x77, 0x7F, 0xE6, 0x93, 0x9E, 0xDE, 0xD9, 0xCC, + 0xC8, 0xA3, 0x78, 0xC7, 0x6A + }, + }; + + static const uint8_t init_nonce[HMAC_TEST_COUNT][16] = { + { + 0x0E, 0x66, 0xF7, 0x1E, 0xDC, 0x43, 0xE4, 0x2A, 0x45, + 0xAD, 0x3C, 0x6F, 0xC6, 0xCD, 0xC4, 0xDF + }, + { + 0x9C, 0xCC, 0x9D, 0x80, 0xC8, 0x9A, 0xC5, 0x5A, 0x8C, + 0xFE, 0x0F, 0x99, 0x94, 0x2F, 0x5A, 0x4D + }, + }; + + static const uint8_t reseed_entropy[HMAC_TEST_COUNT][32] = { + { + 0x01, 0x92, 0x0A, 0x4E, 0x66, 0x9E, 0xD3, 0xA8, 0x5A, + 0xE8, 0xA3, 0x3B, 0x35, 0xA7, 0x4A, 0xD7, 0xFB, 0x2A, + 0x6B, 0xB4, 0xCF, 0x39, 0x5C, 0xE0, 0x03, 0x34, 0xA9, + 0xC9, 0xA5, 0xA5, 0xD5, 0x52 + }, + { + 0x03, 0xA5, 0x77, 0x92, 0x54, 0x7E, 0x0C, 0x98, 0xEA, + 0x17, 0x76, 0xE4, 0xBA, 0x80, 0xC0, 0x07, 0x34, 0x62, + 0x96, 0xA5, 0x6A, 0x27, 0x0A, 0x35, 0xFD, 0x9E, 0xA2, + 0x84, 0x5C, 0x7E, 0x81, 0xE2 + } + }; + + static const uint8_t expected_output[HMAC_TEST_COUNT][128] = { + { + 0x76, 0xFC, 0x79, 0xFE, 0x9B, 0x50, 0xBE, 0xCC, 0xC9, + 0x91, 0xA1, 0x1B, 0x56, 0x35, 0x78, 0x3A, 0x83, 0x53, + 0x6A, 0xDD, 0x03, 0xC1, 0x57, 0xFB, 0x30, 0x64, 0x5E, + 0x61, 0x1C, 0x28, 0x98, 0xBB, 0x2B, 0x1B, 0xC2, 0x15, + 0x00, 0x02, 0x09, 0x20, 0x8C, 0xD5, 0x06, 0xCB, 0x28, + 0xDA, 0x2A, 0x51, 0xBD, 0xB0, 0x38, 0x26, 0xAA, 0xF2, + 0xBD, 0x23, 0x35, 0xD5, 0x76, 0xD5, 0x19, 0x16, 0x08, + 0x42, 0xE7, 0x15, 0x8A, 0xD0, 0x94, 0x9D, 0x1A, 0x9E, + 0xC3, 0xE6, 0x6E, 0xA1, 0xB1, 0xA0, 0x64, 0xB0, 0x05, + 0xDE, 0x91, 0x4E, 0xAC, 0x2E, 0x9D, 0x4F, 0x2D, 0x72, + 0xA8, 0x61, 0x6A, 0x80, 0x22, 0x54, 0x22, 0x91, 0x82, + 0x50, 0xFF, 0x66, 0xA4, 0x1B, 0xD2, 0xF8, 0x64, 0xA6, + 0xA3, 0x8C, 0xC5, 0xB6, 0x49, 0x9D, 0xC4, 0x3F, 0x7F, + 0x2B, 0xD0, 0x9E, 0x1E, 0x0F, 0x8F, 0x58, 0x85, 0x93, + 0x51, 0x24 + }, + { + 0x17, 0xD0, 0x9F, 0x40, 0xA4, 0x37, 0x71, 0xF4, 0xA2, + 0xF0, 0xDB, 0x32, 0x7D, 0xF6, 0x37, 0xDE, 0xA9, 0x72, + 0xBF, 0xFF, 0x30, 0xC9, 0x8E, 0xBC, 0x88, 0x42, 0xDC, + 0x7A, 0x9E, 0x3D, 0x68, 0x1C, 0x61, 0x90, 0x2F, 0x71, + 0xBF, 0xFA, 0xF5, 0x09, 0x36, 0x07, 0xFB, 0xFB, 0xA9, + 0x67, 0x4A, 0x70, 0xD0, 0x48, 0xE5, 0x62, 0xEE, 0x88, + 0xF0, 0x27, 0xF6, 0x30, 0xA7, 0x85, 0x22, 0xEC, 0x6F, + 0x70, 0x6B, 0xB4, 0x4A, 0xE1, 0x30, 0xE0, 0x5C, 0x8D, + 0x7E, 0xAC, 0x66, 0x8B, 0xF6, 0x98, 0x0D, 0x99, 0xB4, + 0xC0, 0x24, 0x29, 0x46, 0x45, 0x23, 0x99, 0xCB, 0x03, + 0x2C, 0xC6, 0xF9, 0xFD, 0x96, 0x28, 0x47, 0x09, 0xBD, + 0x2F, 0xA5, 0x65, 0xB9, 0xEB, 0x9F, 0x20, 0x04, 0xBE, + 0x6C, 0x9E, 0xA9, 0xFF, 0x91, 0x28, 0xC3, 0xF9, 0x3B, + 0x60, 0xDC, 0x30, 0xC5, 0xFC, 0x85, 0x87, 0xA1, 0x0D, + 0xE6, 0x8C + } + }; + + static uint8_t output[128]; + + int i, cmp_result; + + for (i = 0; i < HMAC_TEST_COUNT; i++) { + hmac_drbg_init(&ctx, + init_entropy[i], sizeof(init_entropy[i]), + init_nonce[i], sizeof(init_nonce[i]), + NULL, 0); + + hmac_drbg_reseed(&ctx, + reseed_entropy[i], sizeof(reseed_entropy[i]), + NULL, 0, + NULL, 0); + + hmac_drbg_generate(&ctx, + output, sizeof(output), + NULL, 0); + + hmac_drbg_generate(&ctx, + output, sizeof(output), + NULL, 0); + + cmp_result = memcmp(output, expected_output[i], sizeof(output)); + ccprintf("HMAC DRBG generate test %d, %s\n", + i, cmp_result ? "failed" : "passed"); + } + + return 0; +} +DECLARE_SAFE_CONSOLE_COMMAND(hmac_drbg, cmd_hmac_drbg, NULL, NULL); + +/* + * Sanity check to exercise random initialization. + */ +static int cmd_hmac_drbg_rand(int argc, char **argv) +{ + static struct drbg_ctx ctx; + static uint8_t output[128]; + + int i; + + hmac_drbg_init_rand(&ctx, 256); + + hmac_drbg_generate(&ctx, output, sizeof(output), NULL, 0); + + ccprintf("Randomly initialized HMAC DRBG, 1024 bit output: "); + + for (i = 0; i < sizeof(output); i++) + ccprintf("%x", output[i]); + ccprintf("\n"); + + return 0; +} +DECLARE_SAFE_CONSOLE_COMMAND(hmac_drbg_rand, cmd_hmac_drbg_rand, NULL, NULL); + +enum drbg_command { + DRBG_INIT = 0, + DRBG_RESEED = 1, + DRBG_GENERATE = 2 +}; + +/* + * DRBG_TEST command structure: + * + * field | size | note + * ========================================================================== + * mode | 1 | 0 - DRBG_INIT, 1 - DRBG_RESEED, 2 - DRBG_GENERATE + * p0_len | 2 | size of first input in bytes + * p0 | p0_len | entropy for INIT & SEED, input for GENERATE + * p1_len | 2 | size of second input in bytes (for INIT & RESEED) + * | | or size of expected output for GENERATE + * p1 | p1_len | nonce for INIT & SEED + * p2_len | 2 | size of third input in bytes for DRBG_INIT + * p2 | p2_len | personalization for INIT & SEED + * + * DRBG_INIT (entropy, nonce, perso) + * DRBG_RESEED (entropy, additional input 1, additional input 2) + * DRBG_INIT and DRBG_RESEED returns empty response + * DRBG_GENERATE (p0_len, p0 - additional input 1, p1_len - size of output) + * DRBG_GENERATE returns p1_len bytes of generated data + * (up to a maximum of 128 bytes) + */ +static enum vendor_cmd_rc drbg_test(enum vendor_cmd_cc code, void *buf, + size_t input_size, size_t *response_size) +{ + static struct drbg_ctx drbg_ctx; + static uint8_t output[512]; + uint8_t *p0 = NULL, *p1 = NULL, *p2 = NULL; + uint16_t p0_len = 0, p1_len = 0, p2_len = 0; + uint8_t *cmd = (uint8_t *)buf; + size_t max_out_len = *response_size; + enum drbg_command drbg_op; + + *response_size = 0; + /* there is always op + first parameter, even if zero length */ + if (input_size < sizeof(p0_len) + 1) + return VENDOR_RC_BOGUS_ARGS; + drbg_op = *cmd++; + p0_len = *cmd++; + p0_len = p0_len * 256 + *cmd++; + input_size -= 3; + if (p0_len > input_size) + return VENDOR_RC_BOGUS_ARGS; + input_size -= p0_len; + if (p0_len) + p0 = cmd; + cmd += p0_len; + + /* there should be enough space for p1_len */ + if (input_size && input_size < sizeof(p1_len)) + return VENDOR_RC_BOGUS_ARGS; + + /* DRBG_GENERATE should just have p1_len defined */ + if (drbg_op == DRBG_GENERATE && input_size != sizeof(p1_len)) + return VENDOR_RC_BOGUS_ARGS; + + if (input_size) { + p1_len = *cmd++; + p1_len = p1_len * 256 + *cmd++; + input_size -= 2; + + if (drbg_op != DRBG_GENERATE) { + if (p1_len > input_size) + return VENDOR_RC_BOGUS_ARGS; + input_size -= p1_len; + if (p1_len) + p1 = cmd; + cmd += p1_len; + } + } + + if (input_size) { + if (drbg_op == DRBG_GENERATE) + return VENDOR_RC_BOGUS_ARGS; + p2_len = *cmd++; + p2_len = p2_len * 256 + *cmd++; + input_size -= 2; + if (p2_len > input_size) + return VENDOR_RC_BOGUS_ARGS; + if (p2_len) + p2 = cmd; + } + + switch (drbg_op) { + case DRBG_INIT: { + hmac_drbg_init(&drbg_ctx, p0, p0_len, p1, p1_len, p2, p2_len); + break; + } + case DRBG_RESEED: { + hmac_drbg_reseed(&drbg_ctx, p0, p0_len, p1, p1_len, p2, p2_len); + break; + } + case DRBG_GENERATE: { + if (p1_len > sizeof(output) || max_out_len < p1_len) + return VENDOR_RC_BOGUS_ARGS; + + hmac_drbg_generate(&drbg_ctx, output, p1_len, p0, p0_len); + + memcpy(buf, output, p1_len); + *response_size = p1_len; + break; + } + default: + return VENDOR_RC_BOGUS_ARGS; + } + + return VENDOR_RC_SUCCESS; +} +DECLARE_VENDOR_COMMAND(VENDOR_CC_DRBG_TEST, drbg_test); + +#endif /* CRYPTO_TEST_SETUP */ diff --git a/chip/g/dcrypto/internal.h b/chip/g/dcrypto/internal.h new file mode 100644 index 0000000000..1811426f2a --- /dev/null +++ b/chip/g/dcrypto/internal.h @@ -0,0 +1,219 @@ +/* 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. + */ + +#ifndef __EC_CHIP_G_DCRYPTO_INTERNAL_H +#define __EC_CHIP_G_DCRYPTO_INTERNAL_H + +#include +#include + +#include "common.h" +#include "util.h" + +#include "cryptoc/p256.h" +#include "cryptoc/sha.h" +#include "cryptoc/sha256.h" +#include "cryptoc/sha384.h" +#include "cryptoc/sha512.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * SHA. + */ +#define CTRL_CTR_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#define CTRL_ENABLE 1 +#define CTRL_ENCRYPT 1 +#define CTRL_NO_SOFT_RESET 0 + +#define SHA_DIGEST_WORDS (SHA_DIGEST_SIZE / sizeof(uint32_t)) +#define SHA256_DIGEST_WORDS (SHA256_DIGEST_SIZE / sizeof(uint32_t)) + +#ifdef SHA512_SUPPORT +#define SHA_DIGEST_MAX_BYTES SHA512_DIGEST_SIZE +#else +#define SHA_DIGEST_MAX_BYTES SHA256_DIGEST_SIZE +#endif + +enum sha_mode { + SHA1_MODE = 0, + SHA256_MODE = 1 +}; + +/* + * Use this structure to avoid alignment problems with input and output + * pointers. + */ +struct access_helper { + uint32_t udata; +} __packed; + +#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 void *data, uint32_t n); +void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest); + +/* + * BIGNUM. + */ +#define LITE_BN_BITS2 32 +#define LITE_BN_BYTES 4 + +struct LITE_BIGNUM { + uint32_t dmax; /* Size of d, in 32-bit words. */ + struct access_helper *d; /* Word array, little endian format ... */ +}; + +#define BN_DIGIT(b, i) ((b)->d[(i)].udata) + +void bn_init(struct LITE_BIGNUM *bn, void *buf, size_t len); +#define bn_size(b) ((b)->dmax * LITE_BN_BYTES) +#define bn_words(b) ((b)->dmax) +#define bn_bits(b) ((b)->dmax * LITE_BN_BITS2) +int bn_eq(const struct LITE_BIGNUM *a, const struct LITE_BIGNUM *b); +int bn_check_topbit(const struct LITE_BIGNUM *N); +int bn_modexp(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, + const struct LITE_BIGNUM *N); +int bn_modexp_word(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + uint32_t pubexp, + const struct LITE_BIGNUM *N); +int bn_modexp_blinded(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, + const struct LITE_BIGNUM *N, + uint32_t pubexp); +uint32_t bn_add(struct LITE_BIGNUM *c, + const struct LITE_BIGNUM *a); +uint32_t bn_sub(struct LITE_BIGNUM *c, + const struct LITE_BIGNUM *a); +int bn_modinv_vartime(struct LITE_BIGNUM *r, + const struct LITE_BIGNUM *e, + const struct LITE_BIGNUM *MOD); +int bn_is_bit_set(const struct LITE_BIGNUM *a, int n); + +/* + * Accelerated bn. + */ +int dcrypto_modexp(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, + const struct LITE_BIGNUM *N); +int dcrypto_modexp_word(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + uint32_t pubexp, + const struct LITE_BIGNUM *N); +int dcrypto_modexp_blinded(struct LITE_BIGNUM *output, + const struct LITE_BIGNUM *input, + const struct LITE_BIGNUM *exp, + const struct LITE_BIGNUM *N, + uint32_t pubexp); + +struct drbg_ctx { + uint32_t k[SHA256_DIGEST_WORDS]; + uint32_t v[SHA256_DIGEST_WORDS]; + uint32_t reseed_counter; +}; + +/* + * NIST SP 800-90A HMAC DRBG. + */ +enum hmac_result { + HMAC_DRBG_SUCCESS = 0, + HMAC_DRBG_INVALID_PARAM = 1, + HMAC_DRBG_RESEED_REQUIRED = 2 +}; + +/* Standard initialization. */ +void hmac_drbg_init(struct drbg_ctx *ctx, + const void *p0, size_t p0_len, + const void *p1, size_t p1_len, + const void *p2, size_t p2_len); +/* Initialize for use as RFC6979 DRBG. */ +void hmac_drbg_init_rfc6979(struct drbg_ctx *ctx, + const p256_int *key, + const p256_int *message); +/* Initialize with at least nbits of random entropy. */ +void hmac_drbg_init_rand(struct drbg_ctx *ctx, size_t nbits); +void hmac_drbg_reseed(struct drbg_ctx *ctx, + const void *p0, size_t p0_len, + const void *p1, size_t p1_len, + const void *p2, size_t p2_len); +enum hmac_result hmac_drbg_generate(struct drbg_ctx *ctx, void *out, + size_t out_len, const void *input, + size_t input_len); +/* Generate p256, with no additional input. */ +enum hmac_result hmac_drbg_generate_p256(struct drbg_ctx *ctx, p256_int *k_out); +void drbg_exit(struct drbg_ctx *ctx); + +/* + * Accelerated p256. FIPS PUB 186-4 + */ +int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key, + const p256_int *message, p256_int *r, p256_int *s) + __attribute__((warn_unused_result)); +int dcrypto_p256_base_point_mul(const p256_int *k, p256_int *x, p256_int *y) + __attribute__((warn_unused_result)); +int dcrypto_p256_point_mul(const p256_int *k, + const p256_int *in_x, const p256_int *in_y, + p256_int *x, p256_int *y) + __attribute__((warn_unused_result)); +int dcrypto_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y, + const p256_int *message, const p256_int *r, + const p256_int *s) + __attribute__((warn_unused_result)); +int dcrypto_p256_is_valid_point(const p256_int *x, const p256_int *y) + __attribute__((warn_unused_result)); + +/* Pick a p256 number between 1 < k < |p256| */ +int dcrypto_p256_pick(struct drbg_ctx *drbg, p256_int *output); + +/* Overwrite with random p256 value */ +void dcrypto_p256_rnd(p256_int *output); + +/* + * Accelerator runtime. + * + * Note dcrypto_init_and_lock grabs a mutex and dcrypto_unlock releases it. + * Do not use dcrypto_call, dcrypto_imem_load or dcrypto_dmem_load w/o holding + * the mutex. + */ +void dcrypto_init_and_lock(void); +void dcrypto_unlock(void); +uint32_t dcrypto_call(uint32_t adr) __attribute__((warn_unused_result)); +void dcrypto_imem_load(size_t offset, const uint32_t *opcodes, + size_t n_opcodes); +/* + * Returns 0 iff no difference was observed between existing and new content. + */ +uint32_t dcrypto_dmem_load(size_t offset, const void *words, size_t n_words); + +/* + * Key ladder. + */ +#ifndef __cplusplus +enum dcrypto_appid; /* Forward declaration. */ + +int dcrypto_ladder_compute_usr(enum dcrypto_appid id, + const uint32_t usr_salt[8]); +int dcrypto_ladder_derive(enum dcrypto_appid appid, const uint32_t salt[8], + const uint32_t input[8], uint32_t output[8]); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ! __EC_CHIP_G_DCRYPTO_INTERNAL_H */ diff --git a/chip/g/dcrypto/key_ladder.c b/chip/g/dcrypto/key_ladder.c new file mode 100644 index 0000000000..77055e4159 --- /dev/null +++ b/chip/g/dcrypto/key_ladder.c @@ -0,0 +1,300 @@ +/* Copyright 2017 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 "endian.h" +#include "registers.h" +#include "trng.h" + +static void ladder_init(void) +{ + /* Do not reset keyladder engine here, as before. + * + * Should not be needed and if it is, it is indicative + * of sync error between this and sha engine usage. + * Reset will make this flow work, but will have broken + * the other pending sha flow. + * Hence leave as is and observe the error. + */ + + /* Enable random stalls for key-ladder usage. Note that + * the stall rate used for key-ladder operations is + * 25% (vs. 12% for generic SHA operations). This distinction + * is made so as to increase the difficulty in characterizng + * the key-ladder engine via random inputs provided over the + * generic SHA interface. + */ + /* Turn off random nops (which are enabled by default). */ + GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 0); + /* Configure random nop percentage at 25%. */ + GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, FREQ, 1); + /* Now turn on random nops. */ + GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 1); +} + +static int ladder_step(uint32_t cert, const uint32_t input[8]) +{ + GREG32(KEYMGR, SHA_ITOP) = 0; /* clear status */ + + GREG32(KEYMGR, SHA_USE_CERT_INDEX) = + (cert << GC_KEYMGR_SHA_USE_CERT_INDEX_LSB) | + GC_KEYMGR_SHA_USE_CERT_ENABLE_MASK; + + GREG32(KEYMGR, SHA_CFG_EN) = + GC_KEYMGR_SHA_CFG_EN_INT_EN_DONE_MASK; + GREG32(KEYMGR, SHA_TRIG) = + GC_KEYMGR_SHA_TRIG_TRIG_GO_MASK; + + if (input) { + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[0]; + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[1]; + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[2]; + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[3]; + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[4]; + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[5]; + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[6]; + GREG32(KEYMGR, SHA_INPUT_FIFO) = input[7]; + + GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_STOP_MASK; + } + + while (!GREG32(KEYMGR, SHA_ITOP)) + ; + + GREG32(KEYMGR, SHA_ITOP) = 0; /* clear status */ + + return !!GREG32(KEYMGR, HKEY_ERR_FLAGS); +} + +static int compute_certs(const uint32_t *certs, size_t num_certs) +{ + int i; + + for (i = 0; i < num_certs; i++) { + if (ladder_step(certs[i], NULL)) + return 0; + } + + return 1; +} + +#define KEYMGR_CERT_0 0 +#define KEYMGR_CERT_3 3 +#define KEYMGR_CERT_4 4 +#define KEYMGR_CERT_5 5 +#define KEYMGR_CERT_7 7 +#define KEYMGR_CERT_15 15 +#define KEYMGR_CERT_20 20 +#define KEYMGR_CERT_25 25 +#define KEYMGR_CERT_26 26 +#define KEYMGR_CERT_27 27 +#define KEYMGR_CERT_28 28 +#define KEYMGR_CERT_34 34 +#define KEYMGR_CERT_35 35 +#define KEYMGR_CERT_38 38 + +static const uint32_t FRK2_CERTS_PREFIX[] = { + KEYMGR_CERT_0, + KEYMGR_CERT_3, + KEYMGR_CERT_4, + KEYMGR_CERT_5, + KEYMGR_CERT_7, + KEYMGR_CERT_15, + KEYMGR_CERT_20, +}; + +static const uint32_t FRK2_CERTS_POSTFIX[] = { + KEYMGR_CERT_26, +}; + +#define MAX_MAJOR_FW_VERSION 254 + +int DCRYPTO_ladder_compute_frk2(size_t fw_version, uint8_t *frk2) +{ + int result = 0; + + if (fw_version > MAX_MAJOR_FW_VERSION) + return 0; + + if (!dcrypto_grab_sha_hw()) + return 0; + + do { + int i; + + ladder_init(); + + if (!compute_certs(FRK2_CERTS_PREFIX, + ARRAY_SIZE(FRK2_CERTS_PREFIX))) + break; + + for (i = 0; i < MAX_MAJOR_FW_VERSION - fw_version; i++) { + if (ladder_step(KEYMGR_CERT_25, NULL)) + break; + } + + if (!compute_certs(FRK2_CERTS_POSTFIX, + ARRAY_SIZE(FRK2_CERTS_POSTFIX))) + break; + + memcpy(frk2, (void *) GREG32_ADDR(KEYMGR, HKEY_FRR0), + AES256_BLOCK_CIPHER_KEY_SIZE); + + result = 1; + } while (0); + + dcrypto_release_sha_hw(); + return result; +} + +/* ISR salt (SHA256("ISR_SALT")) to use for USR generation. */ +static const uint32_t ISR_SALT[8] = { + 0x6ba1b495, 0x4b7ca214, 0xfe07e922, 0x09735185, + 0xfcca43ca, 0xc6d4dfd9, 0x5fc2fcca, 0xaa45400b +}; + +/* Map of populated USR registers. */ +static int usr_ready[8] = {}; + +int dcrypto_ladder_compute_usr(enum dcrypto_appid id, + const uint32_t usr_salt[8]) +{ + int result = 0; + + /* Check for USR readiness. */ + if (usr_ready[id]) + return 1; + + if (!dcrypto_grab_sha_hw()) + return 0; + + do { + int i; + + /* The previous check performed without lock acquisition. */ + if (usr_ready[id]) { + result = 1; + break; + } + + ladder_init(); + + if (!compute_certs(FRK2_CERTS_PREFIX, + ARRAY_SIZE(FRK2_CERTS_PREFIX))) + break; + + /* USR generation requires running the key-ladder till + * the end (version 0), plus one additional iteration. + */ + for (i = 0; i < MAX_MAJOR_FW_VERSION - 0 + 1; i++) { + if (ladder_step(KEYMGR_CERT_25, NULL)) + break; + } + if (i != MAX_MAJOR_FW_VERSION - 0 + 1) + break; + + if (ladder_step(KEYMGR_CERT_34, ISR_SALT)) + break; + + /* Output goes to USR[appid] (the multiply by 2 is an + * artifact of slot addressing). + */ + GWRITE_FIELD(KEYMGR, SHA_CERT_OVERRIDE, DIGEST_PTR, 2 * id); + if (ladder_step(KEYMGR_CERT_35, usr_salt)) + break; + + /* Check for key-ladder errors. */ + if (GREG32(KEYMGR, HKEY_ERR_FLAGS)) + break; + + /* Key deposited in USR[id], and ready to use. */ + usr_ready[id] = 1; + + result = 1; + } while (0); + + dcrypto_release_sha_hw(); + return result; +} + +static void ladder_out(uint32_t output[8]) +{ + output[0] = GREG32(KEYMGR, SHA_STS_H0); + output[1] = GREG32(KEYMGR, SHA_STS_H1); + output[2] = GREG32(KEYMGR, SHA_STS_H2); + output[3] = GREG32(KEYMGR, SHA_STS_H3); + output[4] = GREG32(KEYMGR, SHA_STS_H4); + output[5] = GREG32(KEYMGR, SHA_STS_H5); + output[6] = GREG32(KEYMGR, SHA_STS_H6); + output[7] = GREG32(KEYMGR, SHA_STS_H7); +} + +/* + * Stir TRNG entropy into RSR and pull some out. + */ +int DCRYPTO_ladder_random(void *output) +{ + int error = 1; + uint32_t tmp[8]; + + if (!dcrypto_grab_sha_hw()) + goto fail; + + rand_bytes(tmp, sizeof(tmp)); + /* Mix TRNG bytes with RSR entropy */ + error = ladder_step(KEYMGR_CERT_27, tmp); + if (!error) + ladder_out(output); + +fail: + dcrypto_release_sha_hw(); + return !error; +} + +int dcrypto_ladder_derive(enum dcrypto_appid appid, const uint32_t salt[8], + const uint32_t input[8], uint32_t output[8]) +{ + int error; + + if (!dcrypto_grab_sha_hw()) + return 0; + + GWRITE_FIELD(KEYMGR, SHA_CERT_OVERRIDE, KEY_PTR, 2 * appid); + error = ladder_step(KEYMGR_CERT_38, input); /* HMAC */ + if (!error) + ladder_out(output); + + dcrypto_release_sha_hw(); + return !error; +} + +void DCRYPTO_ladder_revoke(void) +{ + /* Revoke certificates */ + GWRITE(KEYMGR, CERT_REVOKE_CTRL0, 0xffffffff); + GWRITE(KEYMGR, CERT_REVOKE_CTRL1, 0xffffffff); + + /* Wipe out the hidden keys cached in AES and SHA engines. */ + GWRITE_FIELD(KEYMGR, AES_USE_HIDDEN_KEY, ENABLE, 0); + GWRITE_FIELD(KEYMGR, SHA_USE_HIDDEN_KEY, ENABLE, 0); + + /* Clear usr_ready[] */ + memset(usr_ready, 0, sizeof(usr_ready)); +} + +#define KEYMGR_CERT_REVOKE_CTRL0_DEFAULT_VAL 0xa8028a82 +#define KEYMGR_CERT_REVOKE_CTRL1_DEFAULT_VAL 0xaaaaaaaa + +int DCRYPTO_ladder_is_enabled(void) +{ + uint32_t ctrl0; + uint32_t ctrl1; + + ctrl0 = GREAD(KEYMGR, CERT_REVOKE_CTRL0); + ctrl1 = GREAD(KEYMGR, CERT_REVOKE_CTRL1); + + return ctrl0 == KEYMGR_CERT_REVOKE_CTRL0_DEFAULT_VAL && + ctrl1 == KEYMGR_CERT_REVOKE_CTRL1_DEFAULT_VAL; +} diff --git a/chip/g/dcrypto/p256.c b/chip/g/dcrypto/p256.c new file mode 100644 index 0000000000..665144e31b --- /dev/null +++ b/chip/g/dcrypto/p256.c @@ -0,0 +1,30 @@ +/* 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 "cryptoc/p256.h" +#include "cryptoc/util.h" + +static const p256_int p256_one = P256_ONE; + +/* + * Key selection based on FIPS-186-4, section B.4.2 (Key Pair + * Generation by Testing Candidates). + */ +int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d, + const uint8_t key_bytes[P256_NBYTES]) +{ + p256_int key; + + p256_from_bin(key_bytes, &key); + if (p256_cmp(&SECP256r1_nMin2, &key) < 0) + return 0; + p256_add(&key, &p256_one, d); + always_memset(&key, 0, sizeof(key)); + if (x == NULL || y == NULL) + return 1; + return dcrypto_p256_base_point_mul(d, x, y); +} diff --git a/chip/g/dcrypto/p256_ec.c b/chip/g/dcrypto/p256_ec.c new file mode 100644 index 0000000000..cb33a15774 --- /dev/null +++ b/chip/g/dcrypto/p256_ec.c @@ -0,0 +1,39 @@ +/* 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 + +#include "cryptoc/p256.h" + +/* p256_base_point_mul sets {out_x,out_y} = nG, where n is < the + * order of the group. */ +int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y, + const p256_int *n) +{ + if (p256_is_zero(n) != 0) { + p256_clear(out_x); + p256_clear(out_y); + return 0; + } + + return dcrypto_p256_base_point_mul(n, out_x, out_y); +} + +/* DCRYPTO_p256_point_mul sets {out_x,out_y} = n*{in_x,in_y}, where n is < + * the order of the group. */ +int DCRYPTO_p256_point_mul(p256_int *out_x, p256_int *out_y, + const p256_int *n, const p256_int *in_x, + const p256_int *in_y) +{ + if (p256_is_zero(n) != 0) { + p256_clear(out_x); + p256_clear(out_y); + return 0; + } + + return dcrypto_p256_point_mul(n, in_x, in_y, out_x, out_y); +} diff --git a/chip/g/dcrypto/p256_ecies.c b/chip/g/dcrypto/p256_ecies.c new file mode 100644 index 0000000000..30a410d828 --- /dev/null +++ b/chip/g/dcrypto/p256_ecies.c @@ -0,0 +1,175 @@ +/* Copyright 2016 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 "internal.h" +#include "dcrypto.h" + +#include "trng.h" +#include "util.h" + +#include "cryptoc/p256.h" +#include "cryptoc/sha256.h" + +#define AES_KEY_BYTES 16 +#define HMAC_KEY_BYTES 32 + +#define AES_BLOCK_BYTES 16 + +/* P256 based hybrid encryption. The output format is: + * + * 0x04 || PUBKEY || AUTH_DATA || AES128_CTR(PLAINTEXT) || + * HMAC_SHA256(AUTH_DATA || CIPHERTEXT) + */ +size_t DCRYPTO_ecies_encrypt( + void *out, size_t out_len, const void *in, size_t in_len, + size_t auth_data_len, const uint8_t *iv, + const p256_int *pub_x, const p256_int *pub_y, + const uint8_t *salt, size_t salt_len, + const uint8_t *info, size_t info_len) +{ + p256_int eph_d; + p256_int eph_x; + p256_int eph_y; + uint8_t seed[P256_NBYTES]; + p256_int secret_x; + p256_int secret_y; + /* Key bytes to be extracted from HKDF. */ + uint8_t key[AES_KEY_BYTES + HMAC_KEY_BYTES]; + const uint8_t *aes_key; + const uint8_t *hmac_key; + LITE_HMAC_CTX ctx; + uint8_t *outp = out; + uint8_t *ciphertext; + + if (auth_data_len > in_len) + return 0; + if (out_len < 1 + P256_NBYTES + P256_NBYTES + + in_len + SHA256_DIGEST_SIZE) + return 0; + + /* Generate emphemeral EC key. */ + rand_bytes(seed, sizeof(seed)); + if (!DCRYPTO_p256_key_from_bytes(&eph_x, &eph_y, &eph_d, seed)) + return 0; + /* Compute DH point. */ + if (!DCRYPTO_p256_point_mul(&secret_x, &secret_y, + &eph_d, pub_x, pub_y)) + return 0; + /* Check for computational errors. */ + if (!dcrypto_p256_is_valid_point(&secret_x, &secret_y)) + return 0; + /* Convert secret to big-endian. */ + reverse(&secret_x, sizeof(secret_x)); + /* Derive shared secret. */ + if (!DCRYPTO_hkdf(key, sizeof(key), salt, salt_len, + (uint8_t *) &secret_x, sizeof(secret_x), + info, info_len)) + return 0; + + aes_key = &key[0]; + hmac_key = &key[AES_KEY_BYTES]; + + if (out == in) + ciphertext = out + auth_data_len; /* In place encrypt. */ + else + ciphertext = out + 1 + P256_NBYTES + P256_NBYTES + + auth_data_len; + + /* Compute ciphertext. */ + if (!DCRYPTO_aes_ctr(ciphertext, aes_key, AES_KEY_BYTES * 8, iv, + in + auth_data_len, in_len - auth_data_len)) + return 0; + + /* Write out auth_data / ciphertext. */ + outp = out + 1 + P256_NBYTES + P256_NBYTES; + if (out == in) + memmove(outp, in, in_len); + else + memcpy(outp, in, auth_data_len); + + /* Write out ephemeral pub key. */ + outp = out; + *outp++ = 0x04; /* uncompressed EC public key. */ + p256_to_bin(&eph_x, outp); + outp += P256_NBYTES; + p256_to_bin(&eph_y, outp); + outp += P256_NBYTES; + + /* Calculate HMAC(auth_data || ciphertext). */ + DCRYPTO_HMAC_SHA256_init(&ctx, hmac_key, HMAC_KEY_BYTES); + HASH_update(&ctx.hash, outp, in_len); + outp += in_len; + memcpy(outp, DCRYPTO_HMAC_final(&ctx), SHA256_DIGEST_SIZE); + outp += SHA256_DIGEST_SIZE; + + return outp - (uint8_t *) out; +} + +size_t DCRYPTO_ecies_decrypt( + void *out, size_t out_len, const void *in, size_t in_len, + size_t auth_data_len, const uint8_t *iv, + const p256_int *d, + const uint8_t *salt, size_t salt_len, + const uint8_t *info, size_t info_len) +{ + p256_int eph_x; + p256_int eph_y; + p256_int secret_x; + p256_int secret_y; + uint8_t key[AES_KEY_BYTES + HMAC_KEY_BYTES]; + const uint8_t *aes_key; + const uint8_t *hmac_key; + LITE_HMAC_CTX ctx; + const uint8_t *inp = in; + uint8_t *outp = out; + + if (in_len < 1 + P256_NBYTES + P256_NBYTES + auth_data_len + + SHA256_DIGEST_SIZE) + return 0; + if (inp[0] != 0x04) + return 0; + + in_len -= 1 + P256_NBYTES + P256_NBYTES + SHA256_DIGEST_SIZE; + + inp++; + p256_from_bin(inp, &eph_x); + inp += P256_NBYTES; + p256_from_bin(inp, &eph_y); + inp += P256_NBYTES; + + /* Verify that the public point is on the curve. */ + if (!dcrypto_p256_is_valid_point(&eph_x, &eph_y)) + return 0; + /* Compute the DH point. */ + if (!DCRYPTO_p256_point_mul(&secret_x, &secret_y, + d, &eph_x, &eph_y)) + return 0; + /* Check for computational errors. */ + if (!dcrypto_p256_is_valid_point(&secret_x, &secret_y)) + return 0; + /* Convert secret to big-endian. */ + reverse(&secret_x, sizeof(secret_x)); + /* Derive shared secret. */ + if (!DCRYPTO_hkdf(key, sizeof(key), salt, salt_len, + (uint8_t *) &secret_x, sizeof(secret_x), + info, info_len)) + return 0; + + aes_key = &key[0]; + hmac_key = &key[AES_KEY_BYTES]; + DCRYPTO_HMAC_SHA256_init(&ctx, hmac_key, HMAC_KEY_BYTES); + HASH_update(&ctx.hash, inp, in_len); + if (!DCRYPTO_equals(inp + in_len, DCRYPTO_HMAC_final(&ctx), + SHA256_DIGEST_SIZE)) + return 0; + + memmove(outp, inp, auth_data_len); + inp += auth_data_len; + outp += auth_data_len; + if (!DCRYPTO_aes_ctr(outp, aes_key, AES_KEY_BYTES * 8, iv, + inp, in_len - auth_data_len)) + return 0; + return in_len; +} diff --git a/chip/g/dcrypto/proofs_p256.md b/chip/g/dcrypto/proofs_p256.md new file mode 100644 index 0000000000..c0fa7ef6ad --- /dev/null +++ b/chip/g/dcrypto/proofs_p256.md @@ -0,0 +1,28 @@ +Proving P256 dcrypto code +========================= + +In 2018, partial proofs of modular reduction were written in the Coq proof +assistant. +They can be used against the crypto accelerator code in [chip/g/dcrypto/dcrypto_p256.c](dcrypto_p256.c). + +The Coq code is in this file: +[github.com/mit-plv/fiat-crypto/.../Experiments/SimplyTypedArithmetic.v](https://github.com/mit-plv/fiat-crypto/blob/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Experiments/SimplyTypedArithmetic.v) + +Specific lines of interest: + +Instruction specifications: +[fiat-crypto/.../Experiments/SimplyTypedArithmetic.v#L10014](https://github.com/mit-plv/fiat-crypto/blob/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Experiments/SimplyTypedArithmetic.v#L10014) + +Printouts of verified code versions with explanatory comments are at the very +end of the same file (which GitHub cuts off, so here is the link to the raw +version): +https://raw.githubusercontent.com/mit-plv/fiat-crypto/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Experiments/SimplyTypedArithmetic.v + +Additionally, the MulMod procedure in p256 uses a non-standard Barrett +reduction optimization. In particular, it assumes that the quotient estimate is +off by no more than 1, while most resources say it can be off by 2. This +assumption was proven correct for most primes (including p256) here: + +[fiat-crypto/.../Arithmetic/BarrettReduction/Generalized.v#L140](https://github.com/mit-plv/fiat-crypto/blob/e469076c37fc8b1b6d66eb700e379b9b2a093cb7/src/Arithmetic/BarrettReduction/Generalized.v#L140) + +The proofs can be re-checked using Coq version 8.7 or 8.8 (or above, probably). diff --git a/chip/g/dcrypto/rsa.c b/chip/g/dcrypto/rsa.c new file mode 100644 index 0000000000..8a4115398d --- /dev/null +++ b/chip/g/dcrypto/rsa.c @@ -0,0 +1,743 @@ +/* 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 "trng.h" +#include "util.h" + +#include + +#include "cryptoc/sha.h" +#include "cryptoc/sha256.h" +#include "cryptoc/sha384.h" +#include "cryptoc/sha512.h" +#include "cryptoc/util.h" + +/* Extend the MSB throughout the word. */ +static uint32_t msb_extend(uint32_t a) +{ + return 0u - (a >> 31); +} + +/* Return 0xFF..FF if a is zero, and zero otherwise. */ +static uint32_t is_zero(uint32_t a) +{ + return msb_extend(~a & (a - 1)); +} + +/* Select a or b based on mask. Mask expected to be 0xFF..FF or 0. */ +static uint32_t select(uint32_t mask, uint32_t a, uint32_t b) +{ + return (mask & a) | (~mask & b); +} + +static void MGF1_xor(uint8_t *dst, uint32_t dst_len, + const uint8_t *seed, uint32_t seed_len, + enum hashing_mode hashing) +{ + HASH_CTX ctx; + struct { + uint8_t b3; + uint8_t b2; + uint8_t b1; + uint8_t b0; + } cnt; + const uint8_t *digest; + const size_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE + : SHA256_DIGEST_SIZE; + + cnt.b0 = cnt.b1 = cnt.b2 = cnt.b3 = 0; + while (dst_len) { + int i; + + if (hashing == HASH_SHA1) + DCRYPTO_SHA1_init(&ctx, 0); + else + DCRYPTO_SHA256_init(&ctx, 0); + + HASH_update(&ctx, seed, seed_len); + HASH_update(&ctx, (uint8_t *) &cnt, sizeof(cnt)); + digest = HASH_final(&ctx); + for (i = 0; i < dst_len && i < hash_size; ++i) + *dst++ ^= *digest++; + dst_len -= i; + if (!++cnt.b0) + ++cnt.b1; + } +} + +/* + * struct OAEP { // MSB to LSB. + * uint8_t zero; + * uint8_t seed[HASH_SIZE]; + * uint8_t phash[HASH_SIZE]; + * uint8_t PS[]; // Variable length (optional) zero-pad. + * uint8_t one; // 0x01, message demarcator. + * uint8_t msg[]; // Input message. + * }; + */ +/* encrypt */ +static int oaep_pad(uint8_t *output, uint32_t output_len, + const uint8_t *msg, uint32_t msg_len, + enum hashing_mode hashing, const char *label) +{ + int i; + const size_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE + : SHA256_DIGEST_SIZE; + uint8_t *const seed = output + 1; + uint8_t *const phash = seed + hash_size; + uint8_t *const PS = phash + hash_size; + const uint32_t max_msg_len = output_len - 2 - 2 * hash_size; + const uint32_t ps_len = max_msg_len - msg_len; + uint8_t *const one = PS + ps_len; + struct HASH_CTX ctx; + + if (output_len < 2 + 2 * hash_size) + return 0; /* Key size too small for chosen hash. */ + if (msg_len > output_len - 2 - 2 * hash_size) + return 0; /* Input message too large for key size. */ + + always_memset(output, 0, output_len); + for (i = 0; i < hash_size;) { + uint32_t r = rand(); + + seed[i++] = r >> 0; + seed[i++] = r >> 8; + seed[i++] = r >> 16; + seed[i++] = r >> 24; + } + + if (hashing == HASH_SHA1) + DCRYPTO_SHA1_init(&ctx, 0); + else + DCRYPTO_SHA256_init(&ctx, 0); + + HASH_update(&ctx, label, label ? strlen(label) + 1 : 0); + memcpy(phash, HASH_final(&ctx), hash_size); + *one = 1; + memcpy(one + 1, msg, msg_len); + MGF1_xor(phash, hash_size + 1 + max_msg_len, + seed, hash_size, hashing); + MGF1_xor(seed, hash_size, phash, hash_size + 1 + max_msg_len, + hashing); + return 1; +} + +/* decrypt */ +static int check_oaep_pad(uint8_t *out, uint32_t *out_len, + uint8_t *padded, uint32_t padded_len, + enum hashing_mode hashing, const char *label) +{ + const size_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE + : SHA256_DIGEST_SIZE; + uint8_t *seed = padded + 1; + uint8_t *phash = seed + hash_size; + uint8_t *PS = phash + hash_size; + const uint32_t max_msg_len = padded_len - 2 - 2 * hash_size; + struct HASH_CTX ctx; + size_t one_index = 0; + uint32_t looking_for_one_byte = ~0; + int bad; + int i; + + if (padded_len < 2 + 2 * hash_size) + return 0; /* Invalid input size. */ + + /* Recover seed. */ + MGF1_xor(seed, hash_size, phash, hash_size + 1 + max_msg_len, hashing); + /* Recover db. */ + MGF1_xor(phash, hash_size + 1 + max_msg_len, seed, hash_size, hashing); + + if (hashing == HASH_SHA1) + DCRYPTO_SHA1_init(&ctx, 0); + else + DCRYPTO_SHA256_init(&ctx, 0); + HASH_update(&ctx, label, label ? strlen(label) + 1 : 0); + + bad = !DCRYPTO_equals(phash, HASH_final(&ctx), hash_size); + bad |= padded[0]; + + for (i = PS - padded; i < padded_len; i++) { + uint32_t equals0 = is_zero(padded[i]); + uint32_t equals1 = is_zero(padded[i] ^ 1); + + one_index = select(looking_for_one_byte & equals1, + i, one_index); + looking_for_one_byte = select(equals1, 0, looking_for_one_byte); + + /* Bad padding if padded[i] is neither 1 nor 0. */ + bad |= looking_for_one_byte & ~equals0; + } + + bad |= looking_for_one_byte; + + if (bad) + return 0; + + one_index++; + if (*out_len < padded_len - one_index) + return 0; + memcpy(out, padded + one_index, padded_len - one_index); + *out_len = padded_len - one_index; + return 1; +} + +/* Constants from RFC 3447. */ +#define RSA_PKCS1_PADDING_SIZE 11 + +/* encrypt */ +static int pkcs1_type2_pad(uint8_t *padded, uint32_t padded_len, + const uint8_t *in, uint32_t in_len) +{ + uint32_t PS_len; + + if (padded_len < RSA_PKCS1_PADDING_SIZE) + return 0; + if (in_len > padded_len - RSA_PKCS1_PADDING_SIZE) + return 0; + PS_len = padded_len - 3 - in_len; + + *(padded++) = 0; + *(padded++) = 2; + while (PS_len) { + int i; + uint32_t r = rand(); + + for (i = 0; i < 4 && PS_len; i++) { + uint8_t b = ((uint8_t *) &r)[i]; + + if (b) { + *padded++ = b; + PS_len--; + } + } + } + *(padded++) = 0; + memcpy(padded, in, in_len); + return 1; +} + +/* decrypt */ +static int check_pkcs1_type2_pad(uint8_t *out, uint32_t *out_len, + const uint8_t *padded, uint32_t padded_len) +{ + int i; + int valid; + uint32_t zero_index = 0; + uint32_t looking_for_index = ~0; + + if (padded_len < RSA_PKCS1_PADDING_SIZE) + return 0; + + valid = (padded[0] == 0); + valid &= (padded[1] == 2); + + for (i = 2; i < padded_len; i++) { + uint32_t found = is_zero(padded[i]); + + zero_index = select(looking_for_index & found, i, zero_index); + looking_for_index = select(found, 0, looking_for_index); + } + + zero_index++; + + valid &= ~looking_for_index; + valid &= (zero_index >= RSA_PKCS1_PADDING_SIZE); + if (!valid) + return 0; + + if (*out_len < padded_len - zero_index) + return 0; + memcpy(out, &padded[zero_index], padded_len - zero_index); + *out_len = padded_len - zero_index; + return 1; +} + +static const uint8_t SHA1_DER[] = { + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, + 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 +}; +static const uint8_t SHA256_DER[] = { + 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, + 0x00, 0x04, 0x20 +}; +static const uint8_t SHA384_DER[] = { + 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, + 0x00, 0x04, 0x30 +}; +static const uint8_t SHA512_DER[] = { + 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, + 0x00, 0x04, 0x40 +}; + +static int pkcs1_get_der(enum hashing_mode hashing, const uint8_t **der, + uint32_t *der_size, uint32_t *hash_size) +{ + switch (hashing) { + case HASH_SHA1: + *der = &SHA1_DER[0]; + *der_size = sizeof(SHA1_DER); + *hash_size = SHA_DIGEST_SIZE; + break; + case HASH_SHA256: + *der = &SHA256_DER[0]; + *der_size = sizeof(SHA256_DER); + *hash_size = SHA256_DIGEST_SIZE; + break; + case HASH_SHA384: + *der = &SHA384_DER[0]; + *der_size = sizeof(SHA384_DER); + *hash_size = SHA384_DIGEST_SIZE; + break; + case HASH_SHA512: + *der = &SHA512_DER[0]; + *der_size = sizeof(SHA512_DER); + *hash_size = SHA512_DIGEST_SIZE; + break; + case HASH_NULL: + *der = NULL; + *der_size = 0; + *hash_size = 0; /* any size allowed */ + break; + default: + return 0; + } + + return 1; +} + +/* sign */ +static int pkcs1_type1_pad(uint8_t *padded, uint32_t padded_len, + const uint8_t *in, uint32_t in_len, + enum hashing_mode hashing) +{ + const uint8_t *der; + uint32_t der_size; + uint32_t hash_size; + uint32_t ps_len; + + if (!pkcs1_get_der(hashing, &der, &der_size, &hash_size)) + return 0; + if (padded_len < RSA_PKCS1_PADDING_SIZE + der_size) + return 0; + if (!in_len || (hash_size && in_len != hash_size)) + return 0; + if (in_len > padded_len - RSA_PKCS1_PADDING_SIZE - der_size) + return 0; + ps_len = padded_len - 3 - der_size - in_len; + + *(padded++) = 0; + *(padded++) = 1; + always_memset(padded, 0xFF, ps_len); + padded += ps_len; + *(padded++) = 0; + memcpy(padded, der, der_size); + padded += der_size; + memcpy(padded, in, in_len); + return 1; +} + +/* verify */ +static int check_pkcs1_type1_pad(const uint8_t *msg, uint32_t msg_len, + const uint8_t *padded, uint32_t padded_len, + enum hashing_mode hashing) +{ + int i; + const uint8_t *der; + uint32_t der_size; + uint32_t hash_size; + uint32_t ps_len; + + if (!pkcs1_get_der(hashing, &der, &der_size, &hash_size)) + return 0; + if (msg_len != hash_size) + return 0; + if (padded_len < RSA_PKCS1_PADDING_SIZE + der_size + hash_size) + return 0; + ps_len = padded_len - 3 - der_size - hash_size; + + if (padded[0] != 0 || padded[1] != 1) + return 0; + for (i = 2; i < ps_len + 2; i++) { + if (padded[i] != 0xFF) + return 0; + } + + if (padded[i++] != 0) + return 0; + if (!DCRYPTO_equals(&padded[i], der, der_size)) + return 0; + i += der_size; + return DCRYPTO_equals(msg, &padded[i], hash_size); +} + +/* sign */ +static int pkcs1_pss_pad(uint8_t *padded, uint32_t padded_len, + const uint8_t *in, uint32_t in_len, + enum hashing_mode hashing) +{ + const uint32_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE + : SHA256_DIGEST_SIZE; + const uint32_t salt_len = MIN(padded_len - hash_size - 2, hash_size); + uint32_t db_len; + uint32_t ps_len; + struct HASH_CTX ctx; + + if (in_len != hash_size) + return 0; + if (padded_len < hash_size + 2) + return 0; + db_len = padded_len - hash_size - 1; + + if (hashing == HASH_SHA1) + DCRYPTO_SHA1_init(&ctx, 0); + else + DCRYPTO_SHA256_init(&ctx, 0); + + /* Pilfer bits of output for temporary use. */ + memset(padded, 0, 8); + HASH_update(&ctx, padded, 8); + HASH_update(&ctx, in, in_len); + /* Pilfer bits of output for temporary use. */ + rand_bytes(padded, salt_len); + HASH_update(&ctx, padded, salt_len); + + /* Output hash. */ + memcpy(padded + db_len, HASH_final(&ctx), hash_size); + + /* Prepare DB. */ + ps_len = db_len - salt_len - 1; + memmove(padded + ps_len + 1, padded, salt_len); + memset(padded, 0, ps_len); + padded[ps_len] = 0x01; + MGF1_xor(padded, db_len, padded + db_len, hash_size, hashing); + + /* Clear most significant bit. */ + padded[0] &= 0x7F; + /* Set trailing byte. */ + padded[padded_len - 1] = 0xBC; + return 1; +} + +/* verify */ +static int check_pkcs1_pss_pad(const uint8_t *in, uint32_t in_len, + uint8_t *padded, uint32_t padded_len, + enum hashing_mode hashing) +{ + const uint32_t hash_size = (hashing == HASH_SHA1) ? SHA_DIGEST_SIZE + : SHA256_DIGEST_SIZE; + const uint8_t zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint32_t db_len; + uint32_t max_ps_len; + uint32_t salt_len; + HASH_CTX ctx; + int bad = 0; + int i; + + if (in_len != hash_size) + return 0; + if (padded_len < hash_size + 2) + return 0; + db_len = padded_len - hash_size - 1; + + /* Top bit should be zero. */ + bad |= padded[0] & 0x80; + /* Check trailing byte. */ + bad |= padded[padded_len - 1] ^ 0xBC; + + /* Recover DB. */ + MGF1_xor(padded, db_len, padded + db_len, hash_size, hashing); + /* Clear top bit. */ + padded[0] &= 0x7F; + /* Verify padding2. */ + max_ps_len = db_len - 1; + for (i = 0; i < max_ps_len; i++) { + if (padded[i] == 0x01) + break; + else + bad |= padded[i]; + } + bad |= (padded[i] ^ 0x01); + /* Continue with zero-length salt if 0x01 was not found. */ + salt_len = max_ps_len - i; + + if (hashing == HASH_SHA1) + DCRYPTO_SHA1_init(&ctx, 0); + else + DCRYPTO_SHA256_init(&ctx, 0); + HASH_update(&ctx, zeros, sizeof(zeros)); + HASH_update(&ctx, in, in_len); + HASH_update(&ctx, padded + db_len - salt_len, salt_len); + bad |= !DCRYPTO_equals(padded + db_len, HASH_final(&ctx), hash_size); + return !bad; +} + +static int check_modulus_params( + const struct LITE_BIGNUM *N, size_t rsa_max_bytes, uint32_t *out_len) +{ + if (bn_size(N) > rsa_max_bytes) + return 0; /* Unsupported key size. */ + if (!bn_check_topbit(N)) /* Check that top bit is set. */ + return 0; + if (out_len && *out_len < bn_size(N)) + return 0; /* Output buffer too small. */ + return 1; +} + +int DCRYPTO_rsa_encrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len, + const uint8_t *in, uint32_t in_len, + enum padding_mode padding, enum hashing_mode hashing, + const char *label) +{ + uint8_t *p; + uint32_t padded_buf[RSA_MAX_WORDS]; + uint32_t e_buf[LITE_BN_BYTES / sizeof(uint32_t)]; + + struct LITE_BIGNUM padded; + struct LITE_BIGNUM encrypted; + int ret; + + if (!check_modulus_params(&rsa->N, sizeof(padded_buf), out_len)) + return 0; + + bn_init(&padded, padded_buf, bn_size(&rsa->N)); + bn_init(&encrypted, out, bn_size(&rsa->N)); + + switch (padding) { + case PADDING_MODE_OAEP: + if (!oaep_pad((uint8_t *) padded.d, bn_size(&padded), + (const uint8_t *) in, in_len, hashing, label)) + return 0; + break; + case PADDING_MODE_PKCS1: + if (!pkcs1_type2_pad((uint8_t *) padded.d, bn_size(&padded), + (const uint8_t *) in, in_len)) + return 0; + break; + case PADDING_MODE_NULL: + /* Input is allowed to have more bytes than N, in + * which case the excess must be zero. */ + for (; in_len > bn_size(&padded); in_len--) + if (*in++ != 0) + return 0; + p = (uint8_t *) padded.d; + /* If in_len < bn_size(&padded), padded will + * have leading zero bytes. */ + memcpy(&p[bn_size(&padded) - in_len], in, in_len); + /* TODO(ngm): in may be > N, bn_mod_exp() should + * handle this case. */ + break; + default: + return 0; /* Unsupported padding mode. */ + } + + /* Reverse from big-endian to little-endian notation. */ + reverse((uint8_t *) padded.d, bn_size(&padded)); + ret = bn_modexp_word(&encrypted, &padded, rsa->e, &rsa->N); + /* Back to big-endian notation. */ + reverse((uint8_t *) encrypted.d, bn_size(&encrypted)); + *out_len = bn_size(&encrypted); + + always_memset(padded_buf, 0, sizeof(padded_buf)); + always_memset(e_buf, 0, sizeof(e_buf)); + return ret; +} + +int DCRYPTO_rsa_decrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len, + const uint8_t *in, const uint32_t in_len, + enum padding_mode padding, enum hashing_mode hashing, + const char *label) +{ + uint32_t encrypted_buf[RSA_MAX_WORDS]; + uint32_t padded_buf[RSA_MAX_WORDS]; + + struct LITE_BIGNUM encrypted; + struct LITE_BIGNUM padded; + int ret; + + if (!check_modulus_params(&rsa->N, sizeof(padded_buf), NULL)) + return 0; + if (in_len != bn_size(&rsa->N)) + return 0; /* Invalid input length. */ + + /* TODO(ngm): this copy can be eliminated if input may be modified. */ + bn_init(&encrypted, encrypted_buf, in_len); + memcpy(encrypted_buf, in, in_len); + bn_init(&padded, padded_buf, in_len); + + /* Reverse from big-endian to little-endian notation. */ + reverse((uint8_t *) encrypted.d, encrypted.dmax * LITE_BN_BYTES); + ret = bn_modexp_blinded(&padded, &encrypted, &rsa->d, &rsa->N, rsa->e); + /* Back to big-endian notation. */ + reverse((uint8_t *) padded.d, padded.dmax * LITE_BN_BYTES); + + switch (padding) { + case PADDING_MODE_OAEP: + if (!check_oaep_pad(out, out_len, (uint8_t *) padded.d, + bn_size(&padded), hashing, label)) + ret = 0; + break; + case PADDING_MODE_PKCS1: + if (!check_pkcs1_type2_pad( + out, out_len, (const uint8_t *) padded.d, + bn_size(&padded))) + ret = 0; + break; + case PADDING_MODE_NULL: + if (*out_len < bn_size(&padded)) { + ret = 0; + } else { + *out_len = bn_size(&padded); + memcpy(out, padded.d, *out_len); + } + break; + default: + /* Unsupported padding mode. */ + ret = 0; + break; + } + + always_memset(encrypted_buf, 0, sizeof(encrypted_buf)); + always_memset(padded_buf, 0, sizeof(padded_buf)); + return ret; +} + +int DCRYPTO_rsa_sign(struct RSA *rsa, uint8_t *out, uint32_t *out_len, + const uint8_t *in, const uint32_t in_len, + enum padding_mode padding, enum hashing_mode hashing) +{ + uint32_t padded_buf[RSA_MAX_WORDS]; + + struct LITE_BIGNUM padded; + struct LITE_BIGNUM signature; + int ret; + + if (!check_modulus_params(&rsa->N, sizeof(padded_buf), out_len)) + return 0; + + bn_init(&padded, padded_buf, bn_size(&rsa->N)); + bn_init(&signature, out, bn_size(&rsa->N)); + + switch (padding) { + case PADDING_MODE_PKCS1: + if (!pkcs1_type1_pad((uint8_t *) padded.d, bn_size(&padded), + (const uint8_t *) in, in_len, hashing)) + return 0; + break; + case PADDING_MODE_PSS: + if (!pkcs1_pss_pad((uint8_t *) padded.d, bn_size(&padded), + (const uint8_t *) in, in_len, hashing)) + return 0; + break; + default: + return 0; + } + + /* Reverse from big-endian to little-endian notation. */ + reverse((uint8_t *) padded.d, bn_size(&padded)); + ret = bn_modexp_blinded(&signature, &padded, &rsa->d, &rsa->N, rsa->e); + /* Back to big-endian notation. */ + reverse((uint8_t *) signature.d, bn_size(&signature)); + *out_len = bn_size(&rsa->N); + + always_memset(padded_buf, 0, sizeof(padded_buf)); + return ret; +} + +int DCRYPTO_rsa_verify(const struct RSA *rsa, const uint8_t *digest, + uint32_t digest_len, const uint8_t *sig, + const uint32_t sig_len, enum padding_mode padding, + enum hashing_mode hashing) +{ + uint32_t padded_buf[RSA_WORDS_4K]; + uint32_t signature_buf[RSA_WORDS_4K]; + + struct LITE_BIGNUM padded; + struct LITE_BIGNUM signature; + int ret; + + if (!check_modulus_params(&rsa->N, sizeof(padded_buf), NULL)) + return 0; + if (sig_len != bn_size(&rsa->N)) + return 0; /* Invalid input length. */ + + bn_init(&signature, signature_buf, bn_size(&rsa->N)); + memcpy(signature_buf, sig, bn_size(&rsa->N)); + bn_init(&padded, padded_buf, bn_size(&rsa->N)); + + /* Reverse from big-endian to little-endian notation. */ + reverse((uint8_t *) signature.d, bn_size(&signature)); + ret = bn_modexp_word(&padded, &signature, rsa->e, &rsa->N); + /* Back to big-endian notation. */ + reverse((uint8_t *) padded.d, bn_size(&padded)); + + switch (padding) { + case PADDING_MODE_PKCS1: + if (!check_pkcs1_type1_pad( + digest, digest_len, (uint8_t *) padded.d, + bn_size(&padded), hashing)) + ret = 0; + break; + case PADDING_MODE_PSS: + if (!check_pkcs1_pss_pad( + digest, digest_len, (uint8_t *) padded.d, + bn_size(&padded), hashing)) + ret = 0; + break; + default: + /* Unsupported padding mode. */ + ret = 0; + break; + } + + always_memset(padded_buf, 0, sizeof(padded_buf)); + always_memset(signature_buf, 0, sizeof(signature_buf)); + return ret; +} + +int DCRYPTO_rsa_key_compute(struct LITE_BIGNUM *N, struct LITE_BIGNUM *d, + struct LITE_BIGNUM *p, struct LITE_BIGNUM *q, + uint32_t e_buf) +{ + uint32_t ONE_buf = 1; + uint32_t phi_buf[RSA_MAX_WORDS]; + uint32_t q_buf[RSA_MAX_WORDS / 2 + 1]; + + struct LITE_BIGNUM ONE; + struct LITE_BIGNUM e; + struct LITE_BIGNUM phi; + struct LITE_BIGNUM q_local; + + DCRYPTO_bn_wrap(&ONE, &ONE_buf, sizeof(ONE_buf)); + DCRYPTO_bn_wrap(&phi, phi_buf, bn_size(N)); + if (!q) { + /* q not provided, calculate it. */ + memcpy(phi_buf, N->d, bn_size(N)); + bn_init(&q_local, q_buf, bn_size(p)); + q = &q_local; + + if (!DCRYPTO_bn_div(q, NULL, &phi, p)) + return 0; + + /* Check that p * q == N */ + DCRYPTO_bn_mul(&phi, p, q); + if (!bn_eq(N, &phi)) + return 0; + } else { + DCRYPTO_bn_mul(N, p, q); + memcpy(phi_buf, N->d, bn_size(N)); + } + + bn_sub(&phi, p); + bn_sub(&phi, q); + bn_add(&phi, &ONE); + DCRYPTO_bn_wrap(&e, &e_buf, sizeof(e_buf)); + return bn_modinv_vartime(d, &e, &phi); +} diff --git a/chip/g/dcrypto/sha1.c b/chip/g/dcrypto/sha1.c new file mode 100644 index 0000000000..07ef3a34ef --- /dev/null +++ b/chip/g/dcrypto/sha1.c @@ -0,0 +1,65 @@ +/* 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 "cryptoc/sha.h" + +static void dcrypto_sha1_init(SHA_CTX *ctx); +static const uint8_t *dcrypto_sha1_final(SHA_CTX *unused); + +/* + * Hardware SHA implementation. + */ +static const HASH_VTAB HW_SHA1_VTAB = { + dcrypto_sha1_init, + dcrypto_sha_update, + dcrypto_sha1_final, + DCRYPTO_SHA1_hash, + SHA_DIGEST_SIZE +}; + +/* Requires dcrypto_grab_sha_hw() to be called first. */ +static void dcrypto_sha1_init(SHA_CTX *ctx) +{ + ctx->f = &HW_SHA1_VTAB; + dcrypto_sha_init(SHA1_MODE); +} + +/* 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(SHA_CTX *ctx, uint32_t sw_required) +{ + if (!sw_required && dcrypto_grab_sha_hw()) + dcrypto_sha1_init(ctx); + else + SHA_init(ctx); +} + +static const uint8_t *dcrypto_sha1_final(SHA_CTX *ctx) +{ + dcrypto_sha_wait(SHA1_MODE, (uint32_t *) ctx->buf); + return ctx->buf; +} + +const uint8_t *DCRYPTO_SHA1_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(SHA1_MODE, data, n, digest); + else + SHA_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..f127ab445a --- /dev/null +++ b/chip/g/dcrypto/sha256.c @@ -0,0 +1,195 @@ +/* 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" + +#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) +{ + 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) ? + 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(); +} + +/* 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) +{ + 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 void *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) +{ + 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; +} + +static void dcrypto_sha256_init(LITE_SHA256_CTX *ctx) +{ + ctx->f = &HW_SHA256_VTAB; + dcrypto_sha_init(SHA256_MODE); +} + +/* 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 +} + +static const uint8_t *dcrypto_sha256_final(LITE_SHA256_CTX *ctx) +{ + dcrypto_sha_wait(SHA256_MODE, (uint32_t *) ctx->buf); + return ctx->buf; +} + +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 + return digest; +} diff --git a/chip/g/dcrypto/sha384.c b/chip/g/dcrypto/sha384.c new file mode 100644 index 0000000000..6f3c6ca096 --- /dev/null +++ b/chip/g/dcrypto/sha384.c @@ -0,0 +1,20 @@ +/* Copyright 2016 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 "cryptoc/sha384.h" + +void DCRYPTO_SHA384_init(LITE_SHA512_CTX *ctx) +{ + SHA384_init(ctx); +} + +const uint8_t *DCRYPTO_SHA384_hash(const void *data, uint32_t n, + uint8_t *digest) +{ + return SHA384_hash(data, n, digest); +} diff --git a/chip/g/dcrypto/sha512.c b/chip/g/dcrypto/sha512.c new file mode 100644 index 0000000000..1446970174 --- /dev/null +++ b/chip/g/dcrypto/sha512.c @@ -0,0 +1,20 @@ +/* Copyright 2016 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 "cryptoc/sha512.h" + +void DCRYPTO_SHA512_init(LITE_SHA512_CTX *ctx) +{ + SHA512_init(ctx); +} + +const uint8_t *DCRYPTO_SHA512_hash(const void *data, uint32_t n, + uint8_t *digest) +{ + return SHA512_hash(data, n, digest); +} diff --git a/chip/g/dcrypto/x509.c b/chip/g/dcrypto/x509.c new file mode 100644 index 0000000000..81f1674db1 --- /dev/null +++ b/chip/g/dcrypto/x509.c @@ -0,0 +1,545 @@ +/* Copyright 2016 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 + +/* Limit the size of long form encoded objects to < 64 kB. */ +#define MAX_ASN1_OBJ_LEN_BYTES 3 + +/* Reserve space for TLV encoding */ +#define SEQ_SMALL 2 /* < 128 bytes (1B type, 1B 7-bit length) */ +#define SEQ_MEDIUM 3 /* < 256 bytes (1B type, 1B length size, 1B length) */ +#define SEQ_LARGE 4 /* < 65536 bytes (1B type, 1B length size, 2B length) */ + +/* Tag related constants. */ +enum { + V_ASN1_INT = 0x02, + V_ASN1_BIT_STRING = 0x03, + V_ASN1_BYTES = 0x04, + V_ASN1_OBJ = 0x06, + V_ASN1_UTF8 = 0x0c, + V_ASN1_SEQUENCE = 0x10, + V_ASN1_SET = 0x11, + V_ASN1_ASCII = 0x13, + V_ASN1_TIME = 0x18, + V_ASN1_CONSTRUCTED = 0x20, + /* short helpers */ + V_BITS = V_ASN1_BIT_STRING, + V_SEQ = V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE, + V_SET = V_ASN1_CONSTRUCTED | V_ASN1_SET, +}; + +struct asn1 { + uint8_t *p; + size_t n; +}; + + +#define SEQ_START(X, T, L) \ + do { \ + int __old = (X).n; \ + uint8_t __t = (T); \ + int __l = (L); \ + (X).n += __l; +#define SEQ_END(X) \ + (X).n = asn1_seq((X).p + __old, __t, __l, (X).n - __old - __l) + __old;\ + } \ + while (0) + +/* The SHA256 OID, from https://tools.ietf.org/html/rfc5754#section-3.2 + * Only the object bytes below, the DER encoding header ([0x30 0x0d]) + * is verified by the parser. */ +static const uint8_t OID_SHA256_WITH_RSA_ENCRYPTION[13] = { + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00 +}; +static const uint8_t OID_commonName[3] = {0x55, 0x04, 0x03}; +static const uint8_t OID_ecdsa_with_SHA256[8] = {0x2A, 0x86, 0x48, 0xCE, + 0x3D, 0x04, 0x03, 0x02}; +static const uint8_t OID_id_ecPublicKey[7] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, + 0x02, 0x01}; +static const uint8_t OID_prime256v1[8] = {0x2A, 0x86, 0x48, 0xCE, + 0x3D, 0x03, 0x01, 0x07}; +static const uint8_t OID_fido_u2f[11] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, + 0xE5, 0x1C, 0x02, 0x01, 0x01}; +#define OID(X) sizeof(OID_##X), OID_##X + +/* ---- ASN.1 Generation ---- */ + +/* start a tag and return write ptr */ +static uint8_t *asn1_tag(struct asn1 *ctx, uint8_t tag) +{ + ctx->p[(ctx->n)++] = tag; + return ctx->p + ctx->n; +} + +/* DER encode length and return encoded size thereof */ +static int asn1_len(uint8_t *p, size_t size) +{ + if (size < 128) { + p[0] = size; + return 1; + } else if (size < 256) { + p[0] = 0x81; + p[1] = size; + return 2; + } else { + p[0] = 0x82; + p[1] = size >> 8; + p[2] = size; + return 3; + } +} + +/* + * close sequence and move encapsulated data if needed + * return total length. + */ +static size_t asn1_seq(uint8_t *p, uint8_t tag, size_t l, size_t size) +{ + size_t tl; + + p[0] = tag; + tl = asn1_len(p + 1, size) + 1; + /* TODO: tl > l fail */ + if (tl < l) + memmove(p + tl, p + l, size); + + return tl + size; +} + +/* DER encode (small positive) integer */ +static void asn1_int(struct asn1 *ctx, uint32_t val) +{ + uint8_t *p = asn1_tag(ctx, V_ASN1_INT); + + if (!val) { + *p++ = 1; + *p++ = 0; + } else { + int nbits = 32 - __builtin_clz(val); + int nbytes = (nbits + 7) / 8; + + if ((nbits & 7) == 0) { + *p++ = nbytes + 1; + *p++ = 0; + } else { + *p++ = nbytes; + } + while (nbytes--) + *p++ = val >> (nbytes * 8); + } + + ctx->n = p - ctx->p; +} + +/* DER encode positive p256_int */ +static void asn1_p256_int(struct asn1 *ctx, const p256_int *n) +{ + uint8_t *p = asn1_tag(ctx, V_ASN1_INT); + uint8_t bn[P256_NBYTES]; + int i; + + p256_to_bin(n, bn); + for (i = 0; i < P256_NBYTES; ++i) { + if (bn[i] != 0) + break; + } + if (bn[i] & 0x80) { + *p++ = P256_NBYTES - i + 1; + *p++ = 0; + } else { + *p++ = P256_NBYTES - i; + } + for (; i < P256_NBYTES; ++i) + *p++ = bn[i]; + + ctx->n = p - ctx->p; +} + +/* DER encode p256 signature */ +static void asn1_sig(struct asn1 *ctx, const p256_int *r, const p256_int *s) +{ + SEQ_START(*ctx, V_SEQ, SEQ_SMALL) { + asn1_p256_int(ctx, r); + asn1_p256_int(ctx, s); + } + SEQ_END(*ctx); +} + +/* DER encode printable string */ +static void asn1_string(struct asn1 *ctx, uint8_t tag, const char *s) +{ + uint8_t *p = asn1_tag(ctx, tag); + size_t n = strlen(s); + + p += asn1_len(p, n); + while (n--) + *p++ = *s++; + + ctx->n = p - ctx->p; +} + +/* DER encode bytes */ +static void asn1_object(struct asn1 *ctx, size_t n, const uint8_t *b) +{ + uint8_t *p = asn1_tag(ctx, V_ASN1_OBJ); + + p += asn1_len(p, n); + while (n--) + *p++ = *b++; + + ctx->n = p - ctx->p; +} + +/* DER encode p256 pk */ +static void asn1_pub(struct asn1 *ctx, const p256_int *x, const p256_int *y) +{ + uint8_t *p = asn1_tag(ctx, 4); /* uncompressed format */ + + p256_to_bin(x, p); p += P256_NBYTES; + p256_to_bin(y, p); p += P256_NBYTES; + + ctx->n = p - ctx->p; +} + +size_t DCRYPTO_asn1_sigp(uint8_t *buf, const p256_int *r, const p256_int *s) +{ + struct asn1 asn1 = {buf, 0}; + + asn1_sig(&asn1, r, s); + return asn1.n; +} + +size_t DCRYPTO_asn1_pubp(uint8_t *buf, const p256_int *x, const p256_int *y) +{ + struct asn1 asn1 = {buf, 0}; + + asn1_pub(&asn1, x, y); + return asn1.n; +} + +/* ---- ASN.1 Parsing ---- */ + +/* + * An ASN.1 DER (Definite Encoding Rules) parser. + * Details about the format are available here: + * https://en.wikipedia.org/wiki/X.690#Definite_form + */ +static size_t asn1_parse(const uint8_t **p, size_t available, + uint8_t expected_type, const uint8_t **out, + size_t *out_len, size_t *remaining) +{ + const size_t tag_len = 1; + const uint8_t *in = *p; + size_t obj_len = 0; + size_t obj_len_bytes; + size_t consumed; + + if (available < 2) + return 0; + if (in[0] != expected_type) /* in[0] specifies the tag. */ + return 0; + + if ((in[1] & 128) == 0) { + /* Short-length encoding (i.e. obj_len <= 127). */ + obj_len = in[1]; + obj_len_bytes = 1; + } else { + int i; + + obj_len_bytes = 1 + (in[1] & 127); + if (obj_len_bytes > MAX_ASN1_OBJ_LEN_BYTES || + tag_len + obj_len_bytes > available) + return 0; + + if (in[2] == 0) + /* Definite form encoding requires minimal + * length encoding. */ + return 0; + for (i = 0; i < obj_len_bytes - 1; i++) { + obj_len <<= 8; + obj_len |= in[tag_len + 1 + i]; + } + } + + consumed = tag_len + obj_len_bytes + obj_len; + if (consumed > available) + return 0; /* Invalid object length.*/ + if (out) + *out = &in[tag_len + obj_len_bytes]; + if (out_len) + *out_len = obj_len; + + *p = in + consumed; + if (remaining) + *remaining = available - consumed; + return consumed; +} + +static size_t asn1_parse_certificate(const uint8_t **p, size_t *available) +{ + size_t consumed; + size_t obj_len; + const uint8_t *in = *p; + + consumed = asn1_parse(&in, *available, + V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE, + NULL, &obj_len, NULL); + if (consumed == 0 || consumed != *available) /* Invalid SEQUENCE. */ + return 0; + *p += consumed - obj_len; + *available -= consumed - obj_len; + return 1; +} + +static size_t asn1_parse_tbs(const uint8_t **p, size_t *available, + size_t *tbs_len) +{ + size_t consumed; + + consumed = asn1_parse(p, *available, + V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE, + NULL, NULL, available); + if (consumed == 0) + return 0; + *tbs_len = consumed; + return 1; +} + +static size_t asn1_parse_signature_algorithm(const uint8_t **p, + size_t *available) +{ + const uint8_t *alg_oid; + size_t alg_oid_len; + + if (!asn1_parse(p, *available, V_ASN1_CONSTRUCTED | V_ASN1_SEQUENCE, + &alg_oid, &alg_oid_len, available)) + return 0; + if (alg_oid_len != sizeof(OID_SHA256_WITH_RSA_ENCRYPTION)) + return 0; + if (memcmp(alg_oid, OID_SHA256_WITH_RSA_ENCRYPTION, + sizeof(OID_SHA256_WITH_RSA_ENCRYPTION)) != 0) + return 0; + return 1; +} + +static size_t asn1_parse_signature_value(const uint8_t **p, size_t *available, + const uint8_t **sig, size_t *sig_len) +{ + if (!asn1_parse(p, *available, V_ASN1_BIT_STRING, + sig, sig_len, available)) + return 0; + if (*available != 0) + return 0; /* Not all input bytes consumed. */ + return 1; +} + +/* This method verifies that the provided X509 certificate was issued + * by the specified certifcate authority. + * + * cert is a pointer to a DER encoded X509 certificate, as specified + * in https://tools.ietf.org/html/rfc5280#section-4.1. In ASN.1 + * notation, the certificate has the following structure: + * + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + * + * TBSCertificate ::= SEQUENCE { } + * AlgorithmIdentifier ::= SEQUENCE { } + * + * where signatureValue = SIGN(HASH(tbsCertificate)), with SIGN and + * HASH specified by signatureAlgorithm. + */ +int DCRYPTO_x509_verify(const uint8_t *cert, size_t len, + const struct RSA *ca_pub_key) +{ + const uint8_t *p = cert; + const uint8_t *tbs; + size_t tbs_len; + const uint8_t *sig; + size_t sig_len; + + uint8_t digest[SHA256_DIGEST_SIZE]; + + /* Read Certificate SEQUENCE. */ + if (!asn1_parse_certificate(&p, &len)) + return 0; + + /* Read tbsCertificate SEQUENCE. */ + tbs = p; + if (!asn1_parse_tbs(&p, &len, &tbs_len)) + return 0; + + /* Read signatureAlgorithm SEQUENCE. */ + if (!asn1_parse_signature_algorithm(&p, &len)) + return 0; + + /* Read signatureValue BIT STRING. */ + if (!asn1_parse_signature_value(&p, &len, &sig, &sig_len)) + return 0; + + /* Check that the signature length corresponds to the issuer's + * public key size. */ + if (sig_len != bn_size(&ca_pub_key->N) && + sig_len != bn_size(&ca_pub_key->N) + 1) + return 0; + /* Check that leading signature bytes (if any) are zero. */ + if (sig_len == bn_size(&ca_pub_key->N) + 1) { + if (sig[0] != 0) + return 0; + sig++; + sig_len--; + } + + DCRYPTO_SHA256_hash(tbs, tbs_len, digest); + return DCRYPTO_rsa_verify(ca_pub_key, digest, sizeof(digest), + sig, sig_len, PADDING_MODE_PKCS1, HASH_SHA256); +} + +/* ---- Certificate generation ---- */ + +static void add_common_name(struct asn1 *ctx, const char *cname) +{ + SEQ_START(*ctx, V_SEQ, SEQ_SMALL) { + SEQ_START(*ctx, V_SET, SEQ_SMALL) { + SEQ_START(*ctx, V_SEQ, SEQ_SMALL) { + asn1_object(ctx, OID(commonName)); + asn1_string(ctx, V_ASN1_ASCII, cname); + } + SEQ_END(*ctx); + } + SEQ_END(*ctx); + } + SEQ_END(*ctx); +} + +int DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x, + const p256_int *pk_y, const p256_int *serial, + const char *name, uint8_t *cert, const int n) +{ + struct asn1 ctx = {cert, 0}; + HASH_CTX sha; + p256_int h, r, s; + struct drbg_ctx drbg; + + SEQ_START(ctx, V_SEQ, SEQ_LARGE) { /* outer seq */ + /* + * Grab current pointer to data to hash later. + * Note this will fail if cert body + cert sign is less + * than 256 bytes (SEQ_MEDIUM) -- not likely. + */ + uint8_t *body = ctx.p + ctx.n; + + /* Cert body seq */ + SEQ_START(ctx, V_SEQ, SEQ_MEDIUM) { + /* X509 v3 */ + SEQ_START(ctx, 0xa0, SEQ_SMALL) { + asn1_int(&ctx, 2); + } + SEQ_END(ctx); + + /* Serial number */ + if (serial) + asn1_p256_int(&ctx, serial); + else + asn1_int(&ctx, 1); + + /* Signature algo */ + SEQ_START(ctx, V_SEQ, SEQ_SMALL) { + asn1_object(&ctx, OID(ecdsa_with_SHA256)); + } + SEQ_END(ctx); + + /* Issuer */ + add_common_name(&ctx, name); + + /* Expiry */ + SEQ_START(ctx, V_SEQ, SEQ_SMALL) { + asn1_string(&ctx, V_ASN1_TIME, "20000101000000Z"); + asn1_string(&ctx, V_ASN1_TIME, "20991231235959Z"); + } + SEQ_END(ctx); + + /* Subject */ + add_common_name(&ctx, name); + + /* Subject pk */ + SEQ_START(ctx, V_SEQ, SEQ_SMALL) { + /* pk parameters */ + SEQ_START(ctx, V_SEQ, SEQ_SMALL) { + asn1_object(&ctx, OID(id_ecPublicKey)); + asn1_object(&ctx, OID(prime256v1)); + } + SEQ_END(ctx); + /* pk bits */ + SEQ_START(ctx, V_BITS, SEQ_SMALL) { + /* No unused bit at the end */ + asn1_tag(&ctx, 0); + asn1_pub(&ctx, pk_x, pk_y); + } + SEQ_END(ctx); + } + SEQ_END(ctx); + + /* U2F transports indicator extension */ + SEQ_START(ctx, 0xa3, SEQ_SMALL) { + SEQ_START(ctx, V_SEQ, SEQ_SMALL) { + SEQ_START(ctx, V_SEQ, SEQ_SMALL) { + asn1_object(&ctx, OID(fido_u2f)); + SEQ_START(ctx, V_ASN1_BYTES, SEQ_SMALL) { + SEQ_START(ctx, V_BITS, SEQ_SMALL) { + /* 3 zero bits */ + asn1_tag(&ctx, 3); + /* usb-internal transport */ + asn1_tag(&ctx, 0x08); + } + SEQ_END(ctx); + } + SEQ_END(ctx); + } + SEQ_END(ctx); + } + SEQ_END(ctx); + } + SEQ_END(ctx); + } + SEQ_END(ctx); /* Cert body */ + + /* Sign all of cert body */ + DCRYPTO_SHA256_init(&sha, 0); + HASH_update(&sha, body, (ctx.p + ctx.n) - body); + p256_from_bin(HASH_final(&sha), &h); + hmac_drbg_init_rfc6979(&drbg, d, &h); + if (!dcrypto_p256_ecdsa_sign(&drbg, d, &h, &r, &s)) + return 0; + + /* Append X509 signature */ + SEQ_START(ctx, V_SEQ, SEQ_SMALL); + asn1_object(&ctx, OID(ecdsa_with_SHA256)); + SEQ_END(ctx); + SEQ_START(ctx, V_BITS, SEQ_SMALL) { + /* no unused/zero bit at the end */ + asn1_tag(&ctx, 0); + asn1_sig(&ctx, &r, &s); + } SEQ_END(ctx); + + } SEQ_END(ctx); /* end of outer seq */ + + return ctx.n; +} + +int DCRYPTO_x509_gen_u2f_cert(const p256_int *d, const p256_int *pk_x, + const p256_int *pk_y, const p256_int *serial, + uint8_t *cert, const int n) +{ + return DCRYPTO_x509_gen_u2f_cert_name(d, pk_x, pk_y, serial, + serial ? STRINGIFY(BOARD) : "U2F", + cert, n); +} diff --git a/chip/g/trng.c b/chip/g/trng.c new file mode 100644 index 0000000000..94363b29c4 --- /dev/null +++ b/chip/g/trng.c @@ -0,0 +1,236 @@ +/* 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 "common.h" +#include "flash_log.h" +#include "init_chip.h" +#include "registers.h" +#include "trng.h" +#include "watchdog.h" +#include "console.h" + +/** + * The H1 TRNG uses the collapse time of a ring oscillator (RO) that is + * initialized in a 3x mode (three enable pulses) and eventually collapses + * to a stable 1x mode as a result of accumulated jitter (thermal noise). + * A Phase-Frequency Detector (PFD) compares the 3x RO to a reference + * RO (1.5x) and captures the state of a counter that is incremented + * from the reference RO. The resulting reference-cycles-to-collapse + * distribution is log-normal, and truncation of the counter bits results in + * a distribution that approaches uniform. + * + * TRNG_SAMPLE_BITS defines how many bits to use from the 16 bit counter + * output coming from the analog unit. Entropy is highest in least significant + * bits of counter. For FIPS-certified code use just Bit 0 - it provides + * highest entropy, allows better security settings for TRNG and simplifies + * implementation of continuous health tests. + */ +#ifndef TRNG_SAMPLE_BITS +#define TRNG_SAMPLE_BITS 1 +#endif + +/** + * Attempts to read TRNG_EMPTY before reporting a stall. Practically data should + * be available in less than 0x7ff cycles under normal conditions. 0x7ff was + * chosen to match the hardware TRNG TIMEOUT_COUNTER. Test on boards with slow + * TRNG before reducing this number. + */ +#define TRNG_EMPTY_COUNT 0x7ff + +void init_trng(void) +{ +#if (!(defined(CONFIG_CUSTOMIZED_RO) && defined(SECTION_IS_RO))) + /* + * Most of the trng initialization requires high permissions. If RO has + * dropped the permission level, dont try to read or write these high + * permission registers because it will cause rolling reboots. RO + * should do the TRNG initialization before dropping the level. + */ + if (!runlevel_is_high()) + return; +#endif + /** + * According to NIST SP 800-90B only vetted conditioning mechanism + * should be used for post-processing raw entropy. + * See SP 800-90B, 3.1.5.1 Using Vetted Conditioning Components. + * Use of non-vetted algorithms is governed in 3.1.5.2, but + * assumes conservative coefficient 0.85 for entropy estimate, + * which increase number of requests to TRNG to get desirable + * entropy and prevents from getting full entropy. + */ + GWRITE(TRNG, POST_PROCESSING_CTRL, 0); + + /** + * TRNG can return up to 16 bits at a time, but highest bits + * have lower entropy. Practically on Cr50 only 13 bits can be + * used - setting to higher value makes TRNG_EMPTY always set. + * Entropy assessed to be reasonable (one bit H > 0.85) + * for up to 8 bits [7..0]. + * Time to get 32bit random is roughly 160/TRNG_SAMPLE_BITS us. + */ + GWRITE(TRNG, SLICE_MAX_UPPER_LIMIT, TRNG_SAMPLE_BITS - 1); + + /* lowest bit have highest entropy, so always start from it */ + GWRITE(TRNG, SLICE_MIN_LOWER_LIMIT, 0); + + /** + * Analog logic cannot create a value < 8 under normal operating + * conditions, but there's a chance that an attacker could coax + * them out. + * Bit 0 - Enable rejection for values outside of range specified + * by TRNG_ALLOWED_VALUES register + */ + GWRITE(TRNG, SECURE_POST_PROCESSING_CTRL, 0x1); + + /** + * Since for FIPS settings we use TRNG_SAMPLE_BITS = 1, + * and take only bit 0 from internal 16 bit reading, no bias is + * created for bit 0 if allowed_min is set to 6, which + * actually means min accepted value is 8 (RTL adds +2). + * TRNG_ALLOWED_VALUES_MAX=0x04 (accept all values up to 2^16-1). + * So, range will be [8..65535], with probability for bit 0 and 1 + * remaining 50/50. + */ + GWRITE(TRNG, ALLOWED_VALUES_MIN, 0x26); + + GWRITE(TRNG, TIMEOUT_COUNTER, 0x7ff); + GWRITE(TRNG, TIMEOUT_MAX_TRY_NUM, 4); + GWRITE(TRNG, POWER_DOWN_B, 1); + GWRITE(TRNG, GO_EVENT, 1); +} + +uint32_t rand(void) +{ uint32_t empty_count = 0; + + while (GREAD(TRNG, EMPTY)) { + if (GREAD_FIELD(TRNG, FSM_STATE, FSM_IDLE) || + empty_count > TRNG_EMPTY_COUNT) { + /* TRNG timed out, restart */ + GWRITE(TRNG, STOP_WORK, 1); +#if !defined(SECTION_IS_RO) && defined(CONFIG_FLASH_LOG) + flash_log_add_event(FE_LOG_TRNG_STALL, 0, NULL); +#endif + GWRITE(TRNG, GO_EVENT, 1); + empty_count = 0; + } + empty_count++; + } + return GREAD(TRNG, READ_DATA); +} + +void rand_bytes(void *buffer, size_t len) +{ + int random_togo = 0; + int buffer_index = 0; + uint32_t random_value; + uint8_t *buf = (uint8_t *) buffer; + + /* + * Retrieve random numbers in 4 byte quantities and pack as many bytes + * as needed into 'buffer'. If len is not divisible by 4, the + * remaining random bytes get dropped. + */ + while (buffer_index < len) { + if (!random_togo) { + random_value = rand(); + random_togo = sizeof(random_value); + } + buf[buffer_index++] = random_value >> + ((random_togo-- - 1) * 8); + } +} + +#if !defined(SECTION_IS_RO) && defined(CRYPTO_TEST_SETUP) +#include "console.h" +#include "watchdog.h" + +static void print_rand_stat(uint32_t *histogram, size_t size) +{ + struct pair { + uint32_t value; + uint32_t count; + }; + struct pair min; + struct pair max; + size_t count; + + min.count = ~0; + max.count = 0; + max.value = ~0; + min.value = ~0; + + for (count = 0; count < size; count++) { + if (histogram[count] > max.count) { + max.count = histogram[count]; + max.value = count; + } + if (histogram[count] < min.count) { + min.count = histogram[count]; + min.value = count; + } + } + + ccprintf("min %d(%d), max %d(%d)", min.count, min.value, + max.count, max.value); + + for (count = 0; count < size; count++) { + if (!(count % 8)) { + ccprintf("\n"); + cflush(); + } + ccprintf(" %6d", histogram[count]); + } + ccprintf("\n"); +} + +/* histogram at byte level */ +static uint32_t histogram[256]; +/* histogram at level of TRNG samples */ +static uint32_t histogram_trng[1 << TRNG_SAMPLE_BITS]; + +static int command_rand(int argc, char **argv) +{ + int count = 1000; /* Default number of cycles. */ + uint32_t val = 0, bits = 0; + + if (argc == 2) + count = strtoi(argv[1], NULL, 10); + + memset(histogram, 0, sizeof(histogram)); + memset(histogram_trng, 0, sizeof(histogram_trng)); + ccprintf("Retrieving %d 32-bit random words.\n", count); + while (count-- > 0) { + uint32_t rvalue; + int size; + + rvalue = rand(); + /* update byte-level histogram */ + for (size = 0; size < sizeof(rvalue); size++) + histogram[((uint8_t *)&rvalue)[size]]++; + + /* update histogram on TRNG sample size level */ + val = (val | (rvalue << bits)) & ((1 << TRNG_SAMPLE_BITS) - 1); + rvalue >>= TRNG_SAMPLE_BITS - bits; + bits += 32; + while (bits >= TRNG_SAMPLE_BITS) { + histogram_trng[val]++; + val = rvalue & ((1 << TRNG_SAMPLE_BITS) - 1); + rvalue >>= TRNG_SAMPLE_BITS; + bits -= TRNG_SAMPLE_BITS; + }; + + if (!(count % 10000)) + watchdog_reload(); + } + ccprintf("Byte-level histogram:\n"); + print_rand_stat(histogram, ARRAY_SIZE(histogram)); + ccprintf("\nSample-level (%d bits) histogram:\n", TRNG_SAMPLE_BITS); + print_rand_stat(histogram_trng, ARRAY_SIZE(histogram_trng)); + + return EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(rand, command_rand, NULL, NULL); + +#endif /* CRYPTO_TEST_SETUP */ -- cgit v1.2.1