diff options
| author | J08nY | 2020-02-26 14:28:52 +0100 |
|---|---|---|
| committer | J08nY | 2020-02-26 14:28:52 +0100 |
| commit | f78ff987ac2df62dbd8326ce33ae61c97673710e (patch) | |
| tree | 9b63026e223254bc3c4e6af164bd3ae3bdcc0404 /pyecsca/codegen | |
| parent | 3892d994470b181f950703fabf719a9c963d1c20 (diff) | |
| download | pyecsca-codegen-f78ff987ac2df62dbd8326ce33ae61c97673710e.tar.gz pyecsca-codegen-f78ff987ac2df62dbd8326ce33ae61c97673710e.tar.zst pyecsca-codegen-f78ff987ac2df62dbd8326ce33ae61c97673710e.zip | |
Get stuff to work on STM32F0.
Diffstat (limited to 'pyecsca/codegen')
| -rw-r--r-- | pyecsca/codegen/Makefile.inc | 9 | ||||
| -rw-r--r-- | pyecsca/codegen/bn/bn.c | 166 | ||||
| -rw-r--r-- | pyecsca/codegen/bn/bn.h | 49 | ||||
| -rw-r--r-- | pyecsca/codegen/builder.py | 18 | ||||
| -rw-r--r-- | pyecsca/codegen/client.py | 150 | ||||
| -rw-r--r-- | pyecsca/codegen/fat.h | 4 | ||||
| -rw-r--r-- | pyecsca/codegen/hal/Makefile.hal | 5 | ||||
| -rw-r--r-- | pyecsca/codegen/hal/host/Makefile.host | 1 | ||||
| -rw-r--r-- | pyecsca/codegen/hal/stm32f0/Makefile.stm32f0 | 1 | ||||
| -rw-r--r-- | pyecsca/codegen/hal/stm32f0/stm32f0_hal.c | 5 | ||||
| -rw-r--r-- | pyecsca/codegen/hal/stm32f0/stm32f0_hal_lowlevel.c | 15 | ||||
| -rw-r--r-- | pyecsca/codegen/hal/stm32f3/Makefile.stm32f3 | 7 | ||||
| -rw-r--r-- | pyecsca/codegen/hal/xmega/Makefile.xmega | 1 | ||||
| -rw-r--r-- | pyecsca/codegen/simpleserial/Makefile.simpleserial | 23 | ||||
| -rw-r--r-- | pyecsca/codegen/simpleserial/simpleserial.c | 31 | ||||
| -rw-r--r-- | pyecsca/codegen/simpleserial/simpleserial.h | 4 | ||||
| -rw-r--r-- | pyecsca/codegen/templates/Makefile | 11 | ||||
| -rw-r--r-- | pyecsca/codegen/templates/main.c | 9 | ||||
| -rw-r--r-- | pyecsca/codegen/templates/mult.c | 2 |
19 files changed, 274 insertions, 237 deletions
diff --git a/pyecsca/codegen/Makefile.inc b/pyecsca/codegen/Makefile.inc index 2b809d2..bb8a08d 100644 --- a/pyecsca/codegen/Makefile.inc +++ b/pyecsca/codegen/Makefile.inc @@ -14,6 +14,8 @@ # # make extcoff = Convert ELF to AVR Extended COFF. # +# make strip = Strip the binary. +# # make program = Download the hex file to the device, using avrdude. # Please customize the avrdude settings below first! # @@ -291,7 +293,7 @@ MSG_CREATING_LIBRARY = Creating library: # Define all object files. -OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o) +OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o) # Define all listing files. LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst) @@ -347,6 +349,9 @@ ifeq ($(ELFSIZE),) ELFSIZE = $(SIZE) $(TARGET-PLAT).elf endif +strip: + $(STRIP) $(TARGET-PLAT).elf + sizeafter: build @echo $(MSG_SIZE_AFTER) @$(ELFSIZE) @@ -551,7 +556,7 @@ clean_list : # Listing of phony targets. -.PHONY : all begin finish end sizeafter gccversion \ +.PHONY : all begin finish end strip sizeafter gccversion \ build elf hex eep lss sym coff extcoff \ clean clean_list clean_print clean_objs program debug gdb-config diff --git a/pyecsca/codegen/bn/bn.c b/pyecsca/codegen/bn/bn.c index c953119..930dea7 100644 --- a/pyecsca/codegen/bn/bn.c +++ b/pyecsca/codegen/bn/bn.c @@ -6,8 +6,8 @@ bn_err bn_init(bn_t *bn) { return mp_init(bn); } -void bn_copy(const bn_t *from, bn_t *to) { - mp_copy(from, to); +bn_err bn_copy(const bn_t *from, bn_t *to) { + return mp_copy(from, to); } void bn_clear(bn_t *bn) { @@ -22,95 +22,125 @@ int bn_from_hex(const char *data, bn_t *out) { return mp_read_radix(out, data, 16); } -int bn_from_int(uint64_t value, bn_t *out) { - mp_set_u64(out, value); +int bn_from_int(unsigned int value, bn_t *out) { + if (sizeof(unsigned int) == 8) { + mp_set_u64(out, value); + } else { + mp_set_u32(out, value); + } return MP_OKAY; } -void bn_to_binpad(const bn_t *one, uint8_t *data, size_t size) { +bn_err bn_to_binpad(const bn_t *one, uint8_t *data, size_t size) { size_t ubin_size = mp_ubin_size(one); size_t offset = size - ubin_size; memset(data, 0, offset); - mp_to_ubin(one, data + offset, ubin_size, NULL); + return mp_to_ubin(one, data + offset, ubin_size, NULL); } -void bn_to_bin(const bn_t *one, uint8_t *data) { - mp_to_ubin(one, data, mp_ubin_size(one), NULL); +bn_err bn_to_bin(const bn_t *one, uint8_t *data) { + return mp_to_ubin(one, data, mp_ubin_size(one), NULL); } size_t bn_to_bin_size(const bn_t *one) { return mp_ubin_size(one); } -void bn_rand_mod_sample(bn_t *out, const bn_t *mod) { +bn_err bn_rand_mod_sample(bn_t *out, const bn_t *mod) { int mod_len = bn_bit_length(mod); + bn_err err = BN_OKAY; bn_t mask; bn_init(&mask); - mp_2expt(&mask, mod_len + 1); - mp_decr(&mask); + if ((err = mp_2expt(&mask, mod_len + 1)) != BN_OKAY) { + goto out; + } + if ((err = mp_decr(&mask)) != BN_OKAY) { + goto out; + } while (1) { - mp_rand(out, (mod_len / (sizeof(mp_digit) * 8)) + 1); - mp_and(out, &mask, out); + if ((err = mp_rand(out, (mod_len / (sizeof(mp_digit) * 8)) + 1)) != BN_OKAY) { + break; + } + if ((err = mp_and(out, &mask, out)) != BN_OKAY) { + break; + } if (mp_cmp_mag(out, mod) == MP_LT) { - bn_clear(&mask); break; } } + out: + bn_clear(&mask); + return err; } -void bn_rand_mod_reduce(bn_t *out, const bn_t *mod) { +bn_err bn_rand_mod_reduce(bn_t *out, const bn_t *mod) { int mod_len = bn_bit_length(mod); - mp_rand(out, (mod_len / MP_DIGIT_BIT) + 2); - mp_mod(out, mod, out); + bn_err err = BN_OKAY; + if ((err = mp_rand(out, (mod_len / MP_DIGIT_BIT) + 2)) != BN_OKAY) { + return err; + } + return mp_mod(out, mod, out); } -void bn_mod_add(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out) { - mp_addmod(one, other, mod, out); +bn_err bn_mod_add(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out) { + return mp_addmod(one, other, mod, out); } -void bn_mod_sub(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out) { - mp_submod(one, other, mod, out); +bn_err bn_mod_sub(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out) { + return mp_submod(one, other, mod, out); } -void bn_mod_neg(const bn_t *one, const bn_t *mod, bn_t *out) { - mp_neg(one, out); - mp_mod(out, mod, out); +bn_err bn_mod_neg(const bn_t *one, const bn_t *mod, bn_t *out) { + bn_err err = BN_OKAY; + if ((err = mp_neg(one, out)) != BN_OKAY) { + return err; + } + return mp_mod(out, mod, out); } -void bn_mod_mul(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out) { - mp_mulmod(one, other, mod, out); +bn_err bn_mod_mul(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out) { + return mp_mulmod(one, other, mod, out); } -void bn_mod_sqr(const bn_t *one, const bn_t *mod, bn_t *out) { - mp_sqrmod(one, mod, out); +bn_err bn_mod_sqr(const bn_t *one, const bn_t *mod, bn_t *out) { + return mp_sqrmod(one, mod, out); } -void bn_mod_div(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out) { +bn_err bn_mod_div(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out) { bn_t inv; - mp_init(&inv); - mp_invmod(other, mod, &inv); - mp_mulmod(one, &inv, mod, out); + bn_err err = BN_OKAY; + if ((err = mp_init(&inv)) != BN_OKAY) { + return err; + } + if ((err = mp_invmod(other, mod, &inv)) != BN_OKAY) { + goto out; + } + if ((err = mp_mulmod(one, &inv, mod, out)) != BN_OKAY) { + goto out; + } +out: mp_clear(&inv); + return err; } -void bn_mod_inv(const bn_t *one, const bn_t *mod, bn_t *out) { - mp_invmod(one, mod, out); +bn_err bn_mod_inv(const bn_t *one, const bn_t *mod, bn_t *out) { + return mp_invmod(one, mod, out); } -void bn_mod_pow(const bn_t *one, const bn_t *exp, const bn_t *mod, bn_t *out) { - mp_exptmod(one, exp, mod, out); +bn_err bn_mod_pow(const bn_t *one, const bn_t *exp, const bn_t *mod, bn_t *out) { + return mp_exptmod(one, exp, mod, out); } -void bn_mod(const bn_t *one, const bn_t *mod, bn_t *out) { - mp_mod(one, mod, out); +bn_err bn_mod(const bn_t *one, const bn_t *mod, bn_t *out) { + return mp_mod(one, mod, out); } -void bn_lsh(const bn_t *one, int amount, bn_t *out) { - mp_mul_2d(one, amount, out); +bn_err bn_lsh(const bn_t *one, int amount, bn_t *out) { + return mp_mul_2d(one, amount, out); } -void bn_rsh(const bn_t *one, int amount, bn_t *out) { - mp_div_2d(one, amount, out, NULL); +bn_err bn_rsh(const bn_t *one, int amount, bn_t *out) { + return mp_div_2d(one, amount, out, NULL); } bool bn_eq(const bn_t *one, const bn_t *other) { @@ -146,44 +176,70 @@ wnaf_t *bn_wnaf(const bn_t *bn, int w) { if (w > 8 || w < 2) { return NULL; } - wnaf_t *result = malloc(sizeof(wnaf_t)); - result->w = w; - result->length = bn_bit_length(bn) + 1; - result->data = calloc(result->length, sizeof(int8_t)); + wnaf_t *result = NULL; bn_t half_width; - bn_init(&half_width); + if (mp_init(&half_width) != BN_OKAY) { + return NULL; + } bn_from_int(1, &half_width); bn_lsh(&half_width, w - 1, &half_width); bn_t full_width; - bn_init(&full_width); + if (mp_init(&full_width) != BN_OKAY) { + goto exit_full_width; + } bn_from_int(1, &full_width); bn_lsh(&full_width, w, &full_width); - bn_t k; bn_init(&k); + bn_t k; + if (mp_init(&k) != BN_OKAY) { + goto exit_k; + } bn_copy(bn, &k); - bn_t val_mod; bn_init(&val_mod); + bn_t val_mod; + if (mp_init(&val_mod) != BN_OKAY) { + goto exit_val_mod; + } + + result = malloc(sizeof(wnaf_t)); + result->w = w; + result->length = bn_bit_length(bn) + 1; + result->data = calloc(result->length, sizeof(int8_t)); size_t i = 0; - while (!bn_is_0(&k) && !(bn_get_sign(&k) == MP_NEG)) { + while (!bn_is_0(&k) && !(bn_get_sign(&k) == BN_NEG)) { if (bn_get_bit(&k, 0) == 1) { bn_mod(&k, &full_width, &val_mod); if (mp_cmp(&val_mod, &half_width) == MP_GT) { - mp_sub(&val_mod, &full_width, &val_mod); + if (mp_sub(&val_mod, &full_width, &val_mod) != BN_OKAY) { + free(result->data); + free(result); + result = NULL; + break; + } } int8_t val = (int8_t) mp_get_i32(&val_mod); result->data[i++] = val; - mp_sub(&k, &val_mod, &k); + if (mp_sub(&k, &val_mod, &k) != BN_OKAY) { + free(result->data); + free(result); + result = NULL; + break; + } } else { result->data[i++] = 0; } bn_rsh(&k, 1, &k); } bn_clear(&val_mod); - bn_clear(&half_width); - bn_clear(&full_width); + +exit_val_mod: bn_clear(&k); +exit_k: + bn_clear(&full_width); +exit_full_width: + bn_clear(&half_width); return result; } diff --git a/pyecsca/codegen/bn/bn.h b/pyecsca/codegen/bn/bn.h index e323170..02b3e93 100644 --- a/pyecsca/codegen/bn/bn.h +++ b/pyecsca/codegen/bn/bn.h @@ -7,6 +7,21 @@ #define bn_err mp_err #define bn_sign mp_sign +#define BN_OKAY MP_OKAY /* no error */ +#define BN_ERR MP_ERR /* unknown error */ +#define BN_MEM MP_MEM /* out of mem */ +#define BN_VAL MP_VAL /* invalid input */ +#define BN_ITER MP_ITER /* maximum iterations reached */ +#define BN_BUF MP_BUF /* buffer overflow, supplied buffer too small */ +#define BN_OVF MP_OVF /* mp_int overflow, too many digits */ + +#define BN_ZPOS MP_ZPOS +#define BN_NEG MP_NEG + +#define BN_LT MP_LT /* less than */ +#define BN_EQ MP_EQ /* equal */ +#define BN_GT MP_GT /* greater than */ + typedef struct { char name; bn_t value; @@ -19,19 +34,19 @@ typedef struct { } wnaf_t; bn_err bn_init(bn_t *bn); -void bn_copy(const bn_t *from, bn_t *to); +bn_err bn_copy(const bn_t *from, bn_t *to); void bn_clear(bn_t *bn); int bn_from_bin(const uint8_t *data, size_t size, bn_t *out); int bn_from_hex(const char *data, bn_t *out); -int bn_from_int(uint64_t value, bn_t *out); +int bn_from_int(unsigned int value, bn_t *out); -void bn_to_binpad(const bn_t *one, uint8_t *data, size_t size); -void bn_to_bin(const bn_t *one, uint8_t *data); +bn_err bn_to_binpad(const bn_t *one, uint8_t *data, size_t size); +bn_err bn_to_bin(const bn_t *one, uint8_t *data); size_t bn_to_bin_size(const bn_t *one); -void bn_rand_mod_sample(bn_t *out, const bn_t *mod); -void bn_rand_mod_reduce(bn_t *out, const bn_t *mod); +bn_err bn_rand_mod_sample(bn_t *out, const bn_t *mod); +bn_err bn_rand_mod_reduce(bn_t *out, const bn_t *mod); #if MOD_RAND == MOD_RAND_SAMPLE #define bn_rand_mod bn_rand_mod_sample @@ -39,18 +54,18 @@ void bn_rand_mod_reduce(bn_t *out, const bn_t *mod); #define bn_rand_mod bn_rand_mod_reduce #endif -void bn_mod_add(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out); -void bn_mod_sub(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out); -void bn_mod_neg(const bn_t *one, const bn_t *mod, bn_t *out); -void bn_mod_mul(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out); -void bn_mod_sqr(const bn_t *one, const bn_t *mod, bn_t *out); -void bn_mod_div(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out); -void bn_mod_inv(const bn_t *one, const bn_t *mod, bn_t *out); -void bn_mod_pow(const bn_t *one, const bn_t *exp, const bn_t *mod, bn_t *out); -void bn_mod(const bn_t *one, const bn_t *mod, bn_t *out); +bn_err bn_mod_add(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out); +bn_err bn_mod_sub(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out); +bn_err bn_mod_neg(const bn_t *one, const bn_t *mod, bn_t *out); +bn_err bn_mod_mul(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out); +bn_err bn_mod_sqr(const bn_t *one, const bn_t *mod, bn_t *out); +bn_err bn_mod_div(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out); +bn_err bn_mod_inv(const bn_t *one, const bn_t *mod, bn_t *out); +bn_err bn_mod_pow(const bn_t *one, const bn_t *exp, const bn_t *mod, bn_t *out); +bn_err bn_mod(const bn_t *one, const bn_t *mod, bn_t *out); -void bn_lsh(const bn_t *one, int amount, bn_t *out); -void bn_rsh(const bn_t *one, int amount, bn_t *out); +bn_err bn_lsh(const bn_t *one, int amount, bn_t *out); +bn_err bn_rsh(const bn_t *one, int amount, bn_t *out); bool bn_eq(const bn_t *one, const bn_t *other); bool bn_is_0(const bn_t *one); diff --git a/pyecsca/codegen/builder.py b/pyecsca/codegen/builder.py index bf8e6be..1919c09 100644 --- a/pyecsca/codegen/builder.py +++ b/pyecsca/codegen/builder.py @@ -10,11 +10,11 @@ import click from public import public from pyecsca.ec.configuration import Multiplication, Squaring, Reduction, HashType, RandomMod from pyecsca.ec.coordinates import CoordinateModel -from pyecsca.ec.formula import (Formula, AdditionFormula) -from pyecsca.ec.model import (CurveModel) -from pyecsca.ec.mult import (ScalarMultiplier) +from pyecsca.ec.formula import Formula, AdditionFormula +from pyecsca.ec.model import CurveModel +from pyecsca.ec.mult import ScalarMultiplier -from pyecsca.codegen.render import render +from .render import render from .common import Platform, DeviceConfiguration, MULTIPLIERS, wrap_enum, get_model, get_coords @@ -150,12 +150,10 @@ def build_impl(ctx, platform, hash, rand, mul, sqr, red, keygen, ecdh, ecdsa, st platform, keygen, ecdh, ecdsa) dir, elf_file, hex_file = render(config) - res = subprocess.run(["make"], cwd=dir, capture_output=True) - if verbose >= 1: - click.echo(res.stdout.decode()) + subprocess.run(["make"], cwd=dir, capture_output=not verbose) if strip: - subprocess.run(["strip", elf_file], cwd=dir) + subprocess.run(["make", "strip"], cwd=dir, capture_output=not verbose) full_elf_path = path.join(dir, elf_file) full_hex_path = path.join(dir, hex_file) shutil.copy(full_elf_path, outdir) @@ -231,14 +229,14 @@ def list_impl(model: Optional[CurveModel], coords: Optional[CoordinateModel], subsequent_indent="\t")) -@main.command() +@main.command("flash") @click.option("--platform", envvar="PLATFORM", required=True, type=click.Choice(Platform.names()), callback=wrap_enum(Platform), help="The platform to flash.") @click.argument("dir") @public -def flash(platform, dir): # pragma: no cover +def flash_impl(platform, dir): # pragma: no cover """This command flashes a chip through the ChipWhisperer framework with the built implementation. \b diff --git a/pyecsca/codegen/client.py b/pyecsca/codegen/client.py index cd4cff7..04f47d3 100644 --- a/pyecsca/codegen/client.py +++ b/pyecsca/codegen/client.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 -import subprocess from binascii import hexlify, unhexlify from os import path -from subprocess import Popen +from time import time, sleep from typing import Mapping, Union, Optional, Tuple +import chipwhisperer as cw import click +from chipwhisperer.capture.api.programmers import STM32FProgrammer, XMEGAProgrammer +from chipwhisperer.capture.targets import SimpleSerial from public import public from pyecsca.ec.coordinates import CoordinateModel, AffineCoordinateModel from pyecsca.ec.curves import get_params @@ -13,7 +15,8 @@ from pyecsca.ec.mod import Mod from pyecsca.ec.model import CurveModel from pyecsca.ec.params import DomainParameters from pyecsca.ec.point import Point, InfinityPoint -from pyecsca.sca import SerialTarget +from pyecsca.sca.target import (SimpleSerialTarget, ChipWhispererTarget, BinaryTarget, Flashable, + SimpleSerialMessage as SMessage) from .common import wrap_enum, Platform, get_model, get_coords @@ -121,15 +124,21 @@ def cmd_debug() -> str: return "d" -class ImplTarget(SerialTarget): +class ImplTarget(SimpleSerialTarget): model: CurveModel coords: CoordinateModel seed: Optional[bytes] params: Optional[DomainParameters] privkey: Optional[int] pubkey: Optional[Point] + timeout: int - def __init__(self, model: CurveModel, coords: CoordinateModel): + def __init__(self, model: CurveModel, coords: CoordinateModel, **kwargs): + super().__init__(**kwargs) + if "timeout" in kwargs: + self.timeout = kwargs["timeout"] + else: + self.timeout = 1000 self.model = model self.coords = coords self.seed = None @@ -138,20 +147,17 @@ class ImplTarget(SerialTarget): self.pubkey = None def init_prng(self, seed: bytes) -> None: - self.write(cmd_init_prng(seed).encode()) - self.read(1) + self.send_cmd(SMessage.from_raw(cmd_init_prng(seed)), self.timeout) self.seed = seed def set_params(self, params: DomainParameters) -> None: - self.write(cmd_set_params(params).encode()) - self.read(1) + self.send_cmd(SMessage.from_raw(cmd_set_params(params)), self.timeout) self.params = params def generate(self) -> Tuple[int, Point]: - self.write(cmd_generate().encode()) - priv = self.read(1).decode()[1:-1] - pub = self.read(1).decode()[1:-1] - self.read(1) + resp = self.send_cmd(SMessage.from_raw(cmd_generate()), self.timeout) + priv = resp["s"].data + pub = resp["w"].data self.privkey = int(priv, 16) pub_len = len(pub) x = int(pub[:pub_len // 2], 16) @@ -161,88 +167,62 @@ class ImplTarget(SerialTarget): return self.privkey, self.pubkey def set_privkey(self, privkey: int) -> None: - self.write(cmd_set_privkey(privkey).encode()) - self.read(1) + self.send_cmd(SMessage.from_raw(cmd_set_privkey(privkey)), self.timeout) self.privkey = privkey def set_pubkey(self, pubkey: Point) -> None: - self.write(cmd_set_pubkey(pubkey).encode()) - self.read(1) + self.send_cmd(SMessage.from_raw(cmd_set_pubkey(pubkey)), self.timeout) self.pubkey = pubkey def scalar_mult(self, scalar: int) -> Point: - self.write(cmd_scalar_mult(scalar).encode()) - result = self.read(1)[1:-1] + resp = self.send_cmd(SMessage.from_raw(cmd_scalar_mult(scalar)), self.timeout) + result = resp["w"] plen = ((self.params.curve.prime.bit_length() + 7) // 8) * 2 - self.read(1) - params = {var: Mod(int(result[i * plen:(i + 1) * plen], 16), self.params.curve.prime) for + params = {var: Mod(int(result.data[i * plen:(i + 1) * plen], 16), self.params.curve.prime) for i, var in enumerate(self.coords.variables)} return Point(self.coords, **params) def ecdh(self, other_pubkey: Point) -> bytes: - self.write(cmd_ecdh(other_pubkey).encode()) - result = self.read(1) - self.read(1) - return unhexlify(result[1:-1]) + resp = self.send_cmd(SMessage.from_raw(cmd_ecdh(other_pubkey)), self.timeout) + result = resp["r"] + return unhexlify(result.data) def ecdsa_sign(self, data: bytes) -> bytes: - self.write(cmd_ecdsa_sign(data).encode()) - signature = self.read(1) - self.read(1) - return unhexlify(signature[1:-1]) + resp = self.send_cmd(SMessage.from_raw(cmd_ecdsa_sign(data)), self.timeout) + signature = resp["s"] + return unhexlify(signature.data) def ecdsa_verify(self, data: bytes, signature: bytes) -> bool: - self.write(cmd_ecdsa_verify(data, signature).encode()) - result = self.read(1) - self.read(1) - return unhexlify(result[1:-1])[0] == 1 + resp = self.send_cmd(SMessage.from_raw(cmd_ecdsa_verify(data, signature)), self.timeout) + result = resp["v"] + return unhexlify(result.data)[0] == 1 def debug(self) -> Tuple[str, str]: - self.write(cmd_debug().encode()) - resp = self.read(1) - self.read(1) - model, coords = unhexlify(resp[1:-1]).decode().split(",") + resp = self.send_cmd(SMessage.from_raw(cmd_debug()), self.timeout)["d"] + model, coords = unhexlify(resp.data).decode().split(",") return model, coords @public -class BinaryTarget(ImplTarget): - binary: str - process: Optional[Popen] - debug_output: bool - - def __init__(self, binary: str, model: CurveModel, coords: CoordinateModel, debug_output: bool = False): - super().__init__(model, coords) - self.binary = binary - self.debug_output = debug_output - - def connect(self): - self.process = Popen([self.binary], stdin=subprocess.PIPE, stdout=subprocess.PIPE, - text=True, bufsize=1) +class DeviceTarget(ImplTarget, ChipWhispererTarget): - def write(self, data: bytes): - if self.process is None: + def __init__(self, model: CurveModel, coords: CoordinateModel, platform: Platform): + scope = cw.scope() + scope.default_setup() + target = SimpleSerial() + if platform in (Platform.STM32F0, Platform.STM32F3): + programmer = STM32FProgrammer + elif platform == Platform.XMEGA: + programmer = XMEGAProgrammer + else: raise ValueError - if self.debug_output: - print(">>", data.decode()) - self.process.stdin.write(data.decode() + "\n") - self.process.stdin.flush() + super().__init__(model, coords, target=target, scope=scope, programmer=programmer) - def read(self, timeout: int) -> bytes: - if self.process is None: - raise ValueError - read = self.process.stdout.readline().encode() - if self.debug_output: - print("<<", read.decode(), end="") - return read +@public +class HostTarget(ImplTarget, BinaryTarget): - def disconnect(self): - if self.process is None: - return - self.process.stdin.close() - self.process.stdout.close() - self.process.terminate() - self.process.wait() + def __init__(self, model: CurveModel, coords: CoordinateModel, **kwargs): + super().__init__(model, coords, **kwargs) @click.group(context_settings={"help_option_names": ["-h", "--help"]}) @@ -250,7 +230,9 @@ class BinaryTarget(ImplTarget): type=click.Choice(Platform.names()), callback=wrap_enum(Platform), help="The target platform to use.") -@click.option("--binary", help="For HOST target only. The binary to run.") +@click.option("--fw", + help="The firmware. Either a .hex file for a device platform or .elf for HOST platform.", + required=True) @click.argument("model", required=True, type=click.Choice(["shortw", "montgom", "edwards", "twisted"]), callback=get_model) @@ -259,29 +241,19 @@ class BinaryTarget(ImplTarget): @click.version_option() @click.pass_context @public -def main(ctx, platform, binary, model, coords): +def main(ctx, platform, fw, model, coords): """ A tool for communicating with built and flashed ECC implementations. """ ctx.ensure_object(dict) + ctx.obj["fw"] = fw if platform != Platform.HOST: - from pyecsca.sca.target import has_chipwhisperer - if not has_chipwhisperer: - click.secho("ChipWhisperer not installed, targets require it.", fg="red", err=True) - raise click.Abort - from pyecsca.sca.target import SimpleSerialTarget - import chipwhisperer as cw - from chipwhisperer.capture.targets.simpleserial_readers.cwlite import \ - SimpleSerial_ChipWhispererLite - ser = SimpleSerial_ChipWhispererLite() - scope = cw.scope() - scope.default_setup() - ctx.obj["target"] = SimpleSerialTarget(ser, scope) + ctx.obj["target"] = DeviceTarget(model, coords, platform) else: - if binary is None or not path.isfile(binary): + if fw is None or not path.isfile(fw): click.secho("Binary is required if the target is the host.", fg="red", err=True) raise click.Abort - ctx.obj["target"] = BinaryTarget(binary, model, coords) + ctx.obj["target"] = HostTarget(model, coords, binary=fw) def get_curve(ctx: click.Context, param, value: Optional[str]) -> DomainParameters: @@ -294,12 +266,16 @@ def get_curve(ctx: click.Context, param, value: Optional[str]) -> DomainParamete @main.command("gen") +@click.option("--timeout", type=int, default=15000) @click.argument("curve", required=True, callback=get_curve) @click.pass_context @public -def generate(ctx: click.Context, curve): +def generate(ctx: click.Context, timeout, curve): ctx.ensure_object(dict) target: ImplTarget = ctx.obj["target"] + if isinstance(target, Flashable): + target.flash(ctx.obj["fw"]) + target.timeout = timeout target.connect() target.set_params(curve) click.echo(target.generate()) diff --git a/pyecsca/codegen/fat.h b/pyecsca/codegen/fat.h index b1c094b..0032c91 100644 --- a/pyecsca/codegen/fat.h +++ b/pyecsca/codegen/fat.h @@ -1,8 +1,10 @@ #ifndef FAT_H_ #define FAT_H_ +#include <stdlib.h> + typedef struct { - size_t len; + uint32_t len; void *value; } fat_t; diff --git a/pyecsca/codegen/hal/Makefile.hal b/pyecsca/codegen/hal/Makefile.hal index 3c81d00..186b96e 100644 --- a/pyecsca/codegen/hal/Makefile.hal +++ b/pyecsca/codegen/hal/Makefile.hal @@ -9,7 +9,7 @@ VPATH += :$(HALPATH) #Default stuff EXTRAINCDIRS += $(HALPATH) -PLATFORM_LIST = CW308_STM32F0 CW308_STM32F3 CW308_XMEGA +PLATFORM_LIST = CW308_STM32F0 CW308_STM32F3 CW308_XMEGA HOST define KNOWN_PLATFORMS @@ -27,9 +27,6 @@ endef PLTNAME = Unknown Platform -ifeq ($(DEMO),SECCAN) - CFLAGS += -DSECCAN -endif ifeq ($(MCU_CLK), INT) CFLAGS += -DUSE_INTERNAL_CLK diff --git a/pyecsca/codegen/hal/host/Makefile.host b/pyecsca/codegen/hal/host/Makefile.host index 933c899..1192a78 100644 --- a/pyecsca/codegen/hal/host/Makefile.host +++ b/pyecsca/codegen/hal/host/Makefile.host @@ -5,6 +5,7 @@ EXTRAINCDIRS += $(HALPATH)/host CC = gcc OBJCOPY = objcopy OBJDUMP = objdump +STRIP = strip SIZE = size AR = ar rcs NM = nm
\ No newline at end of file diff --git a/pyecsca/codegen/hal/stm32f0/Makefile.stm32f0 b/pyecsca/codegen/hal/stm32f0/Makefile.stm32f0 index c95ce3d..231eafd 100644 --- a/pyecsca/codegen/hal/stm32f0/Makefile.stm32f0 +++ b/pyecsca/codegen/hal/stm32f0/Makefile.stm32f0 @@ -9,6 +9,7 @@ MCU_FLAGS = -mcpu=cortex-m0 CC = arm-none-eabi-gcc OBJCOPY = arm-none-eabi-objcopy OBJDUMP = arm-none-eabi-objdump +STRIP = arm-none-eabi-strip SIZE = arm-none-eabi-size AR = arm-none-eabi-ar rcs NM = arm-none-eabi-nm diff --git a/pyecsca/codegen/hal/stm32f0/stm32f0_hal.c b/pyecsca/codegen/hal/stm32f0/stm32f0_hal.c index 7f09627..ee70dd7 100644 --- a/pyecsca/codegen/hal/stm32f0/stm32f0_hal.c +++ b/pyecsca/codegen/hal/stm32f0/stm32f0_hal.c @@ -23,11 +23,10 @@ void platform_init(void) HAL_RCC_OscConfig(&RCC_OscInitStruct); RCC_ClkInitTypeDef RCC_ClkInitStruct; - RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1); RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; uint32_t flash_latency = 0; HAL_RCC_ClockConfig(&RCC_ClkInitStruct, flash_latency); #else @@ -61,7 +60,7 @@ void init_uart(void) __HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_USART1_CONFIG(RCC_USART1CLKSOURCE_SYSCLK); UartHandle.Instance = USART1; - UartHandle.Init.BaudRate = 38400; + UartHandle.Init.BaudRate = 115200; UartHandle.Init.WordLength = UART_WORDLENGTH_8B; UartHandle.Init.StopBits = UART_STOPBITS_1; UartHandle.Init.Parity = UART_PARITY_NONE; diff --git a/pyecsca/codegen/hal/stm32f0/stm32f0_hal_lowlevel.c b/pyecsca/codegen/hal/stm32f0/stm32f0_hal_lowlevel.c index 554f261..f3870da 100644 --- a/pyecsca/codegen/hal/stm32f0/stm32f0_hal_lowlevel.c +++ b/pyecsca/codegen/hal/stm32f0/stm32f0_hal_lowlevel.c @@ -54,7 +54,7 @@ uint32_t HAL_GetTick(void) #define UART_CR1_FIELDS ((uint32_t)(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | \ USART_CR1_TE | USART_CR1_RE | USART_CR1_OVER8)) /*!< UART or USART CR1 fields of parameters set by UART_SetConfig API */ -uint32_t SystemCoreClock = 8000000; +uint32_t SystemCoreClock = 7372800; uint32_t HAL_RCC_GetSysClockFreq(void) @@ -68,19 +68,6 @@ uint32_t HAL_RCC_GetPCLK1Freq(void) } /** - * @brief Returns the PCLK2 frequency - * @note Each time PCLK2 changes, this function must be called to update the - * right PCLK2 value. Otherwise, any configuration based on this function will be incorrect. - * @retval PCLK2 frequency - */ -uint32_t HAL_RCC_GetPCLK2Freq(void) -{ - /* Get HCLK source and Compute PCLK2 frequency ---------------------------*/ - //return (HAL_RCC_GetHCLKFreq()>> APBPrescTable[(RCC->CFGR & RCC_CFGR_PPRE2)>> POSITION_VAL(RCC_CFGR_PPRE2)]); - return 7372800; -} - -/** * @brief Initializes the RCC Oscillators according to the specified parameters in the * RCC_OscInitTypeDef. * @param RCC_OscInitStruct pointer to an RCC_OscInitTypeDef structure that diff --git a/pyecsca/codegen/hal/stm32f3/Makefile.stm32f3 b/pyecsca/codegen/hal/stm32f3/Makefile.stm32f3 index 5d84aa4..3b9579b 100644 --- a/pyecsca/codegen/hal/stm32f3/Makefile.stm32f3 +++ b/pyecsca/codegen/hal/stm32f3/Makefile.stm32f3 @@ -13,6 +13,7 @@ MCU_FLAGS = -mcpu=cortex-m4 CC = arm-none-eabi-gcc OBJCOPY = arm-none-eabi-objcopy OBJDUMP = arm-none-eabi-objdump +STRIP = arm-none-eabi-strip SIZE = arm-none-eabi-size AR = arm-none-eabi-ar rcs NM = arm-none-eabi-nm @@ -20,9 +21,9 @@ NM = arm-none-eabi-nm #Output Format = Binary for this target FORMAT = binary -CFLAGS += -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fmessage-length=0 -ffunction-sections -CPPFLAGS += -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fmessage-length=0 -ffunction-sections -ASFLAGS += -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fmessage-length=0 -ffunction-sections +CFLAGS += -mthumb -mfloat-abi=soft -mfpu=fpv4-sp-d16 -fmessage-length=0 -ffunction-sections +CPPFLAGS += -mthumb -mfloat-abi=soft -mfpu=fpv4-sp-d16 -fmessage-length=0 -ffunction-sections +ASFLAGS += -mthumb -mfloat-abi=soft -mfpu=fpv4-sp-d16 -fmessage-length=0 -ffunction-sections CDEFS += -DSTM32F303xC -DSTM32F3 -DSTM32 -DDEBUG CPPDEFS += -DSTM32F303xC -DSTM32F3 -DSTM32 -DDEBUG diff --git a/pyecsca/codegen/hal/xmega/Makefile.xmega b/pyecsca/codegen/hal/xmega/Makefile.xmega index 8b7950e..743fca3 100644 --- a/pyecsca/codegen/hal/xmega/Makefile.xmega +++ b/pyecsca/codegen/hal/xmega/Makefile.xmega @@ -8,6 +8,7 @@ CFLAGS += -fpack-struct CC = avr-gcc OBJCOPY = avr-objcopy OBJDUMP = avr-objdump +STRIP = avr-strip SIZE = avr-size AR = avr-ar rcs NM = avr-nm
\ No newline at end of file diff --git a/pyecsca/codegen/simpleserial/Makefile.simpleserial b/pyecsca/codegen/simpleserial/Makefile.simpleserial index 47a0d1e..1cb855b 100644 --- a/pyecsca/codegen/simpleserial/Makefile.simpleserial +++ b/pyecsca/codegen/simpleserial/Makefile.simpleserial @@ -1,26 +1,3 @@ SRC += simpleserial.c VPATH += :$(FIRMWAREPATH)/simpleserial/ EXTRAINCDIRS += $(FIRMWAREPATH)/simpleserial/ - -SS_VERS_ALLOWED = SS_VER_1_0 SS_VER_1_1 - -define SS_VERS_LIST - - +---------+--------------+ - | Version | SS_VER value | - +---------+--------------+ - | V1.0 | SS_VER_1_0 | - | V1.1 | SS_VER_1_1 | - +---------+--------------+ - -endef - -# SimpleSerial version -# To change this, define SS_VER before including this file -ifeq ($(SS_VER),) - SS_VER = SS_VER_1_1 -else ifeq ($(filter $(SS_VER),$(SS_VERS_ALLOWED)),) - $(error Invalid SimpleSerial version: $(SS_VER); allowed verions: $(SS_VERS_LIST)) -endif - -CDEFS += -DSS_VER=$(SS_VER)
\ No newline at end of file diff --git a/pyecsca/codegen/simpleserial/simpleserial.c b/pyecsca/codegen/simpleserial/simpleserial.c index 8ca20c4..9a8be4c 100644 --- a/pyecsca/codegen/simpleserial/simpleserial.c +++ b/pyecsca/codegen/simpleserial/simpleserial.c @@ -7,23 +7,20 @@ typedef struct ss_cmd { char c; - unsigned int len; + uint32_t len; uint8_t (*fp)(uint8_t*, uint16_t); } ss_cmd; static ss_cmd commands[MAX_SS_CMDS]; static int num_commands = 0; -#define SS_VER_1_0 0 -#define SS_VER_1_1 1 - static char hex_lookup[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; -int hex_decode(int len, char* ascii_buf, uint8_t* data_buf) +int hex_decode(uint32_t len, char* ascii_buf, uint8_t* data_buf) { if (len % 2 != 0) return 1; @@ -69,7 +66,7 @@ void simpleserial_init() simpleserial_addcmd('v', 0, check_version); } -int simpleserial_addcmd(char c, unsigned int len, uint8_t (*fp)(uint8_t*, uint16_t)) +int simpleserial_addcmd(char c, uint32_t len, uint8_t (*fp)(uint8_t*, uint16_t)) { if(num_commands >= MAX_SS_CMDS) return 1; @@ -109,7 +106,7 @@ int simpleserial_get(void) return 1; // Receive characters until we fill the ASCII buffer - int i = 0; + uint32_t i = 0; for(; i < 2*commands[cmd].len; i++) { c = getch(); @@ -120,6 +117,21 @@ int simpleserial_get(void) ascii_buf[i] = c; } +// uint8_t ik[4]; +// ik[3] = (uint8_t) i & 0xff; +// ik[2] = (uint8_t) (i>>8) & 0xff; +// ik[1] = (uint8_t) (i>>16) & 0xff; +// ik[0] = (uint8_t) (i>>24) & 0xff; +// uint8_t ic[4]; +// ic[3] = (uint8_t) c & 0xff; +// ic[2] = (uint8_t) (c>>8) & 0xff; +// ic[1] = (uint8_t) (c>>16) & 0xff; +// ic[0] = (uint8_t) (c>>24) & 0xff; +// if (commands[cmd].c == 'd') { +// simpleserial_put('o', 4, ik); +// simpleserial_put('c', 4, ic); +// } + // ASCII buffer is full: convert to bytes // Check for illegal characters here @@ -130,14 +142,11 @@ int simpleserial_get(void) uint8_t ret[1]; ret[0] = commands[cmd].fp(data_buf, i/2); - // Acknowledge (if version is 1.1) -#if SS_VER == SS_VER_1_1 simpleserial_put('z', 1, ret); -#endif return 1; } -void simpleserial_put(char c, int size, uint8_t* output) +void simpleserial_put(char c, uint32_t size, uint8_t* output) { // Write first character putch(c); diff --git a/pyecsca/codegen/simpleserial/simpleserial.h b/pyecsca/codegen/simpleserial/simpleserial.h index a5dff81..224cc3b 100644 --- a/pyecsca/codegen/simpleserial/simpleserial.h +++ b/pyecsca/codegen/simpleserial/simpleserial.h @@ -27,7 +27,7 @@ void simpleserial_init(void); // - Returns 1 if either of these fail; otherwise 0 // - The callback function returns a number in [0x00, 0xFF] as a status code; // in protocol v1.1, this status code is returned through a "z" message -int simpleserial_addcmd(char c, unsigned int len, uint8_t (*fp)(uint8_t*, uint16_t)); +int simpleserial_addcmd(char c, uint32_t len, uint8_t (*fp)(uint8_t*, uint16_t)); // Attempt to process a command // If a full string is found, the relevant callback function is called @@ -40,6 +40,6 @@ int simpleserial_get(void); // Write some data to the serial port // Prepends the character c to the start of the line // Example: simpleserial_put('r', 16, ciphertext) -void simpleserial_put(char c, int size, uint8_t* output); +void simpleserial_put(char c, uint32_t size, uint8_t* output); #endif // SIMPLESERIAL_H diff --git a/pyecsca/codegen/templates/Makefile b/pyecsca/codegen/templates/Makefile index 5d842c4..be1ab08 100644 --- a/pyecsca/codegen/templates/Makefile +++ b/pyecsca/codegen/templates/Makefile @@ -12,6 +12,17 @@ EXTRAINCDIRS += hash prng asn1 bn gen tommath LDFLAGS += tommath/libtommath-{{ platform }}.a +ifeq ($(PLATFORM),CW308_XMEGA) + +else ifeq ($(PLATFORM),CW308_STM32F0) +CFLAGS += -DMP_NO_DEV_URANDOM -DMP_32BIT -DMP_LOW_MEM -DMP_PREC=10 +else ifeq ($(PLATFORM),CW308_STM32F3) +CFLAGS += -DMP_NO_DEV_URANDOM -DMP_32BIT -DMP_LOW_MEM -DMP_PREC=10 +else ifeq ($(PLATFORM),HOST) +CFLAGS += -DMP_NO_DEV_URANDOM -DMP_LOW_MEM -DMP_PREC=10 +else + $(error Invalid or empty PLATFORM: $(PLATFORM). Known platforms: $(KNOWN_PLATFORMS)) +endif include simpleserial/Makefile.simpleserial FIRMWAREPATH = . diff --git a/pyecsca/codegen/templates/main.c b/pyecsca/codegen/templates/main.c index b0f81f1..467a417 100644 --- a/pyecsca/codegen/templates/main.c +++ b/pyecsca/codegen/templates/main.c @@ -420,17 +420,20 @@ static uint8_t cmd_debug(uint8_t *data, uint16_t len) { char *debug_string = "{{ ','.join((model.shortname, coords.name))}}"; size_t debug_len = strlen(debug_string); + simpleserial_put('r', len, data); + simpleserial_put('d', debug_len, (uint8_t *) debug_string); return 0; } int main(void) { - platform_init(); - prng_init(); - formulas_init(); + platform_init(); init_uart(); trigger_setup(); + prng_init(); + formulas_init(); + curve = curve_new(); pubkey = point_new(); bn_init(&privkey); diff --git a/pyecsca/codegen/templates/mult.c b/pyecsca/codegen/templates/mult.c index 896fdd8..f611e95 100644 --- a/pyecsca/codegen/templates/mult.c +++ b/pyecsca/codegen/templates/mult.c @@ -1,6 +1,4 @@ -#include "mult.h" - {%- if isinstance(scalarmult, LTRMultiplier) -%} {% include "mult_ltr.c" %} |
