diff --git a/pkg/micro-ecc/.gitignore b/pkg/micro-ecc/.gitignore new file mode 100644 index 000000000..41c895140 --- /dev/null +++ b/pkg/micro-ecc/.gitignore @@ -0,0 +1 @@ +micro-ecc diff --git a/pkg/micro-ecc/0001-Add-RIOT-Makefile.patch b/pkg/micro-ecc/0001-Add-RIOT-Makefile.patch new file mode 100644 index 000000000..ef6f00c42 --- /dev/null +++ b/pkg/micro-ecc/0001-Add-RIOT-Makefile.patch @@ -0,0 +1,23 @@ +From d6c1cb4244c72a8fa7d5a8550c8193700cd0de03 Mon Sep 17 00:00:00 2001 +From: Frank Holtz +Date: Sat, 27 Dec 2014 19:57:01 +0100 +Subject: [PATCH 1/2] Add RIOT Makefile + +--- + Makefile | 4 ++++ + 1 file changed, 4 insertions(+) + create mode 100644 Makefile + +diff --git a/Makefile b/Makefile +new file mode 100644 +index 0000000..33c8152 +--- /dev/null ++++ b/Makefile +@@ -0,0 +1,4 @@ ++MODULE:=$(shell basename $(CURDIR)) ++INCLUDES += -I$(RIOTBASE) -I$(RIOTBASE)/sys/include -I$(RIOTBASE)/core/include -I$(RIOTBASE)/drivers/include -I$(RIOTCPU)/$(CPU)/include ++ ++include $(RIOTBASE)/Makefile.base +-- +1.8.3.1 + diff --git a/pkg/micro-ecc/0002-Include-RIOT-Hardware-RNG-interface.patch b/pkg/micro-ecc/0002-Include-RIOT-Hardware-RNG-interface.patch new file mode 100644 index 000000000..9c470e028 --- /dev/null +++ b/pkg/micro-ecc/0002-Include-RIOT-Hardware-RNG-interface.patch @@ -0,0 +1,220 @@ +From 60ac2261d89d1a483bef4676c1e9b16fec8830d1 Mon Sep 17 00:00:00 2001 +From: Frank Holtz +Date: Sat, 17 Jan 2015 18:41:14 +0100 +Subject: [PATCH 2/2] Include RIOT Hardware RNG interface + +--- + uECC.c | 99 +++++++++++------------------------------------------------------- + uECC.h | 28 +------------------ + 2 files changed, 17 insertions(+), 110 deletions(-) + +diff --git a/uECC.c b/uECC.c +index aded242..5fe3389 100644 +--- a/uECC.c ++++ b/uECC.c +@@ -322,85 +322,6 @@ static void vli_square(uECC_word_t *p_result, uECC_word_t *p_left); + static void vli_modSquare_fast(uECC_word_t *p_result, uECC_word_t *p_left); + #endif + +-#if (defined(_WIN32) || defined(_WIN64)) +-/* Windows */ +- +-#define WIN32_LEAN_AND_MEAN +-#include +-#include +- +-static int default_RNG(uint8_t *p_dest, unsigned p_size) +-{ +- HCRYPTPROV l_prov; +- if(!CryptAcquireContext(&l_prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) +- { +- return 0; +- } +- +- CryptGenRandom(l_prov, p_size, (BYTE *)p_dest); +- CryptReleaseContext(l_prov, 0); +- +- return 1; +-} +- +-#elif defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \ +- (defined(__APPLE__) && defined(__MACH__)) || defined(uECC_POSIX) +- +-/* Some POSIX-like system with /dev/urandom or /dev/random. */ +-#include +-#include +-#include +- +-#ifndef O_CLOEXEC +- #define O_CLOEXEC 0 +-#endif +- +-static int default_RNG(uint8_t *p_dest, unsigned p_size) +-{ +- int l_fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); +- if(l_fd == -1) +- { +- l_fd = open("/dev/random", O_RDONLY | O_CLOEXEC); +- if(l_fd == -1) +- { +- return 0; +- } +- } +- +- char *l_ptr = (char *)p_dest; +- size_t l_left = p_size; +- while(l_left > 0) +- { +- int l_read = read(l_fd, l_ptr, l_left); +- if(l_read <= 0) +- { // read failed +- close(l_fd); +- return 0; +- } +- l_left -= l_read; +- l_ptr += l_read; +- } +- +- close(l_fd); +- return 1; +-} +- +-#else /* Some other platform */ +- +-static int default_RNG(uint8_t *p_dest, unsigned p_size) +-{ +- return 0; +-} +- +-#endif +- +-static uECC_RNG_Function g_rng = &default_RNG; +- +-void uECC_set_rng(uECC_RNG_Function p_rng) +-{ +- g_rng = p_rng; +-} +- + #ifdef __GNUC__ /* Only support GCC inline asm for now */ + #if (uECC_ASM && (uECC_PLATFORM == uECC_avr)) + #include "asm_avr.inc" +@@ -1779,11 +1700,15 @@ int uECC_make_key(uint8_t p_publicKey[uECC_BYTES*2], uint8_t p_privateKey[uECC_B + uECC_word_t l_private[uECC_WORDS]; + uECC_word_t l_tries = 0; + ++ /* power on rng */ ++ random_poweron(); ++ + do + { + repeat: +- if(!g_rng((uint8_t *)l_private, sizeof(l_private)) || (l_tries++ >= MAX_TRIES)) ++ if(random_read((char *)l_private, sizeof(l_private))!=sizeof(l_private) || (l_tries++ >= MAX_TRIES)) + { ++ random_poweroff(); + return 0; + } + if(vli_isZero(l_private)) +@@ -1805,6 +1730,7 @@ int uECC_make_key(uint8_t p_publicKey[uECC_BYTES*2], uint8_t p_privateKey[uECC_B + vli_nativeToBytes(p_privateKey, l_private); + vli_nativeToBytes(p_publicKey, l_public.x); + vli_nativeToBytes(p_publicKey + uECC_BYTES, l_public.y); ++ random_poweroff(); + return 1; + } + +@@ -1814,7 +1740,9 @@ int uECC_shared_secret(const uint8_t p_publicKey[uECC_BYTES*2], const uint8_t p_ + uECC_word_t l_private[uECC_WORDS]; + uECC_word_t l_random[uECC_WORDS]; + +- g_rng((uint8_t *)l_random, sizeof(l_random)); ++ random_poweron(); ++ random_read((char *)l_random, sizeof(l_random)); ++ random_poweroff(); + + vli_bytesToNative(l_private, p_privateKey); + vli_bytesToNative(l_public.x, p_publicKey); +@@ -2152,11 +2080,14 @@ int uECC_sign(const uint8_t p_privateKey[uECC_BYTES], const uint8_t p_hash[uECC_ + EccPoint p; + uECC_word_t l_tries = 0; + ++ random_poweron(); ++ + do + { + repeat: +- if(!g_rng((uint8_t *)k, sizeof(k)) || (l_tries++ >= MAX_TRIES)) ++ if(random_read((char *)k, sizeof(k))!=sizeof(k) || (l_tries++ >= MAX_TRIES)) + { ++ random_poweroff(); + return 0; + } + +@@ -2203,8 +2134,9 @@ int uECC_sign(const uint8_t p_privateKey[uECC_BYTES], const uint8_t p_hash[uECC_ + l_tries = 0; + do + { +- if(!g_rng((uint8_t *)l_tmp, sizeof(l_tmp)) || (l_tries++ >= MAX_TRIES)) ++ if(random_read((char *)l_tmp, sizeof(l_tmp))!=sizeof(l_tmp) || (l_tries++ >= MAX_TRIES)) + { ++ random_poweroff(); + return 0; + } + } while(vli_isZero(l_tmp)); +@@ -2234,6 +2166,7 @@ int uECC_sign(const uint8_t p_privateKey[uECC_BYTES], const uint8_t p_hash[uECC_ + #endif + vli_nativeToBytes(p_signature + uECC_BYTES, s); + ++ random_poweroff(); + return 1; + } + +diff --git a/uECC.h b/uECC.h +index 2c9927b..27a2e47 100644 +--- a/uECC.h ++++ b/uECC.h +@@ -4,6 +4,7 @@ + #define _MICRO_ECC_H_ + + #include ++#include "periph/random.h" + + /* Platform selection options. + If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros. +@@ -57,33 +58,6 @@ extern "C" + { + #endif + +-/* uECC_RNG_Function type +-The RNG function should fill p_size random bytes into p_dest. It should return 1 if +-p_dest was filled with random data, or 0 if the random data could not be generated. +-The filled-in values should be either truly random, or from a cryptographically-secure PRNG. +- +-A correctly functioning RNG function must be set (using uECC_set_rng()) before calling +-uECC_make_key() or uECC_sign(). +- +-A correct RNG function is set by default when building for Windows, Linux, or OS X. +-If you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom, +-you can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined +-RNG function; you must provide your own. +-*/ +-typedef int (*uECC_RNG_Function)(uint8_t *p_dest, unsigned p_size); +- +-/* uECC_set_rng() function. +-Set the function that will be used to generate random bytes. The RNG function should +-return 1 if the random data was generated, or 0 if the random data could not be generated. +- +-On platforms where there is no predefined RNG function (eg embedded platforms), this must +-be called before uECC_make_key() or uECC_sign() are used. +- +-Inputs: +- p_rng - The function that will be used to generate random bytes. +-*/ +-void uECC_set_rng(uECC_RNG_Function p_rng); +- + /* uECC_make_key() function. + Create a public/private key pair. + +-- +1.8.3.1 + diff --git a/pkg/micro-ecc/Makefile b/pkg/micro-ecc/Makefile new file mode 100644 index 000000000..961ca7782 --- /dev/null +++ b/pkg/micro-ecc/Makefile @@ -0,0 +1,43 @@ +PKG_NAME=micro-ecc +PKG_URL=https://github.com/kmackay/micro-ecc.git +PKG_VERSION=f3d46f0fb77b42535168a17b4b51802beb124a32 + +ifneq ($(RIOTBOARD),) +include $(RIOTBOARD)/$(BOARD)/Makefile.include +endif + +ifneq ($(RIOTBASE),) +INCLUDES += -I$(RIOTBASE)/sys/include -I$(RIOTBASE)/sys/net/include \ + -I$(RIOTBASE)/sys/posix/include -I$(RIOTBASE)/sys/posix/pnet/include +endif + +MODULE:=$(shell basename $(CURDIR)) + +.PHONY: all clean patch reset + +all: patch + make -C $(CURDIR)/$(PKG_NAME) + make $(BINDIR)$(MODULE).a + +patch: $(CURDIR)/$(PKG_NAME)/Makefile + +$(CURDIR)/$(PKG_NAME)/Makefile: $(CURDIR)/$(PKG_NAME) + $(foreach patch,$(shell ls [0-9][0-9][0-9][0-9]*.patch),cd "$<" && git am "../$(patch)" || { git am --abort; exit 1; };) + touch $(CURDIR)/$(PKG_NAME)/Makefile + +$(CURDIR)/$(PKG_NAME): + test -d $(PKG_NAME) || \ + git clone $(PKG_URL) $@ && \ + cd $@ && git reset --hard $(PKG_VERSION) + +clean:: + # Reset package to checkout state. + cd $(CURDIR)/$(PKG_NAME) || true && \ + git clean -x -f && \ + git reset --hard $(PKG_VERSION) + +distclean:: + rm -rf $(CURDIR)/$(PKG_NAME) + +#$(BINDIR)$(MODULE).a: $(BINDIR)micro-ecc_*.a +# mkdir -p $(BINDIR)$(MODULE); cd $(BINDIR)$(MODULE); for var in $?; do ar -x $$var; done; ar -r -c -s $(BINDIR)$(MODULE).a *.o diff --git a/pkg/micro-ecc/Makefile.include b/pkg/micro-ecc/Makefile.include new file mode 100644 index 000000000..4fc603e35 --- /dev/null +++ b/pkg/micro-ecc/Makefile.include @@ -0,0 +1 @@ +INCLUDES += -I $(RIOTBASE)/pkg/micro-ecc/micro-ecc diff --git a/tests/pkg_micro-ecc/Makefile b/tests/pkg_micro-ecc/Makefile new file mode 100644 index 000000000..6f9dd7a87 --- /dev/null +++ b/tests/pkg_micro-ecc/Makefile @@ -0,0 +1,7 @@ +APPLICATION = micro-ecc +include ../Makefile.tests_common + +FEATURES_REQUIRED = periph_random +USEPKG += micro-ecc + +include $(RIOTBASE)/Makefile.include diff --git a/tests/pkg_micro-ecc/main.c b/tests/pkg_micro-ecc/main.c new file mode 100644 index 000000000..fe433a13f --- /dev/null +++ b/tests/pkg_micro-ecc/main.c @@ -0,0 +1,118 @@ +/*- + * Copyright 2014 Kenneth MacKay + * Copyright 2014 Frank Holtz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + */ + +/** + * @file + * @brief Check if the micro-ecc builds and working + * + * @author Frank Holtz + * + */ + +#include +#include +#include "uECC.h" +#include "periph/random.h" + +#define TESTROUNDS 16 + +int main(void) +{ + printf("micro-ecc compiled!\n"); + + int i, errorc = 0; + + uint8_t l_private1[uECC_BYTES]; + uint8_t l_private2[uECC_BYTES]; + + uint8_t l_public1[uECC_BYTES * 2]; + uint8_t l_public2[uECC_BYTES * 2]; + + uint8_t l_secret1[uECC_BYTES]; + uint8_t l_secret2[uECC_BYTES]; + + uint8_t l_hash[uECC_BYTES]; + + uint8_t l_sig[uECC_BYTES * 2]; + + /* initialize hardware random number generator */ + random_init(); + /* power off RNG to save energy */ + random_poweroff(); + + printf("Testing %d random private key pairs and signature\n", TESTROUNDS); + + for (i = 0; i < TESTROUNDS; ++i) { + printf("."); + + if (!uECC_make_key(l_public1, l_private1) || !uECC_make_key(l_public2, l_private2)) { + printf("\nRound %d: uECC_make_key() failed", i); + errorc++; + } + else { + if (!uECC_shared_secret(l_public2, l_private1, l_secret1)) { + printf("\nRound %d: shared_secret() failed (1)", i); + errorc++; + } + else { + if (!uECC_shared_secret(l_public1, l_private2, l_secret2)) { + printf("\nRound: %d: shared_secret() failed (2)", i); + errorc++; + } + else { + if (memcmp(l_secret1, l_secret2, sizeof(l_secret1)) != 0) { + printf("\nShared secrets are not identical!\n"); + errorc++; + } + + memcpy(l_hash, l_public1, uECC_BYTES); + + if ((uECC_sign(l_private1, l_hash, l_sig)) != 1) { + printf("\nRound %d: uECC_sign() failed", i); + errorc++; + } + else { + if ((uECC_verify(l_public1, l_hash, l_sig)) != 1) { + printf("\nRound %d: uECC_verify() failed", i); + errorc++; + } + } + } + } + } + } + + printf(" done with %d error(s)\n", errorc); + + if (errorc == 0) { + return 0; + } + else { + return 1; + } +}