def key_xchange(self, user, user_pkey, key_len): # return public_key, passwd_of_user if hashlib.md5(user_pkey).digest() in self.pkeyuser: raise ValueError('public key already registered. user: %s' % user) if len(self.userpkeys[user]) > self._limit: raise ValueError('connection limit exceeded. user: %s' % user) ecc = ECC(key_len) shared_secret = ecc.get_dh_key(user_pkey) user_pkey_md5 = hashlib.md5(user_pkey).digest() self.userpkeys[user].append(user_pkey_md5) self.pkeyuser[user_pkey_md5] = user self.pkeykey[user_pkey_md5] = shared_secret return ecc.get_pub_key(), self.user_pass[user]
def key_xchange(self, user, user_pkey, key_len): # create_key if hashlib.md5(user_pkey).digest() in self.pkeyuser: return 0, 0 if len(self.userpkeys[user]) > self._limit: self.del_key(self.userpkeys[user][0]) ecc = ECC(key_len) shared_secret = ecc.get_dh_key(user_pkey) user_pkey_md5 = hashlib.md5(user_pkey).digest() self.userpkeys[user].append(user_pkey_md5) self.pkeyuser[user_pkey_md5] = user self.pkeykey[user_pkey_md5] = shared_secret self.pkeytime[user_pkey_md5] = time.time() return ecc.get_pub_key(), self.USER_PASS[user]
async def get_key(self): self.logger.debug('hxsocks2 getKey') usn, psw = (self.proxy.username, self.proxy.password) self.logger.info('%s connect to server', self.name) from .connection import open_connection self.remote_reader, self.remote_writer, _ = await open_connection( self.proxy.hostname, self.proxy.port, proxy=self.proxy.get_via(), timeout=self.timeout, tunnel=True) # prep key exchange request self.__pskcipher = Encryptor(self._psk, self.method) ecc = ECC(self.__pskcipher._key_len) pubk = ecc.get_pub_key() ts = int(time.time()) // 30 ts = struct.pack('>I', ts) padding_len = random.randint(64, 255) data = b''.join([chr(len(pubk)).encode('latin1'), pubk, hmac.new(psw.encode(), ts + pubk + usn.encode(), hashlib.sha256).digest(), b'\x00' * padding_len]) data = chr(20).encode() + struct.pack('>H', len(data)) + data ct = self.__pskcipher.encrypt(data) # send key exchange request self.remote_writer.write(ct) await self.remote_writer.drain() # read iv iv = await self._rfile_read(self.__pskcipher._iv_len, self.timeout) self.__pskcipher.decrypt(iv) # read server response if is_aead(self.method): ct_len = await self._rfile_read(18, self.timeout) ct_len = self.__pskcipher.decrypt(ct_len) ct_len, = struct.unpack('!H', ct_len) ct = await self._rfile_read(ct_len + 16) ct = self.__pskcipher.decrypt(ct) data = ct[2:] else: resp_len = await self._rfile_read(2, self.timeout) resp_len = self.__pskcipher.decrypt(resp_len) resp_len, = struct.unpack('>H', resp_len) data = await self._rfile_read(resp_len) data = self.__pskcipher.decrypt(data) data = io.BytesIO(data) resp_code = byte2int(data.read(1)) if resp_code == 0: self.logger.debug('hxsocks read key exchange respond') pklen = byte2int(data.read(1)) scertlen = byte2int(data.read(1)) siglen = byte2int(data.read(1)) server_key = data.read(pklen) auth = data.read(32) server_cert = data.read(scertlen) signature = data.read(siglen) # TODO: ask user if a certificate should be accepted or not. host, port = self.proxy._host_port server_id = '%s_%d' % (host, port) if server_id not in KNOWN_HOSTS: self.logger.info('hxs: server %s new cert %s saved.', server_id, hashlib.sha256(server_cert).hexdigest()[:8]) with open('./.hxs_known_hosts/' + server_id + '.cert', 'wb') as f: f.write(server_cert) KNOWN_HOSTS[server_id] = server_cert elif KNOWN_HOSTS[server_id] != server_cert: self.logger.error('hxs: server %s certificate mismatch! PLEASE CHECK!', server_id) raise ConnectionResetError(0, 'hxs: bad certificate') if auth == hmac.new(psw.encode(), pubk + server_key + usn.encode(), hashlib.sha256).digest(): try: ECC.verify_with_pub_key(server_cert, auth, signature, self.hash_algo) shared_secret = ecc.get_dh_key(server_key) self.logger.debug('hxs key exchange success') self.__cipher = AEncryptor(shared_secret, self.method, CTX) # start reading from connection asyncio.ensure_future(self.read_from_connection()) asyncio.ensure_future(self.stat()) self.connected = True return except InvalidSignature: self.logger.error('hxs getKey Error: server auth failed, bad signature') else: self.logger.error('hxs getKey Error: server auth failed, bad username or password') else: self.logger.error('hxs getKey Error. bad password or timestamp.') raise ConnectionResetError(0, 'hxs getKey Error')