multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength);
}
+bool ECC_CheckPointIsInElliCur_P256(Point *p)
+{
+ /* y^2 % q */
+ DWORD y_y_q[KEY_LENGTH_DWORDS_P256] = {0x0};
+ /* x^2 % q */
+ DWORD x_x_q[KEY_LENGTH_DWORDS_P256] = {0x0};
+ /* x % q */
+ DWORD x_q[KEY_LENGTH_DWORDS_P256] = {0x0};
+ /* x^2, To prevent overflow, the length of the x square here needs to
+ be expanded to two times the original one. */
+ DWORD x_x[2*KEY_LENGTH_DWORDS_P256] = {0x0};
+ /* y_y_q =(p->y)^2(mod q) */
+ multiprecision_mersenns_squa_mod(y_y_q, p->y, KEY_LENGTH_DWORDS_P256);
+ /* Calculate the value of p->x square, x_x = (p->x)^2 */
+ multiprecision_mult(x_x, p->x, p->x, KEY_LENGTH_DWORDS_P256);
+ /* The function of the elliptic curve is y^2 = x^3 - 3x + b (mod q) ==>
+ y^2 = (x^2 - 3)*x + b (mod q),
+ so we calculate the x^2 - 3 value here */
+ x_x[0] -= 3;
+ /* Using math relations. (a*b) % q = ((a%q)*(b%q)) % q ==>
+ (x^2 - 3)*x = (((x^2 - 3) % q) * x % q) % q */
+ multiprecision_fast_mod_P256(x_x_q, x_x);
+ /* x_x = x_x_q * x_q */
+ multiprecision_mult(x_x, x_x_q, p->x, KEY_LENGTH_DWORDS_P256);
+ /* x_q = x_x % q */
+ multiprecision_fast_mod_P256(x_q, x_x);
+ /* Save the result in x_x_q */
+ multiprecision_add_mod(x_x_q, x_q, curve_p256.b, KEY_LENGTH_DWORDS_P256);
+ /* compare the y_y_q and x_x_q, see if they are on a given elliptic curve. */
+ if (multiprecision_compare(y_y_q, x_x_q, KEY_LENGTH_DWORDS_P256)) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
#include "btm_int.h"
#include "stack/l2c_api.h"
#include "smp_int.h"
+#include "p_256_ecc_pp.h"
//#include "utils/include/bt_utils.h"
#if SMP_INCLUDED == TRUE
STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN);
STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN);
+ /* In order to prevent the x and y coordinates of the public key from being modified,
+ we need to check whether the x and y coordinates are on the given elliptic curve. */
+ if (!ECC_CheckPointIsInElliCur_P256((Point *)&p_cb->peer_publ_key)) {
+ SMP_TRACE_ERROR("%s, Invalid Public key.", __func__);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
smp_wait_for_both_public_keys(p_cb, NULL);
--- /dev/null
+/*
+ Tests for the BLE SMP implementation
+*/
+
+#include <esp_types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <string.h>
+#include <string.h>
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/xtensa_api.h"
+#include "unity.h"
+#include "esp_heap_caps.h"
+#include "esp_log.h"
+#include "freertos/ringbuf.h"
+#include "esp_system.h"
+#include "nvs_flash.h"
+
+#include "esp_bt.h"
+#include "esp_bt_main.h"
+#include "esp_bt_device.h"
+#include "esp_gap_ble_api.h"
+
+#define TAG "ble_smp_test"
+
+#define KEY_LENGTH_DWORDS_P256 8
+
+typedef unsigned long DWORD;
+typedef uint32_t UINT32;
+
+typedef struct {
+DWORD x[KEY_LENGTH_DWORDS_P256];
+ DWORD y[KEY_LENGTH_DWORDS_P256];
+ DWORD z[KEY_LENGTH_DWORDS_P256];
+} Point;
+
+typedef struct {
+ // curve's coefficients
+ DWORD a[KEY_LENGTH_DWORDS_P256];
+ DWORD b[KEY_LENGTH_DWORDS_P256];
+
+ //whether a is -3
+ int a_minus3;
+
+ // prime modulus
+ DWORD p[KEY_LENGTH_DWORDS_P256];
+
+ // Omega, p = 2^m -omega
+ DWORD omega[KEY_LENGTH_DWORDS_P256];
+
+ // base point, a point on E of order r
+ Point G;
+
+} elliptic_curve_t;
+
+extern void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength);
+extern bool ECC_CheckPointIsInElliCur_P256(Point *p);
+extern void p_256_init_curve(UINT32 keyLength);
+extern elliptic_curve_t curve_p256;
+
+static void bt_rand(void *buf, size_t len)
+{
+ if (!len) {
+ return;
+ }
+ // Reset the buf value to the fixed value.
+ memset(buf, 0x55, len);
+
+ for (int i = 0; i < (int)(len / sizeof(uint32_t)); i++) {
+ uint32_t rand = esp_random();
+ memcpy(buf + i*sizeof(uint32_t), &rand, sizeof(uint32_t));
+ }
+
+ return;
+}
+
+TEST_CASE("ble_smp_public_key_check", "[ble_smp]")
+{
+ /* We wait init finish 200ms here */
+ vTaskDelay(200 / portTICK_PERIOD_MS);
+ Point public_key;
+ DWORD private_key[KEY_LENGTH_DWORDS_P256] = {[0 ... (KEY_LENGTH_DWORDS_P256 - 1)] = 0x12345678};
+ p_256_init_curve(KEY_LENGTH_DWORDS_P256);
+ ECC_PointMult_Bin_NAF(&public_key, &(curve_p256.G), private_key, KEY_LENGTH_DWORDS_P256);
+ /* Check Is the public key generated by the system on the given elliptic curve */
+ TEST_ASSERT(ECC_CheckPointIsInElliCur_P256(&public_key));
+ /* We simulate the attacker and set the y coordinate of the public key to 0. */
+ for (int i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
+ public_key.y[i] = 0x0;
+ }
+ /* At this point the public key should not be on the given elliptic curve. */
+ TEST_ASSERT(!ECC_CheckPointIsInElliCur_P256(&public_key));
+ /* Test whether the G point on the protocol is on a given elliptic curve */
+ TEST_ASSERT(ECC_CheckPointIsInElliCur_P256(&(curve_p256.G)));
+ /* test 100 times when the private key is generated by the random number. */
+ for (int j = 0; j < 100; j++) {
+ bt_rand(private_key, sizeof(DWORD)*KEY_LENGTH_DWORDS_P256);
+ ECC_PointMult_Bin_NAF(&public_key, &(curve_p256.G), private_key, KEY_LENGTH_DWORDS_P256);
+ /* Check Is the public key generated by the system on the given elliptic curve */
+ TEST_ASSERT(ECC_CheckPointIsInElliCur_P256(&public_key));
+ }
+}