From e16515bb643b9329318809ecc134f74c22a86382 Mon Sep 17 00:00:00 2001 From: jaseg Date: Tue, 13 Nov 2018 21:45:24 +0900 Subject: Pairing and passthrough mostly working, except it's too slow --- hexnoise.py | 32 ++++++++++++++++--------- pairing.py | 65 ++++++++++++++++++++++---------------------------- src/demo.c | 34 +++++++++++++++++++------- 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 diff --git a/pairing.py b/pairing.py index fccc554..605b002 100755 --- a/pairing.py +++ b/pairing.py @@ -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('Step 1\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'{binding_incantation}') - 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'Done!') - #noise.uinput_passthrough() + # FIXME demo + self.noise.uinput_passthrough() if __name__ == '__main__': import argparse diff --git a/src/demo.c b/src/demo.c index 49157e9..c176f25 100644 --- a/src/demo.c +++ b/src/demo.c @@ -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; } -- cgit