Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[crypto/otbn/sca] ecc256 device software for SCA #17273

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
133eb94
[crypto] Adjust P-256 implementation to read k in 320 bits.
jadephilipoom Dec 5, 2022
8327cad
[crypto] Make p256_ecdsa_sign_test randomize shares of k.
jadephilipoom Dec 5, 2022
798f271
[crypto] Use properly masked values in mod_inv.
jadephilipoom Dec 8, 2022
88b97bd
[crypto] Store ECDSA-P256 private key d in 320-bit shares.
jadephilipoom Dec 8, 2022
953380a
[crypto] Make p256_ecdsa_sign_test randomize private key.
jadephilipoom Dec 8, 2022
cea4cce
[crypto] Randomize both shares in p256_ecdsa_sign_test.
jadephilipoom Dec 8, 2022
5d4d37f
[crypto] Remove unnecessary instructions from P256.
jadephilipoom Dec 14, 2022
3d9bdc0
[crypto] Update C code to use longer P-256 scalars.
jadephilipoom Dec 22, 2022
dca76ad
[crypto] Reduce register pressure in scalar_mult_int.
jadephilipoom Dec 14, 2022
f177836
[crypto] Support extra bits in scalar_mult_int.
jadephilipoom Dec 14, 2022
9d71bf7
[crypto] Update P-256 random scalar generation subroutine.
jadephilipoom Dec 22, 2022
d505813
wip, using check_scalar_nonzero subroutine
jadephilipoom Jan 16, 2023
b723b3f
first draft done
jadephilipoom Jan 16, 2023
3fbd384
fix bugs after testing
jadephilipoom Jan 17, 2023
67591a3
add test for p256 key derivation
jadephilipoom Jan 17, 2023
6b5893e
change to a test that has a carry bit
jadephilipoom Jan 17, 2023
2e97f72
add SCA interface for P256 keygen
jadephilipoom Jan 17, 2023
727415f
add keypair generation
jadephilipoom Jan 17, 2023
2698902
simplify a little
jadephilipoom Jan 17, 2023
00e5bc9
formatting
jadephilipoom Jan 17, 2023
9330d35
add simple script to generate test data
jadephilipoom Jan 17, 2023
767a69a
fix so it works with capture
jadephilipoom Jan 17, 2023
80babb9
fix typos in sca file
jadephilipoom Jan 18, 2023
31dfb43
add default data to sca asm
jadephilipoom Jan 18, 2023
3f16166
cleanup serial file
jadephilipoom Jan 18, 2023
fee0a0e
change error back to byte
jadephilipoom Jan 19, 2023
54c8df2
move trigger
jadephilipoom Jan 19, 2023
347a277
[sca/otbn] Split loading of OTBN IMEM and DMEM
wettermo Feb 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions p256_key_from_seed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#! /usr/bin/env python3

import argparse
import random

CURVE = 'ECDSA-P256'
KEY_SIZE = 256
SEED_SIZE = 320
CURVE_ORDER = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551

def key_from_seed(seed0, seed1):
'''Mimics the behavior of the secret-key derivation algorithm.'''
# The modulus is the curve order (n) shifted by the number of extra bits in
# the seed compared to the key.
mod = CURVE_ORDER << (SEED_SIZE - KEY_SIZE)
# The computation of d0 is more complex in the masked version, but here we
# can simply combine shares and compute based on the real seed.
d0 = ((seed0 ^ seed1) - seed1) % mod
d1 = seed1 % mod
return d0, d1


def seed_size_int_from_arg(seed):
'''Parses the input argument into a valid SEED_SIZE-bit number.

If `seed` is None, generates a random number. If `seed` is out of the range
[0, 2^SEED_SIZE), prints a warning and reduces modulo (2^SEED_SIZE).
'''
if seed is None:
seed = random.randrange(1 << SEED_SIZE)
elif int.bit_length(seed) > SEED_SIZE:
seed = seed & ((1 << SEED_SIZE) - 1)
print(f'WARNING: seed is too large. Reducing to {SEED_SIZE} bits.')
return seed

def print_int(name, value, nbits):
'''Prints an integer with `nbits` bits in hexadecimal form.'''
# Size of the number in hex is 2 characters for the `0x` prefix plus the
# number of nibbles (size / 4 rounded up).
length = ((nbits + 3) // 4) + 2
print('{name}={value:#0{length}x}'
.format(name=name, value=value, length=length))

if __name__ == "__main__":
parser = argparse.ArgumentParser(
description=('Mimics the behavior of an OTBN routine '
'that derives a private key from a seed '
f'for {CURVE}.'))
parser.add_argument('-s',
'--seed',
type=int,
required=False,
help=f'Real seed value ({SEED_SIZE} bits).')
parser.add_argument('-m',
'--mask',
type=int,
required=False,
help=f'Mask value for seed ({SEED_SIZE} bits).')
args = parser.parse_args()

# Size for seed print formatting
seed_print_size = (SEED_SIZE // 4) + 2

seed = seed_size_int_from_arg(args.seed)
mask = seed_size_int_from_arg(args.mask)
print_int('seed', seed, SEED_SIZE)
print_int('mask', mask, SEED_SIZE)

# Generate the two shares for the seed.
seed0 = seed ^ mask
seed1 = mask
print_int('seed0', seed0, SEED_SIZE)
print_int('seed1', seed1, SEED_SIZE)

# Compute the shares for the resulting key.
d0, d1 = key_from_seed(seed0, seed1)
print_int('d0', d0, SEED_SIZE)
print_int('d1', d1, SEED_SIZE)

# Compute the real key.
d = (d0 + d1) % CURVE_ORDER
print_int('d', d, KEY_SIZE)
15 changes: 15 additions & 0 deletions sw/device/lib/crypto/drivers/otbn.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,21 @@ otbn_error_t otbn_dmem_write(size_t num_words, const uint32_t *src,
return kOtbnErrorOk;
}

otbn_error_t otbn_dmem_set(size_t num_words, const uint32_t src,
otbn_addr_t dest) {
OTBN_RETURN_IF_ERROR(check_offset_len(dest, num_words, kOtbnDMemSizeBytes));

// No need to randomize here, since all the values are the same.
size_t i = 0;
for (; launder32(i) < num_words; ++i) {
abs_mmio_write32(kBase + OTBN_DMEM_REG_OFFSET + dest + i * sizeof(uint32_t),
src);
HARDENED_CHECK_LT(i, num_words);
}
HARDENED_CHECK_EQ(i, num_words);
return kOtbnErrorOk;
}

otbn_error_t otbn_dmem_read(size_t num_words, otbn_addr_t src, uint32_t *dest) {
OTBN_RETURN_IF_ERROR(check_offset_len(src, num_words, kOtbnDMemSizeBytes));

Expand Down
19 changes: 18 additions & 1 deletion sw/device/lib/crypto/drivers/otbn.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ typedef enum otbn_err_bits {
/** A BUS_INTG_VIOLATION error was observed. */
kOtbnErrBitsBusIntgViolation = (1 << 19),
/** A BAD_INTERNAL_STATE error was observed. */
kDifOtbnErrBitsBadInternalState = (1 << 20),
kOtbnErrBitsBadInternalState = (1 << 20),
/** An ILLEGAL_BUS_ACCESS error was observed. */
kOtbnErrBitsIllegalBusAccess = (1 << 21),
/** A LIFECYCLE_ESCALATION error was observed. */
Expand Down Expand Up @@ -251,6 +251,23 @@ typedef struct otbn_app {
otbn_error_t otbn_dmem_write(size_t num_words, const uint32_t *src,
otbn_addr_t dest);

/**
* Set a range of OTBN's data memory (DMEM) to a particular value.
*
* Only 32b-aligned 32b word accesses are allowed. If `dest` is not
* word-aligned or if the length and offset exceed the DMEM size, this function
* will return an error.
*
* The caller must ensure OTBN is idle before calling this function.
*
* @param num_words Length of the range to set in 32-bit words.
* @param src The value to set each word in DMEM to.
* @param dest The DMEM location to set.
* @return Result of the operation.
*/
otbn_error_t otbn_dmem_set(size_t num_words, const uint32_t src,
otbn_addr_t dest);

/**
* Read from OTBN's data memory (DMEM)
*
Expand Down
17 changes: 13 additions & 4 deletions sw/device/lib/crypto/impl/ecdsa_p256/ecdsa_p256.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,19 @@ otbn_error_t ecdsa_p256_sign(const ecdsa_p256_message_digest_t *digest,
otbn_dmem_write(kP256ScalarNumWords, digest->h, kOtbnVarEcdsaMsg));

// Set the private key shares.
OTBN_RETURN_IF_ERROR(
otbn_dmem_write(kP256ScalarNumWords, private_key->d0, kOtbnVarEcdsaD0));
OTBN_RETURN_IF_ERROR(
otbn_dmem_write(kP256ScalarNumWords, private_key->d1, kOtbnVarEcdsaD1));
OTBN_RETURN_IF_ERROR(otbn_dmem_write(kP256SecretScalarNumWords,
private_key->d0, kOtbnVarEcdsaD0));
OTBN_RETURN_IF_ERROR(otbn_dmem_write(kP256SecretScalarNumWords,
private_key->d1, kOtbnVarEcdsaD1));

// Write trailing 0s to the upper parts of d0 and d1 so that OTBN's 256-bit
// read of the 64-bit second share does not cause an error.
size_t num_zeroes = kOtbnWideWordNumWords -
(kP256SecretScalarNumWords % kOtbnWideWordNumWords);
OTBN_RETURN_IF_ERROR(otbn_dmem_set(
num_zeroes, 0, kOtbnVarEcdsaD0 + kP256SecretScalarNumBytes));
OTBN_RETURN_IF_ERROR(otbn_dmem_set(
num_zeroes, 0, kOtbnVarEcdsaD1 + kP256SecretScalarNumBytes));

// Start the OTBN routine.
OTBN_RETURN_IF_ERROR(otbn_execute());
Expand Down
14 changes: 10 additions & 4 deletions sw/device/lib/crypto/impl/ecdsa_p256/ecdsa_p256.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,14 @@ enum {
kP256ScalarNumBits = 256,
/* Length of a number modulo the P-256 "n" parameter in words */
kP256ScalarNumWords = kP256ScalarNumBits / (sizeof(uint32_t) * 8),
/* Length of the message digest in bits */
kP256MessageDigestNumBits = 256,
/**
* Length of a secret scalar share (uses extra redundant bits).
*/
kP256SecretScalarNumBits = kP256ScalarNumBits + 64,
/* Length of secret scalar share in bytes. */
kP256SecretScalarNumBytes = kP256SecretScalarNumBits / 8,
/* Length of secret scalar share in words. */
kP256SecretScalarNumWords = kP256SecretScalarNumBytes / sizeof(uint32_t),
};

/**
Expand All @@ -52,8 +58,8 @@ typedef struct ecdsa_p256_signature_t {
* shares d0 and d1 are also both computed modulo n.
*/
typedef struct ecdsa_p256_private_key_t {
uint32_t d0[kP256ScalarNumWords];
uint32_t d1[kP256ScalarNumWords];
uint32_t d0[kP256SecretScalarNumWords];
uint32_t d1[kP256SecretScalarNumWords];
} ecdsa_p256_private_key_t;

/**
Expand Down
24 changes: 22 additions & 2 deletions sw/device/sca/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,28 @@ opentitan_flash_binary(
)

opentitan_flash_binary(
name = "ecc_serial",
srcs = ["ecc_serial.c"],
name = "ecc256_keygen_serial",
srcs = ["ecc256_keygen_serial.c"],
deps = [
"//hw/top_earlgrey/sw/autogen:top_earlgrey",
"//sw/device/lib/base:abs_mmio",
"//sw/device/lib/base:memory",
"//sw/device/lib/crypto/drivers:otbn",
"//sw/device/lib/runtime:ibex",
"//sw/device/lib/runtime:log",
"//sw/device/lib/testing:entropy_testutils",
"//sw/device/lib/testing/test_framework:ottf_ld_silicon_creator_slot_a",
"//sw/device/lib/testing/test_framework:ottf_main",
"//sw/device/sca/lib:prng",
"//sw/device/sca/lib:sca",
"//sw/device/sca/lib:simple_serial",
"//sw/otbn/crypto:p256_key_from_seed_sca",
],
)

opentitan_flash_binary(
name = "ecc256_sign_serial",
srcs = ["ecc256_sign_serial.c"],
deps = [
"//hw/top_earlgrey/sw/autogen:top_earlgrey",
"//sw/device/lib/base:abs_mmio",
Expand Down
Loading