aboutsummaryrefslogtreecommitdiffhomepage
path: root/pyecsca/codegen
diff options
context:
space:
mode:
authorJ08nY2020-02-26 14:28:52 +0100
committerJ08nY2020-02-26 14:28:52 +0100
commitf78ff987ac2df62dbd8326ce33ae61c97673710e (patch)
tree9b63026e223254bc3c4e6af164bd3ae3bdcc0404 /pyecsca/codegen
parent3892d994470b181f950703fabf719a9c963d1c20 (diff)
downloadpyecsca-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.inc9
-rw-r--r--pyecsca/codegen/bn/bn.c166
-rw-r--r--pyecsca/codegen/bn/bn.h49
-rw-r--r--pyecsca/codegen/builder.py18
-rw-r--r--pyecsca/codegen/client.py150
-rw-r--r--pyecsca/codegen/fat.h4
-rw-r--r--pyecsca/codegen/hal/Makefile.hal5
-rw-r--r--pyecsca/codegen/hal/host/Makefile.host1
-rw-r--r--pyecsca/codegen/hal/stm32f0/Makefile.stm32f01
-rw-r--r--pyecsca/codegen/hal/stm32f0/stm32f0_hal.c5
-rw-r--r--pyecsca/codegen/hal/stm32f0/stm32f0_hal_lowlevel.c15
-rw-r--r--pyecsca/codegen/hal/stm32f3/Makefile.stm32f37
-rw-r--r--pyecsca/codegen/hal/xmega/Makefile.xmega1
-rw-r--r--pyecsca/codegen/simpleserial/Makefile.simpleserial23
-rw-r--r--pyecsca/codegen/simpleserial/simpleserial.c31
-rw-r--r--pyecsca/codegen/simpleserial/simpleserial.h4
-rw-r--r--pyecsca/codegen/templates/Makefile11
-rw-r--r--pyecsca/codegen/templates/main.c9
-rw-r--r--pyecsca/codegen/templates/mult.c2
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" %}