Noise integration compiles
This commit is contained in:
parent
8ee5f4ce6a
commit
050d49a56b
10 changed files with 745 additions and 5 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -8,3 +8,8 @@
|
|||
*.project
|
||||
*.a
|
||||
doc
|
||||
Makefile
|
||||
CMakeCache.txt
|
||||
cmake_install.cmake
|
||||
CMakeFiles
|
||||
src/demo
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ set (ARCH_FLAGS
|
|||
"-mthumb -mcpu=cortex-m4 ${FP_FLAGS}"
|
||||
)
|
||||
set (COMMON_FLAGS
|
||||
"-O2 -g -Wextra -Wshadow -Wredundant-decls -fno-common -ffunction-sections -fdata-sections"
|
||||
"-O2 -g -Wextra -Wshadow -Wredundant-decls -fno-common -ffunction-sections -fdata-sections --specs=nosys.specs"
|
||||
)
|
||||
|
||||
set (CMAKE_C_FLAGS
|
||||
|
|
@ -57,7 +57,10 @@ set (CMAKE_EXE_LINKER_FLAGS
|
|||
"--static -nostartfiles -T${CMAKE_SOURCE_DIR}/libusbhost_stm32f4.ld -Wl,-Map=FIXME_ONE.map -Wl,--gc-sections -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group"
|
||||
)
|
||||
|
||||
include_directories (${CMAKE_SOURCE_DIR}/include)
|
||||
include_directories (
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
src/crypto/noise-c/include
|
||||
)
|
||||
|
||||
function (init_libopencm3)
|
||||
include_directories (${CMAKE_SOURCE_DIR}/libopencm3/include)
|
||||
|
|
|
|||
23
include/cobs.h
Normal file
23
include/cobs.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef __COBS_H__
|
||||
#define __COBS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
struct cobs_decode_state {
|
||||
size_t p;
|
||||
size_t c;
|
||||
};
|
||||
|
||||
|
||||
ssize_t cobs_encode(char *dst, size_t dstlen, char *src, size_t srclen);
|
||||
ssize_t cobs_decode(char *dst, size_t dstlen, char *src, size_t srclen);
|
||||
|
||||
int cobs_encode_incremental(void *f, int (*output)(void *, char), char *src, size_t srclen);
|
||||
|
||||
void cobs_decode_incremental_initialize(struct cobs_decode_state *state);
|
||||
int cobs_decode_incremental(struct cobs_decode_state *state, char *dst, size_t dstlen, char src);
|
||||
|
||||
#endif//__COBS_H__
|
||||
|
|
@ -33,3 +33,9 @@ MEMORY
|
|||
/* Include the common ld script. */
|
||||
INCLUDE libopencm3_stm32f4.ld
|
||||
|
||||
PROVIDE(_ram_start = ORIGIN(ram));
|
||||
PROVIDE(_ram_end = ORIGIN(ram) + LENGTH(ram));
|
||||
PROVIDE(_rom_start = ORIGIN(rom));
|
||||
PROVIDE(_rom_end = ORIGIN(rom) + LENGTH(rom));
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -24,16 +24,25 @@ add_library (usbhost
|
|||
cobs.c
|
||||
)
|
||||
|
||||
add_subdirectory (crypto)
|
||||
|
||||
add_definitions (
|
||||
-DBLAKE2S_USE_VECTOR_MATH=0
|
||||
)
|
||||
|
||||
target_link_libraries (usbhost
|
||||
noise
|
||||
${LIBOPENCM3_LIB}
|
||||
)
|
||||
|
||||
add_executable (demo
|
||||
rand_stm32.c
|
||||
demo.c
|
||||
)
|
||||
|
||||
target_link_libraries (demo
|
||||
usbhost
|
||||
noise
|
||||
)
|
||||
|
||||
add_custom_command (TARGET demo
|
||||
|
|
|
|||
292
src/cobs.c
Normal file
292
src/cobs.c
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
|
||||
#include <cobs.h>
|
||||
|
||||
/*@ requires \valid(dst + (0..dstlen-1));
|
||||
@ requires \valid_read(src + (0..srclen-1));
|
||||
@ requires \separated(dst + (0..dstlen-1), src + (0..srclen-1));
|
||||
@
|
||||
@ behavior valid:
|
||||
@ assumes 0 <= srclen <= 254;
|
||||
@ assumes 0 <= dstlen <= 65535;
|
||||
@ assumes dstlen >= srclen+2;
|
||||
@ assigns dst[0..srclen+1];
|
||||
@ ensures \forall integer i; (0 <= i < srclen && \old(src[i]) != 0) ==> dst[i+1] == src[i];
|
||||
@ ensures \result == srclen+2;
|
||||
@ ensures \forall integer i; 0 <= i <= srclen ==> dst[i] != 0;
|
||||
@ ensures dst[srclen+1] == 0;
|
||||
@
|
||||
@ behavior invalid:
|
||||
@ assumes srclen < 0 || srclen > 254
|
||||
@ || dstlen < 0 || dstlen > 65535
|
||||
@ || dstlen < srclen+2;
|
||||
@ assigns \nothing;
|
||||
@ ensures \result == -1;
|
||||
@
|
||||
@ complete behaviors;
|
||||
@ disjoint behaviors;
|
||||
@*/
|
||||
ssize_t cobs_encode(char *dst, size_t dstlen, char *src, size_t srclen) {
|
||||
if (dstlen > 65535 || srclen > 254)
|
||||
return -1;
|
||||
//@ assert 0 <= dstlen <= 65535 && 0 <= srclen <= 254;
|
||||
|
||||
if (dstlen < srclen+2)
|
||||
return -1;
|
||||
//@ assert 0 <= srclen < srclen+2 <= dstlen;
|
||||
|
||||
size_t p = 0;
|
||||
/*@ loop invariant 0 <= p <= srclen+1;
|
||||
@ loop invariant \forall integer i; 0 <= i < p ==> dst[i] != 0;
|
||||
@ loop invariant \forall integer i; 0 < i < p ==> (src[i-1] != 0 ==> dst[i] == src[i-1]);
|
||||
@ loop assigns p, dst[0..srclen+1];
|
||||
@ loop variant srclen-p+1;
|
||||
@*/
|
||||
while (p <= srclen) {
|
||||
|
||||
char val;
|
||||
if (p != 0 && src[p-1] != 0) {
|
||||
val = src[p-1];
|
||||
|
||||
} else {
|
||||
size_t q = p;
|
||||
/*@ loop invariant 0 <= p <= q <= srclen;
|
||||
@ loop invariant \forall integer i; p <= i < q ==> src[i] != 0;
|
||||
@ loop assigns q;
|
||||
@ loop variant srclen-q;
|
||||
@*/
|
||||
while (q < srclen && src[q] != 0)
|
||||
q++;
|
||||
//@ assert q == srclen || src[q] == 0;
|
||||
//@ assert q <= srclen <= 254;
|
||||
val = (char)q-p+1;
|
||||
//@ assert val != 0;
|
||||
}
|
||||
|
||||
dst[p] = val;
|
||||
p++;
|
||||
}
|
||||
|
||||
dst[p] = 0;
|
||||
//@ assert p == srclen+1;
|
||||
|
||||
return srclen+2;
|
||||
}
|
||||
|
||||
int cobs_encode_incremental(void *f, int (*output)(void *f, char c), char *src, size_t srclen) {
|
||||
if (srclen > 254)
|
||||
return -1;
|
||||
//@ assert 0 <= srclen <= 254;
|
||||
|
||||
size_t p = 0;
|
||||
/*@ loop invariant 0 <= p <= srclen+1;
|
||||
@ loop assigns p;
|
||||
@ loop variant srclen-p+1;
|
||||
@*/
|
||||
while (p <= srclen) {
|
||||
|
||||
char val;
|
||||
if (p != 0 && src[p-1] != 0) {
|
||||
val = src[p-1];
|
||||
|
||||
} else {
|
||||
size_t q = p;
|
||||
/*@ loop invariant 0 <= p <= q <= srclen;
|
||||
@ loop invariant \forall integer i; p <= i < q ==> src[i] != 0;
|
||||
@ loop assigns q;
|
||||
@ loop variant srclen-q;
|
||||
@*/
|
||||
while (q < srclen && src[q] != 0)
|
||||
q++;
|
||||
//@ assert q == srclen || src[q] == 0;
|
||||
//@ assert q <= srclen <= 254;
|
||||
val = (char)q-p+1;
|
||||
//@ assert val != 0;
|
||||
}
|
||||
|
||||
int rv = output(f, val);
|
||||
if (rv)
|
||||
return rv;
|
||||
p++;
|
||||
}
|
||||
|
||||
int rv = output(f, 0);
|
||||
if (rv)
|
||||
return rv;
|
||||
//@ assert p == srclen+1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*@ requires \valid(dst + (0..dstlen-1));
|
||||
@ requires \valid_read(src + (0..srclen-1));
|
||||
@ requires \separated(dst + (0..dstlen-1), src + (0..srclen-1));
|
||||
@
|
||||
@ behavior maybe_valid_frame:
|
||||
@ assumes 1 <= srclen <= dstlen <= 65535;
|
||||
@ assumes \exists integer j; j > 0 && \forall integer i; 0 <= i < j ==> src[i] != 0;
|
||||
@ assumes \exists integer i; 0 <= i < srclen && src[i] == 0;
|
||||
@ assigns dst[0..dstlen-1];
|
||||
@ ensures \result >= 0 || \result == -3;
|
||||
@ ensures \result >= 0 ==> src[\result+1] == 0;
|
||||
@ ensures \result >= 0 ==> (\forall integer i; 0 <= i < \result ==> src[i] != 0);
|
||||
@
|
||||
@ behavior invalid_frame:
|
||||
@ assumes 1 <= srclen <= dstlen <= 65535;
|
||||
@ assumes src[0] == 0 || \forall integer i; 0 <= i < srclen ==> src[i] != 0;
|
||||
@ assigns dst[0..dstlen-1];
|
||||
@ ensures \result == -2;
|
||||
@
|
||||
@ behavior invalid_buffers:
|
||||
@ assumes dstlen < 0 || dstlen > 65535
|
||||
@ || srclen < 1 || srclen > 65535
|
||||
@ || dstlen < srclen;
|
||||
@ assigns \nothing;
|
||||
@ ensures \result == -1;
|
||||
@
|
||||
@ complete behaviors;
|
||||
@ disjoint behaviors;
|
||||
@*/
|
||||
ssize_t cobs_decode(char *dst, size_t dstlen, char *src, size_t srclen) {
|
||||
if (dstlen > 65535 || srclen > 65535)
|
||||
return -1;
|
||||
|
||||
if (srclen < 1)
|
||||
return -1;
|
||||
|
||||
if (dstlen < srclen)
|
||||
return -1;
|
||||
|
||||
size_t p = 1;
|
||||
size_t c = (unsigned char)src[0];
|
||||
//@ assert 0 <= c < 256;
|
||||
//@ assert 0 <= c;
|
||||
//@ assert c < 256;
|
||||
if (c == 0)
|
||||
return -2; /* invalid framing. An empty frame would be [...] 00 01 00, not [...] 00 00 */
|
||||
//@ assert c >= 0;
|
||||
//@ assert c != 0;
|
||||
//@ assert c <= 257;
|
||||
//@ assert c > 0;
|
||||
//@ assert c >= 0 && c != 0 ==> c > 0;
|
||||
|
||||
/*@ //loop invariant \forall integer i; 0 <= i <= p ==> (i == srclen || src[i] != 0);
|
||||
@ loop invariant \forall integer i; 1 <= i < p ==> src[i] != 0;
|
||||
@ loop invariant c > 0;
|
||||
@ loop invariant 1 <= p <= srclen <= dstlen <= 65535;
|
||||
@ loop invariant \separated(dst + (0..dstlen-1), src + (0..srclen-1));
|
||||
@ loop invariant \valid_read(src + (0..srclen-1));
|
||||
@ loop invariant \forall integer i; 1 <= i <= srclen ==> \valid(dst + i - 1);
|
||||
@ loop assigns dst[0..dstlen-1], p, c;
|
||||
@ loop variant srclen-p;
|
||||
@*/
|
||||
while (p < srclen && src[p]) {
|
||||
char val;
|
||||
c--;
|
||||
|
||||
//@ assert src[p] != 0;
|
||||
if (c == 0) {
|
||||
c = (unsigned char)src[p];
|
||||
val = 0;
|
||||
} else {
|
||||
val = src[p];
|
||||
}
|
||||
|
||||
//@ assert 0 <= p-1 <= dstlen-1;
|
||||
dst[p-1] = val;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (p == srclen)
|
||||
return -2; /* Invalid framing. The terminating null byte should always be present in the input buffer. */
|
||||
|
||||
if (c != 1)
|
||||
return -3; /* Invalid framing. The skip counter does not hit the end of the frame. */
|
||||
|
||||
//@ assert 0 < p <= srclen <= 65535;
|
||||
//@ assert src[p] == 0;
|
||||
//@ assert \forall integer i; 1 <= i < p ==> src[i] != 0;
|
||||
return p-1;
|
||||
}
|
||||
|
||||
void cobs_decode_incremental_initialize(struct cobs_decode_state *state) {
|
||||
state->p = 0;
|
||||
state->c = 0;
|
||||
}
|
||||
|
||||
int cobs_decode_incremental(struct cobs_decode_state *state, char *dst, size_t dstlen, char src) {
|
||||
if (state->p == 0) {
|
||||
if (src == 0)
|
||||
goto errout; /* invalid framing. An empty frame would be [...] 00 01 00, not [...] 00 00 */
|
||||
state->c = (unsigned char)src;
|
||||
state->p++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!src) {
|
||||
if (state->c != 1)
|
||||
goto errout; /* Invalid framing. The skip counter does not hit the end of the frame. */
|
||||
int rv = state->p-1;
|
||||
cobs_decode_incremental_initialize(state);
|
||||
return rv;
|
||||
}
|
||||
|
||||
char val;
|
||||
state->c--;
|
||||
|
||||
if (state->c == 0) {
|
||||
state->c = (unsigned char)src;
|
||||
val = 0;
|
||||
} else {
|
||||
val = src;
|
||||
}
|
||||
|
||||
size_t pos = state->p-1;
|
||||
if (pos >= dstlen)
|
||||
return -2; /* output buffer too small */
|
||||
dst[pos] = val;
|
||||
state->p++;
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
cobs_decode_incremental_initialize(state);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef VALIDATION
|
||||
/*@
|
||||
@ requires 0 <= d < 256;
|
||||
@ assigns \nothing;
|
||||
@*/
|
||||
size_t test(char foo, unsigned int d) {
|
||||
unsigned int c = (unsigned char)foo;
|
||||
if (c != 0) {
|
||||
//@ assert c < 256;
|
||||
//@ assert c >= 0;
|
||||
//@ assert c != 0;
|
||||
//@ assert c > 0;
|
||||
}
|
||||
if (d != 0) {
|
||||
//@ assert d >= 0;
|
||||
//@ assert d != 0;
|
||||
//@ assert d > 0;
|
||||
}
|
||||
return c + d;
|
||||
}
|
||||
|
||||
#include <__fc_builtin.h>
|
||||
|
||||
void main(void) {
|
||||
char inbuf[254];
|
||||
char cobsbuf[256];
|
||||
char outbuf[256];
|
||||
|
||||
size_t range = Frama_C_interval(0, sizeof(inbuf));
|
||||
Frama_C_make_unknown((char *)inbuf, range);
|
||||
|
||||
cobs_encode(cobsbuf, sizeof(cobsbuf), inbuf, sizeof(inbuf));
|
||||
cobs_decode(outbuf, sizeof(outbuf), cobsbuf, sizeof(cobsbuf));
|
||||
|
||||
//@ assert \forall integer i; 0 <= i < sizeof(inbuf) ==> outbuf[i] == inbuf[i];
|
||||
}
|
||||
#endif//VALIDATION
|
||||
|
||||
93
src/crypto/CMakeLists.txt
Normal file
93
src/crypto/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
include_directories (
|
||||
noise-c/include
|
||||
noise-c/include/noise/keys
|
||||
noise-c/src
|
||||
noise-c/src/crypto/goldilocks/include
|
||||
noise-c/src/crypto/goldilocks/src/include
|
||||
noise-c/src/crypto/goldilocks/src/p448/arch_arm_32
|
||||
noise-c/src/crypto/goldilocks/src/p448
|
||||
noise-c/src/protocol
|
||||
)
|
||||
|
||||
add_library (noise
|
||||
noise-c/src/protocol/util.c
|
||||
noise-c/src/protocol/patterns.c
|
||||
noise-c/src/protocol/signstate.c
|
||||
noise-c/src/protocol/randstate.c
|
||||
noise-c/src/protocol/symmetricstate.c
|
||||
noise-c/src/protocol/internal.c
|
||||
noise-c/src/protocol/names.c
|
||||
noise-c/src/protocol/hashstate.c
|
||||
noise-c/src/protocol/errors.c
|
||||
noise-c/src/protocol/cipherstate.c
|
||||
noise-c/src/protocol/handshakestate.c
|
||||
noise-c/src/protocol/dhstate.c
|
||||
noise-c/src/keys/certificate.c
|
||||
noise-c/src/keys/loader.c
|
||||
noise-c/src/crypto/sha2/sha256.c
|
||||
noise-c/src/crypto/sha2/sha512.c
|
||||
noise-c/src/crypto/ghash/ghash.c
|
||||
noise-c/src/crypto/ed25519/ed25519.c
|
||||
noise-c/src/crypto/blake2/blake2s.c
|
||||
noise-c/src/crypto/blake2/blake2b.c
|
||||
noise-c/src/crypto/chacha/chacha.c
|
||||
noise-c/src/crypto/goldilocks/src/ec_point.c
|
||||
noise-c/src/crypto/goldilocks/src/sha512.c
|
||||
noise-c/src/crypto/goldilocks/src/p448/arch_32/p448.c
|
||||
noise-c/src/crypto/goldilocks/src/p448/f_arithmetic.c
|
||||
noise-c/src/crypto/goldilocks/src/p448/arch_arm_32/p448.c
|
||||
noise-c/src/crypto/goldilocks/src/p448/magic.c
|
||||
noise-c/src/crypto/goldilocks/src/barrett_field.c
|
||||
noise-c/src/crypto/goldilocks/src/goldilocks.c
|
||||
noise-c/src/crypto/goldilocks/src/arithmetic.c
|
||||
noise-c/src/crypto/goldilocks/src/crandom.c
|
||||
noise-c/src/crypto/goldilocks/src/scalarmul.c
|
||||
noise-c/src/crypto/newhope/poly.c
|
||||
noise-c/src/crypto/newhope/randombytes.c
|
||||
noise-c/src/crypto/newhope/reduce.c
|
||||
noise-c/src/crypto/newhope/ntt.c
|
||||
noise-c/src/crypto/newhope/crypto_stream_chacha20.c
|
||||
noise-c/src/crypto/newhope/error_correction.c
|
||||
noise-c/src/crypto/newhope/batcher.c
|
||||
noise-c/src/crypto/newhope/fips202.c
|
||||
noise-c/src/crypto/newhope/newhope.c
|
||||
noise-c/src/crypto/newhope/precomp.c
|
||||
noise-c/src/crypto/aes/rijndael-alg-fst.c
|
||||
noise-c/src/crypto/curve448/curve448.c
|
||||
noise-c/src/crypto/donna/poly1305-donna.c
|
||||
noise-c/src/crypto/donna/curve25519-donna.c
|
||||
noise-c/src/protobufs/protobufs.c
|
||||
noise-c/src/backend/ref/sign-ed25519.c
|
||||
noise-c/src/backend/ref/hash-blake2b.c
|
||||
noise-c/src/backend/ref/hash-sha512.c
|
||||
noise-c/src/backend/ref/hash-sha256.c
|
||||
noise-c/src/backend/ref/cipher-aesgcm.c
|
||||
noise-c/src/backend/ref/cipher-chachapoly.c
|
||||
noise-c/src/backend/ref/dh-curve25519.c
|
||||
noise-c/src/backend/ref/dh-newhope.c
|
||||
noise-c/src/backend/ref/dh-curve448.c
|
||||
noise-c/src/backend/ref/hash-blake2s.c
|
||||
)
|
||||
|
||||
add_definitions (
|
||||
-DUSE_LIBSODIUM=0
|
||||
-DUSE_SODIUM=0
|
||||
-DHAVE_PTHREAD=0
|
||||
-DUSE_OPENSSL=0
|
||||
-D__WORDSIZE=32
|
||||
-D__BIG_ENDIAN=4321
|
||||
-D__LITTLE_ENDIAN=1234
|
||||
-D__BYTE_ORDER=__LITTLE_ENDIAN
|
||||
-DED25519_CUSTOMRANDOM=1
|
||||
-DED25519_CUSTOMHASH=1
|
||||
-DED25519_REFHASH=1
|
||||
-DBLAKE2S_USE_VECTOR_MATH=0
|
||||
-DEXPERIMENT_CRANDOM_CUTOFF_BYTES=0
|
||||
-D__clang__=0
|
||||
)
|
||||
|
||||
set (CMAKE_C_FLAGS
|
||||
"${CMAKE_C_FLAGS} -Wno-implicit-fallthrough -Wno-shadow -Wno-unused-parameter"
|
||||
)
|
||||
|
||||
172
src/demo.c
172
src/demo.c
|
|
@ -25,6 +25,8 @@
|
|||
#include "usbh_lld_stm32f4.h" /// provides low level usb host driver for stm32f4 platform
|
||||
#include "usbh_driver_hid.h" /// provides generic usb device driver for Human Interface Device (HID)
|
||||
#include "usbh_driver_hub.h" /// provides usb full speed hub driver (Low speed devices on hub are not supported)
|
||||
#include "cobs.h"
|
||||
#include "rand_stm32.h"
|
||||
|
||||
// STM32f407 compatible
|
||||
#include <libopencm3/stm32/rcc.h>
|
||||
|
|
@ -41,6 +43,11 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <noise/protocol.h>
|
||||
|
||||
void _fini(void);
|
||||
int generate_identity_key(void);
|
||||
|
||||
static inline void delay_ms_busy_loop(uint32_t ms) {
|
||||
for (volatile uint32_t i = 0; i < 14903*ms; i++);
|
||||
}
|
||||
|
|
@ -59,6 +66,8 @@ static void clock_setup(void) {
|
|||
rcc_periph_clock_enable(RCC_TIM6);
|
||||
rcc_periph_clock_enable(RCC_DMA2);
|
||||
rcc_periph_clock_enable(RCC_DMA1);
|
||||
|
||||
rcc_periph_clock_enable(RCC_RNG);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -182,6 +191,96 @@ void dma1_stream6_isr(void) {
|
|||
schedule_dma(usart2_out);
|
||||
}
|
||||
|
||||
static struct cobs_decode_state host_cobs_state;
|
||||
#define CURVE25519_KEY_LEN 32
|
||||
#define MAX_HOST_PACKET_SIZE 256
|
||||
static volatile uint8_t host_packet_buf[MAX_HOST_PACKET_SIZE];
|
||||
static volatile uint8_t host_packet_length = 0;
|
||||
|
||||
void usart2_isr(void) {
|
||||
if (USART2_SR & USART_SR_ORE) { /* Overrun handling */
|
||||
LOG_PRINTF("USART2 data register overrun\n");
|
||||
/* Clear interrupt flag */
|
||||
(void)USART2_DR; /* FIXME make sure this read is not optimized out */
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t data = USART2_DR; /* This automatically acknowledges the IRQ */
|
||||
|
||||
if (host_packet_length) {
|
||||
LOG_PRINTF("USART2 COBS buffer overrun\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ssize_t rv = cobs_decode_incremental(&host_cobs_state, (char *)host_packet_buf, sizeof(host_packet_buf), data);
|
||||
if (rv == -2) {
|
||||
LOG_PRINTF("Host interface COBS packet too large\n");
|
||||
} else if (rv < 0) {
|
||||
LOG_PRINTF("Host interface COBS framing error\n");
|
||||
} else if (rv > 0) {
|
||||
host_packet_length = rv;
|
||||
} /* else just return and wait for next byte */
|
||||
}
|
||||
|
||||
static uint8_t local_key[CURVE25519_KEY_LEN];
|
||||
NoiseCipherState *tx_cipher, *rx_cipher;
|
||||
|
||||
#define HANDLE_NOISE_ERROR(x, msg) do { \
|
||||
err = x; \
|
||||
if (err != NOISE_ERROR_NONE) { \
|
||||
char errbuf[256]; \
|
||||
noise_strerror(err, errbuf, sizeof(errbuf)); \
|
||||
LOG_PRINTF("Error " msg ": %s\n", errbuf); \
|
||||
goto errout; \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
static NoiseHandshakeState *start_protocol_handshake(void) {
|
||||
/* TODO Noise-C is nice for prototyping, but we should really get rid of it for mostly two reasons:
|
||||
* * We don't need cipher/protocol agility, and by baking the final protocol into the firmware we can save a lot
|
||||
* of flash space by not including all the primitives we don't need as well as noise's dynamic protocol
|
||||
* abstraction layer.
|
||||
* * Noise-c is not very embedded-friendly, in particular it uses malloc and free. We should be able to run
|
||||
* everything with statically allocated buffers instead.
|
||||
*/
|
||||
NoiseHandshakeState *handshake;
|
||||
int err;
|
||||
|
||||
HANDLE_NOISE_ERROR(noise_init(), "initializing noise");
|
||||
|
||||
HANDLE_NOISE_ERROR(noise_handshakestate_new_by_name(&handshake, "Noise_XX_25519_ChaChaPoly_BLAKE2s", NOISE_ROLE_RESPONDER), "instantiating handshake pattern");
|
||||
|
||||
NoiseDHState *dh = noise_handshakestate_get_local_keypair_dh(handshake);
|
||||
HANDLE_NOISE_ERROR(noise_dhstate_set_keypair_private(dh, local_key, sizeof(local_key)), "loading local private keys");
|
||||
|
||||
HANDLE_NOISE_ERROR(noise_handshakestate_start(handshake), "starting handshake");
|
||||
|
||||
return handshake;
|
||||
|
||||
errout:
|
||||
noise_handshakestate_free(handshake);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int generate_identity_key(void) {
|
||||
NoiseDHState *dh;
|
||||
int err;
|
||||
|
||||
HANDLE_NOISE_ERROR(noise_dhstate_new_by_name(&dh, "25519"), "creating dhstate for key generation");
|
||||
HANDLE_NOISE_ERROR(noise_dhstate_generate_keypair(dh), "generating key pair");
|
||||
|
||||
uint8_t unused[CURVE25519_KEY_LEN]; /* the noise api is a bit bad here. */
|
||||
memset(local_key, 0, sizeof(local_key));
|
||||
|
||||
HANDLE_NOISE_ERROR(noise_dhstate_get_keypair(dh, local_key, sizeof(local_key), unused, sizeof(unused)), "saving key pair");
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
if (dh)
|
||||
noise_dhstate_free(dh);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
|
@ -194,12 +293,17 @@ int main(void)
|
|||
#ifdef USART_DEBUG
|
||||
usart_dma_init(debug_out);
|
||||
#endif
|
||||
|
||||
usart_dma_init(usart2_out);
|
||||
cobs_decode_incremental_initialize(&host_cobs_state);
|
||||
usart_enable_rx_interrupt(USART2);
|
||||
nvic_enable_irq(NVIC_USART2_IRQ);
|
||||
|
||||
LOG_PRINTF("\n==================================\n");
|
||||
LOG_PRINTF("SecureHID device side initializing\n");
|
||||
LOG_PRINTF("==================================\n");
|
||||
|
||||
LOG_PRINTF("Initializing USB...\n");
|
||||
hid_driver_init(&hid_config);
|
||||
hub_driver_init();
|
||||
|
||||
|
|
@ -212,7 +316,18 @@ int main(void)
|
|||
*/
|
||||
usbh_init(lld_drivers, device_drivers);
|
||||
|
||||
LOG_PRINTF("USB init complete\n");
|
||||
LOG_PRINTF("Initializing RNG...\n");
|
||||
rand_init();
|
||||
|
||||
/* FIXME only run this on first boot and persist key in backup sram. Allow reset via jumper-triggered factory reset function. */
|
||||
LOG_PRINTF("Generating identity key...\n");
|
||||
if (generate_identity_key())
|
||||
LOG_PRINTF("Error generating identiy key\n");
|
||||
|
||||
LOG_PRINTF("Starting noise protocol handshake...\n");
|
||||
NoiseHandshakeState *handshake = start_protocol_handshake();
|
||||
if (!handshake)
|
||||
LOG_PRINTF("Error starting protocol handshake.\n");
|
||||
|
||||
int i = 0, j = 0;
|
||||
while (23) {
|
||||
|
|
@ -220,10 +335,61 @@ int main(void)
|
|||
delay_ms_busy_loop(1); /* approx 1ms interval between usbh_poll() */
|
||||
if (i++ == 1000) {
|
||||
i = 0;
|
||||
const char *s = "foobarfoobarfoobarfoobarfoobar";
|
||||
send_packet(usart2_out, (uint8_t *)s, strlen(s));
|
||||
LOG_PRINTF("Loop iteration %d\n", 1000*(j++));
|
||||
}
|
||||
|
||||
if (handshake) {
|
||||
#define MAX_MESSAGE_LEN 256
|
||||
uint8_t message[MAX_MESSAGE_LEN];
|
||||
NoiseBuffer noise_msg;
|
||||
/* Run the protocol handshake */
|
||||
switch (noise_handshakestate_get_action(handshake)) {
|
||||
case NOISE_ACTION_WRITE_MESSAGE:
|
||||
/* Write the next handshake message with a zero-length payload */
|
||||
noise_buffer_set_output(noise_msg, message, sizeof(message));
|
||||
if (noise_handshakestate_write_message(handshake, &noise_msg, NULL) != NOISE_ERROR_NONE) {
|
||||
LOG_PRINTF("Error writing handshake message\n");
|
||||
noise_handshakestate_free(handshake);
|
||||
handshake = NULL;
|
||||
}
|
||||
send_packet(usart2_out, message, noise_msg.size);
|
||||
break;
|
||||
|
||||
case NOISE_ACTION_READ_MESSAGE:
|
||||
if (host_packet_length > 0) {
|
||||
/* Read the next handshake message and discard the payload */
|
||||
noise_buffer_set_input(noise_msg, (uint8_t *)host_packet_buf, host_packet_length);
|
||||
if (noise_handshakestate_read_message(handshake, &noise_msg, NULL) != NOISE_ERROR_NONE) {
|
||||
LOG_PRINTF("Error reading handshake message\n");
|
||||
noise_handshakestate_free(handshake);
|
||||
handshake = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NOISE_ACTION_SPLIT:
|
||||
if (noise_handshakestate_split(handshake, &tx_cipher, &rx_cipher) != NOISE_ERROR_NONE) {
|
||||
LOG_PRINTF("Error splitting handshake state\n");
|
||||
} else {
|
||||
LOG_PRINTF("Noise protocol handshake completed successfully\n");
|
||||
}
|
||||
|
||||
noise_handshakestate_free(handshake);
|
||||
handshake = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_PRINTF("Noise protocol handshake failed\n");
|
||||
noise_handshakestate_free(handshake);
|
||||
handshake = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _fini() {
|
||||
while (1);
|
||||
}
|
||||
|
||||
|
|
|
|||
134
src/rand_stm32.c
Normal file
134
src/rand_stm32.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/* Quick-and-dirty cryptographic RNG based on BLAKE2s
|
||||
*
|
||||
* This system uses a 32-byte BLAKE2s hash as internal state seeded by somewhat random post-powerup SRAM content, the
|
||||
* unique device ID and the program flash contents. This seed state is mixed with values from the hardware RNG for each
|
||||
* 32-byte block of output data.
|
||||
*
|
||||
* The RNG's chaining looks like the following, with H(...) being the BLAKE2s hash function, | being binary
|
||||
* concatenation and hw_rng(...) being the hardware RNG. c and e are the fixed extraction and chain string constants
|
||||
* defined below.
|
||||
*
|
||||
* Seed: state = H(SRAM | FLASH | hw_rng(64 byte))
|
||||
*
|
||||
* Extract: state = H(state | c | hw_rng(64 byte)) block[0] = H(state | e)
|
||||
* state = H(state | c | hw_rng(64 byte)) block[1] = H(state | e)
|
||||
* [...]
|
||||
* state = H(state | c | hw_rng(64 byte)) block[n] = H(state | e)
|
||||
* state = H(state | c | hw_rng(64 byte))
|
||||
*
|
||||
*
|
||||
* Graphically, with C = H( state | c | rng ) being the chaining function
|
||||
* and X = H( state | e ) being the extraction function
|
||||
* this becomes:
|
||||
*
|
||||
* rng rng rng rng
|
||||
* | | | |
|
||||
* v v v v
|
||||
* state ---> [C] ---> [C] -- . . . --> [C] ---> [C] ---> new state
|
||||
* | | |
|
||||
* v v v
|
||||
* [X] [X] [X]
|
||||
* | | |
|
||||
* v v v
|
||||
* out[0] out[1] . . . out[n]
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libopencm3/stm32/f4/rng.h>
|
||||
|
||||
#include "usart_helpers.h"
|
||||
#include "rand_stm32.h"
|
||||
|
||||
#include "crypto/noise-c/src/protocol/internal.h"
|
||||
#include "crypto/noise-c/src/crypto/blake2/blake2s.h"
|
||||
|
||||
#define BLAKE2S_HASH_SIZE 32
|
||||
|
||||
/* FIXME persist state in backup sram */
|
||||
extern unsigned _ram_start, _ram_end, _rom_start, _rom_end;
|
||||
static uint8_t global_stm_rand_state[BLAKE2S_HASH_SIZE];
|
||||
|
||||
static uint32_t stm32_read_rng_raw(void) {
|
||||
if ((RNG_SR & (RNG_SR_SEIS | RNG_SR_CEIS)) || !(RNG_CR & RNG_CR_RNGEN)) {
|
||||
LOG_PRINTF("RNG error detected, bailing out.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (!(RNG_SR & RNG_SR_DRDY))
|
||||
;
|
||||
|
||||
return RNG_DR;
|
||||
}
|
||||
|
||||
static void rng_seed_blake(BLAKE2s_context_t *bc) {
|
||||
/* This pulls out 64 bytes. Even though the resulting BLAKE2s hash only is 32 bytes large, the internal state of
|
||||
* BLAKE2s is larger. Also I don't quite trust the STM32F4's hardware RNG. */
|
||||
for (int i=0; i<16; i++) {
|
||||
uint32_t val = stm32_read_rng_raw();
|
||||
BLAKE2s_update(bc, &val, sizeof(val));
|
||||
}
|
||||
}
|
||||
|
||||
void rand_init() {
|
||||
RNG_CR |= RNG_CR_RNGEN;
|
||||
BLAKE2s_context_t bc;
|
||||
BLAKE2s_reset(&bc);
|
||||
|
||||
/* Seed with entire SRAM area */
|
||||
BLAKE2s_update(&bc, &_ram_start, &_ram_end - &_ram_start);
|
||||
/* Seed with entire flash area. This includes the device unique ID if it has not been overwritten. */
|
||||
BLAKE2s_update(&bc, &_rom_start, &_rom_end - &_rom_start);
|
||||
/* Seed with 64 bytes of handware RNG input */
|
||||
rng_seed_blake(&bc);
|
||||
/* FIXME use ADC to seeed */
|
||||
|
||||
BLAKE2s_finish(&bc, global_stm_rand_state);
|
||||
/* FIXME make sure this is not optimized out */
|
||||
memset(&bc, 0, sizeof(bc));
|
||||
}
|
||||
|
||||
const char *extraction_constant = "Blake2 RNG extraction constant";
|
||||
const char *chain_constant = "Blake2 RNG chaining constant";
|
||||
|
||||
void noise_rand_bytes(void *bytes, size_t size) {
|
||||
BLAKE2s_context_t out_ctx, chain_ctx;
|
||||
uint8_t *out = (uint8_t *)bytes;
|
||||
uint8_t hash_buf[BLAKE2S_HASH_SIZE];
|
||||
|
||||
for (size_t wr_pos = 0; wr_pos<size; wr_pos += BLAKE2S_HASH_SIZE) {
|
||||
BLAKE2s_reset(&chain_ctx);
|
||||
BLAKE2s_update(&chain_ctx, global_stm_rand_state, sizeof(global_stm_rand_state));
|
||||
BLAKE2s_update(&chain_ctx, chain_constant, strlen(chain_constant));
|
||||
rng_seed_blake(&chain_ctx);
|
||||
BLAKE2s_finish(&chain_ctx, global_stm_rand_state);
|
||||
|
||||
BLAKE2s_reset(&out_ctx);
|
||||
BLAKE2s_update(&out_ctx, global_stm_rand_state, sizeof(global_stm_rand_state));
|
||||
BLAKE2s_update(&out_ctx, extraction_constant, strlen(extraction_constant));
|
||||
BLAKE2s_finish(&out_ctx, hash_buf);
|
||||
|
||||
size_t rem = size-wr_pos;
|
||||
memcpy(&out[wr_pos], hash_buf, rem < BLAKE2S_HASH_SIZE ? rem : BLAKE2S_HASH_SIZE);
|
||||
}
|
||||
|
||||
BLAKE2s_reset(&chain_ctx);
|
||||
BLAKE2s_update(&chain_ctx, global_stm_rand_state, sizeof(global_stm_rand_state));
|
||||
BLAKE2s_update(&chain_ctx, chain_constant, strlen(chain_constant));
|
||||
rng_seed_blake(&chain_ctx);
|
||||
BLAKE2s_finish(&chain_ctx, global_stm_rand_state);
|
||||
|
||||
/* FIXME make sure this is not optimized out */
|
||||
memset(&out_ctx, 0, sizeof(out_ctx));
|
||||
memset(&chain_ctx, 0, sizeof(chain_ctx));
|
||||
memset(hash_buf, 0, sizeof(hash_buf));
|
||||
}
|
||||
|
||||
#ifdef ED25519_CUSTOMRANDOM /* We are building against ed25519-donna, which needs a random function */
|
||||
void ed25519_randombytes_unsafe(void *p, size_t len) {
|
||||
noise_rand_bytes(p, len);
|
||||
}
|
||||
#endif
|
||||
9
src/rand_stm32.h
Normal file
9
src/rand_stm32.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef __RAND_STM32_H__
|
||||
#define __RAND_STM32_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void rand_init(void);
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue