aboutsummaryrefslogtreecommitdiff
path: root/modexp.c
diff options
context:
space:
mode:
Diffstat (limited to 'modexp.c')
-rw-r--r--modexp.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/modexp.c b/modexp.c
new file mode 100644
index 0000000..7444d57
--- /dev/null
+++ b/modexp.c
@@ -0,0 +1,215 @@
+/*
+ * modexp.c
+ * ----------
+ * Wrapper around Cryptech ModExp core.
+ *
+ * This doesn't do full RSA, that's another module. This module's job
+ * is just the I/O to get bits in and out of the ModExp core, including
+ * compensating for a few known bugs that haven't been resolved yet.
+ *
+ * If at some point the interface to the ModExp core becomes simple
+ * enough that this module is no longer needed, it will go away.
+ *
+ * Authors: Rob Austein
+ * Copyright (c) 2015, SUNET
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "cryptech.h"
+
+/*
+ * Whether we want debug output.
+ */
+
+static int debug = 0;
+
+void hal_modexp_set_debug(const int onoff)
+{
+ debug = onoff;
+}
+
+/*
+ * Check a result, report on failure if debugging, pass failures up
+ * the chain.
+ */
+
+#define check(_expr_) \
+ do { \
+ hal_error_t _err = (_expr_); \
+ if (_err != HAL_OK && debug) \
+ printf("%s failed: %s\n", #_expr_, hal_error_string(_err)); \
+ if (_err != HAL_OK) \
+ return _err; \
+ } while (0)
+
+/*
+ * Set an ordinary register.
+ */
+
+static hal_error_t set_register(const off_t addr,
+ uint32_t value)
+{
+ uint8_t w[4];
+ int i;
+
+ for (i = 3; i >= 0; i--) {
+ w[i] = value & 0xFF;
+ value >>= 8;
+ }
+
+ return hal_io_write(addr, w, sizeof(w));
+}
+
+/*
+ * Get value of a block memory.
+ */
+
+static hal_error_t get_blockmem(const off_t reset_addr,
+ const off_t data_addr,
+ uint8_t *value,
+ const size_t length,
+ const size_t io_len)
+{
+ uint8_t discard[4];
+ size_t i;
+
+ assert(value != NULL && length % 4 == 0);
+
+ assert(io_len >= length && io_len % 4 == 0);
+
+ check(set_register(reset_addr, 1));
+
+ for (i = 0; i < io_len - length; i += 4) {
+ check(hal_io_read(data_addr, discard, 4));
+ if (discard[0] != 0 || discard[1] != 0 || discard[2] != 0 || discard[3] != 0)
+ return HAL_ERROR_IO_UNEXPECTED;
+ }
+
+ for (i = 0; i < length; i += 4)
+ check(hal_io_read(data_addr, &value[i], 4));
+
+ return HAL_OK;
+}
+
+/*
+ * Set value of a block memory.
+ */
+
+static hal_error_t set_blockmem(const off_t reset_addr,
+ const off_t data_addr,
+ const uint8_t * const value,
+ const size_t length,
+ const size_t io_len)
+{
+ const uint8_t zero[4] = { 0, 0, 0, 0 };
+ size_t i;
+
+ assert(value != NULL && length % 4 == 0);
+
+ assert(io_len >= length && io_len % 4 == 0);
+
+ check(set_register(reset_addr, 1));
+
+ for (i = 0; i < io_len - length; i += 4)
+ check(hal_io_write(data_addr, zero, 4));
+
+ for (i = 0; i < length; i += 4)
+ check(hal_io_write(data_addr, &value[i], 4));
+
+ return HAL_OK;
+}
+
+/*
+ * Run one modexp operation.
+ */
+
+hal_error_t hal_modexp(const uint8_t * const msg, const size_t msg_len, /* Message */
+ const uint8_t * const exp, const size_t exp_len, /* Exponent */
+ const uint8_t * const mod, const size_t mod_len, /* Modulus */
+ uint8_t *result, const size_t result_len)
+{
+ /*
+ * All pointers must be set, neither message nor exponent may be
+ * longer than modulus, result buffer must not be shorter than
+ * modulus, and all input lengths must be a multiple of four.
+ *
+ * The multiple-of-four restriction is a pain, but the rest of the
+ * HAL code currently enforces the same restriction, and allowing
+ * arbitrary lengths would require some tedious shuffling to deal
+ * with alignment issues, so it's not worth trying to fix only here.
+ */
+
+ if (msg == NULL || exp == NULL || mod == NULL || result == NULL ||
+ msg_len > mod_len || exp_len > mod_len || result_len < mod_len ||
+ ((msg_len | exp_len | mod_len) & 3) != 0)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ /*
+ * This insanity is a work-around for a current bug in the ModExp
+ * core: we have to zero-pad everything out to the size of the
+ * modulus plus 32-bits. Some kind of overflow issue. All of this
+ * "io_len" nonsense can go away once that's fixed.
+ */
+
+ const size_t io_len = mod_len + 4;
+ assert((io_len & 3) == 0);
+
+ check(set_blockmem(MODEXP_MODULUS_PTR_RST, MODEXP_MODULUS_DATA, mod, mod_len, io_len));
+ check(set_blockmem(MODEXP_MESSAGE_PTR_RST, MODEXP_MESSAGE_DATA, msg, msg_len, io_len));
+ check(set_register(MODEXP_MODULUS_LENGTH, mod_len / 4));
+
+ check(set_blockmem(MODEXP_EXPONENT_PTR_RST, MODEXP_EXPONENT_DATA, exp, exp_len, io_len));
+ check(set_register(MODEXP_EXPONENT_LENGTH, exp_len / 4));
+
+ check(hal_io_wait_ready(MODEXP_ADDR_STATUS));
+
+ check(set_register(MODEXP_ADDR_CTRL, 1));
+
+ /*
+ * ModExp core is not very fast (yet), so wait a long time for a
+ * response, but not forever.
+ */
+
+ int timeout = 0x7FFFFFFF;
+ check(hal_io_wait(MODEXP_ADDR_STATUS, STATUS_READY, &timeout));
+
+ check(get_blockmem(MODEXP_RESULT_PTR_RST, MODEXP_RESULT_DATA, result, mod_len, io_len));
+
+ return HAL_OK;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */