summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjaseg <git@jaseg.net>2018-11-12 11:59:11 +0900
committerjaseg <git@jaseg.net>2018-11-12 11:59:11 +0900
commit2f4f3e13aa6a6dbbb5a45e02b792eb935e91c766 (patch)
tree80a4520254d93523fc75f25624d53b161944013d
parent42d4bebde7d3cc7f536dec114ca5a54072b9e21b (diff)
downloadsecure-hid-2f4f3e13aa6a6dbbb5a45e02b792eb935e91c766.tar.gz
secure-hid-2f4f3e13aa6a6dbbb5a45e02b792eb935e91c766.tar.bz2
secure-hid-2f4f3e13aa6a6dbbb5a45e02b792eb935e91c766.zip
Handshake working with new abstractions
-rwxr-xr-xhexnoise.py36
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/adjectives.c262
-rw-r--r--src/demo.c190
-rw-r--r--src/hid_keycodes.c43
-rw-r--r--src/hid_keycodes.h194
-rw-r--r--src/noise.c138
-rw-r--r--src/noise.h35
-rw-r--r--src/nouns.c262
-rw-r--r--src/packet_interface.h27
-rw-r--r--src/words.h7
11 files changed, 1119 insertions, 78 deletions
diff --git a/hexnoise.py b/hexnoise.py
index df71d93..1f53fcd 100755
--- a/hexnoise.py
+++ b/hexnoise.py
@@ -2,6 +2,7 @@
import time
import string
+import enum
from cobs import cobs
@@ -28,9 +29,22 @@ def hexdump(write, packet, width=16):
_print_line(write, ts-startup, packet, width=width)
write()
-def send_packet(ser, data, width=16):
- print(f'\033[93mSending {len(data)} bytes\033[0m')
+class PacketType(enum.Enum):
+ _RESERVED = 0
+ INITIATE_HANDSHAKE = 1
+ HANDSHAKE = 2
+ DATA = 3
+
+class ReportType(enum.Enum):
+ _RESERVED = 0
+ KEYBOARD = 1
+ MOUSE = 2
+ PAIRING = 3 # keyboard in disguise
+
+def send_packet(ser, pkt_type, data, width=16):
+ print(f'\033[93mSending {len(data)} bytes, packet type {pkt_type.name} ({pkt_type.value})\033[0m')
hexdump(print, data, width)
+ data = bytes([pkt_type.value]) + data
encoded = cobs.encode(data) + b'\0'
ser.write(encoded)
ser.flushOutput()
@@ -40,7 +54,7 @@ def receive_packet(ser, width=16):
data = cobs.decode(packet[:-1])
print(f'\033[93mReceived {len(data)} bytes\033[0m')
hexdump(print, data, width)
- return data
+ return data[0], data[1:]
if __name__ == '__main__':
import argparse
@@ -85,16 +99,21 @@ if __name__ == '__main__':
proto.set_as_initiator()
proto.set_keypair_from_private_bytes(Keypair.STATIC, STATIC_LOCAL)
proto.start_handshake()
+ send_packet(ser, PacketType.INITIATE_HANDSHAKE, b'', args.width)
print('Handshake started')
while True:
if proto.handshake_finished:
break
- send_packet(ser, proto.write_message(), args.width)
+ send_packet(ser, PacketType.HANDSHAKE, proto.write_message(), args.width)
if proto.handshake_finished:
break
- proto.read_message(receive_packet(ser, args.width))
+ pkt_type, payload = receive_packet(ser, args.width)
+ if pkt_type == PacketType.HANDSHAKE.value:
+ proto.read_message(payload)
+ else:
+ print(f'Incorrect packet type {pkt_type}. Ignoring since this is only test code.')
print('Handshake finished, handshake hash:')
hexdump(print, proto.get_handshake_hash(), args.width)
@@ -126,7 +145,11 @@ if __name__ == '__main__':
with uinput.Device(ALL_KEYS) as ui:
while True:
try:
- received = receive_packet(ser, args.width)
+ pkt_type, received = receive_packet(ser, args.width)
+ if pkt_type != PacketType.DATA.value:
+ print(f'Unexpected packet type {pkt_type}. Ignoring.')
+ continue
+
try:
noise_rx(received, ui)
except NoiseInvalidMessage as e:
@@ -145,3 +168,4 @@ if __name__ == '__main__':
proto.noise_protocol.cipher_state_decrypt.n = orig_n
except Exception as e:
print('Invalid framing:', e)
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e5e23ac..9084cbb 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -24,6 +24,9 @@ add_library (usbhost
cobs.c
noise.c
packet_interface.c
+ adjectives.c
+ nouns.c
+ hid_keycodes.c
)
add_subdirectory (crypto)
diff --git a/src/adjectives.c b/src/adjectives.c
new file mode 100644
index 0000000..e3bc3d0
--- /dev/null
+++ b/src/adjectives.c
@@ -0,0 +1,262 @@
+
+#include "words.h"
+
+const char * const adjectives[256] = {
+ "wrathful", /* 0 */
+ "worthy", /* 1 */
+ "weird", /* 2 */
+ "warm", /* 3 */
+ "volatile", /* 4 */
+ "veiled", /* 5 */
+ "vacuous", /* 6 */
+ "useless", /* 7 */
+ "upset", /* 8 */
+ "unsoiled", /* 9 */
+ "unsightly", /* 10 */
+ "unpronounceable", /* 11 */
+ "unfriendly", /* 12 */
+ "unfree", /* 13 */
+ "unfit", /* 14 */
+ "unfaithful", /* 15 */
+ "unchaste", /* 16 */
+ "unbroken", /* 17 */
+ "unbound", /* 18 */
+ "unblessed", /* 19 */
+ "unbefitting", /* 20 */
+ "unaltered", /* 21 */
+ "unabused", /* 22 */
+ "unable", /* 23 */
+ "ugly", /* 24 */
+ "tongued", /* 25 */
+ "thorny", /* 26 */
+ "thirsty", /* 27 */
+ "thick", /* 28 */
+ "terminal", /* 29 */
+ "ten-sided", /* 30 */
+ "teeming", /* 31 */
+ "tangerine", /* 32 */
+ "taken", /* 33 */
+ "substantial", /* 34 */
+ "stupefying", /* 35 */
+ "stringy", /* 36 */
+ "strange", /* 37 */
+ "stillborn", /* 38 */
+ "sticky", /* 39 */
+ "stagnant", /* 40 */
+ "spongy", /* 41 */
+ "sour", /* 42 */
+ "soul-destroying", /* 43 */
+ "smoldering", /* 44 */
+ "smitten", /* 45 */
+ "slain", /* 46 */
+ "six-sided", /* 47 */
+ "shifting", /* 48 */
+ "shadowy", /* 49 */
+ "severed", /* 50 */
+ "seven-sided", /* 51 */
+ "serene", /* 52 */
+ "salty", /* 53 */
+ "rust-red", /* 54 */
+ "royal", /* 55 */
+ "rotten", /* 56 */
+ "riddled", /* 57 */
+ "resentful", /* 58 */
+ "regrettable", /* 59 */
+ "reeking", /* 60 */
+ "rare", /* 61 */
+ "rank", /* 62 */
+ "rancid", /* 63 */
+ "quiescent", /* 64 */
+ "putrid", /* 65 */
+ "putrid", /* 66 */
+ "putrescent", /* 67 */
+ "prehistoric", /* 68 */
+ "predatory", /* 69 */
+ "predaceous", /* 70 */
+ "porous", /* 71 */
+ "poisonous", /* 72 */
+ "pierced", /* 73 */
+ "phlegmatic", /* 74 */
+ "petrifying", /* 75 */
+ "pessimal", /* 76 */
+ "pathetic", /* 77 */
+ "odorless", /* 78 */
+ "oddish", /* 79 */
+ "obsessed", /* 80 */
+ "obscene", /* 81 */
+ "numb", /* 82 */
+ "nine-sided", /* 83 */
+ "nasty", /* 84 */
+ "mysterious", /* 85 */
+ "mute", /* 86 */
+ "musky", /* 87 */
+ "morose", /* 88 */
+ "moribund", /* 89 */
+ "moldy", /* 90 */
+ "miasmic", /* 91 */
+ "material", /* 92 */
+ "many-lobed", /* 93 */
+ "malodorous", /* 94 */
+ "malign", /* 95 */
+ "maimed", /* 96 */
+ "luminescent", /* 97 */
+ "low-cut", /* 98 */
+ "lousy", /* 99 */
+ "live", /* 100 */
+ "limp", /* 101 */
+ "lifeless", /* 102 */
+ "leering", /* 103 */
+ "leaky", /* 104 */
+ "layered", /* 105 */
+ "latent", /* 106 */
+ "lackluster", /* 107 */
+ "jagged", /* 108 */
+ "irregular", /* 109 */
+ "iridescent", /* 110 */
+ "intangible", /* 111 */
+ "infinite", /* 112 */
+ "inept", /* 113 */
+ "incomprehensible", /* 114 */
+ "in-between", /* 115 */
+ "improper", /* 116 */
+ "idle", /* 117 */
+ "hunted", /* 118 */
+ "hideous", /* 119 */
+ "heavy", /* 120 */
+ "hairy", /* 121 */
+ "guilty", /* 122 */
+ "grotesque", /* 123 */
+ "grey", /* 124 */
+ "greedy", /* 125 */
+ "gory", /* 126 */
+ "gorgeous", /* 127 */
+ "gooey", /* 128 */
+ "golden-brown", /* 129 */
+ "golden", /* 130 */
+ "ghastly", /* 131 */
+ "frostbitten", /* 132 */
+ "fresh-cut", /* 133 */
+ "freakish", /* 134 */
+ "frantic", /* 135 */
+ "fossilized", /* 136 */
+ "formless", /* 137 */
+ "formidable", /* 138 */
+ "floccose", /* 139 */
+ "five-lobed", /* 140 */
+ "firstborn", /* 141 */
+ "filthy", /* 142 */
+ "fickle", /* 143 */
+ "fetid", /* 144 */
+ "fertile", /* 145 */
+ "fearful", /* 146 */
+ "fatal", /* 147 */
+ "familiar", /* 148 */
+ "fallen", /* 149 */
+ "fallacious", /* 150 */
+ "faint", /* 151 */
+ "faceless", /* 152 */
+ "extinct", /* 153 */
+ "esoteric", /* 154 */
+ "errant", /* 155 */
+ "emergent", /* 156 */
+ "elastic", /* 157 */
+ "eight-sided", /* 158 */
+ "eerie", /* 159 */
+ "ebon", /* 160 */
+ "dysphoric", /* 161 */
+ "dying", /* 162 */
+ "dumb", /* 163 */
+ "dull-purple", /* 164 */
+ "dull", /* 165 */
+ "dull", /* 166 */
+ "dull", /* 167 */
+ "dormant", /* 168 */
+ "doomed", /* 169 */
+ "disfigured", /* 170 */
+ "dirty", /* 171 */
+ "defenseless", /* 172 */
+ "deep-pink", /* 173 */
+ "deep", /* 174 */
+ "deconsecrated", /* 175 */
+ "deathlike", /* 176 */
+ "deadly", /* 177 */
+ "dead", /* 178 */
+ "dark-blue", /* 179 */
+ "dark", /* 180 */
+ "curly", /* 181 */
+ "curious", /* 182 */
+ "cured", /* 183 */
+ "cunning", /* 184 */
+ "crystalline", /* 185 */
+ "cryptic", /* 186 */
+ "crying", /* 187 */
+ "crumbly", /* 188 */
+ "crimson", /* 189 */
+ "crested", /* 190 */
+ "creepy", /* 191 */
+ "crazy", /* 192 */
+ "corrupt", /* 193 */
+ "corporeal", /* 194 */
+ "contemptible", /* 195 */
+ "contained", /* 196 */
+ "concrete", /* 197 */
+ "cloudy", /* 198 */
+ "chopped", /* 199 */
+ "chained", /* 200 */
+ "caustic", /* 201 */
+ "catholic", /* 202 */
+ "cathartic", /* 203 */
+ "captive", /* 204 */
+ "cancerous", /* 205 */
+ "cabalistic", /* 206 */
+ "burnt", /* 207 */
+ "buoyant", /* 208 */
+ "bronze-red", /* 209 */
+ "bronze", /* 210 */
+ "broken", /* 211 */
+ "bright-red", /* 212 */
+ "breathless", /* 213 */
+ "bound", /* 214 */
+ "bound", /* 215 */
+ "bottomless", /* 216 */
+ "bony", /* 217 */
+ "bodiless", /* 218 */
+ "blue-lilac", /* 219 */
+ "blue", /* 220 */
+ "bloody", /* 221 */
+ "bloodthirsty", /* 222 */
+ "bloodsucking", /* 223 */
+ "bloodstained", /* 224 */
+ "bloodcurdling", /* 225 */
+ "blonde", /* 226 */
+ "blistered", /* 227 */
+ "blank", /* 228 */
+ "bitter", /* 229 */
+ "bilgy", /* 230 */
+ "bewitched", /* 231 */
+ "befouled", /* 232 */
+ "beardless", /* 233 */
+ "bastardly", /* 234 */
+ "barbed", /* 235 */
+ "baleful", /* 236 */
+ "balding", /* 237 */
+ "awkward", /* 238 */
+ "awful", /* 239 */
+ "atrocious", /* 240 */
+ "arcane", /* 241 */
+ "appalling", /* 242 */
+ "antic", /* 243 */
+ "anonymous", /* 244 */
+ "angry", /* 245 */
+ "ample", /* 246 */
+ "ambiguous", /* 247 */
+ "amber-green", /* 248 */
+ "amber", /* 249 */
+ "aghast", /* 250 */
+ "activated", /* 251 */
+ "acidic", /* 252 */
+ "abused", /* 253 */
+ "abstruse", /* 254 */
+ "abject", /* 255 */
+};
+
diff --git a/src/demo.c b/src/demo.c
index d080844..3a76a5d 100644
--- a/src/demo.c
+++ b/src/demo.c
@@ -28,6 +28,8 @@
#include "rand_stm32.h"
#include "packet_interface.h"
#include "noise.h"
+#include "hid_keycodes.h"
+#include "words.h"
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
@@ -40,13 +42,21 @@
#include <libopencmsis/core_cm3.h>
#include <stdint.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
#ifndef USE_STM32F4_USBH_DRIVER_FS
#error The full-speed USB driver must be enabled with USE_STM32F4_USBH_DRIVER_FS in usbh_config.h!
#endif
+#ifndef MAX_FAILED_HANDSHAKES
+#define MAX_FAILED_HANDSHAKES 3
+#endif
+
+
+static struct NoiseState noise_state;
+static uint8_t remote_key_reference[CURVE25519_KEY_LEN];
+
void _fini(void);
@@ -113,17 +123,99 @@ static void gpio_setup(void)
gpio_mode_setup(GPIOE, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO3 | GPIO4);
}
-enum packet_types {
- _RESERVED = 0,
- HID_KEYBOARD_REPORT = 1,
- HID_MOUSE_REPORT = 2
-};
+struct hid_report {
+ uint8_t modifiers;
+ uint8_t _reserved;
+ uint8_t keycodes[6];
+} __attribute__((__packed__));
+
+static char pairing_buf[512];
+static size_t pairing_buf_pos = 0;
+
+int pairing_check(struct NoiseState *st, const char *buf);
+void pairing_input(uint8_t keycode);
+void pairing_parse_report(struct hid_report *buf, uint8_t len);
+
+int pairing_check(struct NoiseState *st, const char *buf) {
+ const char *p = buf;
+ int idx = 0;
+ do {
+ const char *found = strchr(p, ' ');
+ size_t plen = found ? (size_t)(found - p) : strlen(p); /* p >= found */
+ int num = -1;
+ for (int i=0; i<256; i++) {
+ if (!strncmp(p, adjectives[i], plen) || !strncmp(p, nouns[i], plen)) {
+ num = i;
+ break;
+ }
+ }
+ if (num == -1) {
+ LOG_PRINTF("Pairing word not found in dictionary\n");
+ return -1;
+ }
+ if (st->handshake_hash[idx] != num) {
+ LOG_PRINTF("Pairing data does not match hash\n");
+ return -1;
+ }
+ idx++;
+ p = strchr(p, ' ');
+ } while (p != NULL && idx < BLAKE2S_HASH_SIZE);
+
+ if (idx < 8) {
+ LOG_PRINTF("Pairing sequence too short, only %d bytes of hash checked\n", idx);
+ return -1;
+ }
-struct hid_report_packet {
- uint8_t type;
- uint8_t len;
- uint8_t report[8];
-};
+ return 0;
+}
+
+void pairing_input(uint8_t keycode) {
+ switch (keycode) {
+ case KEY_ENTER:
+ pairing_buf[pairing_buf_pos++] = '\0';
+ if (!pairing_check(&noise_state, pairing_buf)) {
+ persist_remote_key(&noise_state);
+ /* FIXME write key to backup memory */
+ }
+ break;
+
+ case KEY_BACKSPACE:
+ if (pairing_buf_pos > 0)
+ pairing_buf_pos--;
+ break;
+
+ default:
+ for (size_t i=0; i<sizeof(keycode_mapping)/sizeof(keycode_mapping[0]); i++) {
+ if (keycode_mapping[i].kc == keycode) {
+ if (pairing_buf_pos < sizeof(pairing_buf)-1) /* allow for terminating null byte */
+ pairing_buf[pairing_buf_pos++] = keycode_mapping[i].ch;
+ break;
+ }
+ }
+ break;
+ }
+}
+
+void pairing_parse_report(struct hid_report *buf, uint8_t len) {
+ static uint8_t old_keycodes[6] = {0};
+
+ for (int i=0; i<len-2; i++) {
+ if (!buf->keycodes[i])
+ break; /* keycodes are always populated from low to high */
+
+ int found = 0;
+ for (int j=0; j<6; j++) {
+ if (old_keycodes[j] == buf->keycodes[i]) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) /* key pressed */
+ pairing_input(buf->keycodes[i]);
+ }
+
+ memcpy(old_keycodes, buf->keycodes, 6);
+}
static void hid_in_message_handler(uint8_t device_id, const uint8_t *data, uint32_t length)
{
@@ -136,21 +228,34 @@ static void hid_in_message_handler(uint8_t device_id, const uint8_t *data, uint3
return;
}
- int type = hid_get_type(device_id);
- if (type != HID_TYPE_KEYBOARD && type != HID_TYPE_MOUSE) {
- LOG_PRINTF("Unsupported HID report type %x\n", type);
- return;
- }
-
LOG_PRINTF("Sending event %02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]);
struct hid_report_packet pkt = {
- .type = type == HID_TYPE_KEYBOARD ? HID_KEYBOARD_REPORT : HID_MOUSE_REPORT,
.len = length,
.report = {0}
};
memcpy(pkt.report, data, length);
- if (send_encrypted_message((uint8_t *)&pkt, sizeof(pkt))) {
+ int type = hid_get_type(device_id);
+ if (type == HID_TYPE_KEYBOARD) {
+ if (noise_state.handshake_state == HANDSHAKE_DONE_UNKNOWN_HOST) {
+ pkt.type = PAIRING;
+ pairing_parse_report((struct hid_report *)data, length);
+ } else {
+ pkt.type = HID_KEYBOARD_REPORT;
+ }
+ } else if (type == HID_TYPE_MOUSE) {
+ if (noise_state.handshake_state == HANDSHAKE_DONE_UNKNOWN_HOST) {
+ LOG_PRINTF("Not sending HID mouse report during pairing\n");
+ return;
+ } else {
+ pkt.type = HID_MOUSE_REPORT;
+ }
+ } else {
+ LOG_PRINTF("Unsupported HID report type %x\n", type);
+ return;
+ }
+
+ if (send_encrypted_message(&noise_state, (uint8_t *)&pkt, sizeof(pkt))) {
LOG_PRINTF("Error sending HID report packet\n");
return;
}
@@ -213,21 +318,52 @@ int main(void)
LOG_PRINTF("Initializing RNG...\n");
rand_init();
+ noise_state_init(&noise_state, remote_key_reference);
+ /* FIXME load remote key from backup memory */
/* 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())
+ if (generate_identity_key(&noise_state))
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");
-
while (23) {
usbh_poll(tim6_get_time_us());
- if (handshake)
- handshake = try_continue_noise_handshake(handshake);
+ if (host_packet_length > 0) {
+ struct control_packet *pkt = (struct control_packet *)host_packet_buf;
+ size_t payload_length = host_packet_length - 1;
+
+ if (pkt->type == HOST_INITIATE_HANDSHAKE) {
+ /* It is important that we acknowledge this command right away. Starting the handshake involves key
+ * generation which takes a few milliseconds. If we'd acknowledge this later, we might run into an
+ * overrun here since we would be blocking the buffer during key generation. */
+ host_packet_length = 0; /* Acknowledge to USART ISR the buffer has been handled */
+
+ if (payload_length > 0) {
+ LOG_PRINTF("Extraneous data in INITIATE_HANDSHAKE message\n");
+ } else if (noise_state.failed_handshakes < MAX_FAILED_HANDSHAKES) {
+ LOG_PRINTF("Starting noise protocol handshake...\n");
+ if (reset_protocol_handshake(&noise_state))
+ LOG_PRINTF("Error starting protocol handshake.\n");
+ pairing_buf_pos = 0; /* Reset channel binding keyboard input buffer */
+ } else {
+ LOG_PRINTF("Too many failed handshake attempts, not starting another one\n");
+ }
+ } else if (pkt->type == HOST_HANDSHAKE) {
+ LOG_PRINTF("Handling handshake packet of length %d\n", payload_length);
+ int consumed = 0;
+ try_continue_noise_handshake(&noise_state, pkt->payload, payload_length, &consumed);
+ if (consumed)
+ host_packet_length = 0; /* Acknowledge to USART ISR the buffer has been handled */
+ else /* Otherwise this gets called again in the next iteration of the main loop. Usually that should not happen. */
+ LOG_PRINTF("Handshake buffer unhandled. Waiting for next iteration.\n");
+
+ } else {
+ host_packet_length = 0; /* Acknowledge to USART ISR the buffer has been handled */
+ }
+ }
+
+ if (noise_state.handshake_state == HANDSHAKE_IN_PROGRESS)
+ try_continue_noise_handshake(&noise_state, NULL, 0, NULL); /* handle outgoing messages */
delay_ms_busy_loop(1); /* approx 1ms interval between usbh_poll() */
}
diff --git a/src/hid_keycodes.c b/src/hid_keycodes.c
new file mode 100644
index 0000000..19b6f69
--- /dev/null
+++ b/src/hid_keycodes.c
@@ -0,0 +1,43 @@
+
+#include "hid_keycodes.h"
+
+struct keymap_entry keycode_mapping[37] = {
+ { KEY_A, 'A' },
+ { KEY_B, 'B' },
+ { KEY_C, 'C' },
+ { KEY_D, 'D' },
+ { KEY_E, 'E' },
+ { KEY_F, 'F' },
+ { KEY_G, 'G' },
+ { KEY_H, 'H' },
+ { KEY_I, 'I' },
+ { KEY_J, 'J' },
+ { KEY_K, 'K' },
+ { KEY_L, 'L' },
+ { KEY_M, 'M' },
+ { KEY_N, 'N' },
+ { KEY_O, 'O' },
+ { KEY_P, 'P' },
+ { KEY_Q, 'Q' },
+ { KEY_R, 'R' },
+ { KEY_S, 'S' },
+ { KEY_T, 'T' },
+ { KEY_U, 'U' },
+ { KEY_V, 'V' },
+ { KEY_W, 'W' },
+ { KEY_X, 'X' },
+ { KEY_Y, 'Y' },
+ { KEY_Z, 'Z' },
+ { KEY_1, '1' },
+ { KEY_2, '2' },
+ { KEY_3, '3' },
+ { KEY_4, '4' },
+ { KEY_5, '5' },
+ { KEY_6, '6' },
+ { KEY_7, '7' },
+ { KEY_8, '8' },
+ { KEY_9, '9' },
+ { KEY_0, '0' },
+ { KEY_SPACE, ' ' },
+};
+
diff --git a/src/hid_keycodes.h b/src/hid_keycodes.h
new file mode 100644
index 0000000..a7f590a
--- /dev/null
+++ b/src/hid_keycodes.h
@@ -0,0 +1,194 @@
+#ifndef __HID_KEYCODES_H__
+#define __HID_KEYCODES_H__
+
+struct keymap_entry {
+ unsigned char kc;
+ char ch;
+};
+
+extern struct keymap_entry keycode_mapping[37];
+
+enum hid_keycode {
+ KEY_NONE = 0x00, // No key pressed
+ KEY_ERR_OVF = 0x01, // Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key")
+ KEY_A = 0x04, // Keyboard a and A
+ KEY_B = 0x05, // Keyboard b and B
+ KEY_C = 0x06, // Keyboard c and C
+ KEY_D = 0x07, // Keyboard d and D
+ KEY_E = 0x08, // Keyboard e and E
+ KEY_F = 0x09, // Keyboard f and F
+ KEY_G = 0x0a, // Keyboard g and G
+ KEY_H = 0x0b, // Keyboard h and H
+ KEY_I = 0x0c, // Keyboard i and I
+ KEY_J = 0x0d, // Keyboard j and J
+ KEY_K = 0x0e, // Keyboard k and K
+ KEY_L = 0x0f, // Keyboard l and L
+ KEY_M = 0x10, // Keyboard m and M
+ KEY_N = 0x11, // Keyboard n and N
+ KEY_O = 0x12, // Keyboard o and O
+ KEY_P = 0x13, // Keyboard p and P
+ KEY_Q = 0x14, // Keyboard q and Q
+ KEY_R = 0x15, // Keyboard r and R
+ KEY_S = 0x16, // Keyboard s and S
+ KEY_T = 0x17, // Keyboard t and T
+ KEY_U = 0x18, // Keyboard u and U
+ KEY_V = 0x19, // Keyboard v and V
+ KEY_W = 0x1a, // Keyboard w and W
+ KEY_X = 0x1b, // Keyboard x and X
+ KEY_Y = 0x1c, // Keyboard y and Y
+ KEY_Z = 0x1d, // Keyboard z and Z
+
+ KEY_1 = 0x1e, // Keyboard 1 and !
+ KEY_2 = 0x1f, // Keyboard 2 and @
+ KEY_3 = 0x20, // Keyboard 3 and #
+ KEY_4 = 0x21, // Keyboard 4 and $
+ KEY_5 = 0x22, // Keyboard 5 and %
+ KEY_6 = 0x23, // Keyboard 6 and ^
+ KEY_7 = 0x24, // Keyboard 7 and &
+ KEY_8 = 0x25, // Keyboard 8 and *
+ KEY_9 = 0x26, // Keyboard 9 and (
+ KEY_0 = 0x27, // Keyboard 0 and )
+
+ KEY_ENTER = 0x28, // Keyboard Return (ENTER)
+ KEY_ESC = 0x29, // Keyboard ESCAPE
+ KEY_BACKSPACE = 0x2a, // Keyboard DELETE (Backspace)
+ KEY_TAB = 0x2b, // Keyboard Tab
+ KEY_SPACE = 0x2c, // Keyboard Spacebar
+ KEY_MINUS = 0x2d, // Keyboard - and _
+ KEY_EQUAL = 0x2e, // Keyboard = and +
+ KEY_LEFTBRACE = 0x2f, // Keyboard [ and {
+ KEY_RIGHTBRACE = 0x30, // Keyboard ] and }
+ KEY_BACKSLASH = 0x31, // Keyboard \ and |
+ KEY_HASHTILDE = 0x32, // Keyboard Non-US # and ~
+ KEY_SEMICOLON = 0x33, // Keyboard ; and :
+ KEY_APOSTROPHE = 0x34, // Keyboard ' and "
+ KEY_GRAVE = 0x35, // Keyboard ` and ~
+ KEY_COMMA = 0x36, // Keyboard , and <
+ KEY_DOT = 0x37, // Keyboard . and >
+ KEY_SLASH = 0x38, // Keyboard / and ?
+ KEY_CAPSLOCK = 0x39, // Keyboard Caps Lock
+
+ KEY_F1 = 0x3a, // Keyboard F1
+ KEY_F2 = 0x3b, // Keyboard F2
+ KEY_F3 = 0x3c, // Keyboard F3
+ KEY_F4 = 0x3d, // Keyboard F4
+ KEY_F5 = 0x3e, // Keyboard F5
+ KEY_F6 = 0x3f, // Keyboard F6
+ KEY_F7 = 0x40, // Keyboard F7
+ KEY_F8 = 0x41, // Keyboard F8
+ KEY_F9 = 0x42, // Keyboard F9
+ KEY_F10 = 0x43, // Keyboard F10
+ KEY_F11 = 0x44, // Keyboard F11
+ KEY_F12 = 0x45, // Keyboard F12
+
+ KEY_SYSRQ = 0x46, // Keyboard Print Screen
+ KEY_SCROLLLOCK = 0x47, // Keyboard Scroll Lock
+ KEY_PAUSE = 0x48, // Keyboard Pause
+ KEY_INSERT = 0x49, // Keyboard Insert
+ KEY_HOME = 0x4a, // Keyboard Home
+ KEY_PAGEUP = 0x4b, // Keyboard Page Up
+ KEY_DELETE = 0x4c, // Keyboard Delete Forward
+ KEY_END = 0x4d, // Keyboard End
+ KEY_PAGEDOWN = 0x4e, // Keyboard Page Down
+ KEY_RIGHT = 0x4f, // Keyboard Right Arrow
+ KEY_LEFT = 0x50, // Keyboard Left Arrow
+ KEY_DOWN = 0x51, // Keyboard Down Arrow
+ KEY_UP = 0x52, // Keyboard Up Arrow
+
+ KEY_NUMLOCK = 0x53, // Keyboard Num Lock and Clear
+ KEY_KPSLASH = 0x54, // Keypad /
+ KEY_KPASTERISK = 0x55, // Keypad *
+ KEY_KPMINUS = 0x56, // Keypad -
+ KEY_KPPLUS = 0x57, // Keypad +
+ KEY_KPENTER = 0x58, // Keypad ENTER
+ KEY_KP1 = 0x59, // Keypad 1 and End
+ KEY_KP2 = 0x5a, // Keypad 2 and Down Arrow
+ KEY_KP3 = 0x5b, // Keypad 3 and PageDn
+ KEY_KP4 = 0x5c, // Keypad 4 and Left Arrow
+ KEY_KP5 = 0x5d, // Keypad 5
+ KEY_KP6 = 0x5e, // Keypad 6 and Right Arrow
+ KEY_KP7 = 0x5f, // Keypad 7 and Home
+ KEY_KP8 = 0x60, // Keypad 8 and Up Arrow
+ KEY_KP9 = 0x61, // Keypad 9 and Page Up
+ KEY_KP0 = 0x62, // Keypad 0 and Insert
+ KEY_KPDOT = 0x63, // Keypad . and Delete
+
+ KEY_102ND = 0x64, // Keyboard Non-US \ and |
+ KEY_COMPOSE = 0x65, // Keyboard Application
+ KEY_POWER = 0x66, // Keyboard Power
+ KEY_KPEQUAL = 0x67, // Keypad =
+
+ KEY_F13 = 0x68, // Keyboard F13
+ KEY_F14 = 0x69, // Keyboard F14
+ KEY_F15 = 0x6a, // Keyboard F15
+ KEY_F16 = 0x6b, // Keyboard F16
+ KEY_F17 = 0x6c, // Keyboard F17
+ KEY_F18 = 0x6d, // Keyboard F18
+ KEY_F19 = 0x6e, // Keyboard F19
+ KEY_F20 = 0x6f, // Keyboard F20
+ KEY_F21 = 0x70, // Keyboard F21
+ KEY_F22 = 0x71, // Keyboard F22
+ KEY_F23 = 0x72, // Keyboard F23
+ KEY_F24 = 0x73, // Keyboard F24
+
+ KEY_OPEN = 0x74, // Keyboard Execute
+ KEY_HELP = 0x75, // Keyboard Help
+ KEY_PROPS = 0x76, // Keyboard Menu
+ KEY_FRONT = 0x77, // Keyboard Select
+ KEY_STOP = 0x78, // Keyboard Stop
+ KEY_AGAIN = 0x79, // Keyboard Again
+ KEY_UNDO = 0x7a, // Keyboard Undo
+ KEY_CUT = 0x7b, // Keyboard Cut
+ KEY_COPY = 0x7c, // Keyboard Copy
+ KEY_PASTE = 0x7d, // Keyboard Paste
+ KEY_FIND = 0x7e, // Keyboard Find
+ KEY_MUTE = 0x7f, // Keyboard Mute
+ KEY_VOLUMEUP = 0x80, // Keyboard Volume Up
+ KEY_VOLUMEDOWN = 0x81, // Keyboard Volume Down
+ KEY_KPCOMMA = 0x85, // Keypad Comma
+ KEY_RO = 0x87, // Keyboard International1
+ KEY_KATAKANAHIRAGANA = 0x88, // Keyboard International2
+ KEY_YEN = 0x89, // Keyboard International3
+ KEY_HENKAN = 0x8a, // Keyboard International4
+ KEY_MUHENKAN = 0x8b, // Keyboard International5
+ KEY_KPJPCOMMA = 0x8c, // Keyboard International6
+ KEY_HANGEUL = 0x90, // Keyboard LANG1
+ KEY_HANJA = 0x91, // Keyboard LANG2
+ KEY_KATAKANA = 0x92, // Keyboard LANG3
+ KEY_HIRAGANA = 0x93, // Keyboard LANG4
+ KEY_ZENKAKUHANKAKU = 0x94, // Keyboard LANG5
+ KEY_KPLEFTPAREN = 0xb6, // Keypad (
+ KEY_KPRIGHTPAREN = 0xb7, // Keypad )
+
+ KEY_LEFTCTRL = 0xe0, // Keyboard Left Control
+ KEY_LEFTSHIFT = 0xe1, // Keyboard Left Shift
+ KEY_LEFTALT = 0xe2, // Keyboard Left Alt
+ KEY_LEFTMETA = 0xe3, // Keyboard Left GUI
+ KEY_RIGHTCTRL = 0xe4, // Keyboard Right Control
+ KEY_RIGHTSHIFT = 0xe5, // Keyboard Right Shift
+ KEY_RIGHTALT = 0xe6, // Keyboard Right Alt
+ KEY_RIGHTMETA = 0xe7, // Keyboard Right GUI
+
+ KEY_MEDIA_PLAYPAUSE = 0xe8,
+ KEY_MEDIA_STOPCD = 0xe9,
+ KEY_MEDIA_PREVIOUSSONG = 0xea,
+ KEY_MEDIA_NEXTSONG = 0xeb,
+ KEY_MEDIA_EJECTCD = 0xec,
+ KEY_MEDIA_VOLUMEUP = 0xed,
+ KEY_MEDIA_VOLUMEDOWN = 0xee,
+ KEY_MEDIA_MUTE = 0xef,
+ KEY_MEDIA_WWW = 0xf0,
+ KEY_MEDIA_BACK = 0xf1,
+ KEY_MEDIA_FORWARD = 0xf2,
+ KEY_MEDIA_STOP = 0xf3,
+ KEY_MEDIA_FIND = 0xf4,
+ KEY_MEDIA_SCROLLUP = 0xf5,
+ KEY_MEDIA_SCROLLDOWN = 0xf6,
+ KEY_MEDIA_EDIT = 0xf7,
+ KEY_MEDIA_SLEEP = 0xf8,
+ KEY_MEDIA_COFFEE = 0xf9,
+ KEY_MEDIA_REFRESH = 0xfa,
+ KEY_MEDIA_CALC = 0xfb,
+};
+
+#endif
diff --git a/src/noise.c b/src/noise.c
index 83f2e4c..09a4c47 100644
--- a/src/noise.c
+++ b/src/noise.c
@@ -19,11 +19,22 @@
volatile uint8_t host_packet_buf[MAX_HOST_PACKET_SIZE];
volatile uint8_t host_packet_length = 0;
-static uint8_t local_key[CURVE25519_KEY_LEN];
-static NoiseCipherState *tx_cipher = NULL, *rx_cipher = NULL;
+void noise_state_init(struct NoiseState *st, uint8_t *remote_key_reference) {
+ st->handshake_state = HANDSHAKE_UNINITIALIZED;
+ st->handshake = NULL;
+ st->tx_cipher = NULL;
+ st->rx_cipher = NULL;
+ st->remote_key_reference = remote_key_reference;
+ st->failed_handshakes = 0;
+}
+
+int reset_protocol_handshake(struct NoiseState *st) {
+ uninit_handshake(st, HANDSHAKE_UNINITIALIZED);
+ return start_protocol_handshake(st);
+}
-NoiseHandshakeState *start_protocol_handshake() {
+int start_protocol_handshake(struct NoiseState *st) {
/* TODO Noise-C is nice for prototyping, but we should really get rid of it for mostly three 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
@@ -40,18 +51,20 @@ NoiseHandshakeState *start_protocol_handshake() {
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_dhstate_set_keypair_private(dh, st->local_key, sizeof(st->local_key)), "loading local private keys");
HANDLE_NOISE_ERROR(noise_handshakestate_start(handshake), "starting handshake");
- return handshake;
+ st->handshake = handshake;
+ st->handshake_state = HANDSHAKE_IN_PROGRESS;
+ return 0;
errout:
noise_handshakestate_free(handshake);
- return 0;
+ return -1;
}
-int generate_identity_key() {
+int generate_identity_key(struct NoiseState *st) {
NoiseDHState *dh;
int err;
@@ -59,84 +72,129 @@ int generate_identity_key() {
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));
+ memset(st->local_key, 0, sizeof(st->local_key));
- HANDLE_NOISE_ERROR(noise_dhstate_get_keypair(dh, local_key, sizeof(local_key), unused, sizeof(unused)), "saving key pair");
+ HANDLE_NOISE_ERROR(noise_dhstate_get_keypair(dh, st->local_key, sizeof(st->local_key), unused, sizeof(unused)), "saving key pair");
return 0;
-
errout:
if (dh)
noise_dhstate_free(dh);
return -1;
}
-NoiseHandshakeState *try_continue_noise_handshake(NoiseHandshakeState *handshake) {
+void uninit_handshake(struct NoiseState *st, enum handshake_state new_state) {
+ if (st->handshake)
+ noise_handshakestate_free(st->handshake);
+ st->handshake_state = new_state;
+ st->handshake = NULL;
+}
+
+enum handshake_state try_continue_noise_handshake(struct NoiseState *st, uint8_t *buf, size_t len, int *buf_consumed) {
int err;
- uint8_t message[MAX_HOST_PACKET_SIZE];
+ struct {
+ struct control_packet header;
+ uint8_t payload[MAX_HOST_PACKET_SIZE];
+ } pkt;
NoiseBuffer noise_msg;
+
+ if (!st->handshake || st->handshake_state != HANDSHAKE_IN_PROGRESS) {
+ LOG_PRINTF("Error: Invalid handshake state\n");
+ goto errout;
+ }
+
/* Run the protocol handshake */
- switch (noise_handshakestate_get_action(handshake)) {
+ switch (noise_handshakestate_get_action(st->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));
- HANDLE_NOISE_ERROR(noise_handshakestate_write_message(handshake, &noise_msg, NULL), "writing handshake message");
- send_packet(usart2_out, message, noise_msg.size);
+ /* Write the next handshake message with a zero-length noise payload */
+ pkt.header.type = HOST_HANDSHAKE;
+ noise_buffer_set_output(noise_msg, &pkt.payload, sizeof(pkt.payload));
+ HANDLE_NOISE_ERROR(noise_handshakestate_write_message(st->handshake, &noise_msg, NULL), "writing handshake message");
+ send_packet(usart2_out, (uint8_t *)&pkt, noise_msg.size + sizeof(pkt.header));
break;
case NOISE_ACTION_READ_MESSAGE:
- if (host_packet_length > 0) {
+ if (buf) {
/* Read the next handshake message and discard the payload */
- noise_buffer_set_input(noise_msg, (uint8_t *)host_packet_buf, host_packet_length);
- HANDLE_NOISE_ERROR(noise_handshakestate_read_message(handshake, &noise_msg, NULL), "reading handshake message");
- host_packet_length = 0; /* Acknowledge to USART ISR the buffer has been handled */
+ *buf_consumed = 1;
+ noise_buffer_set_input(noise_msg, buf, len);
+ HANDLE_NOISE_ERROR(noise_handshakestate_read_message(st->handshake, &noise_msg, NULL), "reading handshake message");
}
break;
case NOISE_ACTION_SPLIT:
- HANDLE_NOISE_ERROR(noise_handshakestate_split(handshake, &tx_cipher, &rx_cipher), "splitting handshake state");
+ HANDLE_NOISE_ERROR(noise_handshakestate_split(st->handshake, &st->tx_cipher, &st->rx_cipher), "splitting handshake state");
LOG_PRINTF("Noise protocol handshake completed successfully, handshake hash:\n");
- uint8_t buf[BLAKE2S_HASH_SIZE];
- if (noise_handshakestate_get_handshake_hash(handshake, buf, sizeof(buf)) != NOISE_ERROR_NONE) {
+ if (noise_handshakestate_get_handshake_hash(st->handshake, st->handshake_hash, sizeof(st->handshake_hash)) != NOISE_ERROR_NONE) {
LOG_PRINTF("Error fetching noise handshake state\n");
} else {
LOG_PRINTF(" ");
- for (size_t i=0; i<sizeof(buf); i++)
- LOG_PRINTF("%02x ", buf[i]);
+ for (size_t i=0; i<sizeof(st->handshake_hash); i++)
+ LOG_PRINTF("%02x ", st->handshake_hash[i]);
LOG_PRINTF("\n");
}
- noise_handshakestate_free(handshake);
- return NULL;
+
+ NoiseDHState *remote_dh = noise_handshakestate_get_remote_public_key_dh(st->handshake);
+ if (!remote_dh) {
+ LOG_PRINTF("Error: Host has not identified itself\n");
+ goto errout;
+ }
+
+
+ HANDLE_NOISE_ERROR(noise_dhstate_get_public_key(remote_dh, st->remote_key, sizeof(st->remote_key)), "getting remote pubkey");
+
+ if (!memcmp(st->remote_key, st->remote_key_reference, sizeof(st->remote_key))) { /* keys match */
+ uninit_handshake(st, HANDSHAKE_DONE_KNOWN_HOST);
+ st->failed_handshakes = 0;
+ } else { /* keys don't match */
+ uninit_handshake(st, HANDSHAKE_DONE_UNKNOWN_HOST);
+ st->failed_handshakes++;
+ }
+ break;
default:
- LOG_PRINTF("Noise protocol handshake failed\n");
goto errout;
}
- return handshake;
-
+ return st->handshake_state;
errout:
- noise_handshakestate_free(handshake);
- return NULL;
+ uninit_handshake(st, HANDSHAKE_UNINITIALIZED);
+ st->failed_handshakes++;
+ LOG_PRINTF("Noise protocol handshake failed, %d failed attempts\n", st->failed_handshakes);
+ return st->handshake_state;
+}
+
+void persist_remote_key(struct NoiseState *st) {
+ memcpy(st->remote_key_reference, st->remote_key, sizeof(st->remote_key));
+ st->handshake_state = HANDSHAKE_DONE_KNOWN_HOST;
}
-int send_encrypted_message(uint8_t *msg, size_t len) {
+int send_encrypted_message(struct NoiseState *st, uint8_t *msg, size_t len) {
int err;
NoiseBuffer noise_buf;
- uint8_t raw_buf[MAX_HOST_PACKET_SIZE];
+ struct {
+ struct control_packet header;
+ uint8_t payload[MAX_HOST_PACKET_SIZE];
+ } pkt;
- if (!tx_cipher) {
+ if (!st->tx_cipher) {
LOG_PRINTF("Cannot send encrypted packet: Data ciphers not yet initialized\n");
return -1;
}
- memcpy(raw_buf, msg, len); /* This is necessary because noises API doesn't support separate in and out buffers. D'oh! */
- noise_buffer_set_inout(noise_buf, raw_buf, len, sizeof(raw_buf));
+ if (len > sizeof(pkt.payload)) {
+ LOG_PRINTF("Packet too long\n");
+ return -3;
+ }
+
+ pkt.header.type = HOST_DATA;
+ memcpy(pkt.payload, msg, len); /* This is necessary because noises API doesn't support separate in and out buffers. D'oh! */
+ noise_buffer_set_inout(noise_buf, pkt.payload, len, sizeof(pkt.payload));
- HANDLE_NOISE_ERROR(noise_cipherstate_encrypt(tx_cipher, &noise_buf), "encrypting data");
- send_packet(usart2_out, raw_buf, noise_buf.size);
+ HANDLE_NOISE_ERROR(noise_cipherstate_encrypt(st->tx_cipher, &noise_buf), "encrypting data");
+ send_packet(usart2_out, (uint8_t *)&pkt, noise_buf.size + sizeof(pkt.header));
return 0;
errout:
diff --git a/src/noise.h b/src/noise.h
index fb1f93d..c777a0b 100644
--- a/src/noise.h
+++ b/src/noise.h
@@ -16,10 +16,35 @@
extern volatile uint8_t host_packet_buf[MAX_HOST_PACKET_SIZE];
extern volatile uint8_t host_packet_length;
-
-NoiseHandshakeState *start_protocol_handshake(void);
-int generate_identity_key(void);
-NoiseHandshakeState *try_continue_noise_handshake(NoiseHandshakeState *handshake);
-int send_encrypted_message(uint8_t *msg, size_t len);
+enum handshake_state {
+ HANDSHAKE_UNINITIALIZED,
+ HANDSHAKE_NOT_STARTED,
+ HANDSHAKE_IN_PROGRESS,
+ HANDSHAKE_DONE_UNKNOWN_HOST,
+ HANDSHAKE_DONE_KNOWN_HOST,
+};
+
+extern volatile enum handshake_state handshake_state;
+
+struct NoiseState {
+ NoiseHandshakeState *handshake;
+ enum handshake_state handshake_state;
+ NoiseCipherState *tx_cipher, *rx_cipher;
+ uint8_t local_key[CURVE25519_KEY_LEN];
+ uint8_t remote_key[CURVE25519_KEY_LEN];
+ uint8_t *remote_key_reference;
+ uint8_t handshake_hash[BLAKE2S_HASH_SIZE];
+ int failed_handshakes;
+};
+
+
+void uninit_handshake(struct NoiseState *st, enum handshake_state new_state);
+void noise_state_init(struct NoiseState *st, uint8_t *remote_key_reference);
+void persist_remote_key(struct NoiseState *st);
+int start_protocol_handshake(struct NoiseState *st);
+int reset_protocol_handshake(struct NoiseState *st);
+int generate_identity_key(struct NoiseState *st);
+enum handshake_state try_continue_noise_handshake(struct NoiseState *st, uint8_t *buf, size_t len, int *buf_consumed);
+int send_encrypted_message(struct NoiseState *st, uint8_t *msg, size_t len);
#endif
diff --git a/src/nouns.c b/src/nouns.c
new file mode 100644
index 0000000..65cae90
--- /dev/null
+++ b/src/nouns.c
@@ -0,0 +1,262 @@
+
+#include "words.h"
+
+const char * const nouns[256] = {
+ "yolk", /* 0 */
+ "writing", /* 1 */
+ "wrath", /* 2 */
+ "wound", /* 3 */
+ "worm", /* 4 */
+ "wings", /* 5 */
+ "whistle", /* 6 */
+ "watchdog", /* 7 */
+ "waste", /* 8 */
+ "vomit", /* 9 */
+ "vermin", /* 10 */
+ "variation", /* 11 */
+ "underachievement", /* 12 */
+ "tusk", /* 13 */
+ "troll", /* 14 */
+ "trick", /* 15 */
+ "transplant", /* 16 */
+ "transgression", /* 17 */
+ "tooth", /* 18 */
+ "tongue", /* 19 */
+ "tickle", /* 20 */
+ "tick", /* 21 */
+ "thorn", /* 22 */
+ "thistle", /* 23 */
+ "thing", /* 24 */
+ "terror", /* 25 */
+ "tentacle", /* 26 */
+ "tease", /* 27 */
+ "surrender", /* 28 */
+ "surge", /* 29 */
+ "sucker", /* 30 */
+ "substance", /* 31 */
+ "storm", /* 32 */
+ "stone", /* 33 */
+ "stew", /* 34 */
+ "stalk", /* 35 */
+ "squid", /* 36 */
+ "sprout", /* 37 */
+ "sponge", /* 38 */
+ "spill", /* 39 */
+ "spider", /* 40 */
+ "sphere", /* 41 */
+ "spectacle", /* 42 */
+ "speck", /* 43 */
+ "spawn", /* 44 */
+ "soul", /* 45 */
+ "solution", /* 46 */
+ "snout", /* 47 */
+ "snake", /* 48 */
+ "smell", /* 49 */
+ "sloth", /* 50 */
+ "slime", /* 51 */
+ "slice", /* 52 */
+ "sleeper", /* 53 */
+ "slave", /* 54 */
+ "sinew", /* 55 */
+ "shell", /* 56 */
+ "shape", /* 57 */
+ "seizure", /* 58 */
+ "seed", /* 59 */
+ "schism", /* 60 */
+ "scam", /* 61 */
+ "scale", /* 62 */
+ "sainthood", /* 63 */
+ "root", /* 64 */
+ "robe", /* 65 */
+ "roach", /* 66 */
+ "rinse", /* 67 */
+ "remains", /* 68 */
+ "relay", /* 69 */
+ "rejuvenation", /* 70 */
+ "realization", /* 71 */
+ "reaction", /* 72 */
+ "ransom", /* 73 */
+ "pupa", /* 74 */
+ "pride", /* 75 */
+ "prey", /* 76 */
+ "predator", /* 77 */
+ "potion", /* 78 */
+ "pornography", /* 79 */
+ "polyp", /* 80 */
+ "plum", /* 81 */
+ "pleasure", /* 82 */
+ "pitch", /* 83 */
+ "pigeon", /* 84 */
+ "phenomenon", /* 85 */
+ "pest", /* 86 */
+ "periwinkle", /* 87 */
+ "percolation", /* 88 */
+ "parasite", /* 89 */
+ "pair", /* 90 */
+ "oyster", /* 91 */
+ "orphan", /* 92 */
+ "orgasm", /* 93 */
+ "organism", /* 94 */
+ "orchid", /* 95 */
+ "object", /* 96 */
+ "nail", /* 97 */
+ "mushroom", /* 98 */
+ "murder", /* 99 */
+ "mucus", /* 100 */
+ "movement", /* 101 */
+ "mother", /* 102 */
+ "mold", /* 103 */
+ "mist", /* 104 */
+ "mildew", /* 105 */
+ "metal", /* 106 */
+ "mesh", /* 107 */
+ "meddling", /* 108 */
+ "mayhem", /* 109 */
+ "masterpiece", /* 110 */
+ "masonry", /* 111 */
+ "mask", /* 112 */
+ "manhood", /* 113 */
+ "maggot", /* 114 */
+ "lust", /* 115 */
+ "loop", /* 116 */
+ "living_thing", /* 117 */
+ "liquor", /* 118 */
+ "liquid", /* 119 */
+ "lining", /* 120 */
+ "laceration", /* 121 */
+ "knife", /* 122 */
+ "kitten", /* 123 */
+ "kiss", /* 124 */
+ "jumper", /* 125 */
+ "jest", /* 126 */
+ "instrument", /* 127 */
+ "injustice", /* 128 */
+ "injury", /* 129 */
+ "influence", /* 130 */
+ "indulgence", /* 131 */
+ "incursion", /* 132 */
+ "impulse", /* 133 */
+ "imago", /* 134 */
+ "hound", /* 135 */
+ "horn", /* 136 */
+ "hook", /* 137 */
+ "hoof", /* 138 */
+ "heirloom", /* 139 */
+ "heart", /* 140 */
+ "hawk", /* 141 */
+ "hare", /* 142 */
+ "hair", /* 143 */
+ "gulp", /* 144 */
+ "guardian", /* 145 */
+ "grass", /* 146 */
+ "goat", /* 147 */
+ "gnat", /* 148 */
+ "gluttony", /* 149 */
+ "glowworm", /* 150 */
+ "gasp", /* 151 */
+ "game", /* 152 */
+ "fusion", /* 153 */
+ "fungus", /* 154 */
+ "frustration", /* 155 */
+ "frog", /* 156 */
+ "foul", /* 157 */
+ "foot", /* 158 */
+ "food", /* 159 */
+ "fog", /* 160 */
+ "foal", /* 161 */
+ "fluke", /* 162 */
+ "fluff", /* 163 */
+ "flower", /* 164 */
+ "flicker", /* 165 */
+ "flea", /* 166 */
+ "flattery", /* 167 */
+ "flask", /* 168 */
+ "flare", /* 169 */
+ "firefly", /* 170 */
+ "finger", /* 171 */
+ "filtration", /* 172 */
+ "female", /* 173 */
+ "feeder", /* 174 */
+ "feather", /* 175 */
+ "fart", /* 176 */
+ "fang", /* 177 */
+ "failure", /* 178 */
+ "face", /* 179 */
+ "fabrication", /* 180 */
+ "extract", /* 181 */
+ "exodus", /* 182 */
+ "evil", /* 183 */
+ "envy", /* 184 */
+ "enema", /* 185 */
+ "embryo", /* 186 */
+ "egress", /* 187 */
+ "echo", /* 188 */
+ "eater", /* 189 */
+ "ear", /* 190 */
+ "dwarf", /* 191 */
+ "dust", /* 192 */
+ "drop", /* 193 */
+ "draft", /* 194 */
+ "domestication", /* 195 */
+ "distortion", /* 196 */
+ "dew", /* 197 */
+ "depravity", /* 198 */
+ "deity", /* 199 */
+ "death", /* 200 */
+ "daughter", /* 201 */
+ "dash", /* 202 */
+ "dagger", /* 203 */
+ "culture", /* 204 */
+ "crutch", /* 205 */
+ "crow", /* 206 */
+ "critter", /* 207 */
+ "creeper", /* 208 */
+ "creation", /* 209 */
+ "crab", /* 210 */
+ "corruption", /* 211 */
+ "cocoon", /* 212 */
+ "claw", /* 213 */
+ "chip", /* 214 */
+ "child", /* 215 */
+ "cell", /* 216 */
+ "catch", /* 217 */
+ "carving", /* 218 */
+ "carrot", /* 219 */
+ "carnival", /* 220 */
+ "cancer", /* 221 */
+ "butterfly", /* 222 */
+ "burn", /* 223 */
+ "buildup", /* 224 */
+ "brush", /* 225 */
+ "brew", /* 226 */
+ "bottle", /* 227 */
+ "boot", /* 228 */
+ "book", /* 229 */
+ "bone", /* 230 */
+ "blunder", /* 231 */
+ "blot", /* 232 */
+ "blood", /* 233 */
+ "blink", /* 234 */
+ "bite", /* 235 */
+ "bird", /* 236 */
+ "benthos", /* 237 */
+ "beak", /* 238 */
+ "basket", /* 239 */
+ "bark", /* 240 */
+ "ball", /* 241 */
+ "baby", /* 242 */
+ "axolotl", /* 243 */
+ "ashes", /* 244 */
+ "artifact", /* 245 */
+ "arson", /* 246 */
+ "armor", /* 247 */
+ "apparition", /* 248 */
+ "antenna", /* 249 */
+ "alms", /* 250 */
+ "alienation", /* 251 */
+ "advent", /* 252 */
+ "adornment", /* 253 */
+ "abomination", /* 254 */
+ "abandonment", /* 255 */
+};
+
diff --git a/src/packet_interface.h b/src/packet_interface.h
index 546918b..9e1327d 100644
--- a/src/packet_interface.h
+++ b/src/packet_interface.h
@@ -3,8 +3,35 @@
#include "usart_helpers.h"
+
extern struct dma_usart_file *usart2_out;
+enum control_packet_types {
+ _HOST_RESERVED = 0,
+ HOST_INITIATE_HANDSHAKE = 1,
+ HOST_HANDSHAKE = 2,
+ HOST_DATA = 3,
+};
+
+enum packet_types {
+ _PACKET_RESERVED = 0,
+ HID_KEYBOARD_REPORT = 1,
+ HID_MOUSE_REPORT = 2,
+ PAIRING = 3,
+};
+
+struct hid_report_packet {
+ uint8_t type;
+ uint8_t len;
+ uint8_t report[8];
+} __attribute__((__packed__));
+
+struct control_packet {
+ uint8_t type;
+ uint8_t payload[0];
+} __attribute__((__packed__));
+
+
void send_packet(struct dma_usart_file *f, const uint8_t *data, size_t len);
#endif
diff --git a/src/words.h b/src/words.h
new file mode 100644
index 0000000..e8cb628
--- /dev/null
+++ b/src/words.h
@@ -0,0 +1,7 @@
+#ifndef __ADJECTIVES_H__
+#define __ADJECTIVES_H__
+
+extern const char * const adjectives[256];
+extern const char * const nouns[256];
+
+#endif