def resetPrivate(self): self.__key = None self.__ecckey = ECC(256) pubk_hash = ECC.b64u_to_hash(self.get_pubkey_b64u()) _tr = QtCore.QCoreApplication.translate self.ui.pubkeyButton.setText( _tr('Crypto', 'Copy Public Key') + ' - ' + pubk_hash) if self.other_key: self.exchange(self.other_key)
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]
def __init__(self, server_cert, limit=10): '''server_cert: path to server_cert''' self.SERVER_CERT = ECC(from_file=server_cert) self._limit = limit self.user_pass = {} self.userpkeys = defaultdict(deque) # user name: client key self.pkeyuser = {} # user pubkey: user name self.pkeykey = {} # user pubkey: shared secret
def exchange_edit(self): if self.ui.otherKeyEdit.isReadOnly(): return otherkey = self.ui.otherKeyEdit.text() if otherkey: try: self.exchange(otherkey) except Exception as err: self.statusBar().showMessage(repr(err), 5000) else: self.other_key = otherkey pubk_hash = ECC.b64u_to_hash(otherkey) self.ui.otherKeyEdit.setText(pubk_hash) self.ui.otherKeyEdit.setReadOnly(True)
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')
class MainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_Crypto() self.ui.setupUi(self) self.__ecckey = None self.__key = None self.other_key = None self._last_active = time.time() self.ui.textEdit.setWordWrapMode(3) self.ui.psktextEdit.setWordWrapMode(3) self.ui.pubkeyButton.clicked.connect(self.copy_pubkey) self.ui.otherKeyEdit.editingFinished.connect(self.exchange_edit) self.ui.encryptButton.clicked.connect(self.encrypt) self.ui.decryptButton.clicked.connect(self.decrypt) self.ui.resetPrivateButton.clicked.connect(self.resetPrivate) self.ui.resetExchangeButton.clicked.connect(self.resetExchange) self.ui.decryptButton.clicked.connect(self.decrypt) self.ui.PSKencryptButton.clicked.connect(self.pskencrypt) self.ui.PSKdecryptButton.clicked.connect(self.pskdecrypt) self.ui.b64EncodeButton.clicked.connect(self.b64encode) self.ui.b64DecodeButton.clicked.connect(self.b64decode) self.resetPrivate() self.show() def resetPrivate(self): self.__key = None self.__ecckey = ECC(256) pubk_hash = ECC.b64u_to_hash(self.get_pubkey_b64u()) _tr = QtCore.QCoreApplication.translate self.ui.pubkeyButton.setText( _tr('Crypto', 'Copy Public Key') + ' - ' + pubk_hash) if self.other_key: self.exchange(self.other_key) def get_pubkey_b64u(self): return self.__ecckey.get_pub_key_b64u() def copy_pubkey(self): public_key = self.get_pubkey_b64u() app = QtWidgets.QApplication.instance() cb = app.clipboard() cb.setText(public_key) def resetExchange(self): self.__key = None self.other_key = None self.ui.otherKeyEdit.setText("") self.ui.otherKeyEdit.setReadOnly(False) def exchange(self, otherkey): self.__key = self.__ecckey.get_dh_key_b64u(otherkey) def exchange_edit(self): if self.ui.otherKeyEdit.isReadOnly(): return otherkey = self.ui.otherKeyEdit.text() if otherkey: try: self.exchange(otherkey) except Exception as err: self.statusBar().showMessage(repr(err), 5000) else: self.other_key = otherkey pubk_hash = ECC.b64u_to_hash(otherkey) self.ui.otherKeyEdit.setText(pubk_hash) self.ui.otherKeyEdit.setReadOnly(True) def encrypt(self): if time.time() - self._last_active < 0.3: return if not self.__key: self.statusBar().showMessage("key exchange not finished", 5000) return plain_text = self.ui.textEdit.toPlainText() if not plain_text: return try: cipher_text = encrypt(self.__key, plain_text) except Exception as err: self.statusBar().showMessage(repr(err), 5000) return self.ui.textEdit.setPlainText(cipher_text) self._last_active = time.time() def decrypt(self): if time.time() - self._last_active < 0.3: return if not self.__key: self.statusBar().showMessage("key exchange not finished", 5000) return cipher_text = self.ui.textEdit.toPlainText() if not cipher_text: return try: plain_text = decrypt(self.__key, cipher_text) if not plain_text: return self.ui.textEdit.setPlainText(plain_text) except Exception as err: self.statusBar().showMessage(repr(err), 5000) return self._last_active = time.time() def pskencrypt(self): if time.time() - self._last_active < 0.3: return plain_text = self.ui.psktextEdit.toPlainText() if not plain_text: return key = self.ui.pskEdit.text() key = key_to_bytes(key) try: cipher_text = encrypt(key, plain_text) if not cipher_text: return except Exception as err: self.statusBar().showMessage(repr(err), 5000) return self.ui.psktextEdit.setPlainText(cipher_text) self._last_active = time.time() def pskdecrypt(self): if time.time() - self._last_active < 0.3: return cipher_text = self.ui.psktextEdit.toPlainText() if not cipher_text: return key = self.ui.pskEdit.text() key = key_to_bytes(key) try: plain_text = decrypt(key, cipher_text) if not plain_text: return self.ui.psktextEdit.setPlainText(plain_text) except Exception as err: self.statusBar().showMessage(repr(err), 5000) return self._last_active = time.time() def b64decode(self): text = self.ui.b64TextEdit.toPlainText() text_bytes = text.encode('utf-8') try: result = base64.urlsafe_b64decode(text_bytes).decode() self.ui.b64TextEdit.setPlainText(result) except Exception as err: self.statusBar().showMessage(repr(err), 5000) return def b64encode(self): text = self.ui.b64TextEdit.toPlainText() text_bytes = text.encode('utf-8') try: result = base64.urlsafe_b64encode(text_bytes).decode() self.ui.b64TextEdit.setPlainText(result) except Exception as err: self.statusBar().showMessage(repr(err), 5000) return