Skip to content

Commit

Permalink
Completed encryption/decryption state machine
Browse files Browse the repository at this point in the history
State machine is written to be fully compliant with C
(even though Arduino supports C++). I wanted to test out
the state machine design pattern in Patterns in C and it worked out
really, really well! The program more or less worked on the first try,
aside from small changes.

Now uses a different input format: byte 0 contains the size of the
upcoming input, then the following N bytes contain the input, and the
last byte contains either 'E' or 'D' to select encryption or
decryption respectively.

The state machine is set up to transition on a time step as
well as on a character input. By default, states will do
nothing in response to either event. In their "constructors"
(the "transition_*" functions) they set up a static function pointer
as an event handler. To transition to another state, they call
that state's transition function. This allows the state struct whose
pointer gets passed around to change its behavior (in line with what
state it's in) at runtime.
  • Loading branch information
rileywood committed Mar 4, 2017
1 parent 070984d commit 4c4a84c
Show file tree
Hide file tree
Showing 16 changed files with 257 additions and 150 deletions.
57 changes: 12 additions & 45 deletions crypto.ino
@@ -1,64 +1,31 @@
#include "tweetnacl.h"

#include "state_idle.h"

#define BUFF_SIZE 256+crypto_box_ZEROBYTES

#define STATUS_LED 13

uint8_t testKey[crypto_box_SECRETKEYBYTES];
uint8_t nonce[crypto_box_NONCEBYTES];

uint8_t serial_in_buff[BUFF_SIZE];
crypto_state_t state_machine;

// Subtract one so that we store delimiting first
// char in padding space to be erased.
uint8_t char_insert_i = crypto_box_ZEROBYTES - 1;
uint8_t crypto_out_buff[BUFF_SIZE];

void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(STATUS_LED, OUTPUT);
memset(serial_in_buff, 0, sizeof(serial_in_buff));
memset(crypto_out_buff, 0, sizeof(crypto_out_buff));

transition_to_idle(&state_machine);
}


void loop() {
if(Serial.available()) {
serial_in_buff[char_insert_i++] = Serial.read();

if(serial_in_buff[char_insert_i-1] == '\n' ||
char_insert_i >= BUFF_SIZE) {
char enc_or_dec = serial_in_buff[crypto_box_ZEROBYTES - 1];
serial_in_buff[crypto_box_ZEROBYTES - 1] = 0;

switch(enc_or_dec) {
case 'E':
{
crypto_secretbox(crypto_out_buff, serial_in_buff, char_insert_i - 1, nonce, testKey);
int crypto_len = char_insert_i - 1 - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES;
Serial.write(&crypto_out_buff[crypto_box_BOXZEROBYTES], crypto_len);
}
break;
case 'D':
{
uint8_t * encrypted_start = serial_in_buff + (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES);
uint8_t encrypted_len = char_insert_i - 1 - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES;
int success = crypto_secretbox_open(crypto_out_buff, encrypted_start, encrypted_len, nonce, testKey);
if(success == -1) {
digitalWrite(STATUS_LED, HIGH);
} else {
digitalWrite(STATUS_LED, LOW);
}
int crypto_len = encrypted_len - crypto_box_ZEROBYTES;
Serial.write(&crypto_out_buff[crypto_box_ZEROBYTES], crypto_len);
}
break;
}

// Cleanup
memset(serial_in_buff, 0, sizeof(serial_in_buff));
memset(crypto_out_buff, 0, sizeof(crypto_out_buff));
char_insert_i = crypto_box_ZEROBYTES - 1;
}
state_machine.recv_char(&state_machine, Serial.read());
}
state_machine.fsm_step(&state_machine);
}

void print(const char * buf, uint16_t len) {
Serial.write(buf, len);
}
27 changes: 27 additions & 0 deletions secrets.cpp
@@ -0,0 +1,27 @@

#include "secrets.h"

#include <stdint.h>
#include "tweetnacl.h"

static const uint8_t secretkey[crypto_secretbox_KEYBYTES] = {
0,1,2,3,4,5,6,7,8,9,
0,1,2,3,4,5,6,7,8,9,
0,1,2,3,4,5,6,7,8,9,
0,1
};

static const uint8_t nonce[crypto_secretbox_NONCEBYTES] = {
0,1,2,3,4,5,6,7,8,9,
0,1,2,3,4,5,6,7,8,9,
0,1,2,3
};

const uint8_t * get_secret_key(void) {
return secretkey;
}

const uint8_t * get_nonce(void) {
return nonce;
}

12 changes: 12 additions & 0 deletions secrets.h
@@ -0,0 +1,12 @@


#ifndef SECRETS_H
#define SECRETS_H

#include <stdint.h>

const uint8_t * get_secret_key(void);
const uint8_t * get_nonce(void);

#endif // SECRETS_H

19 changes: 19 additions & 0 deletions state.cpp
@@ -0,0 +1,19 @@


#include "state.h"

static void default_event_recv_char(crypto_state_t * state, char c) {
// Spin in same state
return;
}

static void default_event_fsm_step(crypto_state_t * state) {
// Spin in same state
return;
}

void state_init_default(crypto_state_t * state) {
state->recv_char = default_event_recv_char;
state->fsm_step = default_event_fsm_step;
}

25 changes: 10 additions & 15 deletions state.h
@@ -1,23 +1,18 @@
/**
* @file
* @author Riley Wood (riley@clearmotion.com)
* @copyright 2017 ClearMotion Inc., All Rights Reserved. *
* @defgroup state GROUP TITLE
* @addtogroup state
* @{
*
* @brief DESCRIPTION HERE
*
*/



#ifndef STATE_H
#define STATE_H

typedef struct crypto_state_struct crypto_state_t;

#endif // STATE_H
typedef void (*event_recv_char) (crypto_state_t * state, char c);
typedef void (*event_fsm_step) (crypto_state_t * state);

struct crypto_state_struct {
event_recv_char recv_char;
event_fsm_step fsm_step;
};

void state_init_default(crypto_state_t * state);

/// @}

#endif // STATE_H
43 changes: 43 additions & 0 deletions state_buffer.cpp
@@ -0,0 +1,43 @@

#include "state_buffer.h"

#include <string.h>
#include "tweetnacl.h"

#include "state_encrypt.h"
#include "state_decrypt.h"
#include "state_idle.h"

#define BUFFER_SIZE (256 + crypto_secretbox_ZEROBYTES)

static uint8_t input_len = 0;
static uint8_t input_i = 0;
static char input_buffer[BUFFER_SIZE];

static void buffer_recv_char(crypto_state_t * state, char c) {
if(input_i < input_len) {
input_buffer[crypto_secretbox_ZEROBYTES + input_i++] = c;
} else {
if(c == 'D') {
char * decrypt_start = input_buffer + crypto_secretbox_ZEROBYTES - crypto_secretbox_BOXZEROBYTES;
uint16_t decrypt_len = input_len + crypto_secretbox_BOXZEROBYTES;
transition_to_decrypt(state, decrypt_start, decrypt_len);
}
else if(c == 'E') {
uint16_t encrypt_len = input_len + crypto_secretbox_ZEROBYTES;
transition_to_encrypt(state, input_buffer, encrypt_len);
}
else {
transition_to_idle(state);
}
}
}

void transition_to_buffer(crypto_state_t * state, uint8_t input_l) {
input_len = input_l;
input_i = 0;
memset(input_buffer, 0, sizeof(input_buffer));

state_init_default(state);
state->recv_char = buffer_recv_char;
}
21 changes: 4 additions & 17 deletions state_buffer.h
@@ -1,25 +1,12 @@
/**
* @file
* @author Riley Wood (riley@clearmotion.com)
* @copyright 2017 ClearMotion Inc., All Rights Reserved. *
* @defgroup state_buffer GROUP TITLE
* @addtogroup state_buffer
* @{
*
* @brief DESCRIPTION HERE
*
*/



#ifndef STATE_BUFFER_H
#define STATE_BUFFER_H

#include <stdbool.h>
#include <stdint.h>
#include "state.h"

#endif // STATE_BUFFER_H
#include <stdint.h>

void transition_to_buffer(crypto_state_t * state, uint8_t input_l);

/// @}

#endif // STATE_BUFFER_H
35 changes: 35 additions & 0 deletions state_decrypt.cpp
@@ -0,0 +1,35 @@

#include "state_decrypt.h"

#include <string.h>
#include "tweetnacl.h"

#include "state.h"
#include "secrets.h"
#include "state_send_result.h"

static char * to_decrypt = NULL;
static uint16_t to_decrypt_len = 0;

static void decrypt_fsm_step(crypto_state_t * state) {
const uint8_t * nonce = get_nonce();
const uint8_t * secret_key = get_secret_key();
crypto_secretbox_open((unsigned char *)to_decrypt,
(unsigned char *)to_decrypt,
to_decrypt_len,
nonce,
secret_key);
const char * result = &to_decrypt[crypto_secretbox_ZEROBYTES];
const uint8_t result_len = to_decrypt_len - crypto_secretbox_ZEROBYTES;
transition_to_send_result(state, result, result_len);
}

void transition_to_decrypt(crypto_state_t * state, char * input, uint16_t input_len){
to_decrypt = input;
to_decrypt_len = input_len;

state_init_default(state);
state->fsm_step = decrypt_fsm_step;
}


22 changes: 4 additions & 18 deletions state_decrypt.h
@@ -1,25 +1,11 @@
/**
* @file
* @author Riley Wood (riley@clearmotion.com)
* @copyright 2017 ClearMotion Inc., All Rights Reserved. *
* @defgroup state_decrypt GROUP TITLE
* @addtogroup state_decrypt
* @{
*
* @brief DESCRIPTION HERE
*
*/



#ifndef STATE_DECRYPT_H
#define STATE_DECRYPT_H

#include <stdbool.h>
#include <stdint.h>
#include "state.h"

#endif // STATE_DECRYPT_H
#include <stdint.h>

void transition_to_decrypt(crypto_state_t * state, char * input, uint16_t input_len);

/// @}

#endif // STATE_DECRYPT_H
33 changes: 33 additions & 0 deletions state_encrypt.cpp
@@ -0,0 +1,33 @@

#include "state_encrypt.h"

#include <string.h>
#include "tweetnacl.h"

#include "state.h"
#include "secrets.h"
#include "state_send_result.h"

static char * to_encrypt = NULL;
static uint16_t to_encrypt_len = 0;

static void encrypt_fsm_step(crypto_state_t * state) {
const uint8_t * nonce = get_nonce();
const uint8_t * secret_key = get_secret_key();
crypto_secretbox((unsigned char *)to_encrypt,
(unsigned char *)to_encrypt,
to_encrypt_len,
nonce,
secret_key);
const char * result = &to_encrypt[crypto_secretbox_BOXZEROBYTES];
const uint8_t result_len = to_encrypt_len - crypto_secretbox_BOXZEROBYTES;
transition_to_send_result(state, result, result_len);
}

void transition_to_encrypt(crypto_state_t * state, char * input, uint16_t input_len){
to_encrypt = input;
to_encrypt_len = input_len;

state_init_default(state);
state->fsm_step = encrypt_fsm_step;
}
22 changes: 4 additions & 18 deletions state_encrypt.h
@@ -1,25 +1,11 @@
/**
* @file
* @author Riley Wood (riley@clearmotion.com)
* @copyright 2017 ClearMotion Inc., All Rights Reserved. *
* @defgroup state_encrypt GROUP TITLE
* @addtogroup state_encrypt
* @{
*
* @brief DESCRIPTION HERE
*
*/



#ifndef STATE_ENCRYPT_H
#define STATE_ENCRYPT_H

#include <stdbool.h>
#include "state.h"

#include <stdint.h>

#endif // STATE_ENCRYPT_H
void transition_to_encrypt(crypto_state_t * state, char * input, uint16_t input_len);

#endif // STATE_ENCRYPT_H

/// @}

16 changes: 16 additions & 0 deletions state_idle.cpp
@@ -0,0 +1,16 @@


#include "state_idle.h"

#include <stdint.h>

#include "state_buffer.h"

static void idle_recv_char(crypto_state_t * state, char c) {
transition_to_buffer(state, (uint8_t)c);
}

void transition_to_idle(crypto_state_t * state) {
state_init_default(state);
state->recv_char = idle_recv_char;
}

0 comments on commit 4c4a84c

Please sign in to comment.