Pairing and passthrough mostly working, except it's too slow

This commit is contained in:
jaseg 2018-11-13 21:45:24 +09:00
parent 6af635bd41
commit e16515bb64
4 changed files with 78 additions and 56 deletions

View file

@ -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

View file

@ -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

View file

@ -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 }

View file

@ -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;
}