Merge pull request #67 from dgarske/btle_example

BTLE / Lightweight secure transport example using ECC Encrypt
pull/69/head
toddouska 2017-07-21 11:33:49 -07:00 committed by GitHub
commit a16f3b1066
9 changed files with 776 additions and 0 deletions

2
.gitignore vendored
View File

@ -93,3 +93,5 @@ certgen/newCert*
certgen/run_certgen_example
btle/ecc-client
btle/ecc-server

View File

@ -111,6 +111,13 @@ cd ./tls
make
```
#### BTLE
This directory contains examples for securing a Bluetooth Low Energy Link (BTLE).
BTLE packets are small and throughput is low, so these examples demonstrate a way
to exchange data securley without BTLE pariing.
## Notes
When necessary, examples will use the example certificates and keys located

Binary file not shown.

39
btle/Makefile 100644
View File

@ -0,0 +1,39 @@
# BTLE Examples Makefile
CC = gcc
LIB_PATH = /usr/local
CFLAGS = -Wall -I$(LIB_PATH)/include
LIBS = -L$(LIB_PATH)/lib
# option variables
DYN_LIB = -lwolfssl
STATIC_LIB = $(LIB_PATH)/lib/libwolfssl.a
DEBUG_FLAGS = -g -DDEBUG
OPTIMIZE = -Os
# Options
CFLAGS+=$(DEBUG_FLAGS)
#CFLAGS+=$(OPTIMIZE)
#LIBS+=$(DYN_LIB) -lm
.PHONY: clean all
all: ecc-client ecc-server
debug: CFLAGS+=$(DEBUG_FLAGS)
debug: all
# build template
%.o: %.c
gcc -c $< -o $@ $(CFLAGS)
ecc-server: ecc-server.o btle-sim.o $(STATIC_LIB)
$(CC) $^ -o $@ $(LIBS)
ecc-client: ecc-client.o btle-sim.o $(STATIC_LIB)
$(CC) $^ -o $@ $(LIBS)
clean:
rm *.o

28
btle/README.md 100644
View File

@ -0,0 +1,28 @@
# BTLE Examples
Bluetooth Low Energy (BTLE or BLE) is a leightweight / low power wireless protocol. Its supported by Apple iPhone 4s and later and most Android phones. It operates in the 2.4GHz spectrum and has 3 advertising channels and 37 data channels.
These examples demonstrate leightweight methods for exchanging data securley over anytype of publically visible link.
The first phase is key establishment, which is done through ECDH and HDKF. ECC was choosen for these examples because its leightweight and widely used. Salt exchanged to provent data reply of messages. The enryption is done with AES CBC. The data integrity is done using HMAC-SHA256.
## ECC Encrypt/Decrypt Example
See `BTLESecureMessageExchange.pdf` for details.
### Building
The wolfSSL library must be built and installed using './configure --enable-ecc --enable-eccencrypt --enable-hkdf && make && sudo make install' or by defining `#define HAVE_ECC`, `#define HAVE_ECC_ENCRYPT` and `HAVE_HKDF`.
### Usage
Use two consoles and STDIN to exchange data between the client and server.
```
./ecc-server
./ecc-client
```
### BTLE Simulator
The simulator uses IPC (pipes) to communicate between threads for simualted communication between two devices.

232
btle/btle-sim.c 100644
View File

@ -0,0 +1,232 @@
/* btle-sim.c
*
* Copyright (C) 2006-2017 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/ssl.h>
#include <wolfssl/wolfcrypt/logging.h>
#include "btle-sim.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/select.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
//#define BTLE_DEBUG_IO
#define BTLE_VER 1
typedef struct {
int role;
int fdmiso;
int fdmosi;
} BtleDev_t;
typedef struct {
unsigned char ver;
unsigned char type;
unsigned short len;
} __attribute__ ((packed)) BtleHeader_t;
static BtleDev_t gBtleDev;
static const char* kBtleMisoFifo = "/tmp/btleMiso";
static const char* kBtleMosiFifo = "/tmp/btleMosi";
static int btle_get_write(BtleDev_t* dev)
{
return (dev->role == BTLE_ROLE_SERVER) ? dev->fdmosi : dev->fdmiso;
}
static int btle_get_read(BtleDev_t* dev)
{
return (dev->role == BTLE_ROLE_SERVER) ? dev->fdmiso : dev->fdmosi;
}
static int btle_send_block(BtleDev_t* dev, const void* buf, int len, int fd)
{
int ret;
ret = write(fd, buf, len);
#ifdef BTLE_DEBUG_IO
printf("Write: %d\n", ret);
WOLFSSL_BUFFER(buf, len);
#endif
(void)dev;
return ret;
}
static int btle_recv_block(BtleDev_t* dev, void* buf, int len, int fd)
{
fd_set set;
int ret, pos = 0;
FD_ZERO(&set);
FD_SET(fd, &set);
while (pos < len) {
ret = select(fd+1, &set, NULL, NULL, NULL);
if (ret == 0)
continue;
if (ret < 0)
return ret;
if (FD_ISSET(fd, &set)) {
ret = read(fd, &buf[pos], len - pos);
#ifdef BTLE_DEBUG_IO
printf("Read: %d\n", ret);
WOLFSSL_BUFFER(&buf[pos], len-pos);
#endif
if (ret > 0) {
pos += ret;
}
else {
if (errno == EWOULDBLOCK) {
continue;
}
else {
return ret;
}
}
}
}
(void)dev;
return pos;
}
int btle_open(void** dev, int role)
{
int fdmiso, fdmosi;
mkfifo(kBtleMisoFifo, 0666);
mkfifo(kBtleMosiFifo, 0666);
if (role == BTLE_ROLE_SERVER) {
fdmiso = open(kBtleMisoFifo, O_RDONLY | O_NONBLOCK);
fdmosi = open(kBtleMosiFifo, O_WRONLY);
}
else {
fdmosi = open(kBtleMosiFifo, O_RDONLY | O_NONBLOCK);
fdmiso = open(kBtleMisoFifo, O_WRONLY);
}
if (fdmiso < 0) {
printf("Open %s failed! %d\n", kBtleMisoFifo, errno);
return -1;
}
if (fdmosi < 0) {
printf("Open %s failed! %d\n", kBtleMosiFifo, errno);
close(fdmiso);
return -1;
}
gBtleDev.role = role;
gBtleDev.fdmiso = fdmiso;
gBtleDev.fdmosi = fdmosi;
if (dev)
*dev = &gBtleDev;
return 0;
}
int btle_send(const unsigned char* buf, int len, int type, void* context)
{
BtleDev_t* dev = (BtleDev_t*)context;
BtleHeader_t header;
int fd = btle_get_write(dev);
int ret;
header.ver = BTLE_VER;
header.type = type;
header.len = len;
ret = btle_send_block(dev, &header, sizeof(header), fd);
if (ret < 0)
return ret;
ret = btle_send_block(dev, buf, len, fd);
if (ret < 0)
return ret;
return len;
}
int btle_recv(unsigned char* buf, int len, int* type, void* context)
{
BtleDev_t* dev = (BtleDev_t*)context;
BtleHeader_t header;
int ret;
int fd = btle_get_read(dev);
ret = btle_recv_block(dev, &header, sizeof(header), fd);
if (ret < 0)
return ret;
if (header.ver != BTLE_VER)
return -1;
if (type)
*type = header.type;
if (len > 0) {
ret = header.len;
if (ret > len)
ret = len;
ret = btle_recv_block(dev, buf, ret, fd);
if (ret < 0)
return ret;
}
return header.len;
}
void btle_close(void* context)
{
BtleDev_t* dev = (BtleDev_t*)context;
close(dev->fdmiso);
close(dev->fdmosi);
unlink(kBtleMisoFifo);
unlink(kBtleMosiFifo);
}
int btle_msg_pad(unsigned char* buf, int* len, void* context)
{
BtleDev_t* dev = (BtleDev_t*)context;
int newLen = *len;
int odd = (newLen % BTLE_BLOCK_SIZE);
if (odd != 0) {
int addLen = (BTLE_BLOCK_SIZE - odd);
newLen += addLen;
if (newLen > BTLE_MSG_MAX_SIZE)
return -1;
memset(&buf[*len], 0, addLen);
}
*len = newLen;
(void)dev;
return 0;
}

44
btle/btle-sim.h 100644
View File

@ -0,0 +1,44 @@
/* btle-sim.h
*
* Copyright (C) 2006-2017 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define BTLE_MSG_MAX_SIZE 1024
#define BTLE_BLOCK_SIZE 16
typedef enum {
BTLE_PKT_TYPE_NULL,
BTLE_PKT_TYPE_KEY,
BTLE_PKT_TYPE_SALT,
BTLE_PKT_TYPE_MSG,
BTLE_PKT_TYPE_MAX,
} BtlePacket_t;
typedef enum {
BTLE_ROLE_CLIENT,
BTLE_ROLE_SERVER,
} BtleRole_t;
int btle_open(void** dev, int role);
int btle_send(const unsigned char* buf, int len, int type, void* context);
int btle_recv(unsigned char* buf, int len, int* type, void* context);
void btle_close(void* context);
int btle_msg_pad(unsigned char* buf, int* len, void* context);

215
btle/ecc-client.c 100644
View File

@ -0,0 +1,215 @@
/* ecc-client.c
*
* Copyright (C) 2006-2017 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/ssl.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include "btle-sim.h"
int main(int argc, char** argv)
{
int ret;
WC_RNG rng;
ecEncCtx* cliCtx = NULL;
void* devCtx = NULL;
const byte* mySalt;
byte peerSalt[EXCHANGE_SALT_SZ];
byte buffer[BTLE_MSG_MAX_SIZE];
word32 bufferSz;
byte plain[BTLE_MSG_MAX_SIZE];
word32 plainSz;
ecc_key myKey, peerKey;
int type;
wolfSSL_Init();
#ifdef DEBUG_WOLFSSL
wolfSSL_Debugging_ON();
#endif
/* make my session key */
ret = wc_ecc_init(&myKey);
ret |= wc_ecc_init(&peerKey);
if (ret != 0) {
printf("wc_ecc_init failed!\n");
goto cleanup;
}
/* open BTLE */
ret = btle_open(&devCtx, BTLE_ROLE_CLIENT);
if (ret != 0) {
printf("btle_open failed %d! errno %d\n", ret, errno);
goto cleanup;
}
ret = wc_InitRng(&rng);
if (ret != 0) {
printf("wc_InitRng failed! %d\n", ret);
goto cleanup;
}
ret = wc_ecc_make_key(&rng, 32, &myKey);
if (ret != 0) {
printf("wc_ecc_make_key failed %d\n", ret);
goto cleanup;
}
cliCtx = wc_ecc_ctx_new(REQ_RESP_CLIENT, &rng);
if (cliCtx == NULL) {
printf("wc_ecc_ctx_new failed!\n");
ret = -1; goto cleanup;
}
/* exchange public keys */
/* export my public key */
bufferSz = sizeof(buffer);
ret = wc_ecc_export_x963(&myKey, buffer, &bufferSz);
if (ret != 0) {
printf("wc_ecc_export_x963 failed %d\n", ret);
goto cleanup;
}
/* send my public key */
ret = btle_send(buffer, bufferSz, BTLE_PKT_TYPE_KEY, devCtx);
if (ret != bufferSz) {
printf("btle_send key failed %d!\n", ret);
goto cleanup;
}
/* Get peer key */
ret = btle_recv(buffer, sizeof(buffer), &type, devCtx);
if (ret <= 0) {
printf("btle_recv key failed %d\n", ret);
goto cleanup;
}
if (type != BTLE_PKT_TYPE_KEY) {
printf("btle_recv expected key!\n");
ret = -1; goto cleanup;
}
/* TODO: Client should hash and verify this public key against trusted ceritifcate (already exchanged) */
/* ECC signature is about 65 bytes */
/* import peer public key */
bufferSz = ret;
ret = wc_ecc_import_x963(buffer, bufferSz, &peerKey);
if (ret != 0) {
printf("wc_ecc_import_x963 failed %d\n", ret);
goto cleanup;
}
/* Collect Message to send and get echo */
while (1) {
/* get my salt */
mySalt = wc_ecc_ctx_get_own_salt(cliCtx);
if (mySalt == NULL) {
printf("wc_ecc_ctx_get_own_salt failed!\n");
ret = -1; goto cleanup;
}
/* Send my salt */
ret = btle_send(mySalt, EXCHANGE_SALT_SZ, BTLE_PKT_TYPE_SALT, devCtx);
if (ret != EXCHANGE_SALT_SZ) {
printf("btle_send salt failed %d!\n", ret);
goto cleanup;
}
/* Get peer salt */
ret = btle_recv(peerSalt, EXCHANGE_SALT_SZ, &type, devCtx);
if (ret <= 0) {
printf("btle_recv failed %d! errno %d\n", ret, errno);
}
if (type != BTLE_PKT_TYPE_SALT) {
printf("btle_recv expected salt!\n");
ret = -1; goto cleanup;
}
ret = wc_ecc_ctx_set_peer_salt(cliCtx, peerSalt);
if (ret != 0) {
printf("wc_ecc_ctx_set_peer_salt failed %d\n", ret);
goto cleanup;
}
/* get message to send */
plainSz = sizeof(plain);
fgets((char*)plain, plainSz, stdin);
plainSz = strlen((char*)plain);
ret = btle_msg_pad(plain, (int*)&plainSz, devCtx);
if (ret != 0) {
printf("btle_msg_pad failed %d\n", ret);
goto cleanup;
}
/* Encrypt message */
bufferSz = sizeof(buffer);
ret = wc_ecc_encrypt(&myKey, &peerKey, plain, plainSz, buffer, &bufferSz, cliCtx);
if (ret != 0) {
printf("wc_ecc_encrypt failed %d!\n", ret);
goto cleanup;
}
/* Send message */
ret = btle_send(buffer, bufferSz, BTLE_PKT_TYPE_MSG, devCtx);
if (ret != bufferSz) {
printf("btle_send failed %d!\n", ret);
goto cleanup;
}
/* Get message */
bufferSz = sizeof(buffer);
ret = btle_recv(buffer, bufferSz, &type, devCtx);
if (type != BTLE_PKT_TYPE_MSG) {
ret = -1; goto cleanup;
}
/* Decrypt message */
bufferSz = ret;
plainSz = sizeof(plain);
ret = wc_ecc_decrypt(&myKey, &peerKey, buffer, bufferSz, plain, &plainSz, cliCtx);
if (ret != 0) {
printf("wc_ecc_decrypt failed %d!\n", ret);
goto cleanup;
}
printf("Recv %d: %s\n", plainSz, plain);
/* check for exit flag */
if (strstr((char*)plain, "EXIT"))
break;
/* reset context (reset my salt) */
ret = wc_ecc_ctx_reset(cliCtx, &rng);
if (ret != 0) {
printf("wc_ecc_ctx_reset failed %d\n", ret);
goto cleanup;
}
}
cleanup:
if (devCtx != NULL)
btle_close(devCtx);
wolfSSL_Cleanup();
return ret;
}

209
btle/ecc-server.c 100644
View File

@ -0,0 +1,209 @@
/* ecc-server.c
*
* Copyright (C) 2006-2017 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/ssl.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include "btle-sim.h"
int main(int argc, char** argv)
{
int ret;
WC_RNG rng;
ecEncCtx* srvCtx = NULL;
void* devCtx = NULL;
const byte* mySalt;
byte peerSalt[EXCHANGE_SALT_SZ];
byte buffer[BTLE_MSG_MAX_SIZE];
word32 bufferSz;
byte plain[BTLE_MSG_MAX_SIZE];
word32 plainSz;
ecc_key myKey, peerKey;
int type;
wolfSSL_Init();
#ifdef DEBUG_WOLFSSL
wolfSSL_Debugging_ON();
#endif
/* make my session key */
ret = wc_ecc_init(&myKey);
ret |= wc_ecc_init(&peerKey);
if (ret != 0) {
printf("wc_ecc_init failed!\n");
goto cleanup;
}
/* open BTLE */
ret = btle_open(&devCtx, BTLE_ROLE_SERVER);
if (ret != 0) {
printf("btle_open failed %d! errno %d\n", ret, errno);
goto cleanup;
}
ret = wc_InitRng(&rng);
if (ret != 0) {
printf("wc_InitRng failed! %d\n", ret);
goto cleanup;
}
ret = wc_ecc_make_key(&rng, 32, &myKey);
if (ret != 0) {
printf("wc_ecc_make_key failed %d\n", ret);
goto cleanup;
}
srvCtx = wc_ecc_ctx_new(REQ_RESP_SERVER, &rng);
if (srvCtx == NULL) {
printf("wc_ecc_ctx_new failed!\n");
ret = -1; goto cleanup;
}
/* exchange public keys */
/* Get peer key */
ret = btle_recv(buffer, sizeof(buffer), &type, devCtx);
if (ret < 0) {
printf("btle_recv key failed %d! errno %d\n", ret, errno);
goto cleanup;
}
if (type != BTLE_PKT_TYPE_KEY) {
printf("btle_recv expected key!\n");
ret = -1; goto cleanup;
}
bufferSz = ret;
ret = wc_ecc_import_x963(buffer, bufferSz, &peerKey);
if (ret != 0) {
printf("wc_ecc_import_x963 failed %d!\n", ret);
goto cleanup;
}
/* send my public key */
/* export my public key */
bufferSz = sizeof(buffer);
ret = wc_ecc_export_x963(&myKey, buffer, &bufferSz);
if (ret != 0) {
printf("wc_ecc_export_x963 failed %d\n", ret);
goto cleanup;
}
/* TODO: Server should hash and sign this public key with a trust ceritifcate (already exchanged) */
/* ECC signature is about 65 bytes */
ret = btle_send(buffer, bufferSz, BTLE_PKT_TYPE_KEY, devCtx);
if (ret != bufferSz) {
printf("btle_send key failed %d!\n", ret);
goto cleanup;
}
while (1) {
mySalt = wc_ecc_ctx_get_own_salt(srvCtx);
if (mySalt == NULL) {
printf("wc_ecc_ctx_get_own_salt failed!\n");
ret = -1; goto cleanup;
}
/* Get peer salt */
ret = btle_recv(peerSalt, EXCHANGE_SALT_SZ, &type, devCtx);
if (ret <= 0) {
printf("btle_recv salt failed %d! errno %d\n", ret, errno);
goto cleanup;
}
if (type != BTLE_PKT_TYPE_SALT) {
printf("btle_recv expected salt!\n");
ret = -1; goto cleanup;
}
/* Send my salt */
/* You must send mySalt before set_peer_salt, because buffer changes */
ret = btle_send(mySalt, EXCHANGE_SALT_SZ, BTLE_PKT_TYPE_SALT, devCtx);
if (ret != EXCHANGE_SALT_SZ) {
printf("btle_send salt failed %d!\n", ret);
goto cleanup;
}
ret = wc_ecc_ctx_set_peer_salt(srvCtx, peerSalt);
if (ret != 0) {
printf("wc_ecc_ctx_set_peer_salt failed %d\n", ret);
goto cleanup;
}
/* Get message */
bufferSz = sizeof(buffer);
ret = btle_recv(buffer, bufferSz, &type, devCtx);
if (ret <= 0) {
printf("btle_recv msg failed %d! errno %d\n", ret, errno);
goto cleanup;
}
if (type != BTLE_PKT_TYPE_MSG) {
printf("btle_recv expected msg!\n");
ret = -1; goto cleanup;
}
/* Decrypt message */
bufferSz = ret;
plainSz = sizeof(plain);
ret = wc_ecc_decrypt(&myKey, &peerKey, buffer, bufferSz, plain, &plainSz, srvCtx);
if (ret != 0) {
printf("wc_ecc_decrypt failed %d!\n", ret);
goto cleanup;
}
printf("Recv %d: %s\n", plainSz, plain);
/* Encrypt message */
bufferSz = sizeof(buffer);
ret = wc_ecc_encrypt(&myKey, &peerKey, plain, plainSz, buffer, &bufferSz, srvCtx);
if (ret != 0) {
printf("wc_ecc_encrypt failed %d!\n", ret);
goto cleanup;
}
/* Send message */
ret = btle_send(buffer, bufferSz, BTLE_PKT_TYPE_MSG, devCtx);
if (ret != bufferSz) {
printf("btle_send failed %d!\n", ret);
goto cleanup;
}
/* check for exit flag */
if (strstr((char*)plain, "EXIT"))
break;
/* reset context (reset my salt) */
ret = wc_ecc_ctx_reset(srvCtx, &rng);
if (ret != 0) {
printf("wc_ecc_ctx_reset failed %d\n", ret);
goto cleanup;
}
}
cleanup:
if (devCtx != NULL)
btle_close(devCtx);
wolfSSL_Cleanup();
return ret;
}