All of lore.kernel.org
 help / color / mirror / Atom feed
From: Johan Hedberg <johan.hedberg@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH 14/49] Bluetooth: Add ECC library for LE Secure Connections
Date: Wed,  3 Dec 2014 17:02:08 +0200	[thread overview]
Message-ID: <1417618963-18010-15-git-send-email-johan.hedberg@gmail.com> (raw)
In-Reply-To: <1417618963-18010-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

This patch adds a simple ECC library that will act as a fundamental
building block for LE Secure Connections. The library has a simple API
consisting of two functions: one for generating a public/private key
pair and another one for generating a Diffie-Hellman key from a local
private key and a remote public key.

The code has been taken from https://github.com/kmackay/easy-ecc and
modified to conform with the kernel coding style.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/Makefile |   2 +-
 net/bluetooth/ecc.c    | 816 +++++++++++++++++++++++++++++++++++++++++++++++++
 net/bluetooth/ecc.h    |  54 ++++
 3 files changed, 871 insertions(+), 1 deletion(-)
 create mode 100644 net/bluetooth/ecc.c
 create mode 100644 net/bluetooth/ecc.h

diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index 886e9aa3ecf1..a5432a6a0ae6 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -13,6 +13,6 @@ bluetooth_6lowpan-y := 6lowpan.o
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
 	hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
-	a2mp.o amp.o
+	a2mp.o amp.o ecc.o
 
 subdir-ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/bluetooth/ecc.c b/net/bluetooth/ecc.c
new file mode 100644
index 000000000000..e1709f8467ac
--- /dev/null
+++ b/net/bluetooth/ecc.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright (c) 2013, Kenneth MacKay
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *  * 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+ * HOLDER 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.
+ */
+
+#include <linux/random.h>
+
+#include "ecc.h"
+
+/* 256-bit curve */
+#define ECC_BYTES 32
+
+#define MAX_TRIES 16
+
+/* Number of u64's needed */
+#define NUM_ECC_DIGITS (ECC_BYTES / 8)
+
+struct ecc_point {
+	u64 x[NUM_ECC_DIGITS];
+	u64 y[NUM_ECC_DIGITS];
+};
+
+typedef struct {
+	u64 m_low;
+	u64 m_high;
+} uint128_t;
+
+#define CURVE_P_32 {	0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull, \
+			0x0000000000000000ull, 0xFFFFFFFF00000001ull }
+
+#define CURVE_G_32 { \
+		{	0xF4A13945D898C296ull, 0x77037D812DEB33A0ull,	\
+			0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull }, \
+		{	0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull,	\
+			0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull }	\
+}
+
+#define CURVE_N_32 {	0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull,	\
+			0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull }
+
+static u64 curve_p[NUM_ECC_DIGITS] = CURVE_P_32;
+static struct ecc_point curve_g = CURVE_G_32;
+static u64 curve_n[NUM_ECC_DIGITS] = CURVE_N_32;
+
+static void vli_clear(u64 *vli)
+{
+	int i;
+
+	for (i = 0; i < NUM_ECC_DIGITS; i++)
+		vli[i] = 0;
+}
+
+/* Returns true if vli == 0, false otherwise. */
+static bool vli_is_zero(const u64 *vli)
+{
+	int i;
+
+	for (i = 0; i < NUM_ECC_DIGITS; i++) {
+		if (vli[i])
+			return false;
+	}
+
+	return true;
+}
+
+/* Returns nonzero if bit bit of vli is set. */
+static u64 vli_test_bit(const u64 *vli, unsigned int bit)
+{
+	return (vli[bit / 64] & ((u64) 1 << (bit % 64)));
+}
+
+/* Counts the number of 64-bit "digits" in vli. */
+static unsigned int vli_num_digits(const u64 *vli)
+{
+	int i;
+
+	/* Search from the end until we find a non-zero digit.
+	 * We do it in reverse because we expect that most digits will
+	 * be nonzero.
+	 */
+	for (i = NUM_ECC_DIGITS - 1; i >= 0 && vli[i] == 0; i--);
+
+	return (i + 1);
+}
+
+/* Counts the number of bits required for vli. */
+static unsigned int vli_num_bits(const u64 *vli)
+{
+	unsigned int i, num_digits;
+	u64 digit;
+
+	num_digits = vli_num_digits(vli);
+	if (num_digits == 0)
+		return 0;
+
+	digit = vli[num_digits - 1];
+	for (i = 0; digit; i++)
+		digit >>= 1;
+
+	return ((num_digits - 1) * 64 + i);
+}
+
+/* Sets dest = src. */
+static void vli_set(u64 *dest, const u64 *src)
+{
+	int i;
+
+	for (i = 0; i < NUM_ECC_DIGITS; i++)
+		dest[i] = src[i];
+}
+
+/* Returns sign of left - right. */
+static int vli_cmp(const u64 *left, const u64 *right)
+{
+    int i;
+
+    for (i = NUM_ECC_DIGITS - 1; i >= 0; i--) {
+	    if (left[i] > right[i])
+		    return 1;
+	    else if (left[i] < right[i])
+		    return -1;
+    }
+
+    return 0;
+}
+
+/* Computes result = in << c, returning carry. Can modify in place
+ * (if result == in). 0 < shift < 64.
+ */
+static u64 vli_lshift(u64 *result, const u64 *in,
+			   unsigned int shift)
+{
+	u64 carry = 0;
+	int i;
+
+	for (i = 0; i < NUM_ECC_DIGITS; i++) {
+		u64 temp = in[i];
+
+		result[i] = (temp << shift) | carry;
+		carry = temp >> (64 - shift);
+	}
+
+	return carry;
+}
+
+/* Computes vli = vli >> 1. */
+static void vli_rshift1(u64 *vli)
+{
+	u64 *end = vli;
+	u64 carry = 0;
+
+	vli += NUM_ECC_DIGITS;
+
+	while (vli-- > end) {
+		u64 temp = *vli;
+		*vli = (temp >> 1) | carry;
+		carry = temp << 63;
+	}
+}
+
+/* Computes result = left + right, returning carry. Can modify in place. */
+static u64 vli_add(u64 *result, const u64 *left,
+			const u64 *right)
+{
+	u64 carry = 0;
+	int i;
+
+	for (i = 0; i < NUM_ECC_DIGITS; i++) {
+		u64 sum;
+
+		sum = left[i] + right[i] + carry;
+		if (sum != left[i])
+			carry = (sum < left[i]);
+
+		result[i] = sum;
+	}
+
+	return carry;
+}
+
+/* Computes result = left - right, returning borrow. Can modify in place. */
+static u64 vli_sub(u64 *result, const u64 *left, const u64 *right)
+{
+	u64 borrow = 0;
+	int i;
+
+	for (i = 0; i < NUM_ECC_DIGITS; i++) {
+		u64 diff;
+
+		diff = left[i] - right[i] - borrow;
+		if (diff != left[i])
+			borrow = (diff > left[i]);
+
+		result[i] = diff;
+	}
+
+	return borrow;
+}
+
+static uint128_t mul_64_64(u64 left, u64 right)
+{
+	u64 a0 = left & 0xffffffffull;
+	u64 a1 = left >> 32;
+	u64 b0 = right & 0xffffffffull;
+	u64 b1 = right >> 32;
+	u64 m0 = a0 * b0;
+	u64 m1 = a0 * b1;
+	u64 m2 = a1 * b0;
+	u64 m3 = a1 * b1;
+	uint128_t result;
+
+	m2 += (m0 >> 32);
+	m2 += m1;
+
+	/* Overflow */
+	if (m2 < m1)
+		m3 += 0x100000000ull;
+
+	result.m_low = (m0 & 0xffffffffull) | (m2 << 32);
+	result.m_high = m3 + (m2 >> 32);
+
+	return result;
+}
+
+static uint128_t add_128_128(uint128_t a, uint128_t b)
+{
+	uint128_t result;
+
+	result.m_low = a.m_low + b.m_low;
+	result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low);
+
+	return result;
+}
+
+static void vli_mult(u64 *result, const u64 *left, const u64 *right)
+{
+	uint128_t r01 = { 0, 0 };
+	u64 r2 = 0;
+	unsigned int i, k;
+
+	/* Compute each digit of result in sequence, maintaining the
+	 * carries.
+	 */
+	for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; k++) {
+		unsigned int min;
+
+		if (k < NUM_ECC_DIGITS)
+			min = 0;
+		else
+			min = (k + 1) - NUM_ECC_DIGITS;
+
+		for (i = min; i <= k && i < NUM_ECC_DIGITS; i++) {
+			uint128_t product;
+
+			product = mul_64_64(left[i], right[k - i]);
+
+			r01 = add_128_128(r01, product);
+			r2 += (r01.m_high < product.m_high);
+		}
+
+		result[k] = r01.m_low;
+		r01.m_low = r01.m_high;
+		r01.m_high = r2;
+		r2 = 0;
+	}
+
+	result[NUM_ECC_DIGITS * 2 - 1] = r01.m_low;
+}
+
+static void vli_square(u64 *result, const u64 *left)
+{
+	uint128_t r01 = { 0, 0 };
+	u64 r2 = 0;
+	int i, k;
+
+	for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; k++) {
+		unsigned int min;
+
+		if (k < NUM_ECC_DIGITS)
+			min = 0;
+		else
+			min = (k + 1) - NUM_ECC_DIGITS;
+
+		for (i = min; i <= k && i <= k - i; i++) {
+			uint128_t product;
+
+			product = mul_64_64(left[i], left[k - i]);
+
+			if (i < k - i) {
+				r2 += product.m_high >> 63;
+				product.m_high = (product.m_high << 1) |
+						 (product.m_low >> 63);
+				product.m_low <<= 1;
+			}
+
+			r01 = add_128_128(r01, product);
+			r2 += (r01.m_high < product.m_high);
+		}
+
+		result[k] = r01.m_low;
+		r01.m_low = r01.m_high;
+		r01.m_high = r2;
+		r2 = 0;
+	}
+
+	result[NUM_ECC_DIGITS * 2 - 1] = r01.m_low;
+}
+
+/* Computes result = (left + right) % mod.
+ * Assumes that left < mod and right < mod, result != mod.
+ */
+static void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
+			const u64 *mod)
+{
+	u64 carry;
+
+	carry = vli_add(result, left, right);
+
+	/* result > mod (result = mod + remainder), so subtract mod to
+	 * get remainder.
+	 */
+	if (carry || vli_cmp(result, mod) >= 0)
+		vli_sub(result, result, mod);
+}
+
+/* Computes result = (left - right) % mod.
+ * Assumes that left < mod and right < mod, result != mod.
+ */
+static void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
+			const u64 *mod)
+{
+	u64 borrow = vli_sub(result, left, right);
+
+	/* In this case, p_result == -diff == (max int) - diff.
+	 * Since -x % d == d - x, we can get the correct result from
+	 * result + mod (with overflow).
+	 */
+	if (borrow)
+		vli_add(result, result, mod);
+}
+
+/* Computes result = product % curve_p
+   from http://www.nsa.gov/ia/_files/nist-routines.pdf */
+static void vli_mmod_fast(u64 *result, const u64 *product)
+{
+	u64 tmp[NUM_ECC_DIGITS];
+	int carry;
+
+	/* t */
+	vli_set(result, product);
+
+	/* s1 */
+	tmp[0] = 0;
+	tmp[1] = product[5] & 0xffffffff00000000ull;
+	tmp[2] = product[6];
+	tmp[3] = product[7];
+	carry = vli_lshift(tmp, tmp, 1);
+	carry += vli_add(result, result, tmp);
+
+	/* s2 */
+	tmp[1] = product[6] << 32;
+	tmp[2] = (product[6] >> 32) | (product[7] << 32);
+	tmp[3] = product[7] >> 32;
+	carry += vli_lshift(tmp, tmp, 1);
+	carry += vli_add(result, result, tmp);
+
+	/* s3 */
+	tmp[0] = product[4];
+	tmp[1] = product[5] & 0xffffffff;
+	tmp[2] = 0;
+	tmp[3] = product[7];
+	carry += vli_add(result, result, tmp);
+
+	/* s4 */
+	tmp[0] = (product[4] >> 32) | (product[5] << 32);
+	tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull);
+	tmp[2] = product[7];
+	tmp[3] = (product[6] >> 32) | (product[4] << 32);
+	carry += vli_add(result, result, tmp);
+
+	/* d1 */
+	tmp[0] = (product[5] >> 32) | (product[6] << 32);
+	tmp[1] = (product[6] >> 32);
+	tmp[2] = 0;
+	tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32);
+	carry -= vli_sub(result, result, tmp);
+
+	/* d2 */
+	tmp[0] = product[6];
+	tmp[1] = product[7];
+	tmp[2] = 0;
+	tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull);
+	carry -= vli_sub(result, result, tmp);
+
+	/* d3 */
+	tmp[0] = (product[6] >> 32) | (product[7] << 32);
+	tmp[1] = (product[7] >> 32) | (product[4] << 32);
+	tmp[2] = (product[4] >> 32) | (product[5] << 32);
+	tmp[3] = (product[6] << 32);
+	carry -= vli_sub(result, result, tmp);
+
+	/* d4 */
+	tmp[0] = product[7];
+	tmp[1] = product[4] & 0xffffffff00000000ull;
+	tmp[2] = product[5];
+	tmp[3] = product[6] & 0xffffffff00000000ull;
+	carry -= vli_sub(result, result, tmp);
+
+	if (carry < 0) {
+		do {
+			carry += vli_add(result, result, curve_p);
+		} while (carry < 0);
+	} else {
+		while (carry || vli_cmp(curve_p, result) != 1)
+			carry -= vli_sub(result, result, curve_p);
+	}
+}
+
+/* Computes result = (left * right) % curve_p. */
+static void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right)
+{
+	u64 product[2 * NUM_ECC_DIGITS];
+
+	vli_mult(product, left, right);
+	vli_mmod_fast(result, product);
+}
+
+/* Computes result = left^2 % curve_p. */
+static void vli_mod_square_fast(u64 *result, const u64 *left)
+{
+	u64 product[2 * NUM_ECC_DIGITS];
+
+	vli_square(product, left);
+	vli_mmod_fast(result, product);
+}
+
+#define EVEN(vli) (!(vli[0] & 1))
+/* Computes result = (1 / p_input) % mod. All VLIs are the same size.
+ * See "From Euclid's GCD to Montgomery Multiplication to the Great Divide"
+ * https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf
+ */
+static void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod)
+{
+	u64 a[NUM_ECC_DIGITS], b[NUM_ECC_DIGITS];
+	u64 u[NUM_ECC_DIGITS], v[NUM_ECC_DIGITS];
+	u64 carry;
+	int cmp_result;
+
+	if (vli_is_zero(input)) {
+		vli_clear(result);
+		return;
+	}
+
+	vli_set(a, input);
+	vli_set(b, mod);
+	vli_clear(u);
+	u[0] = 1;
+	vli_clear(v);
+
+	while ((cmp_result = vli_cmp(a, b)) != 0) {
+		carry = 0;
+
+		if (EVEN(a)) {
+			vli_rshift1(a);
+
+			if (!EVEN(u))
+				carry = vli_add(u, u, mod);
+
+			vli_rshift1(u);
+			if (carry)
+				u[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
+		} else if (EVEN(b)) {
+			vli_rshift1(b);
+
+			if (!EVEN(v))
+				carry = vli_add(v, v, mod);
+
+			vli_rshift1(v);
+			if (carry)
+				v[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
+		} else if (cmp_result > 0) {
+			vli_sub(a, a, b);
+			vli_rshift1(a);
+
+			if (vli_cmp(u, v) < 0)
+				vli_add(u, u, mod);
+
+			vli_sub(u, u, v);
+			if (!EVEN(u))
+				carry = vli_add(u, u, mod);
+
+			vli_rshift1(u);
+			if (carry)
+				u[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
+		} else {
+			vli_sub(b, b, a);
+			vli_rshift1(b);
+
+			if (vli_cmp(v, u) < 0)
+				vli_add(v, v, mod);
+
+			vli_sub(v, v, u);
+			if (!EVEN(v))
+				carry = vli_add(v, v, mod);
+
+			vli_rshift1(v);
+			if (carry)
+				v[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
+		}
+	}
+
+	vli_set(result, u);
+}
+
+/* ------ Point operations ------ */
+
+/* Returns true if p_point is the point at infinity, false otherwise. */
+static bool ecc_point_is_zero(const struct ecc_point *point)
+{
+	return (vli_is_zero(point->x) && vli_is_zero(point->y));
+}
+
+/* Point multiplication algorithm using Montgomery's ladder with co-Z
+ * coordinates. From http://eprint.iacr.org/2011/338.pdf
+ */
+
+/* Double in place */
+static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1)
+{
+	/* t1 = x, t2 = y, t3 = z */
+	u64 t4[NUM_ECC_DIGITS];
+	u64 t5[NUM_ECC_DIGITS];
+
+	if (vli_is_zero(z1))
+		return;
+
+	vli_mod_square_fast(t4, y1);   /* t4 = y1^2 */
+	vli_mod_mult_fast(t5, x1, t4); /* t5 = x1*y1^2 = A */
+	vli_mod_square_fast(t4, t4);   /* t4 = y1^4 */
+	vli_mod_mult_fast(y1, y1, z1); /* t2 = y1*z1 = z3 */
+	vli_mod_square_fast(z1, z1);   /* t3 = z1^2 */
+
+	vli_mod_add(x1, x1, z1, curve_p); /* t1 = x1 + z1^2 */
+	vli_mod_add(z1, z1, z1, curve_p); /* t3 = 2*z1^2 */
+	vli_mod_sub(z1, x1, z1, curve_p); /* t3 = x1 - z1^2 */
+	vli_mod_mult_fast(x1, x1, z1);    /* t1 = x1^2 - z1^4 */
+
+	vli_mod_add(z1, x1, x1, curve_p); /* t3 = 2*(x1^2 - z1^4) */
+	vli_mod_add(x1, x1, z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */
+	if (vli_test_bit(x1, 0)) {
+		u64 carry = vli_add(x1, x1, curve_p);
+		vli_rshift1(x1);
+		x1[NUM_ECC_DIGITS - 1] |= carry << 63;
+	} else {
+		vli_rshift1(x1);
+	}
+	/* t1 = 3/2*(x1^2 - z1^4) = B */
+
+	vli_mod_square_fast(z1, x1);      /* t3 = B^2 */
+	vli_mod_sub(z1, z1, t5, curve_p); /* t3 = B^2 - A */
+	vli_mod_sub(z1, z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */
+	vli_mod_sub(t5, t5, z1, curve_p); /* t5 = A - x3 */
+	vli_mod_mult_fast(x1, x1, t5);    /* t1 = B * (A - x3) */
+	vli_mod_sub(t4, x1, t4, curve_p); /* t4 = B * (A - x3) - y1^4 = y3 */
+
+	vli_set(x1, z1);
+	vli_set(z1, y1);
+	vli_set(y1, t4);
+}
+
+/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */
+static void apply_z(u64 *x1, u64 *y1, u64 *z)
+{
+	u64 t1[NUM_ECC_DIGITS];
+
+	vli_mod_square_fast(t1, z);    /* z^2 */
+	vli_mod_mult_fast(x1, x1, t1); /* x1 * z^2 */
+	vli_mod_mult_fast(t1, t1, z);  /* z^3 */
+	vli_mod_mult_fast(y1, y1, t1); /* y1 * z^3 */
+}
+
+/* P = (x1, y1) => 2P, (x2, y2) => P' */
+static void xycz_initial_double(u64 *x1, u64 *y1, u64 *x2, u64 *y2,
+				u64 *p_initial_z)
+{
+	u64 z[NUM_ECC_DIGITS];
+
+	vli_set(x2, x1);
+	vli_set(y2, y1);
+
+	vli_clear(z);
+	z[0] = 1;
+
+	if (p_initial_z)
+		vli_set(z, p_initial_z);
+
+	apply_z(x1, y1, z);
+
+	ecc_point_double_jacobian(x1, y1, z);
+
+	apply_z(x2, y2, z);
+}
+
+/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
+ * Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3)
+ * or P => P', Q => P + Q
+ */
+static void xycz_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2)
+{
+	/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
+	u64 t5[NUM_ECC_DIGITS];
+
+	vli_mod_sub(t5, x2, x1, curve_p); /* t5 = x2 - x1 */
+	vli_mod_square_fast(t5, t5);      /* t5 = (x2 - x1)^2 = A */
+	vli_mod_mult_fast(x1, x1, t5);    /* t1 = x1*A = B */
+	vli_mod_mult_fast(x2, x2, t5);    /* t3 = x2*A = C */
+	vli_mod_sub(y2, y2, y1, curve_p); /* t4 = y2 - y1 */
+	vli_mod_square_fast(t5, y2);      /* t5 = (y2 - y1)^2 = D */
+
+	vli_mod_sub(t5, t5, x1, curve_p); /* t5 = D - B */
+	vli_mod_sub(t5, t5, x2, curve_p); /* t5 = D - B - C = x3 */
+	vli_mod_sub(x2, x2, x1, curve_p); /* t3 = C - B */
+	vli_mod_mult_fast(y1, y1, x2);    /* t2 = y1*(C - B) */
+	vli_mod_sub(x2, x1, t5, curve_p); /* t3 = B - x3 */
+	vli_mod_mult_fast(y2, y2, x2);    /* t4 = (y2 - y1)*(B - x3) */
+	vli_mod_sub(y2, y2, y1, curve_p); /* t4 = y3 */
+
+	vli_set(x2, t5);
+}
+
+/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
+ * Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
+ * or P => P - Q, Q => P + Q
+ */
+static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2)
+{
+	/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
+	u64 t5[NUM_ECC_DIGITS];
+	u64 t6[NUM_ECC_DIGITS];
+	u64 t7[NUM_ECC_DIGITS];
+
+	vli_mod_sub(t5, x2, x1, curve_p); /* t5 = x2 - x1 */
+	vli_mod_square_fast(t5, t5);      /* t5 = (x2 - x1)^2 = A */
+	vli_mod_mult_fast(x1, x1, t5);    /* t1 = x1*A = B */
+	vli_mod_mult_fast(x2, x2, t5);    /* t3 = x2*A = C */
+	vli_mod_add(t5, y2, y1, curve_p); /* t4 = y2 + y1 */
+	vli_mod_sub(y2, y2, y1, curve_p); /* t4 = y2 - y1 */
+
+	vli_mod_sub(t6, x2, x1, curve_p); /* t6 = C - B */
+	vli_mod_mult_fast(y1, y1, t6);    /* t2 = y1 * (C - B) */
+	vli_mod_add(t6, x1, x2, curve_p); /* t6 = B + C */
+	vli_mod_square_fast(x2, y2);      /* t3 = (y2 - y1)^2 */
+	vli_mod_sub(x2, x2, t6, curve_p); /* t3 = x3 */
+
+	vli_mod_sub(t7, x1, x2, curve_p); /* t7 = B - x3 */
+	vli_mod_mult_fast(y2, y2, t7);    /* t4 = (y2 - y1)*(B - x3) */
+	vli_mod_sub(y2, y2, y1, curve_p); /* t4 = y3 */
+
+	vli_mod_square_fast(t7, t5);      /* t7 = (y2 + y1)^2 = F */
+	vli_mod_sub(t7, t7, t6, curve_p); /* t7 = x3' */
+	vli_mod_sub(t6, t7, x1, curve_p); /* t6 = x3' - B */
+	vli_mod_mult_fast(t6, t6, t5);    /* t6 = (y2 + y1)*(x3' - B) */
+	vli_mod_sub(y1, t6, y1, curve_p); /* t2 = y3' */
+
+	vli_set(x1, t7);
+}
+
+static void ecc_point_mult(struct ecc_point *result,
+			   const struct ecc_point *point, u64 *scalar,
+			   u64 *initial_z, int num_bits)
+{
+	/* R0 and R1 */
+	u64 rx[2][NUM_ECC_DIGITS];
+	u64 ry[2][NUM_ECC_DIGITS];
+	u64 z[NUM_ECC_DIGITS];
+	int i, nb;
+
+	vli_set(rx[1], point->x);
+	vli_set(ry[1], point->y);
+
+	xycz_initial_double(rx[1], ry[1], rx[0], ry[0], initial_z);
+
+	for (i = num_bits - 2; i > 0; i--) {
+		nb = !vli_test_bit(scalar, i);
+		xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb]);
+		xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb]);
+	}
+
+	nb = !vli_test_bit(scalar, 0);
+	xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb]);
+
+	/* Find final 1/Z value. */
+	vli_mod_sub(z, rx[1], rx[0], curve_p); /* X1 - X0 */
+	vli_mod_mult_fast(z, z, ry[1 - nb]); /* Yb * (X1 - X0) */
+	vli_mod_mult_fast(z, z, point->x);   /* xP * Yb * (X1 - X0) */
+	vli_mod_inv(z, z, curve_p);          /* 1 / (xP * Yb * (X1 - X0)) */
+	vli_mod_mult_fast(z, z, point->y);   /* yP / (xP * Yb * (X1 - X0)) */
+	vli_mod_mult_fast(z, z, rx[1 - nb]); /* Xb * yP / (xP * Yb * (X1 - X0)) */
+	/* End 1/Z calculation */
+
+	xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb]);
+
+	apply_z(rx[0], ry[0], z);
+
+	vli_set(result->x, rx[0]);
+	vli_set(result->y, ry[0]);
+}
+
+static void ecc_bytes2native(const u8 bytes[ECC_BYTES],
+			     u64 native[NUM_ECC_DIGITS])
+{
+	int i;
+
+	for (i = 0; i < NUM_ECC_DIGITS; i++) {
+		const u8 *digit = bytes + 8 * (NUM_ECC_DIGITS - 1 - i);
+
+		native[NUM_ECC_DIGITS - 1 - i] =
+				((u64) digit[0] << 0) |
+				((u64) digit[1] << 8) |
+				((u64) digit[2] << 16) |
+				((u64) digit[3] << 24) |
+				((u64) digit[4] << 32) |
+				((u64) digit[5] << 40) |
+				((u64) digit[6] << 48) |
+				((u64) digit[7] << 56);
+	}
+}
+
+static void ecc_native2bytes(const u64 native[NUM_ECC_DIGITS],
+			     u8 bytes[ECC_BYTES])
+{
+	int i;
+
+	for (i = 0; i < NUM_ECC_DIGITS; i++) {
+		u8 *digit = bytes + 8 * (NUM_ECC_DIGITS - 1 - i);
+
+		digit[0] = native[NUM_ECC_DIGITS - 1 - i] >> 0;
+		digit[1] = native[NUM_ECC_DIGITS - 1 - i] >> 8;
+		digit[2] = native[NUM_ECC_DIGITS - 1 - i] >> 16;
+		digit[3] = native[NUM_ECC_DIGITS - 1 - i] >> 24;
+		digit[4] = native[NUM_ECC_DIGITS - 1 - i] >> 32;
+		digit[5] = native[NUM_ECC_DIGITS - 1 - i] >> 40;
+		digit[6] = native[NUM_ECC_DIGITS - 1 - i] >> 48;
+		digit[7] = native[NUM_ECC_DIGITS - 1 - i] >> 56;
+	}
+}
+
+bool ecc_make_key(u8 public_key[64], u8 private_key[32])
+{
+	struct ecc_point pk;
+	u64 priv[NUM_ECC_DIGITS];
+	unsigned int tries = 0;
+
+	do {
+		if (tries++ >= MAX_TRIES)
+			return false;
+
+		get_random_bytes(priv, ECC_BYTES);
+
+		if (vli_is_zero(priv))
+			continue;
+
+		/* Make sure the private key is in the range [1, n-1]. */
+		if (vli_cmp(curve_n, priv) != 1)
+			continue;
+
+		ecc_point_mult(&pk, &curve_g, priv, NULL, vli_num_bits(priv));
+	} while (ecc_point_is_zero(&pk));
+
+	ecc_native2bytes(priv, private_key);
+	ecc_native2bytes(pk.x, public_key);
+	ecc_native2bytes(pk.y, &public_key[32]);
+
+	return true;
+}
+
+bool ecdh_shared_secret(const u8 public_key[64], const u8 private_key[32],
+		        u8 secret[32])
+{
+	u64 priv[NUM_ECC_DIGITS];
+	u64 rand[NUM_ECC_DIGITS];
+	struct ecc_point product, pk;
+
+	get_random_bytes(rand, ECC_BYTES);
+
+	ecc_bytes2native(public_key, pk.x);
+	ecc_bytes2native(&public_key[32], pk.y);
+	ecc_bytes2native(private_key, priv);
+
+	ecc_point_mult(&product, &pk, priv, rand, vli_num_bits(priv));
+
+	ecc_native2bytes(product.x, secret);
+
+	return !ecc_point_is_zero(&product);
+}
diff --git a/net/bluetooth/ecc.h b/net/bluetooth/ecc.h
new file mode 100644
index 000000000000..8d6a2f4d1905
--- /dev/null
+++ b/net/bluetooth/ecc.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, Kenneth MacKay
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *  * 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+ * HOLDER 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.
+ */
+
+/* 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.
+ *
+ * Returns true if the key pair was generated successfully, false
+ * if an error occurred. The keys are with the LSB first.
+ */
+bool ecc_make_key(u8 public_key[64], u8 private_key[32]);
+
+/* 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
+ * before using it for symmetric encryption or HMAC.
+ *
+ * Inputs:
+ *	public_key  - The public key of the remote party
+ *	private_key - Your private key.
+ *
+ * Outputs:
+ *	secret - Will be filled in with the shared secret value.
+ *
+ * Returns true if the shared secret was generated successfully, false
+ * if an error occurred. Both input and output parameters are with the
+ * LSB first.
+ */
+bool ecdh_shared_secret(const u8 public_key[64], const u8 private_key[32],
+		        u8 secret[32]);
-- 
2.1.0


  parent reply	other threads:[~2014-12-03 15:02 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-12-03 15:01 [PATCH 00/49] Bluetooth: LE Secure Connections support Johan Hedberg
2014-12-03 15:01 ` [PATCH 01/49] Bluetooth: Add basic SMP defines for LE Secure Connections Johan Hedberg
2014-12-03 15:01 ` [PATCH 02/49] Bluetooth: Make auth_req mask dependent on SC enabled or not Johan Hedberg
2014-12-03 15:01 ` [PATCH 03/49] Bluetooth: Add SMP flag for SC and set it when necessary Johan Hedberg
2014-12-03 15:01 ` [PATCH 04/49] Bluetooth: Update SMP security level to/from auth_req for SC Johan Hedberg
2014-12-03 15:01 ` [PATCH 05/49] Bluetooth: Add mgmt support for LE Secure Connections LTK types Johan Hedberg
2014-12-03 15:02 ` [PATCH 06/49] Bluetooth: Set the correct security level for SC LTKs Johan Hedberg
2014-12-03 15:02 ` [PATCH 07/49] Bluetooth: Use custom macro for testing BR/EDR SC enabled Johan Hedberg
2014-12-03 15:02 ` [PATCH 08/49] Bluetooth: Add mgmt_set_secure_conn support for any LE adapter Johan Hedberg
2014-12-03 15:02 ` [PATCH 09/49] Bluetooth: Update LTK lookup to correctly deal with SC LTKs Johan Hedberg
2014-12-03 15:02 ` [PATCH 10/49] Bluetooth: Remove unused hci_find_ltk function Johan Hedberg
2014-12-03 15:02 ` [PATCH 11/49] Bluetooth: Rename hci_find_ltk_by_addr to hci_find_ltk Johan Hedberg
2014-12-03 15:02 ` [PATCH 12/49] Bluetooth: Set link key generation bit if necessary for LE SC Johan Hedberg
2014-12-03 15:02 ` [PATCH 13/49] Bluetooth: Add basic support for AES-CMAC Johan Hedberg
2014-12-03 15:02 ` Johan Hedberg [this message]
2014-12-03 15:02 ` [PATCH 15/49] Bluetooth: Add basic support for sending our LE SC public key Johan Hedberg
2014-12-03 15:02 ` [PATCH 16/49] Bluetooth: Add handler function for receiving " Johan Hedberg
2014-12-03 15:02 ` [PATCH 17/49] Bluetooth: Add support for sending LE SC Confirm value Johan Hedberg
2014-12-03 15:02 ` [PATCH 18/49] Bluetooth: Add LE SC support for responding to Pairing Confirm PDU Johan Hedberg
2014-12-03 15:02 ` [PATCH 19/49] Bluetooth: Add support for LE SC numeric comparison Johan Hedberg
2014-12-03 15:02 ` [PATCH 20/49] Bluetooth: Add support for handling LE SC user response Johan Hedberg
2014-12-03 15:02 ` [PATCH 21/49] Bluetooth: Add support for LE SC DHKey check PDU Johan Hedberg
2014-12-03 15:02 ` [PATCH 22/49] Bluetooth: Add support for LE SC key generation Johan Hedberg
2014-12-03 15:02 ` [PATCH 23/49] Bluetooth: Track authentication method in SMP context Johan Hedberg
2014-12-03 15:02 ` [PATCH 24/49] Bluetooth: Add selection of the SC authentication method Johan Hedberg
2014-12-03 15:02 ` [PATCH 25/49] Bluetooth: Detect SMP SC debug keys Johan Hedberg
2014-12-03 15:02 ` [PATCH 26/49] Bluetooth: Add check for accidentally generating a debug key Johan Hedberg
2014-12-03 15:02 ` [PATCH 27/49] Bluetooth: Set correct LTK type and authentication for SC Johan Hedberg
2014-12-03 15:02 ` [PATCH 28/49] Bluetooth: Add support for SC just-works pairing Johan Hedberg
2014-12-03 15:02 ` [PATCH 29/49] Bluetooth: Fix BR/EDR Link Key type when derived through LE SC Johan Hedberg
2014-12-03 15:02 ` [PATCH 30/49] Bluetooth: Add passkey entry support for " Johan Hedberg
2014-12-03 15:02 ` [PATCH 31/49] Bluetooth: Fix DHKey Check sending order for slave role Johan Hedberg
2014-12-03 15:02 ` [PATCH 32/49] Bluetooth: Add dummy handler for LE SC keypress notification Johan Hedberg
2014-12-03 15:02 ` [PATCH 33/49] Bluetooth: Use debug keys for SMP when HCI_USE_DEBUG_KEYS is set Johan Hedberg
2014-12-03 15:02 ` [PATCH 34/49] Bluetooth: Add hci_conn flag for new link key generation Johan Hedberg
2014-12-03 15:02 ` [PATCH 35/49] Bluetooth: Add debugfs switch for forcing SMP over BR/EDR Johan Hedberg
2014-12-03 15:02 ` [PATCH 36/49] Bluetooth: Add skeleton for BR/EDR SMP channel Johan Hedberg
2014-12-03 15:02 ` [PATCH 37/49] Bluetooth: Add full SMP BR/EDR support Johan Hedberg
2014-12-03 15:02 ` [PATCH 38/49] Bluetooth: Add SC-only mode support for SMP Johan Hedberg
2014-12-03 15:02 ` [PATCH 39/49] Bluetooth: Unify remote OOB data functions Johan Hedberg
2014-12-03 15:02 ` [PATCH 40/49] Bluetooth: Store address type with OOB data Johan Hedberg
2014-12-03 15:02 ` [PATCH 41/49] Bluetooth: Add support for adding remote OOB data for LE Johan Hedberg
2014-12-03 15:02 ` [PATCH 42/49] Bluetooth: Set SMP OOB flag if OOB data is available Johan Hedberg
2014-12-03 15:02 ` [PATCH 43/49] Bluetooth: Add basic LE SC OOB support for remote OOB data Johan Hedberg
2014-12-03 15:02 ` [PATCH 44/49] Bluetooth: Introduce SMP_DBG macro for low-level debuging Johan Hedberg
2014-12-03 15:02 ` [PATCH 45/49] Bluetooth: Fix missing const declarations in SMP functions Johan Hedberg
2014-12-03 15:02 ` [PATCH 46/49] Bluetooth: Organize SMP crypto functions to logical sections Johan Hedberg
2014-12-03 15:02 ` [PATCH 47/49] Bluetooth: Fix SMP debug key handling Johan Hedberg
2014-12-03 15:02 ` [PATCH 48/49] Bluetooth: Fix minor coding style issue in smp.c Johan Hedberg
2014-12-03 15:02 ` [PATCH 49/49] Bluetooth: Fix false-positive "uninitialized" compiler warning Johan Hedberg
2014-12-03 15:56 ` [PATCH 00/49] Bluetooth: LE Secure Connections support Marcel Holtmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1417618963-18010-15-git-send-email-johan.hedberg@gmail.com \
    --to=johan.hedberg@gmail.com \
    --cc=linux-bluetooth@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.