diff options
author | jaseg <git@jaseg.net> | 2018-11-13 21:45:24 +0900 |
---|---|---|
committer | jaseg <git@jaseg.net> | 2018-11-13 21:45:24 +0900 |
commit | e16515bb643b9329318809ecc134f74c22a86382 (patch) | |
tree | 30efc4ce885ced6edae4299c3453fa2f28c20926 | |
parent | 6af635bd41b48da04edd1f70a6851cb3f811cea3 (diff) | |
download | secure-hid-e16515bb643b9329318809ecc134f74c22a86382.tar.gz secure-hid-e16515bb643b9329318809ecc134f74c22a86382.tar.bz2 secure-hid-e16515bb643b9329318809ecc134f74c22a86382.zip |
Pairing and passthrough mostly working, except it's too slow
-rwxr-xr-x | hexnoise.py | 32 | ||||
-rwxr-xr-x | pairing.py | 65 | ||||
-rw-r--r-- | src/demo.c | 34 | ||||
-rw-r--r-- | src/packet_interface.c | 3 |
4 files changed, 78 insertions, 56 deletions
diff --git a/hexnoise.py b/hexnoise.py index 8529787..8a8dae5 100755 --- a/hexnoise.py +++ b/hexnoise.py @@ -31,6 +31,9 @@ class ReportType(enum.Enum): PAIRING_SUCESS = 4 PAIRING_ERROR = 5 +class ProtocolError(Exception): + pass + class Packetizer: def __init__(self, serial, debug=False, width=16): self.ser, self.debug, self.width = serial, debug, width @@ -55,11 +58,11 @@ class Packetizer: pkt_type, data = PacketType(data[0]), data[1:] if pkt_type is PacketType.COMM_ERROR: - raise ValueError('Device-side serial communication error') + raise ProtocolError('Device-side serial communication error') elif pkt_type is PacketType.CRYPTO_ERROR: - raise ValueError('Device-side cryptographic error') + raise ProtocolError('Device-side cryptographic error') elif pkt_type is PacketType.TOO_MANY_FAILS: - raise ValueError('Device reports too many failed handshake attempts') + raise ProtocolError('Device reports too many failed handshake attempts') else: return pkt_type, data @@ -222,7 +225,7 @@ class NoiseEngine: if pkt_type is PacketType.HANDSHAKE: self.proto.read_message(payload) else: - raise ValueError(f'Incorrect packet type {pkt_type}. Ignoring since this is only test code.') + raise ProtocolError(f'Incorrect packet type {pkt_type}. Ignoring since this is only test code.') if self.debug: print('Handshake finished, handshake hash:') hexdump(print, self.proto.get_handshake_hash()) @@ -291,19 +294,26 @@ class NoiseEngine: break elif msg_type == ReportType.PAIRING_ERROR: - raise ValueError('Device-side pairing error') # FIXME find better exception subclass here + raise ProtocolError('Device-side pairing error') # FIXME find better exception subclass here else: - raise ValueError('Invalid report type') + raise ProtocolError('Invalid report type') def uinput_passthrough(self): with uinput.Device(KeyMapper.ALL_KEYS) as ui: old_kcs = set() - for msg_type, payload in noise.receive_loop(): - if msg_type == ReportType.KEYBOARD: - modbyte, _reserved, *keycodes = payload + for msg_type, payload in self.receive_loop(): + report_len, *report = payload + if report_len != 8: + raise ValueError('Unsupported report length', report_len) + + if msg_type is ReportType.KEYBOARD: + modbyte, _reserved, *keycodes = report + print(' payload:', payload) + print(' modifier:', list(KeyMapper.map_modifiers(modbyte))) + print(' regular:', list(KeyMapper.map_regulars(keycodes))) keys = { *KeyMapper.map_modifiers(modbyte), *KeyMapper.map_regulars(keycodes) } - if args.debug: + if self.debug: print('Emitting:', keys) for key in keys - old_kcs: @@ -313,7 +323,7 @@ class NoiseEngine: ui.syn() old_kcs = keys - elif msg_type == ReportType.MOUSE: + elif msg_type is ReportType.MOUSE: # FIXME unhandled pass @@ -5,8 +5,7 @@ import re import serial import gi gi.require_version('Gtk', '3.0') -gi.require_version('Pango', '1.0') -from gi.repository import Gtk, Pango +from gi.repository import Gtk, Gdk, Pango, GLib import hexnoise @@ -27,39 +26,27 @@ class PairingWindow(Gtk.Window): self.label.set_markup('<b>Step 1</b>\n\nContacting device...') self.vbox.pack_start(self.label, True, True, 0) - self.textview = Gtk.TextView() - self.textview.set_editable(False) - self.textbuffer = self.textview.get_buffer() - self.tag_nomatch = self.textbuffer.create_tag("nomatch", weight=Pango.Weight.BOLD) - self.tag_match = self.textbuffer.create_tag("match", background='#AAFFAA', weight=Pango.Weight.BOLD) - - self.vbox.pack_start(self.textview, True, True, 0) + self.entry = Gtk.Entry() + self.entry.set_editable(False) + self.vbox.pack_start(self.entry, True, True, 0) self.add(self.vbox) - self.handshaker = threading.Thread(target=self.run_handshake, daemon=True) + self.handshaker = threading.Thread(target=self.pair, daemon=True) self.handshaker.start() - @classmethod - def matchlen(self, ref, text): - words = ref.split() - parts = text.split() - clean = lambda b: re.sub('^[^a-zA-Z0-9-]*', '', re.sub('[^a-zA-Z0-9-]*$', '', b)).lower() - - good = '' - for a, b in zip(words[:-1], parts[:-1]): - if a == clean(b): - good = f'{good}b ' - - rest = clean(parts[-1]) - if words[-1].startswith(rest): - good = f'{good} {rest}' - return len(good) - - def run_handshake(self): + def pair(self): self.packetizer = hexnoise.Packetizer(self.serial, debug=self.debug) self.noise = hexnoise.NoiseEngine(self.packetizer, debug=self.debug) + for i in range(10): + try: + self.run_handshake() + break + except hexnoise.ProtocolError as e: + print(e) + + def run_handshake(self): self.noise.perform_handshake() binding_incantation = self.noise.channel_binding_incantation() @@ -67,19 +54,25 @@ class PairingWindow(Gtk.Window): f'Enter the following incantation, then press enter.\n' f'<b>{binding_incantation}</b>') - for user_input in self.noise.pairing_messages(): - print('got:', user_input) - self.textbuffer.set_text(user_input) - #i1, i2 = self.textbuffer.get_start_iter(), self.textbuffer.get_end_iter() - #self.textbuffer.apply_tag(self.tag_nomatch, i1, i2) + def update_text(text): + self.entry.set_text(text) + self.entry.set_position(len(text)) - #i1, i2 = self.textbuffer.get_start_iter(), self.textbuffer.get_start_iter() - #i2.forward_chars(self.matchlen(binding_incantation, user_input)) - #self.textbuffer.apply_tag(self.tag_match, i1, i2) + clean = lambda s: re.sub('[^a-z0-9-]', '', s.lower()) + if clean(binding_incantation).startswith(clean(text)): + color = 0.9, 1.0, 0.9 # light red + else: + color = 1.0, 0.9, 0.9 # light green + self.entry.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(*color, 1.0)) + + for user_input in self.noise.pairing_messages(): + print(f'User input: "{user_input}"') + GLib.idle_add(update_text, user_input) self.label.set_markup(f'<b>Done!</b>') - #noise.uinput_passthrough() + # FIXME demo + self.noise.uinput_passthrough() if __name__ == '__main__': import argparse @@ -144,14 +144,36 @@ int pairing_check(struct NoiseState *st, const char *buf) { const char *p = buf;
int idx = 0;
do {
+ /* Skip over most special chars */
+ while (*p) {
+ char c = *p;
+ if ('0' <= c && c <= '9') break;
+ if ('a' <= c && c <= 'z') break;
+ if ('A' <= c && c <= 'Z') break;
+ if (c == '-') break;
+ p++;
+ }
+
const char *found = strchr(p, ' ');
size_t plen = found ? (size_t)(found - p) : strlen(p); /* p >= found */
+ while (plen > 0) {
+ char c = p[plen];
+ if ('0' <= c && c <= '9') break;
+ if ('a' <= c && c <= 'z') break;
+ if ('A' <= c && c <= 'Z') break;
+ if (c == '-') break;
+ plen--;
+ }
+ plen++;
+ //LOG_PRINTF("matching: \"%s\" - \"%s\" %d\n", p, p+plen, plen);
+
if (strncasecmp(p, "and", plen)) { /* ignore "and" */
int num = -1;
/* FIXME ignore "and", ignore commata and dots */
for (int i=0; i<256; i++) {
- if ((!strncasecmp(p, adjectives[i], plen)) || (!strncasecmp(p, nouns[i], plen))) {
+ if ((!strncasecmp(p, adjectives[i], plen) && plen == strlen(adjectives[i]))
+ || (!strncasecmp(p, nouns[i], plen) && plen == strlen(nouns[i] ))) {
//LOG_PRINTF(" idx=%02d h=%02x i=%02x adj=%s n=%s plen=%d s=%s\n", idx, st->handshake_hash[idx], i, adjectives[i], nouns[i], plen, p);
num = i;
break;
@@ -218,12 +240,8 @@ void pairing_input(uint8_t modbyte, uint8_t keycode) { for (size_t i=0; keycode_mapping[i].kc != KEY_NONE; i++) {
if (keycode_mapping[i].kc == keycode) {
ch = keycode_mapping[i].ch[level];
- if (!(('a' <= ch && ch <= 'z') ||
- ('A' <= ch && ch <= 'Z') ||
- ('0' <= ch && ch <= '9') ||
- (ch == ' ') ||
- (ch == '-')))
- break; /* ignore special chars */
+ if (!ch)
+ break;
if (pairing_buf_pos < sizeof(pairing_buf)-1) /* allow for terminating null byte */ {
pairing_buf[pairing_buf_pos++] = ch;
@@ -242,7 +260,7 @@ void pairing_input(uint8_t modbyte, uint8_t keycode) { }
if (ch) {
- LOG_PRINTF("Input: %s\n", pairing_buf);
+ //LOG_PRINTF("Input: %s\n", pairing_buf);
struct hid_report_packet pkt = {
.type = REPORT_PAIRING_INPUT,
.pairing_input = { .c = ch }
diff --git a/src/packet_interface.c b/src/packet_interface.c index 9c0ea5c..319ddd1 100644 --- a/src/packet_interface.c +++ b/src/packet_interface.c @@ -25,10 +25,11 @@ struct dma_usart_file usart2_out_s = { struct dma_usart_file *usart2_out = &usart2_out_s; void dma1_stream6_isr(void) { + static unsigned int fifo_errors = 0; /* debug */ if (dma_get_interrupt_flag(usart2_out->dma, usart2_out->stream, DMA_FEIF)) { /* Ignore FIFO errors as they're 100% non-critical for UART applications */ dma_clear_interrupt_flags(usart2_out->dma, usart2_out->stream, DMA_FEIF); - LOG_PRINTF("USART2 DMA FIFO error\n"); + fifo_errors++; return; } |