summaryrefslogtreecommitdiff
path: root/pairing.py
blob: fccc554d69bffd1ee9919641341218857016fa4b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#!/usr/bin/env python3
import threading
import re

import serial
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Pango', '1.0')
from gi.repository import Gtk, Pango

import hexnoise

class PairingWindow(Gtk.Window):
    def __init__(self, serial, debug=False):
        Gtk.Window.__init__(self, title='SecureHID pairing')
        self.serial = serial
        self.debug = debug

        self.set_border_width(10)
        self.set_default_size(600, 200)

        self.vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)

        self.label = Gtk.Label()
        self.label.set_line_wrap(True)
        self.label.set_justify(Gtk.Justification.CENTER)
        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.add(self.vbox)

        self.handshaker = threading.Thread(target=self.run_handshake, 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):
        self.packetizer = hexnoise.Packetizer(self.serial, debug=self.debug)
        self.noise = hexnoise.NoiseEngine(self.packetizer, debug=self.debug)

        self.noise.perform_handshake()

        binding_incantation = self.noise.channel_binding_incantation()
        self.label.set_markup(f'<b>Step 2</b>\n\nPerform channel binding ritual.\n'
                              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)

            #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)

        self.label.set_markup(f'<b>Done!</b>')

        #noise.uinput_passthrough()

if __name__ == '__main__':
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('serial')
    parser.add_argument('baudrate')
    parser.add_argument('-d', '--debug', action='store_true')
    args = parser.parse_args()

    ser = serial.Serial(args.serial, args.baudrate)

    window = PairingWindow(ser, debug=args.debug)
    window.connect('destroy', Gtk.main_quit)
    window.show_all()
    Gtk.main()