def build_pake(self, code): with self._timing.add("pake1", waiting="crypto"): self._sp = SPAKE2_Symmetric(to_bytes(code), idSymmetric=to_bytes(self._appid)) msg1 = self._sp.start() body = dict_to_bytes({"pake_v1": bytes_to_hexstr(msg1)}) self._M.add_message("pake", body)
def test_reversed(self): # A receiver using input_code() will choose the nameplate first, then # the rest of the code. Once the nameplate is selected, we'll claim # it and open the mailbox, which will cause the senders PAKE to # arrive before the code has been set. Key() is supposed to stash the # PAKE message until the code is set (allowing the PAKE computation # to finish). This test exercises that PAKE-then-code sequence. k, b, m, r, events = self.build() code = u"1-foo" sp = SPAKE2_Symmetric(to_bytes(code), idSymmetric=to_bytes(u"appid")) msg2_bytes = sp.start() msg2 = dict_to_bytes({"pake_v1": bytes_to_hexstr(msg2_bytes)}) k.got_pake(msg2) self.assertEqual(len(events), 0) k.got_code(code) self.assertEqual(len(events), 4) self.assertEqual(events[0][:2], ("m.add_message", "pake")) msg1_json = events[0][2].decode("utf-8") msg1 = json.loads(msg1_json) msg1_bytes = hexstr_to_bytes(msg1["pake_v1"]) key2 = sp.finish(msg1_bytes) self.assertEqual(events[1], ("b.got_key", key2)) self.assertEqual(events[2][:2], ("m.add_message", "version")) self.assertEqual(events[3], ("r.got_key", key2))
def run_exchange(transport, code, app_id, side): # Send the SPAKE2 message spake = SPAKE2_Symmetric(util.to_bytes(code), idSymmetric=util.to_bytes(app_id)) outbound = spake.start() transport.send_json({ 'phase': u'pake', 'body': util.bytes_to_hexstr( util.dict_to_bytes({ 'pake_v1': util.bytes_to_hexstr(outbound), })), 'side': side, 'type': 'message', }) # Receive SPAKE2 message pake_msg = transport.receive_json() inbound = util.hexstr_to_bytes( util.bytes_to_dict(util.hexstr_to_bytes(pake_msg['body']))['pake_v1']) spake_key = spake.finish(inbound) transport.send_line(util.bytes_to_hexstr(spake_key))
def from_serialized(klass, data): d = json.loads(data) self = klass(d["appid"].encode("ascii"), d["relay"].encode("ascii")) self._set_code_and_channel_id(d["code"].encode("ascii")) self.side = d["side"].encode("ascii") self.sp = SPAKE2_Symmetric.from_serialized(json.dumps(d["spake2"])) self.msg1 = d["msg1"].decode("hex") return self
def _maybe_build_msg1(self): if not (self._code and self._flag_need_to_build_msg1): return with self._timing.add("pake1", waiting="crypto"): self._sp = SPAKE2_Symmetric(to_bytes(self._code), idSymmetric=to_bytes(self._appid)) self._msg1 = self._sp.start() self._flag_need_to_build_msg1 = False self._event_built_msg1()
def from_serialized(klass, data): d = json.loads(data) self = klass(d["appid"], d["relay_url"]) self._side = d["side"] self._channelid = d["channelid"] self._set_code(d["code"]) sp_data = json.dumps(d["spake2"]).encode("ascii") self._sp = SPAKE2_Symmetric.from_serialized(sp_data) self._msg1 = unhexlify(d["msg1"].encode("ascii")) return self
def get_protocol(code, side, side_id, other_side_id): code = code.encode('utf8') side_id = side_id.encode('utf8') if side == 'S': return SPAKE2_Symmetric(code, idSymmetric=side_id) other_side_id = other_side_id.encode('utf8') if side == 'A': return SPAKE2_A(code, idA=side_id, idB=other_side_id) elif side == 'B': return SPAKE2_B(code, idA=other_side_id, idB=side_id) else: raise AssertionError('Invalid side: %r' % (side, ))
def test_version_error(self): # we should only receive the "version" message after we receive the # PAKE message, by which point we should know the key. If the # confirmation message doesn't decrypt, we signal an error. timing = DebugTiming() w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing) w._drop_connection = mock.Mock() ws = MockWebSocket() w._event_connected(ws) w._event_ws_opened(None) w.set_code("123-foo-bar") response(w, type="claimed", mailbox="mb456") d1 = w.get() d2 = w.verify() self.assertNoResult(d1) self.assertNoResult(d2) out = ws.outbound() # ["bind", "claim", "open", "add"] self.assertEqual(len(out), 4) self.assertEqual(out[3]["type"], "add") sp2 = SPAKE2_Symmetric(b"", idSymmetric=wormhole.to_bytes(APPID)) msg2 = sp2.start() payload = {"pake_v1": bytes_to_hexstr(msg2)} body_hex = bytes_to_hexstr(dict_to_bytes(payload)) response(w, type="message", phase="pake", body=body_hex, side="s2") self.assertNoResult(d1) self.assertNoResult(d2) # verify() waits for confirmation # sending a random version message will cause a confirmation error confkey = w.derive_key("WRONG", SecretBox.KEY_SIZE) nonce = os.urandom(wormhole.CONFMSG_NONCE_LENGTH) badversion = wormhole.make_confmsg(confkey, nonce) badversion_hex = hexlify(badversion).decode("ascii") response(w, type="message", phase="version", body=badversion_hex, side="s2") self.failureResultOf(d1, WrongPasswordError) self.failureResultOf(d2, WrongPasswordError) # once the error is signalled, all API calls should fail self.assertRaises(WrongPasswordError, w.send, "foo") self.assertRaises(WrongPasswordError, w.derive_key, "foo", SecretBox.KEY_SIZE) self.failureResultOf(w.get(), WrongPasswordError) self.failureResultOf(w.verify(), WrongPasswordError)
def run_exchange(transport, code, app_id, side): # Send the SPAKE2 message spake = SPAKE2_Symmetric( util.to_bytes(code), idSymmetric=util.to_bytes(app_id)) outbound = spake.start() transport.send_json({ 'phase': 'pake', 'body': util.bytes_to_hexstr( util.dict_to_bytes({ 'pake_v1': util.bytes_to_hexstr(outbound), }) ), 'side': side, 'type': 'message', }) # Receive SPAKE2 message pake_msg = transport.receive_json() inbound = util.hexstr_to_bytes( util.bytes_to_dict( util.hexstr_to_bytes(pake_msg['body']) )['pake_v1'] ) spake_key = spake.finish(inbound) # Send the versions message version_phase = 'version' transport.send_json({ 'phase': version_phase, 'body': util.bytes_to_hexstr( encrypt_data( derive_phase_key(spake_key, side, version_phase), util.dict_to_bytes({'app_versions': {}}) ) ), 'side': side, 'type': 'message', }) # Receive the versions message versions = transport.receive_json() their_versions = util.bytes_to_dict( decrypt_data( derive_phase_key(spake_key, versions['side'], versions['phase']), util.hexstr_to_bytes( versions['body'] ), ), ) return their_versions
def test_good(self): k, b, m, r, events = self.build() code = u"1-foo" k.got_code(code) self.assertEqual(len(events), 1) self.assertEqual(events[0][:2], ("m.add_message", "pake")) msg1_json = events[0][2].decode("utf-8") events[:] = [] msg1 = json.loads(msg1_json) msg1_bytes = hexstr_to_bytes(msg1["pake_v1"]) sp = SPAKE2_Symmetric(to_bytes(code), idSymmetric=to_bytes(u"appid")) msg2_bytes = sp.start() key2 = sp.finish(msg1_bytes) msg2 = dict_to_bytes({"pake_v1": bytes_to_hexstr(msg2_bytes)}) k.got_pake(msg2) self.assertEqual(len(events), 3, events) self.assertEqual(events[0], ("b.got_key", key2)) self.assertEqual(events[1][:2], ("m.add_message", "version")) self.assertEqual(events[2], ("r.got_key", key2))
def _start(self): # allocate the rest now too, so it can be serialized self.sp = SPAKE2_Symmetric(to_bytes(self.code), idSymmetric=to_bytes(self._appid)) self.msg1 = self.sp.start()
def make_pake(self, code, side, msg1): sp2 = SPAKE2_Symmetric(wormhole.to_bytes(code), idSymmetric=wormhole.to_bytes(APPID)) msg2 = sp2.start() key = sp2.finish(msg1) return key, msg2
def _start(self): # allocate the rest now too, so it can be serialized self.sp = SPAKE2_Symmetric(self.code.encode("ascii"), idA=self.appid + ":SymmetricA", idB=self.appid + ":SymmetricB") self.msg1 = self.sp.start()