def forward_response(self, response): self.last_interaction = time() # cut the padding off response, _ = cut(response, -CTR_MODE_PADDING) msg_type, response = cut(response, MSG_TYPE_FLAG_LEN) msg_ctr, _ = cut(response, CTR_PREFIX_LEN) # todo find better way if msg_ctr != bytes(CTR_PREFIX_LEN): self.response_replay_detector.check_replay_window(b2i(msg_ctr)) self.response_counter.next() cipher = ctr_cipher(self.key, int(self.response_counter)) forward_msg = cipher.encrypt(response) print(self, "Data", "<-", len(forward_msg)) response = msg_type + i2b(self.in_chan_id, CHAN_ID_SIZE) + bytes(self.response_counter) + forward_msg ChannelMid.responses.append(response)
def gen_init_msg(pub_mix_keys, channel_keys, payload): assert len(pub_mix_keys) == len(channel_keys) y_mix_1, y_mix_2, y_mix_3 = pub_mix_keys x_msg_1 = params.group.gensecret() y_msg_1 = params.group.expon_base([x_msg_1]) k_disp_1 = params.group.expon(y_mix_1, [x_msg_1]) blind_1 = gen_blind(k_disp_1) x_msg_2 = params.group.expon(x_msg_1, [blind_1]) k_disp_2 = params.group.expon(y_mix_2, [x_msg_2]) blind_2 = gen_blind(k_disp_2) x_msg_3 = params.group.expon(x_msg_2, [blind_2]) k_disp_3 = params.group.expon(y_mix_3, [x_msg_3]) chan_key_onion = gen_sym_key() * 3 payload_onion = payload for k_disp, k_chan in zip([k_disp_3, k_disp_2, k_disp_1], reversed(channel_keys)): cipher = ctr_cipher(params.get_aes_key(k_disp), 0) chan_key_onion = cipher.encrypt(k_chan + chan_key_onion[0:-SYM_KEY_LEN]) payload_onion = cipher.encrypt(payload_onion) return y_msg_1.export() + chan_key_onion + payload_onion
def _encrypt_fragment(self, fragment): self.request_counter.next() for key in reversed(self.sym_keys): counter = self.request_counter cipher = ctr_cipher(key, int(counter)) fragment = bytes(counter) + cipher.encrypt(fragment) return fragment
def _decrypt_fragment(self, fragment): ctr = 0 for key in self.sym_keys: ctr, cipher_text = cut(fragment, CTR_PREFIX_LEN) ctr = b2i(ctr) cipher = ctr_cipher(key, ctr) fragment = cipher.decrypt(cipher_text) self.replay_detector.check_replay_window(ctr) return fragment
def test_encrypt_fragment(): channel = ChannelEntry(src_addr, dest_addr, public_keys) sym_key = gen_sym_key() channel.sym_keys = [sym_key] * MIX_COUNT fragment = FragmentGenerator(bytes(100)).get_data_fragment() packet1 = channel._encrypt_fragment(fragment) packet2 = fragment counter = 1 for _ in range(MIX_COUNT): cipher = ctr_cipher(sym_key, counter) packet2 = i2b(counter, CTR_PREFIX_LEN) + cipher.encrypt(packet2) assert packet1 == packet2
def process(priv_mix_key, message): y_msg, chan_key_onion, payload_onion = cut_init_message(message) k_disp = params.group.expon(y_msg, [priv_mix_key]) cipher = ctr_cipher(params.get_aes_key(k_disp), 0) k_chan, chan_key_onion = cut(cipher.decrypt(chan_key_onion), SYM_KEY_LEN) chan_key_onion += gen_sym_key() payload_onion = cipher.decrypt(payload_onion) blind_1 = gen_blind(k_disp) y_msg_2 = params.group.expon(y_msg, [blind_1]) message = y_msg_2.export() + chan_key_onion + payload_onion return k_chan, payload_onion, message
def test_decrypt_fragment(): channel = ChannelEntry(src_addr, dest_addr, public_keys) sym_key = gen_sym_key() channel.sym_keys = [sym_key] * MIX_COUNT fragment = FragmentGenerator(bytes(100)).get_data_fragment() fragment = channel._encrypt_fragment(fragment) packet1 = channel._decrypt_fragment(fragment) for _ in range(MIX_COUNT): msg_ctr, fragment = cut(fragment, CTR_PREFIX_LEN) cipher = ctr_cipher(sym_key, b2i(msg_ctr)) fragment = cipher.decrypt(fragment) packet2 = fragment assert packet1 == packet2
def forward_request(self, request): """Takes a mix fragment, already stripped of the channel id.""" self.last_interaction = time() ctr, cipher_text = cut(request, CTR_PREFIX_LEN) ctr = b2i(ctr) self.request_replay_detector.check_replay_window(ctr) cipher = ctr_cipher(self.key, ctr) forward_msg = cipher.decrypt(cipher_text) + get_random_bytes(CTR_MODE_PADDING) print(self, "Data", "->", len(forward_msg) - CTR_PREFIX_LEN) ChannelMid.requests.append(DATA_MSG_FLAG + i2b(self.out_chan_id, CHAN_ID_SIZE) + forward_msg) timed_out = check_for_timed_out_channels(ChannelMid.table_in) for in_id in timed_out: out_id = ChannelMid.table_in[in_id].out_chan_id del ChannelMid.table_in[in_id] del ChannelMid.table_out[out_id]