diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2018-01-22 12:06:31 +0100 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2018-01-22 12:12:23 +0100 |
commit | 9c6cf787576f18d935febe568fe1c84d847f29bd (patch) | |
tree | c2f65f58b89358c76624a0f5142d61e2e4b962c6 | |
parent | 0c8e542c4d4076f7e1558289fabd27410a59475b (diff) | |
download | bluez-9c6cf787576f18d935febe568fe1c84d847f29bd.tar.gz |
shared: Add missing ecc_valid_public_key function
-rw-r--r-- | src/shared/ecc.c | 59 | ||||
-rw-r--r-- | src/shared/ecc.h | 10 | ||||
-rw-r--r-- | unit/test-ecc.c | 35 |
3 files changed, 104 insertions, 0 deletions
diff --git a/src/shared/ecc.c b/src/shared/ecc.c index 41be02b72..eb2cc005d 100644 --- a/src/shared/ecc.c +++ b/src/shared/ecc.c @@ -66,9 +66,13 @@ typedef struct { #define CURVE_N_32 { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull, \ 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull } +#define CURVE_B_32 { 0x3BCE3C3E27D2604Bull, 0x651D06B0CC53B0F6ull, \ + 0xB3EBBD55769886BCull, 0x5AC635D8AA3A93E7ull } + static uint64_t curve_p[NUM_ECC_DIGITS] = CURVE_P_32; static struct ecc_point curve_g = CURVE_G_32; static uint64_t curve_n[NUM_ECC_DIGITS] = CURVE_N_32; +static uint64_t curve_b[NUM_ECC_DIGITS] = CURVE_B_32; static bool get_random_number(uint64_t *vli) { @@ -183,6 +187,19 @@ static int vli_cmp(const uint64_t *left, const uint64_t *right) return 0; } +/* Constant-time comparison function - secure way to compare long integers */ +/* Returns one if left == right, zero otherwise. */ +static bool vli_equal(const uint64_t *left, const uint64_t *right) +{ + uint64_t diff = 0; + int i; + + for (i = NUM_ECC_DIGITS - 1; i >= 0; --i) + diff |= (left[i] ^ right[i]); + + return (diff == 0); +} + /* Computes result = in << c, returning carry. Can modify in place * (if result == in). 0 < shift < 64. */ @@ -770,6 +787,34 @@ static void ecc_point_mult(struct ecc_point *result, vli_set(result->y, ry[0]); } +static bool ecc_valid_point(const struct ecc_point *point) +{ + uint64_t tmp1[NUM_ECC_DIGITS]; + uint64_t tmp2[NUM_ECC_DIGITS]; + uint64_t _3[NUM_ECC_DIGITS] = { 3 }; /* -a = 3 */ + + /* The point at infinity is invalid. */ + if (ecc_point_is_zero(point)) + return false; + + /* x and y must be smaller than p. */ + if (vli_cmp(curve_p, point->x) != 1 || + vli_cmp(curve_p, point->y) != 1) + return false; + + /* Computes result = y^2. */ + vli_mod_square_fast(tmp1, point->y); + + /* Computes result = x^3 + ax + b. result must not overlap x. */ + vli_mod_square_fast(tmp2, point->x); /* r = x^2 */ + vli_mod_sub(tmp2, tmp2, _3, curve_p); /* r = x^2 - 3 */ + vli_mod_mult_fast(tmp2, tmp2, point->x); /* r = x^3 - 3x */ + vli_mod_add(tmp2, tmp2, curve_b, curve_p); /* r = x^3 - 3x + b */ + + /* Make sure that y^2 == x^3 + ax + b */ + return vli_equal(tmp1, tmp2); +} + /* Little endian byte-array to native conversion */ static void ecc_bytes2native(const uint8_t bytes[ECC_BYTES], uint64_t native[NUM_ECC_DIGITS]) @@ -838,6 +883,16 @@ bool ecc_make_key(uint8_t public_key[64], uint8_t private_key[32]) return true; } +bool ecc_valid_public_key(const uint8_t public_key[64]) +{ + struct ecc_point pk; + + ecc_bytes2native(public_key, pk.x); + ecc_bytes2native(&public_key[32], pk.y); + + return ecc_valid_point(&pk); +} + bool ecdh_shared_secret(const uint8_t public_key[64], const uint8_t private_key[32], uint8_t secret[32]) @@ -851,6 +906,10 @@ bool ecdh_shared_secret(const uint8_t public_key[64], ecc_bytes2native(public_key, pk.x); ecc_bytes2native(&public_key[32], pk.y); + + if (!ecc_valid_point(&pk)) + return false; + ecc_bytes2native(private_key, priv); ecc_point_mult(&product, &pk, priv, rand, vli_num_bits(priv)); diff --git a/src/shared/ecc.h b/src/shared/ecc.h index e971375ac..f89f2b0c3 100644 --- a/src/shared/ecc.h +++ b/src/shared/ecc.h @@ -28,6 +28,7 @@ #include <stdint.h> /* Create a public/private key pair. + * * Outputs: * public_key - Will be filled in with the public key. * private_Key - Will be filled in with the private key. @@ -37,6 +38,15 @@ */ bool ecc_make_key(uint8_t public_key[64], uint8_t private_key[32]); +/* Check to see if a public key is valid. + * + * Inputs: + * public_key - The public key to check. + * + * Returns true if the public key is valid, false if it is invalid. +*/ +bool ecc_valid_public_key(const uint8_t public_key[64]); + /* Compute a shared secret given your secret key and someone else's * public key. * Note: It is recommended that you hash the result of ecdh_shared_secret diff --git a/unit/test-ecc.c b/unit/test-ecc.c index 9b48d0b3a..98400a253 100644 --- a/unit/test-ecc.c +++ b/unit/test-ecc.c @@ -243,6 +243,39 @@ static void test_sample_3(const void *data) tester_test_passed(); } +static void test_invalid_pub(const void *data) +{ + uint8_t priv_a[32] = { 0xbd, 0x1a, 0x3c, 0xcd, 0xa6, 0xb8, 0x99, 0x58, + 0x99, 0xb7, 0x40, 0xeb, 0x7b, 0x60, 0xff, 0x4a, + 0x50, 0x3f, 0x10, 0xd2, 0xe3, 0xb3, 0xc9, 0x74, + 0x38, 0x5f, 0xc5, 0xa3, 0xd4, 0xf6, 0x49, 0x3f, + }; + uint8_t pub_a[64] = { 0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc, + 0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef, + 0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e, + 0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20, + + 0x8b, 0xd2, 0x89, 0x15, 0xd0, 0x8e, 0x1c, 0x74, + 0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76, + 0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63, + 0x6d, 0xeb, 0x2a, 0x65, 0x49, 0x9c, 0x80, 0xdc, + }; + uint8_t dhkey[32] = { 0x2d, 0xab, 0x00, 0x48, 0xcb, 0xb3, 0x7b, 0xda, + 0x55, 0x7b, 0x8b, 0x72, 0xa8, 0x57, 0x87, 0xc3, + 0x87, 0x27, 0x99, 0x32, 0xfc, 0x79, 0x5f, 0xae, + 0x7c, 0x1c, 0xf9, 0x49, 0xe6, 0xd7, 0xaa, 0x70, + }; + int fails; + + memset(pub_a + 32, 0x42, 32); + + fails = test_sample(priv_a, priv_a, pub_a, pub_a, dhkey); + + g_assert(fails >= 1); + + tester_test_passed(); +} + int main(int argc, char *argv[]) { tester_init(&argc, &argv); @@ -253,5 +286,7 @@ int main(int argc, char *argv[]) tester_add("/ecdh/sample/2", NULL, NULL, test_sample_2, NULL); tester_add("/ecdh/sample/3", NULL, NULL, test_sample_3, NULL); + tester_add("/ecdh/invalid", NULL, NULL, test_invalid_pub, NULL); + return tester_run(); } |