pkg/micro-ecc: support boards without hwrng feature

pr/spi.typo
Wentao Shang 7 years ago
parent 3dac61aa11
commit ba7f1af7ab

@ -1 +0,0 @@
FEATURES_REQUIRED += periph_hwrng

@ -0,0 +1,37 @@
# Micro-ECC for RIOT
This port of Micro-ECC to RIOT is based on the Micro-ECC
[upstream](https://github.com/kmackay/micro-ecc) and adds `hwrng_read`
(provided by RIOT) as the default RNG function if it is available on the target
platform. This port also fixes a minor issue with unused variables in the
upstream code.
# Usage
## Build
Add
```Makefile
USEPKG += micro-ecc
```
to your Makefile.
## Choosing the right API
Before using the Micro-ECC library, you need to check the `Makefile.features`
of your target board to see if `periph_hwrng` is provided.
If it is provided, you may safely use `uECC_make_key` to generate ECDSA key
pairs and call `uECC_sign`/`uECC_verify` to sign/verify the ECDSA signatures.
If not, you cannot use `uECC_make_key` or `uECC_sign` APIs anymore. The ECDSA
keys have to be generated on a platform with HWRNG support (e.g., `native`) and
transferred to your target device. You need to use `uECC_sign_deterministic` to
perform ECDSA deterministic signing (standardized by RFC 6979). You can still
use `uECC_verify` to verify the signatures from both signing APIs.
**WARNING** Calling `uECC_make_key` and `uECC_sign` APIs on platforms without
HWRNG support will lead to compile failure.
Examples of using these uECC APIs can be found in the `test` folder of the
Micro-ECC upstream.

@ -1,6 +1,6 @@
From 00644c7ab9c538dc43065bf785c9f9a3e8315755 Mon Sep 17 00:00:00 2001
From: Frank Holtz <frank-riot2015@holtznet.de>
Date: Sat, 27 Dec 2014 19:57:01 +0100
From 4356878f78b83c32194dc761f6e1e035f90debe5 Mon Sep 17 00:00:00 2001
From: Wentao Shang <wentaoshang@gmail.com>
Date: Wed, 1 Jun 2016 14:57:36 -0700
Subject: [PATCH 1/3] Add RIOT Makefile
---
@ -19,5 +19,5 @@ index 0000000..33c8152
+
+include $(RIOTBASE)/Makefile.base
--
2.5.0
2.7.4

@ -1,41 +1,145 @@
From d2cb5acad29db4c98af1a965a9c0d0ce67729984 Mon Sep 17 00:00:00 2001
From: Mathias Tausig <mathias.tausig@fh-campuswien.ac.at>
Date: Mon, 7 Mar 2016 17:20:49 +0100
From 459241f2801c3b1a0d28c5669527e165ce4b384e Mon Sep 17 00:00:00 2001
From: Wentao Shang <wentaoshang@gmail.com>
Date: Mon, 12 Dec 2016 16:19:34 -0800
Subject: [PATCH 2/3] Include RIOT Hardware RNG interface
---
uECC.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
platform-specific.inc | 4 ++++
uECC.c | 22 ++++++++++++++++++++++
uECC.h | 8 ++++++++
3 files changed, 34 insertions(+)
diff --git a/platform-specific.inc b/platform-specific.inc
index 1bb595a..b13fdbe 100644
--- a/platform-specific.inc
+++ b/platform-specific.inc
@@ -5,6 +5,8 @@
#include "types.h"
+#ifdef FEATURE_PERIPH_HWRNG
+
#if (defined(_WIN32) || defined(_WIN64))
/* Windows */
@@ -64,4 +66,6 @@ static int default_RNG(uint8_t *dest, unsigned size) {
#endif /* platform */
+#endif /* FEATURE_PERIPH_HWRNG */
+
#endif /* _UECC_PLATFORM_SPECIFIC_H_ */
diff --git a/uECC.c b/uECC.c
index f65fe37..662d899 100644
index daa144a..3691fc4 100644
--- a/uECC.c
+++ b/uECC.c
@@ -2,6 +2,7 @@
@@ -2,6 +2,9 @@
#include "uECC.h"
#include "uECC_vli.h"
+#ifdef FEATURE_PERIPH_HWRNG
+#include "periph/hwrng.h"
+#endif
#ifndef uECC_RNG_MAX_TRIES
#define uECC_RNG_MAX_TRIES 64
@@ -170,10 +171,15 @@ static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
@@ -181,9 +184,20 @@ static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
#include "asm_avr.inc"
#endif
+#ifdef FEATURE_PERIPH_HWRNG
+int riot_hwrng(uint8_t *dest, unsigned size) {
+ hwrng_read(dest, size);
+ return 1;
+ hwrng_read(dest, size);
+ return 1;
+}
+#endif
+
+#ifdef FEATURE_PERIPH_HWRNG
#if default_RNG_defined
static uECC_RNG_Function g_rng_function = &default_RNG;
#else
-static uECC_RNG_Function g_rng_function = 0;
+static uECC_RNG_Function g_rng_function = &riot_hwrng;
+#endif
+#else
static uECC_RNG_Function g_rng_function = 0;
#endif
void uECC_set_rng(uECC_RNG_Function rng_function) {
@@ -1001,6 +1015,8 @@ uECC_VLI_API int uECC_generate_random_int(uECC_word_t *random,
return 0;
}
+#ifdef FEATURE_PERIPH_HWRNG
+
int uECC_make_key(uint8_t *public_key,
uint8_t *private_key,
uECC_Curve curve) {
@@ -1031,6 +1047,8 @@ int uECC_make_key(uint8_t *public_key,
return 0;
}
+#endif /* FEATURE_PERIPH_HWRNG */
+
int uECC_shared_secret(const uint8_t *public_key,
const uint8_t *private_key,
uint8_t *secret,
@@ -1303,6 +1321,8 @@ static int uECC_sign_with_k(const uint8_t *private_key,
return 1;
}
+#ifdef FEATURE_PERIPH_HWRNG
+
int uECC_sign(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
@@ -1323,6 +1343,8 @@ int uECC_sign(const uint8_t *private_key,
return 0;
}
+#endif /* FEATURE_PERIPH_HWRNG */
+
/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always
the same size as the hash result size. */
static void HMAC_init(const uECC_HashContext *hash_context, const uint8_t *K) {
diff --git a/uECC.h b/uECC.h
index 9911763..6433143 100644
--- a/uECC.h
+++ b/uECC.h
@@ -144,6 +144,8 @@ Returns the size of a public key for the curve in bytes.
*/
int uECC_curve_public_key_size(uECC_Curve curve);
+#ifdef FEATURE_PERIPH_HWRNG
+
/* uECC_make_key() function.
Create a public/private key pair.
@@ -162,6 +164,8 @@ Returns 1 if the key pair was generated successfully, 0 if an error occurred.
*/
int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve);
+#endif /* FEATURE_PERIPH_HWRNG */
+
/* uECC_shared_secret() function.
Compute a shared secret given your secret key and someone else's public key.
Note: It is recommended that you hash the result of uECC_shared_secret() before using it for
@@ -235,6 +239,8 @@ Returns 1 if the key was computed successfully, 0 if an error occurred.
*/
int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve);
+#ifdef FEATURE_PERIPH_HWRNG
+
/* uECC_sign() function.
Generate an ECDSA signature for a given hash value.
@@ -258,6 +264,8 @@ int uECC_sign(const uint8_t *private_key,
uint8_t *signature,
uECC_Curve curve);
+#endif /* FEATURE_PERIPH_HWRNG */
+
/* uECC_HashContext structure.
This is used to pass in an arbitrary hash function to uECC_sign_deterministic().
The structure will be used for multiple hash computations; each time a new hash
--
2.5.0
2.7.4

@ -0,0 +1,53 @@
From 17cab9daa22fdff9c3bc884024f330445f558550 Mon Sep 17 00:00:00 2001
From: Wentao Shang <wentaoshang@gmail.com>
Date: Wed, 1 Jun 2016 15:00:43 -0700
Subject: [PATCH 3/3] Silence warning of unused variable
---
asm_avr.inc | 2 +-
curve-specific.inc | 2 +-
uECC.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/asm_avr.inc b/asm_avr.inc
index c988040..cd194da 100644
--- a/asm_avr.inc
+++ b/asm_avr.inc
@@ -986,7 +986,7 @@ uECC_VLI_API void uECC_vli_mult(uECC_word_t *result,
"st z+, %[r0] \n\t" /* Store last result byte. */
"eor r1, r1 \n\t" /* fix r1 to be 0 again */
- : "+z" (result), "+x" (left), "+y" (right),
+ : "+z" (r), "+x" (left), "+y" (right),
[r0] "+r" (r0), [r1] "+r" (r1), [r2] "+r" (r2),
[zero] "+r" (zero), [num] "+r" (num_words),
[k] "=&r" (k), [i] "=&r" (i)
diff --git a/curve-specific.inc b/curve-specific.inc
index 0453b21..e17e75c 100644
--- a/curve-specific.inc
+++ b/curve-specific.inc
@@ -563,7 +563,7 @@ static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve) {
}
}
uECC_vli_modInv(f1, e0, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- 1 / e0 */
- uECC_vli_modMult_fast(a, d0, f1, &curve_secp224r1); /* a <-- d0 / e0 */
+ uECC_vli_modMult_fast(a, d0, f1, curve); /* a <-- d0 / e0 */
}
#endif /* uECC_SUPPORT_COMPRESSED_POINT */
diff --git a/uECC.c b/uECC.c
index 3691fc4..2fc6524 100644
--- a/uECC.c
+++ b/uECC.c
@@ -379,7 +379,7 @@ uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result,
#if !asm_mult || (uECC_SQUARE_FUNC && !asm_square) || \
(uECC_SUPPORTS_secp256k1 && (uECC_OPTIMIZATION_LEVEL > 0) && \
- ((uECC_WORD_SIZE == 1) || (uECC_WORD_SIZE == 8)))
+ (uECC_WORD_SIZE == 8))
static void muladd(uECC_word_t a,
uECC_word_t b,
uECC_word_t *r0,
--
2.7.4

@ -1,26 +0,0 @@
From bea5d775b9a6c0587002fdc70d98f3db6900c8ea Mon Sep 17 00:00:00 2001
From: Mathias Tausig <mathias.tausig@fh-campuswien.ac.at>
Date: Mon, 7 Mar 2016 16:28:40 +0100
Subject: [PATCH 3/3] Use the parameter curve instead of the static reference
so curve_secp224r1 (to prevent a compiler warning)
---
curve-specific.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/curve-specific.inc b/curve-specific.inc
index 81f725f..137855e 100644
--- a/curve-specific.inc
+++ b/curve-specific.inc
@@ -563,7 +563,7 @@ static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve) {
}
}
uECC_vli_modInv(f1, e0, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- 1 / e0 */
- uECC_vli_modMult_fast(a, d0, f1, &curve_secp224r1); /* a <-- d0 / e0 */
+ uECC_vli_modMult_fast(a, d0, f1, curve); /* a <-- d0 / e0 */
}
#endif /* uECC_SUPPORT_COMPRESSED_POINT */
--
2.5.0

@ -0,0 +1,10 @@
APPLICATION = pkg_micro-ecc-with-hwrng
include ../Makefile.tests_common
FEATURES_REQUIRED = periph_hwrng
USEPKG += micro-ecc
CFLAGS += -DFEATURE_PERIPH_HWRNG
include $(RIOTBASE)/Makefile.include

@ -0,0 +1,122 @@
/*-
* 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 <frank-riot2015@holtznet.de>
*
*/
#include <stdio.h>
#include <string.h>
#include "uECC.h"
#include "periph/hwrng.h"
#define TESTROUNDS 16
int main(void)
{
printf("micro-ecc compiled!\n");
const struct uECC_Curve_t *curve = uECC_secp256r1();
int i, errorc = 0;
int curve_size = uECC_curve_private_key_size(curve);
int public_key_size = uECC_curve_public_key_size(curve);
uint8_t l_secret1[curve_size];
uint8_t l_secret2[curve_size];
/* reserve space for a SHA-256 hash */
uint8_t l_hash[32] = { 0 };
uint8_t l_sig[public_key_size];
printf("Testing %d random private key pairs and signature using HWRNG\n", TESTROUNDS);
/* initialize hardware random number generator */
hwrng_init();
uint8_t l_private1[curve_size];
uint8_t l_private2[curve_size];
uint8_t l_public1[public_key_size];
uint8_t l_public2[public_key_size];
for (i = 0; i < TESTROUNDS; ++i) {
printf(".");
if (!uECC_make_key(l_public1, l_private1, curve) || !uECC_make_key(l_public2, l_private2, curve)) {
printf("\nRound %d: uECC_make_key() failed", i);
errorc++;
}
else {
if (!uECC_shared_secret(l_public2, l_private1, l_secret1, curve)) {
printf("\nRound %d: shared_secret() failed (1)", i);
errorc++;
}
else {
if (!uECC_shared_secret(l_public1, l_private2, l_secret2, curve)) {
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++;
}
/* copy some bogus data into the hash */
memcpy(l_hash, l_public1, 32);
if ((uECC_sign(l_private1, l_hash, sizeof(l_hash), l_sig, curve)) != 1) {
printf("\nRound %d: uECC_sign() failed", i);
errorc++;
}
else {
if ((uECC_verify(l_public1, l_hash, sizeof(l_hash), l_sig, curve)) != 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;
}
}

@ -1,6 +1,7 @@
APPLICATION = pkg_micro-ecc
include ../Makefile.tests_common
USEMODULE += hashes
USEPKG += micro-ecc
include $(RIOTBASE)/Makefile.include

@ -36,11 +36,36 @@
#include <stdio.h>
#include <string.h>
#include "hashes/sha256.h"
#include "uECC.h"
#include "periph/hwrng.h"
#define TESTROUNDS 16
typedef struct uECC_SHA256_HashContext {
uECC_HashContext uECC;
sha256_context_t ctx;
} uECC_SHA256_HashContext;
static void _init_sha256(const uECC_HashContext *base)
{
uECC_SHA256_HashContext *context = (uECC_SHA256_HashContext*)base;
sha256_init(&context->ctx);
}
static void _update_sha256(const uECC_HashContext *base,
const uint8_t *message,
unsigned message_size)
{
uECC_SHA256_HashContext *context = (uECC_SHA256_HashContext*)base;
sha256_update(&context->ctx, message, message_size);
}
static void _finish_sha256(const uECC_HashContext *base, uint8_t *hash_result)
{
uECC_SHA256_HashContext *context = (uECC_SHA256_HashContext*)base;
sha256_final(&context->ctx, hash_result);
}
int main(void)
{
printf("micro-ecc compiled!\n");
@ -50,11 +75,6 @@ int main(void)
int curve_size = uECC_curve_private_key_size(curve);
int public_key_size = uECC_curve_public_key_size(curve);
uint8_t l_private1[curve_size];
uint8_t l_private2[curve_size];
uint8_t l_public1[public_key_size];
uint8_t l_public2[public_key_size];
uint8_t l_secret1[curve_size];
uint8_t l_secret2[curve_size];
@ -64,47 +84,79 @@ int main(void)
uint8_t l_sig[public_key_size];
/* initialize hardware random number generator */
hwrng_init();
printf("Testing %d random private key pairs and signature\n", TESTROUNDS);
printf("Testing %d random private key pairs and signature without using HWRNG\n", TESTROUNDS);
/* use pre-generated keys for no-HWRNG platforms */
uint8_t l_private1[] = {
0x9b, 0x4c, 0x4b, 0xa0, 0xb7, 0xb1, 0x25, 0x23,
0x9c, 0x09, 0x85, 0x4f, 0x9a, 0x21, 0xb4, 0x14,
0x70, 0xe0, 0xce, 0x21, 0x25, 0x00, 0xa5, 0x62,
0x34, 0xa4, 0x25, 0xf0, 0x0f, 0x00, 0xeb, 0xe7,
};
uint8_t l_public1[] = {
0x54, 0x3e, 0x98, 0xf8, 0x14, 0x55, 0x08, 0x13,
0xb5, 0x1a, 0x1d, 0x02, 0x02, 0xd7, 0x0e, 0xab,
0xa0, 0x98, 0x74, 0x61, 0x91, 0x12, 0x3d, 0x96,
0x50, 0xfa, 0xd5, 0x94, 0xa2, 0x86, 0xa8, 0xb0,
0xd0, 0x7b, 0xda, 0x36, 0xba, 0x8e, 0xd3, 0x9a,
0xa0, 0x16, 0x11, 0x0e, 0x1b, 0x6e, 0x81, 0x13,
0xd7, 0xf4, 0x23, 0xa1, 0xb2, 0x9b, 0xaf, 0xf6,
0x6b, 0xc4, 0x2a, 0xdf, 0xbd, 0xe4, 0x61, 0x5c,
};
uint8_t l_private2[] = {
0xb5, 0x45, 0xaf, 0xa0, 0x2e, 0x5c, 0xa6, 0x17,
0x3b, 0x5a, 0x55, 0x76, 0x67, 0x5d, 0xd4, 0x5e,
0x41, 0x7c, 0x4f, 0x19, 0x9f, 0xb9, 0x75, 0xdc,
0xba, 0x57, 0xc4, 0xa2, 0x26, 0xc6, 0x86, 0x2a,
};
uint8_t l_public2[] = {
0x2e, 0x81, 0x24, 0x3c, 0x44, 0xac, 0x63, 0x13,
0x9b, 0xc1, 0x27, 0xe9, 0x53, 0x3b, 0x0a, 0xe2,
0xf9, 0x22, 0xcd, 0x06, 0xfd, 0x12, 0x17, 0x2e,
0xe5, 0x0e, 0xb5, 0xce, 0x6b, 0x50, 0xe2, 0x44,
0xbf, 0x6b, 0x3f, 0xe8, 0x4e, 0x70, 0xd1, 0x06,
0x85, 0x84, 0xb8, 0xef, 0xe2, 0x25, 0x91, 0x21,
0xf3, 0x46, 0x70, 0xa9, 0x1c, 0x79, 0x19, 0xe3,
0xfb, 0x11, 0x36, 0x64, 0x37, 0x64, 0x58, 0xc9,
};
uint8_t tmp[2 * SHA256_DIGEST_LENGTH + SHA256_INTERNAL_BLOCK_SIZE];
for (i = 0; i < TESTROUNDS; ++i) {
printf(".");
if (!uECC_make_key(l_public1, l_private1, curve) || !uECC_make_key(l_public2, l_private2, curve)) {
printf("\nRound %d: uECC_make_key() failed", i);
if (!uECC_shared_secret(l_public2, l_private1, l_secret1, curve)) {
printf("\nRound %d: shared_secret() failed (1)", i);
errorc++;
}
else {
if (!uECC_shared_secret(l_public2, l_private1, l_secret1, curve)) {
printf("\nRound %d: shared_secret() failed (1)", i);
} else {
if (!uECC_shared_secret(l_public1, l_private2, l_secret2, curve)) {
printf("\nRound: %d: shared_secret() failed (2)", i);
errorc++;
}
else {
if (!uECC_shared_secret(l_public1, l_private2, l_secret2, curve)) {
printf("\nRound: %d: shared_secret() failed (2)", i);
} else {
if (memcmp(l_secret1, l_secret2, sizeof(l_secret1)) != 0) {
printf("\nShared secrets are not identical!\n");
errorc++;
}
else {
if (memcmp(l_secret1, l_secret2, sizeof(l_secret1)) != 0) {
printf("\nShared secrets are not identical!\n");
errorc++;
}
/* copy some bogus data into the hash */
memcpy(l_hash, l_public1, 32);
if ((uECC_sign(l_private1, l_hash, sizeof(l_hash), l_sig, curve)) != 1) {
printf("\nRound %d: uECC_sign() failed", i);
/* copy some bogus data into the hash */
memcpy(l_hash, l_public1, 32);
uECC_SHA256_HashContext ctx;
ctx.uECC.init_hash = &_init_sha256;
ctx.uECC.update_hash = &_update_sha256;
ctx.uECC.finish_hash = &_finish_sha256;
ctx.uECC.block_size = 64;
ctx.uECC.result_size = 32;
ctx.uECC.tmp = tmp;
if (uECC_sign_deterministic(l_private1, l_hash, sizeof(l_hash),
&ctx.uECC, l_sig, curve) != 1) {
printf("\nRound %d: uECC_sign_deterministic() failed", i);
errorc++;
} else {
if (uECC_verify(l_public1, l_hash, sizeof(l_hash), l_sig,
curve) != 1) {
printf("\nRound %d: uECC_verify() failed", i);
errorc++;
}
else {
if ((uECC_verify(l_public1, l_hash, sizeof(l_hash), l_sig, curve)) != 1) {
printf("\nRound %d: uECC_verify() failed", i);
errorc++;
}
}
}
}
}

Loading…
Cancel
Save