pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long *//*
* ks_token.c
* ----------
* Keystore implementation in flash memory.
*
* Authors: Rob Austein, Fredrik Thulin
* Copyright (c) 2015-2017, NORDUnet A/S All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - 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.
*
* - Neither the name of the NORDUnet nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* 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
* HOLDER 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.
*/
/*
* This keystore driver operates over bare flash, versus over a flash file
* system or flash translation layer. The block size is large enough to
* hold an AES-keywrapped 4096-bit RSA key. Any remaining space in the key
* block may be used to store attributes (opaque TLV blobs). If the
* attributes overflow the key block, additional blocks may be added, but
* no attribute may exceed the block size.
*/
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include "hal.h"
#include "hal_internal.h"
#include "ks.h"
#include "last_gasp_pin_internal.h"
#define HAL_OK CMSIS_HAL_OK
#include "stm-keystore.h"
#undef HAL_OK
#ifndef KS_TOKEN_CACHE_SIZE
#define KS_TOKEN_CACHE_SIZE 4
#endif
#if HAL_KS_BLOCK_SIZE % KEYSTORE_SUBSECTOR_SIZE != 0
#error Keystore block size is not a multiple of flash subsector size
#endif
#define NUM_FLASH_BLOCKS ((KEYSTORE_NUM_SUBSECTORS * KEYSTORE_SUBSECTOR_SIZE) / HAL_KS_BLOCK_SIZE)
#define SUBSECTORS_PER_BLOCK (HAL_KS_BLOCK_SIZE / KEYSTORE_SUBSECTOR_SIZE)
/*
* Keystore database.
*/
typedef struct {
hal_ks_t ks; /* Must be first (C "subclassing") */
hal_ks_pin_t wheel_pin;
hal_ks_pin_t so_pin;
hal_ks_pin_t user_pin;
} ks_token_db_t;
/*
* This is a bit silly, but it's safe enough, and it lets us avoid a
* nasty mess of forward references.
*/
#define db ((ks_token_db_t * const) hal_ks_token)
/*
* Calculate offset of the block in the flash address space.
*/
static inline uint32_t ks_token_offset(const unsigned blockno)
{
return blockno * HAL_KS_BLOCK_SIZE;
}
/*
* Read a flash block.
*
* Flash read on the Alpha is slow enough that it pays to check the
* first page before reading the rest of the block.
*/
static hal_error_t ks_token_read(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block)
{
if (ks != hal_ks_token || block == NULL || blockno >= NUM_FLASH_BLOCKS || sizeof(*block) != HAL_KS_BLOCK_SIZE)
return HAL_ERROR_IMPOSSIBLE;
if (keystore_read_data(ks_token_offset(blockno),
block->bytes,
KEYSTORE_PAGE_SIZE) != CMSIS_HAL_OK)
return HAL_ERROR_KEYSTORE_ACCESS;
switch (hal_ks_block_get_type(block)) {
case HAL_KS_BLOCK_TYPE_ERASED:
case HAL_KS_BLOCK_TYPE_ZEROED:
return HAL_OK;
case HAL_KS_BLOCK_TYPE_KEY:
case HAL_KS_BLOCK_TYPE_PIN:
break;
default:
return HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE;
}
switch (hal_ks_block_get_status(block)) {
case HAL_KS_BLOCK_STATUS_LIVE:
case HAL_KS_BLOCK_STATUS_TOMBSTONE:
break;
default:
return HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE;
}
if (keystore_read_data(ks_token_offset(blockno) + KEYSTORE_PAGE_SIZE,
block->bytes + KEYSTORE_PAGE_SIZE,
sizeof(*block) - KEYSTORE_PAGE_SIZE) != CMSIS_HAL_OK)
return HAL_ERROR_KEYSTORE_ACCESS;
if (hal_ks_block_calculate_crc(block) != block->header.crc)
return HAL_ERROR_KEYSTORE_BAD_CRC;
return HAL_OK;
}
/*
* Convert a live block into a tombstone. Caller is responsible for
* making sure that the block being converted is valid; since we don't
* need to update the CRC for this, we just modify the first page.
*/
static hal_error_t ks_token_deprecate(hal_ks_t *ks, const unsigned blockno)
{
if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS)
return HAL_ERROR_IMPOSSIBLE;
uint8_t page[KEYSTORE_PAGE_SIZE];
hal_ks_block_header_t *header = (void *) page;
uint32_t offset = ks_token_offset(blockno);
if (keystore_read_data(offset, page, sizeof(page)) != CMSIS_HAL_OK)
return HAL_ERROR_KEYSTORE_ACCESS;
header->block_status = HAL_KS_BLOCK_STATUS_TOMBSTONE;
if (keystore_write_data(offset, page, sizeof(page)) != CMSIS_HAL_OK)
return HAL_ERROR_KEYSTORE_ACCESS;
return HAL_OK;
}
/*
* Zero (not erase) a flash block. Just need to zero the first page.
*/
static hal_error_t ks_token_zero(hal_ks_t *ks, const unsigned blockno)
{
if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS)
return HAL_ERROR_IMPOSSIBLE;
uint8_t page[KEYSTORE_PAGE_SIZE] = {0};
if (keystore_write_data(ks_token_offset(blockno), page, sizeof(page)) != CMSIS_HAL_OK)
return HAL_ERROR_KEYSTORE_ACCESS;
return HAL_OK;
}
/*
* Erase a flash block. Also see ks_token_erase_maybe(), below.
*/
static hal_error_t ks_token_erase(hal_ks_t *ks, const unsigned blockno)
{
if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS)
return HAL_ERROR_IMPOSSIBLE;
unsigned subsector = blockno * SUBSECTORS_PER_BLOCK;
const unsigned end = (blockno + 1) * SUBSECTORS_PER_BLOCK;
do {
if (keystore_erase_subsector(subsector) != CMSIS_HAL_OK)
return HAL_ERROR_KEYSTORE_ACCESS;
} while (++subsector < end);
return HAL_OK;
}
/*
* Erase a flash block if it hasn't already been erased.
* May not be necessary, trying to avoid unnecessary wear.
*
* Unclear whether there's any sane reason why this needs to be
* constant time, given how slow erasure is. But side channel attacks
* can be tricky things, and it's theoretically possible that we could
* leak information about, eg, key length, so we do constant time.
*/
static hal_error_t ks_token_erase_maybe(hal_ks_t *ks, const unsigned blockno)
{
if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS)
return HAL_ERROR_IMPOSSIBLE;
uint8_t mask = 0xFF;
for (uint32_t a = ks_token_offset(blockno); a < ks_token_offset(blockno + 1); a += KEYSTORE_PAGE_SIZE) {
uint8_t page[KEYSTORE_PAGE_SIZE];
if (keystore_read_data(a, page, sizeof(page)) != CMSIS_HAL_OK)
return HAL_ERROR_KEYSTORE_ACCESS;
for (int i = 0; i < KEYSTORE_PAGE_SIZE; i++)
mask &= page[i];
}
return mask == 0xFF ? HAL_OK : ks_token_erase(ks, blockno);
}
/*
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long *//*
* 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-2017, NORDUnet A/S
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - 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.
*
* - Neither the name of the NORDUnet nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* 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
* HOLDER 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 "hal.h"
#include "hal_internal.h"
/*
* Whether we want debug output.
*/
static int debug = 0;
void hal_modexp_set_debug(const int onoff)
{
debug = onoff;
}
/*
* Get value of an ordinary register.
*/
static inline hal_error_t get_register(const hal_core_t *core,
const hal_addr_t addr,
uint32_t *value)
{
hal_error_t err;
uint8_t w[4];
if (value == NULL)
return HAL_ERROR_IMPOSSIBLE;
if ((err = hal_io_read(core, addr, w, sizeof(w))) != HAL_OK)
return err;
*value = (w[0] << 0) | (w[1] << 8) | (w[2] << 16) | (w[3] << 24);
return HAL_OK;
}
/*
* Set value of an ordinary register.
*/
static inline hal_error_t set_register(const hal_core_t *core,
const hal_addr_t addr,
const uint32_t value)
{
const uint8_t w[4] = {
((value >> 24) & 0xFF),
((value >> 16) & 0xFF),
((value >> 8) & 0xFF),
((value >> 0) & 0xFF)
};
return hal_io_write(core, addr, w, sizeof(w));
}
/*
* Get value of a data buffer. We reverse the order of 32-bit words
* in the buffer during the transfer to match what the modexpa7 core
* expects.
*/
static inline hal_error_t get_buffer(const hal_core_t *core,
const hal_addr_t data_addr,
uint8_t *value,
const size_t length)
{
hal_error_t err;
size_t i;
if (value == NULL || length % 4 != 0)
return HAL_ERROR_IMPOSSIBLE;
for (i = 0; i < length; i += 4)
if ((err = hal_io_read(core, data_addr + i/4, &value[length - 4 - i], 4)) != HAL_OK)
return err;
return HAL_OK;
}
/*
* Set value of a data buffer. We reverse the order of 32-bit words
* in the buffer during the transfer to match what the modexpa7 core
* expects.
*
* Do we need to zero the portion of the buffer we're not using
* explictly (that is, the portion between `length` and the value of
* the core's MODEXPA7_ADDR_BUFFER_BITS register)? We've gotten away
* without doing this so far, but the core doesn't take an explicit
* length parameter for the message itself, instead it assumes that
* the message is either as long as or twice as long as the exponent,
* depending on the setting of the CRT mode bit. Maybe initializing
* the core clears the excess bits so there's no issue? Dunno. Have
* never seen a problem with this yet, just dont' know why not.
*/
static inline hal_error_t set_buffer(const hal_core_t *core,
const hal_addr_t data_addr,
const uint8_t * const value,
const size_t length)
{
hal_error_t err;
size_t i;
if (value == NULL || length % 4 != 0)
return HAL_ERROR_IMPOSSIBLE;
for (i = 0; i < length; i += 4)
if ((err = hal_io_write(core, data_addr + i/4, &value[length - 4 - i], 4)) != HAL_OK)
return err;
return HAL_OK;
}
/*
* Stuff moved out of modexp so we can run two cores in parallel more
* easily. We have to return to the jacket routine every time we kick
* a core into doing something, since only the jacket routines know
* how many cores we're running for any particular calculation.
*
* In theory we could do something clever where we don't wait for both
* cores to finish precalc before starting either of them on the main
* computation, but that way probably lies madness.
*/
static inline hal_error_t check_args(hal_modexp_arg_t *a)
{
/*
* All data pointers must be set, exponent may not be longer than
* modulus, message may not be longer than twice the modulus (CRT
* mode), result buffer must not be shorter than modulus, and all
* input lengths must be a multiple of four bytes (the core is all
* about 32-bit words).
*/
if (a == NULL ||
a->msg == NULL || a->msg_len > MODEXPA7_OPERAND_BYTES || a->msg_len > a->mod_len * 2 ||
a->exp == NULL || a->exp_len > MODEXPA7_OPERAND_BYTES || a->exp_len > a->mod_len ||
a->mod == NULL || a->mod_len > MODEXPA7_OPERAND_BYTES ||
a->result == NULL || a->result_len > MODEXPA7_OPERAND_BYTES || a->result_len < a->mod_len ||
a->coeff == NULL || a->coeff_len > MODEXPA7_OPERAND_BYTES ||
a->mont == NULL || a->mont_len > MODEXPA7_OPERAND_BYTES ||
((a->msg_len | a->exp_len | a->mod_len) & 3) != 0)
return HAL_ERROR_BAD_ARGUMENTS;
return HAL_OK;
}
static inline hal_error_t setup_precalc(const int precalc, hal_modexp_arg_t *a)
{
hal_error_t err;
/*
* Check that operand size is compatabible with the core.
*/
uint32_t operand_max = 0;
if ((err = get_register(a->core, MODEXPA7_ADDR_BUFFER_BITS, &operand_max)) != HAL_OK)
return err;
operand_max /= 8;
if (a->msg_len > operand_max ||
a->exp_len > operand_max ||
a->mod_len > operand_max ||
a->coeff_len > operand_max ||
a->mont_len > operand_max)
return HAL_ERROR_BAD_ARGUMENTS;
/*
* Set the modulus, then initiate calculation of modulus-dependent
* speedup factors if necessary, by edge-triggering the "init" bit,
* then return to caller so it can wait for precalc.
*/
if ((err = set_register(a->core, MODEXPA7_ADDR_MODULUS_BITS, a->mod_len * 8)) != HAL_OK ||
(err = set_buffer(a->core, MODEXPA7_ADDR_MODULUS, a->mod, a->mod_len)) != HAL_OK ||
(precalc && (err = hal_io_zero(a->core)) != HAL_OK) ||
(precalc && (err = hal_io_init(a->core)) != HAL_OK))
return err;
return HAL_OK;
}
static inline hal_error_t setup_calc(const int precalc, hal_modexp_arg_t *a)
{
hal_error_t err;
/*
* Select CRT mode if and only if message is longer than exponent.
*/
const uint32_t mode = a->msg_len > a->mod_len ? MODEXPA7_MODE_CRT : MODEXPA7_MODE_PLAIN;
/*
* Copy out precalc results if necessary, then load everything and
* start the calculation by edge-triggering the "next" bit. If
* everything works, return to caller so it can wait for the
* calculation to complete.
*/
if ((precalc &&
(err = get_buffer(a->core, MODEXPA7_ADDR_MODULUS_COEFF_OUT, a->coeff, a->coeff_len)) != HAL_OK) ||
(precalc &&
(err = get_buffer(a->core, MODEXPA7_ADDR_MONTGOMERY_FACTOR_OUT, a->mont, a->mont_len)) != HAL_OK) ||
(err = set_buffer(a->core, MODEXPA7_ADDR_MODULUS_COEFF_IN, a->coeff, a->coeff_len)) != HAL_OK ||
(err = set_buffer(a->core, MODEXPA7_ADDR_MONTGOMERY_FACTOR_IN, a->mont, a->mont_len)) != HAL_OK ||
(err = set_register(a->core, MODEXPA7_ADDR_MODE, mode)) != HAL_OK ||
(err = set_buffer(a->core, MODEXPA7_ADDR_MESSAGE, a->msg, a->msg_len)) != HAL_OK ||
(err = set_buffer(a->core, MODEXPA7_ADDR_EXPONENT, a->exp, a->exp_len)) != HAL_OK ||
(err = set_register(a->core, MODEXPA7_ADDR_EXPONENT_BITS, a->exp_len * 8)) != HAL_OK ||
(err = hal_io_zero(a->core)) != HAL_OK ||
(err = hal_io_next(a->core)) != HAL_OK)
return err;
return HAL_OK;
}
static inline hal_error_t extract_result(hal_modexp_arg_t *a)
{
/*
* Extract results from the main calculation and we're done.
* Hardly seems worth making this a separate function.
*/
return get_buffer(a->core, MODEXPA7_ADDR_RESULT, a->result, a->mod_len);
}
/*
* Run one modexp operation.
*/
hal_error_t hal_modexp(const int precalc, hal_modexp_arg_t *a)
{
hal_error_t err;
if ((err = check_args(a)) != HAL_OK)
return err;
if ((err = hal_core_alloc(MODEXPA7_NAME, &a->core)) == HAL_OK &&
(err = setup_precalc(precalc, a)) == HAL_OK &&
(!precalc ||
(err = hal_io_wait_ready(a->core)) == HAL_OK) &&
(err = setup_calc(precalc, a)) == HAL_OK &&
(err = hal_io_wait_valid(a->core)) == HAL_OK &&
(err = extract_result(a)) == HAL_OK)
err = HAL_OK;
hal_core_free(a->core);
return err;
}
/*
* Run two modexp operations in parallel.
*/
hal_error_t hal_modexp2(const int precalc, hal_modexp_arg_t *a1, hal_modexp_arg_t *a2)
{
hal_error_t err;
if ((err = check_args(a1)) != HAL_OK ||
(err = check_args(a2)) != HAL_OK)
return err;
if ((err = hal_core_alloc2(MODEXPA7_NAME, &a1->core,
MODEXPA7_NAME, &a2->core)) == HAL_OK &&
(err = setup_precalc(precalc, a1)) == HAL_OK &&
(err = setup_precalc(precalc, a2)) == HAL_OK &&
(!precalc ||
(err = hal_io_wait_ready2(a1->core, a2->core)) == HAL_OK) &&
(err = setup_calc(precalc, a1)) == HAL_OK &&
(err = setup_calc(precalc, a2)) == HAL_OK &&
(err = hal_io_wait_valid2(a1->core, a2->core)) == HAL_OK &&
(err = extract_result(a1)) == HAL_OK &&
(err = extract_result(a2)) == HAL_OK)
err = HAL_OK;
hal_core_free(a1->core);
hal_core_free(a2->core);
return err;
}
/*
* Local variables:
* indent-tabs-mode: nil
* End:
*/