Skip to content
This repository was archived by the owner on Mar 5, 2024. It is now read-only.

Commit e6cffb8

Browse files
author
Constanza Heath
committed
Significant speedup on EC-DSA verfification: Accelerates ECC point multiplication and modular reduction by removing constant-time bottlenecks (not needed in this process as verification only deals with public information). Slightly increased code size (same lines of expected result for other ECC optmizations).
Fix to make ECC Key Generation FIPS 186-4 compliant - Previous version used a simplified method Additional check in ecc_valid_public_key - Also check that the public key is not the generator of P-256 Fix in double_bytes function - Previous version used by Colin O'Flynn to show power analysis threat Change in HMAC API: - API now ensures it erases secrets before exiting Added Authors file - Clarifies contacts for responsible disclosure Signed-off-by: Constanza Heath <[email protected]>
1 parent d04e95d commit e6cffb8

17 files changed

+137
-59
lines changed

AUTHORS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Open Source Maintainer: Constanza Heath <[email protected]>
2+
Author: Rafael Misoczki <[email protected]>

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ include config.mk
1010

1111
all:
1212
$(MAKE) -C lib
13+
ifeq ($(ENABLE_TESTS),true)
1314
$(MAKE) -C tests
15+
endif
1416

1517
clean:
1618
$(MAKE) -C lib clean

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.2.5
1+
0.2.6

config.mk

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
CC:=gcc
1010
CFLAGS:=-Os -std=c99 -Wall -Wextra -D_ISOC99_SOURCE -MMD -I../lib/include/ -I../lib/source/ -I../tests/include/
1111
vpath %.c ../lib/source/
12+
ENABLE_TESTS=true
1213

1314
# override MinGW built-in recipe
1415
%.o: %.c
@@ -18,4 +19,11 @@ ifeq ($(OS),Windows_NT)
1819
DOTEXE:=.exe
1920
endif
2021

22+
# DO NOT EDIT THIS:
23+
ifeq ($(ENABLE_TESTS), true)
24+
CFLAGS += -DENABLE_TESTS
25+
else
26+
CFLAGS += -DDISABLE_TESTS
27+
endif
28+
2129
################################################################################

documentation/tinycrypt.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ Specific Remarks
132132
memory comparison function (such as compare_constant_time
133133
function provided in lib/utils.c).
134134

135+
* The tc_hmac_final function, responsible for computing the message tag,
136+
cleans the state context before exiting. Thus, applications do not need to
137+
clean the TCHmacState_t ctx after calling tc_hmac_final.
138+
135139
* HMAC-PRNG:
136140

137141
* Before using HMAC-PRNG, you *must* find an entropy source to produce a seed.

lib/include/tinycrypt/constants.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@ extern "C" {
4747
#define NULL ((void *)0)
4848
#endif
4949

50-
#ifndef bool
51-
enum {false, true} bool;
52-
#endif
53-
5450
#define TC_CRYPTO_SUCCESS 1
5551
#define TC_CRYPTO_FAIL 0
5652

lib/include/tinycrypt/ecc.h

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,12 @@
7979
extern "C" {
8080
#endif
8181

82+
/* Word size (4 bytes considering 32-bits architectures) */
83+
#define WORD_SIZE 4
8284
/* Number of words of 32 bits to represent an element of the the curve p-256: */
8385
#define NUM_ECC_DIGITS 8
8486
/* Number of bytes to represent an element of the the curve p-256: */
85-
#define NUM_ECC_BYTES (4*NUM_ECC_DIGITS)
87+
#define NUM_ECC_BYTES (WORD_SIZE*NUM_ECC_DIGITS)
8688

8789
/* struct to represent a point of the curve (uses X and Y coordinates): */
8890
typedef struct EccPoint {
@@ -218,6 +220,8 @@ void vli_modSquare_fast(uint32_t *p_result, uint32_t *p_left);
218220
* @param p_right IN -- buffer p_right in (p_left * p_right) % p_mod.
219221
* @param p_mod IN -- module.
220222
* @param p_barrett IN -- used for Barrett reduction.
223+
* @note Side-channel countermeasure: algorithm strengthened against timing
224+
* attack.
221225
*/
222226
void vli_modMult(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right,
223227
uint32_t *p_mod, uint32_t *p_barrett);
@@ -229,10 +233,27 @@ void vli_modMult(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right,
229233
* @param p_input IN -- buffer p_input in (1/p_intput) % p_mod.
230234
* @param p_mod IN -- module.
231235
* @param p_barrett IN -- used for Barrett reduction.
236+
* @note Side-channel countermeasure: algorithm strengthened against timing
237+
* attack.
232238
*/
233239
void vli_modInv(uint32_t *p_result, uint32_t *p_input,
234240
uint32_t *p_mod, uint32_t *p_barrett);
235241

242+
/*
243+
* @brief modular reduction based on Barrett's method
244+
* @param p_result OUT -- p_product % p_mod.
245+
* @param p_product IN -- buffer p_product in (p_product % p_mod).
246+
* @param p_mod IN -- buffer p_mod in (p_product % p_mod).
247+
* @param p_barrett -- used for Barrett reduction.
248+
* @note Side-channel countermeasure: algorithm strengthened against timing
249+
* attack.
250+
*/
251+
void vli_mmod_barrett(
252+
uint32_t *p_result,
253+
uint32_t *p_product,
254+
uint32_t *p_mod,
255+
uint32_t *p_barrett);
256+
236257
/*
237258
* @brief Check if a point is zero.
238259
* @return Returns 1 if p_point is the point at infinity, 0 otherwise.
@@ -271,10 +292,26 @@ void EccPoint_add(EccPointJacobi *P1, EccPointJacobi *P2);
271292
* @param p_result OUT -- Product of p_point by p_scalar.
272293
* @param p_point IN -- Elliptic curve point
273294
* @param p_scalar IN -- Scalar integer
295+
* @note Side-channel countermeasure: algorithm strengthened against timing
296+
* attack.
274297
*/
275-
void EccPoint_mult(EccPointJacobi *p_result, EccPoint *p_point,
298+
void EccPoint_mult_safe(EccPointJacobi *p_result, EccPoint *p_point,
276299
uint32_t *p_scalar);
277300

301+
/*
302+
* @brief Fast elliptic curve scalar multiplication with result in Jacobi
303+
* coordinates
304+
* @note non constant time
305+
* @param p_result OUT -- Product of p_point by p_scalar.
306+
* @param p_point IN -- Elliptic curve point
307+
* @param p_scalar IN -- Scalar integer
308+
* @note algorithm NOT strengthened against timing attack.
309+
*/
310+
void EccPoint_mult_unsafe(
311+
EccPointJacobi *p_result,
312+
EccPoint *p_point,
313+
uint32_t *p_scalar);
314+
278315
/*
279316
* @brief Convert an integer in standard octet representation to native format.
280317
* @return returns TC_CRYPTO_SUCCESS (1)

lib/include/tinycrypt/ecc_dh.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ extern "C" {
8080

8181
/**
8282
* @brief Create a public/private key pair.
83-
* @return returns TC_CRYPTO_SUCCESS (1) if the key pair was generated successfully
83+
* @return returns TC_CRYPTO_SUCCESS (1) if key pair was generated successfully
8484
* returns TC_CRYPTO_FAIL (0) if:
8585
* the private key is 0
8686
*
@@ -90,13 +90,15 @@ extern "C" {
9090
*
9191
* @note You must use a new non-predictable random number to generate each
9292
* new key pair.
93+
* @note p_random must have NUM_ECC_DIGITS*2 bits of entropy to eliminate
94+
* bias in keys.
9395
*
9496
* @note side-channel countermeasure: algorithm strengthened against timing
9597
* attack.
9698
*/
9799
int32_t ecc_make_key(EccPoint *p_publicKey,
98100
uint32_t p_privateKey[NUM_ECC_DIGITS],
99-
uint32_t p_random[NUM_ECC_DIGITS]);
101+
uint32_t p_random[2 * NUM_ECC_DIGITS]);
100102

101103
/**
102104
* @brief Determine whether or not a given point is on the chosen elliptic curve
@@ -106,15 +108,16 @@ int32_t ecc_make_key(EccPoint *p_publicKey,
106108
* returns -2 if: curve_p - p_publicKey->x != 1 or
107109
* curve_p - p_publicKey->y != 1
108110
* returns -3 if: y^2 != x^3 + ax + b
109-
111+
* returns -4 if: public key is the group generator
112+
*
110113
* @param p_publicKey IN -- The point to be checked.
111114
*/
112115
int32_t ecc_valid_public_key(EccPoint *p_publicKey);
113116

114117
/**
115118
* @brief Compute a shared secret given your secret key and someone else's
116119
* public key.
117-
* @return returns TC_CRYPTO_SUCCESS (1) if the shared secret was computed successfully
120+
* @return returns TC_CRYPTO_SUCCESS (1) if the secret was computed successfully
118121
* returns TC_CRYPTO_FAIL (0) otherwise
119122
*
120123
* @param p_secret OUT -- The shared secret value.
@@ -125,12 +128,9 @@ int32_t ecc_valid_public_key(EccPoint *p_publicKey);
125128
* attacks. The random multiplier should probably be different for each
126129
* invocation of ecdh_shared_secret().
127130
*
128-
* @note It is recommended that you hash the result of ecdh_shared_secret before
129-
* using it for symmetric encryption or HMAC. If you do not hash the shared
130-
* secret, you must call ecc_valid_public_key() to verify that the remote side's
131-
* public key is valid. If this is not done, an attacker could create a public
132-
* key that would cause your use of the shared secret to leak information about
133-
* the private key.
131+
* @warning It is recommended to use the output of ecdh_shared_secret() as the
132+
* input of a recommended Key Derivation Function (see NIST SP 800-108) in
133+
* order to produce a symmetric key.
134134
*/
135135
int32_t ecdh_shared_secret(uint32_t p_secret[NUM_ECC_DIGITS], EccPoint *p_publicKey,
136136
uint32_t p_privateKey[NUM_ECC_DIGITS]);

lib/include/tinycrypt/hmac.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ int32_t tc_hmac_update(TCHmacState_t ctx,
125125
* ctx == NULL or
126126
* key == NULL or
127127
* taglen != TC_SHA256_DIGEST_SIZE
128+
* @note 'ctx' is erased before exiting (this must never be changed/removed).
128129
* @note Assumes the tag bufer is at least sizeof(hmac_tag_size(state)) bytes
129130
* state has been initialized by tc_hmac_init
130131
* @param tag IN/OUT -- buffer to receive computed HMAC tag

lib/source/ecc.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,9 @@ static void vli_clear(uint32_t *p_vli)
9797
}
9898
}
9999

100-
/* Returns nonzero if bit p_bit of p_vli is set. */
100+
/* Returns nonzero if bit p_bit of p_vli is set.
101+
* It is assumed that the value provided in 'bit' is within
102+
* the boundaries of the word-array 'p_vli'.*/
101103
static uint32_t vli_testBit(uint32_t *p_vli, uint32_t p_bit)
102104
{
103105
return (p_vli[p_bit / 32] & (1 << (p_bit % 32)));
@@ -235,7 +237,7 @@ static void vli_square(uint32_t *p_result, uint32_t *p_left)
235237
}
236238

237239
/* Computes p_result = p_product % curve_p using Barrett reduction. */
238-
static void vli_mmod_barrett(uint32_t *p_result, uint32_t *p_product,
240+
void vli_mmod_barrett(uint32_t *p_result, uint32_t *p_product,
239241
uint32_t *p_mod, uint32_t *p_barrett)
240242
{
241243
uint32_t i;
@@ -547,7 +549,7 @@ void EccPoint_add(EccPointJacobi *P1, EccPointJacobi *P2)
547549
*
548550
* p_result = p_scalar * p_point.
549551
*/
550-
void EccPoint_mult(EccPointJacobi *p_result, EccPoint *p_point, uint32_t *p_scalar)
552+
void EccPoint_mult_safe(EccPointJacobi *p_result, EccPoint *p_point, uint32_t *p_scalar)
551553
{
552554

553555
int32_t i;
@@ -568,6 +570,25 @@ void EccPoint_mult(EccPointJacobi *p_result, EccPoint *p_point, uint32_t *p_scal
568570
}
569571
}
570572

573+
/* Ellptic curve scalar multiplication with result in Jacobi coordinates */
574+
/* p_result = p_scalar * p_point */
575+
void EccPoint_mult_unsafe(EccPointJacobi *p_result, EccPoint *p_point, uint32_t *p_scalar)
576+
{
577+
int i;
578+
EccPointJacobi p_point_jacobi;
579+
EccPoint_fromAffine(p_result, p_point);
580+
EccPoint_fromAffine(&p_point_jacobi, p_point);
581+
582+
for(i = vli_numBits(p_scalar) - 2; i >= 0; i--)
583+
{
584+
EccPoint_double(p_result);
585+
if (vli_testBit(p_scalar, i))
586+
{
587+
EccPoint_add(p_result, &p_point_jacobi);
588+
}
589+
}
590+
}
591+
571592
/* -------- Conversions between big endian and little endian: -------- */
572593

573594
void ecc_bytes2native(uint32_t p_native[NUM_ECC_DIGITS],

lib/source/ecc_dh.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,31 +35,36 @@
3535
extern uint32_t curve_p[NUM_ECC_DIGITS];
3636
extern uint32_t curve_b[NUM_ECC_DIGITS];
3737
extern uint32_t curve_n[NUM_ECC_DIGITS];
38+
extern uint32_t curve_pb[NUM_ECC_DIGITS + 1];
3839
extern EccPoint curve_G;
3940

4041
int32_t ecc_make_key(EccPoint *p_publicKey, uint32_t p_privateKey[NUM_ECC_DIGITS],
41-
uint32_t p_random[NUM_ECC_DIGITS])
42+
uint32_t p_random[NUM_ECC_DIGITS * 2])
4243
{
44+
// computing modular reduction of p_random (see FIPS 186.4 B.4.1):
45+
vli_mmod_barrett(p_privateKey, p_random, curve_p, curve_pb);
4346

4447
/* Make sure the private key is in the range [1, n-1].
4548
* For the supported curve, n is always large enough
4649
* that we only need to subtract once at most.
4750
*/
4851
uint32_t p_tmp[NUM_ECC_DIGITS];
49-
50-
vli_set(p_privateKey, p_random);
5152
vli_sub(p_tmp, p_privateKey, curve_n, NUM_ECC_DIGITS);
5253

5354
vli_cond_set(p_privateKey, p_privateKey, p_tmp,
5455
vli_cmp(curve_n, p_privateKey, NUM_ECC_DIGITS) == 1);
5556

57+
/* erasing temporary buffer used to store secret: */
58+
for (uint32_t i = 0; i < NUM_ECC_DIGITS; i++)
59+
p_tmp[i] = 0;
60+
5661
if (vli_isZero(p_privateKey)) {
5762
return TC_CRYPTO_FAIL; /* The private key cannot be 0 (mod p). */
5863
}
5964

6065
EccPointJacobi P;
6166

62-
EccPoint_mult(&P, &curve_G, p_privateKey);
67+
EccPoint_mult_safe(&P, &curve_G, p_privateKey);
6368
EccPoint_toAffine(p_publicKey, &P);
6469

6570
return TC_CRYPTO_SUCCESS;
@@ -102,6 +107,10 @@ int32_t ecc_valid_public_key(EccPoint *p_publicKey)
102107
return -3;
103108
}
104109

110+
if (vli_cmp(p_publicKey->x, curve_G.x, NUM_ECC_DIGITS) == 0 &&
111+
vli_cmp(p_publicKey->y, curve_G.y, NUM_ECC_DIGITS) == 0 )
112+
return -4;
113+
105114
return 0;
106115
}
107116

@@ -112,7 +121,7 @@ int32_t ecdh_shared_secret(uint32_t p_secret[NUM_ECC_DIGITS],
112121
EccPoint p_point;
113122
EccPointJacobi P;
114123

115-
EccPoint_mult(&P, p_publicKey, p_privateKey);
124+
EccPoint_mult_safe(&P, p_publicKey, p_privateKey);
116125
if (EccPointJacobi_isZero(&P)) {
117126
return TC_CRYPTO_FAIL;
118127
}

lib/source/ecc_dsa.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ int32_t ecdsa_sign(uint32_t r[NUM_ECC_DIGITS], uint32_t s[NUM_ECC_DIGITS],
5656
vli_cond_set(k, k, tmp, vli_cmp(curve_n, k, NUM_ECC_DIGITS) == 1);
5757

5858
/* tmp = k * G */
59-
EccPoint_mult(&P, &curve_G, k);
59+
EccPoint_mult_safe(&P, &curve_G, k);
6060
EccPoint_toAffine(&p_point, &P);
6161

6262
/* r = x1 (mod n) */
@@ -101,17 +101,15 @@ int32_t ecdsa_verify(EccPoint *p_publicKey, uint32_t p_hash[NUM_ECC_DIGITS],
101101
vli_modMult(u2, r, z, curve_n, curve_nb); /* u2 = r/s */
102102

103103
/* calculate P = u1*G + u2*Q */
104-
EccPoint_mult(&P, &curve_G, u1);
105-
EccPoint_mult(&R, p_publicKey, u2);
104+
EccPoint_mult_unsafe(&P, &curve_G, u1);
105+
EccPoint_mult_unsafe(&R, p_publicKey, u2);
106106
EccPoint_add(&P, &R);
107107
EccPoint_toAffine(&p_point, &P);
108108

109109
/* Accept only if P.x == r. */
110-
vli_cond_set(
111-
p_point.x,
112-
p_point.x,
113-
z,
114-
vli_sub(z, p_point.x, curve_n, NUM_ECC_DIGITS));
110+
if (!vli_sub(z, p_point.x, curve_n, NUM_ECC_DIGITS)) {
111+
vli_set(p_point.x, z);
112+
}
115113

116114
return (vli_cmp(p_point.x, r, NUM_ECC_DIGITS) == 0);
117115
}

lib/source/utils.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,11 @@ void _set(void *to, uint8_t val, uint32_t len)
5555
}
5656

5757
/*
58-
* Doubles the value of a byte for values up to 127. Original 'return
59-
* ((a<<1) ^ ((a>>7) * 0x1b))' re-written to avoid extra multiplication which
60-
* the compiler won't be able to optimize
58+
* Doubles the value of a byte for values up to 127.
6159
*/
6260
uint8_t _double_byte(uint8_t a)
6361
{
64-
return (a & MASK_MOST_SIG_BIT) ?
65-
((a << 1) ^ MASK_TWENTY_SEVEN) : (a << 1);
62+
return ((a<<1) ^ ((a>>7) * MASK_TWENTY_SEVEN));
6663
}
6764

6865
int32_t _compare(const uint8_t *a, const uint8_t *b, size_t size)

0 commit comments

Comments
 (0)