def testDecidBad(self): # try decoding a non integer ciphertext c = Crypto('some secret key_') plaintext = 'foo' ciphertext = c.enc(plaintext) with throwing(CryptoException): plaintext2 = c.decid(ciphertext)
def update_password(self, session_id, new_password): session = self.session_dao.find_user_by_session(session_id) if session is None: raise Exception('La sesión es inválida.') crypto = Crypto() new_hashed_password = crypto.cypher(new_password) self.users_dao.update_user_password(session.username, new_hashed_password)
def login(self, username, password): user = self.users_dao.find_by_username(username) if user is None: raise Exception('El usuario y/o contraseña son incorrectos, por favor intenta de nuevo.') crypto = Crypto() if not crypto.verify_encrypted_password(password, user.password): raise Exception('El usuario y/o contraseña son incorrectos, por favor intenta de nuevo.') session_uuid = str(uuid.uuid4()) session = Session(username, session_uuid) self.session_dao.save_session(session) return session_uuid
def loadOrGenerateKepair(self): self.crypto = Crypto() if utils.doesSavedKeypairExist(): while(True): passphrase = self.getKeypairPassphrase() try: utils.loadKeypair(self.crypto, passphrase) break except exceptions.CryptoError: CursesDialog(self.screen, errors.BAD_PASSPHRASE, '', isBlocking=True).show() # We still need to generate an AES key self.crypto.generateAESKey() else: self.crypto.generateKeys()
def __init__(self, addr, sock=None, crypto=None): self.addr = addr self.isEncrypted = False self.encryptType = None # Create a new socket if one was not given if sock is None: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.isConnected = False else: self.sock = sock self.isConnected = True # Create a crypto object if one was not given if crypto is None: self.crypto = Crypto() self.crypto.generateKeys() else: self.crypto = crypto
def __loadOrGenerateKepair(self): self.crypto = Crypto() if utils.doesSavedKeypairExist(): while(True): passphrase = qtUtils.getKeypairPassphrase(self.isLightTheme) # Restart the application if the user did not provide a passphrase if passphrase is None: self.__restart() return try: utils.loadKeypair(self.crypto, passphrase) break except exceptions.CryptoError: QMessageBox.warning(self.chatWindow, errors.BAD_PASSPHRASE, errors.BAD_PASSPHRASE_VERBOSE) # We still need to generate an AES key self.crypto.generateAESKey() else: self.crypto.generateKeys()
def signup(self): return cryptoUtil.generateId(self.verify_key)
def testEncDec(self): c = Crypto('some secret key_') plaintext = 'foo' ciphertext = c.enc(plaintext) plaintext2 = c.dec(ciphertext) assert plaintext == plaintext2
def testEncidBad(self): # try encoding a non integer c = Crypto('some secret key_') plaintext = 'foo' with throwing(CryptoException): ciphertext = c.encid(plaintext)
def testEncidDecid(self): c = Crypto('some secret key_') plaintext = 1 ciphertext = c.encid(plaintext) plaintext2 = c.decid(ciphertext) assert plaintext == plaintext2
class QtUI(QApplication): def __init__(self, argv, mode, port, host): QApplication.__init__(self, argv) self.mode = mode self.port = port self.host = host self.isEventLoopRunning = False self.connectedToClient = False self.isLightTheme = qtUtils.isLightTheme(self.palette().color(QPalette.Window)) self.aboutToQuit.connect(self.stop) def start(self): self.timer = QTimer() self.timer.start(500) self.timer.timeout.connect(lambda: None) # Show mode dialog if a mode wasn't given if self.mode is None: self.mode = QModeDialog.getMode(self.isLightTheme) # If the user closed the mode dialog by not selected a mode, stop the app if self.mode is None: qtUtils.exitApp() # Show the chat window self.chatWindow = QChatWindow(None, None, self.isLightTheme) self.chatWindow.show() self.__loadOrGenerateKepair() if self.mode == constants.MODE_SERVER: self.__startServer() self.__waitForClient() elif self.mode == constants.MODE_CLIENT: # Get the host if not given if self.host is None: self.host, ok = QInputDialog.getText(self.chatWindow, "Hostname", "Host:") if not ok: self.__restart() return self.__connectToServer() if not self.isEventLoopRunning: self.isEventLoopRunning = True self.exec_() def stop(self): self.__endConnections() self.quit() def __restart(self): self.__endConnections() self.__restartHelper() self.start() def __endConnections(self): if hasattr(self, 'acceptThread'): self.acceptThread.quit() elif hasattr(self, 'connectThread'): self.connectThread.quit() if hasattr(self, 'sendThread'): self.sendThread.quit() if hasattr(self, 'recvThread'): self.recvThread.quit() # If a client is connected, try to end the connection gracefully if hasattr(self, 'client'): self.client.disconnect() if hasattr(self, 'server'): self.server.stop() def __restartHelper(self): self.mode = None self.host = None self.closeAllWindows() if hasattr(self, 'waitingDialog'): del self.waitingDialog if hasattr(self, 'chatWindow'): del self.chatWindow def __loadOrGenerateKepair(self): self.crypto = Crypto() if utils.doesSavedKeypairExist(): while(True): passphrase = qtUtils.getKeypairPassphrase(self.isLightTheme) # Restart the application if the user did not provide a passphrase if passphrase is None: self.__restart() return try: utils.loadKeypair(self.crypto, passphrase) break except exceptions.CryptoError: QMessageBox.warning(self.chatWindow, errors.BAD_PASSPHRASE, errors.BAD_PASSPHRASE_VERBOSE) # We still need to generate an AES key self.crypto.generateAESKey() else: self.crypto.generateKeys() def __startServer(self): try: self.server = Server() self.server.start(int(self.port)) except exceptions.NetworkError as ne: QMessageBox.critical(self.chatWindow, errors.FAILED_TO_START_SERVER, errors.FAILED_TO_START_SERVER + ": " + str(ne)) self.__restart() def __waitForClient(self): # Start the accept thread self.acceptThread = qtThreads.QtServerAcceptThread(self.server, self.crypto, self.__postAccept) self.acceptThread.start() # Show the waiting dialog self.waitingDialog = QWaitingDialog(self.chatWindow, "Waiting for connection...", self.isLightTheme, self.__userClosedWaitingDialog, showIP=True) self.waitingDialog.show() def __connectToServer(self): # Create the client object to use for the connection self.client = Client(constants.MODE_CLIENT, (self.host, self.port), crypto=self.crypto) # Start the connect thread self.connectThread = qtThreads.QtServerConnectThread(self.client, self.__postConnect, self.__connectFailure) self.connectThread.start() # Show the waiting dialog self.waitingDialog = QWaitingDialog(self.chatWindow, "Connecting to server...", self.isLightTheme, self.__userClosedWaitingDialog) self.waitingDialog.show() @pyqtSlot(Client) def __postAccept(self, client): self.connectedToClient = True self.client = client self.waitingDialog.close() # Show the accept dialog accept = QAcceptDialog.getAnswer(self.chatWindow, self.client.getHostname()) # If not accepted, disconnect and wait for a client again if not accept: self.client.disconnect() self.__waitForClient() return # Do the handshake with the client try: client.doHandshake() except exceptions.NetworkError as ne: self.client.disconnect() self.__waitForClient() self.__startChat() @pyqtSlot() def __postConnect(self): self.connectedToClient = True self.waitingDialog.close() self.__startChat() @pyqtSlot(str) def __connectFailure(self, errorMessage): QMessageBox.critical(self.chatWindow, errors.FAILED_TO_CONNECT, errorMessage) self.__restart() @pyqtSlot() def __userClosedWaitingDialog(self): self.waitingDialog.hide() # If the waiting dialog was closed before we connected to the client, # it means that the user closed the dialog and we should restart the app if not self.connectedToClient: self.__restart() def __startChat(self): # Start the sending and receiving thread self.recvThread = qtThreads.QtRecvThread(self.client, self.chatWindow.appendMessage, self.__threadError) self.recvThread.start() self.sendThread = qtThreads.QtSendThread(self.client, self.__threadError) self.sendThread.start() self.chatWindow.client = self.client self.chatWindow.messageQueue = self.sendThread.messageQueue self.chatWindow.showNowChattingMessage() @pyqtSlot(str, str) def __threadError(self, title, message): QMessageBox.critical(self.chatWindow, title, message) self.__restart()
def create_user(self, username, email, password): self.validate_user_data(username, email, password) crypto = Crypto() hashed_password = crypto.cypher(password) return self.users_dao.create_user(User(username, email, hashed_password))
class NcursesUI(object): def __init__(self, mode, port, host): self.mode = mode self.port = port self.host = host def start(self): curses.wrapper(self.run) def stop(self): # If a client is connected, try to end the connection gracefully if hasattr(self, 'client'): self.client.disconnect() if hasattr(self, 'server'): self.server.stop() def run(self, screen): self.screen = screen (self.height, self.width) = self.screen.getmaxyx() # Change the colors, clear the screen and set the overall border self.setColors() self.screen.clear() self.screen.border(0) # Create the status and chat input windows self.makeChatWindow() self.makeStatusWindow() self.makeChatInputWindow() self.screen.refresh() # Try to load a keypair if one was saved or generate a new keypair self.loadOrGenerateKepair() # Show the options menu self.showOptionsMenuWindow(showStartOption=True) # Get the server/client mode if not given if self.mode == None: self.showOptionsWindow() if self.mode == constants.MODE_SERVER: self.startServer() self.waitForClient() elif self.mode == constants.MODE_CLIENT: # Get the host if not given if self.host == None: self.getHost() self.connectToServer() self.handleNewConnection() def waitForClient(self): while True: # Show the waiting for connections dialog dialogWindow = CursesDialog(self.screen, "Waiting for connection...") dialogWindow.show() self.client = self.server.accept(self.crypto) dialogWindow.hide() # Show the accept dialog if self.showAcceptWindow() == ACCEPT: break else: self.client.disconnect() # Do the handshake with the client try: self.client.doHandshake() except exceptions.NetworkError as ne: CursesDialog(self.screen, str(ne), errors.TITLE_NETWORK_ERROR, isError=True).show() self.client.disconnect() except exceptions.CryptoError as ce: CursesDialog(self.screen, str(ce), errors.TITLE_CRYPTO_ERROR, isError=True).show() self.client.disconnect() def connectToServer(self): try: dialogWindow = CursesDialog(self.screen, "Connecting to server...", "", False) dialogWindow.show() self.client = Client(constants.MODE_CLIENT, (self.host, self.port), crypto=self.crypto) self.client.connect() except exceptions.GenericError as ge: CursesDialog(self.screen, str(ge), errors.FAILED_TO_CONNECT, isError=True).show() # Do the handshake with the server try: self.client.doHandshake() dialogWindow.hide() except exceptions.NetworkError as ne: self.client.disconnect() dialogWindow.hide() CursesDialog(self.screen, str(ne), errors.TITLE_NETWORK_ERROR, isError=True).show() except exceptions.CryptoError as ce: self.client.disconnect() dialogWindow.hide() CursesDialog(self.screen, str(ce), errors.TITLE_CRYPTO_ERROR, isError=True).show() def handleNewConnection(self): # Set the hostname of who we're connected to in the status window self.setStatusWindow() # Add a hint on how to display the options menu self.screen.addstr(0, 5, "Ctrl+U for options") self.screen.refresh() # Start the sending and receiving threads self.startThreads() # Keep the main thread alive so the daemon threads don't die while True: time.sleep(10) def startThreads(self): ncursesThreads.CursesSendThread(self).start() ncursesThreads.CursesRecvThread(self).start() def setColors(self): if curses.has_colors(): curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK) curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK) curses.init_pair(3, curses.COLOR_CYAN, curses.COLOR_BLACK) curses.init_pair(4, curses.COLOR_BLACK, curses.COLOR_GREEN) self.screen.bkgd(curses.color_pair(1)) def showOptionsWindow(self): optionsWindow = self.screen.subwin(6, 11, self.height/2 - 3, self.width/2 - 6) optionsWindow.border(0) # Enable arrow key detection for this window optionsWindow.keypad(True) # Disable the cursor curses.curs_set(0) optionsWindow.addstr(1, 1, "Run as:") pos = constants.MODE_SERVER while True: if pos == constants.MODE_SERVER: optionsWindow.addstr(3, 2, "Server", curses.color_pair(4)) optionsWindow.addstr(4, 2, "Client") else: optionsWindow.addstr(3, 2, "Server") optionsWindow.addstr(4, 2, "Client", curses.color_pair(4)) self.screen.refresh() key = optionsWindow.getch() # Enter key if key == ord('\n'): break elif pos == constants.MODE_SERVER: pos = constants.MODE_CLIENT elif pos == constants.MODE_CLIENT: pos = constants.MODE_SERVER # Re-enable the cursor curses.curs_set(2) # Get rid of the options window optionsWindow.clear() optionsWindow.refresh() self.mode = pos def showAcceptWindow(self): dialogWidth = 23 + len(self.client.getHostname()); acceptWindow = self.screen.subwin(6, dialogWidth, self.height/2 - 3, self.width/2 - int(dialogWidth/2)) acceptWindow.border(0) # Enable arrow key detection for this window acceptWindow.keypad(True) # Disable the cursor curses.curs_set(0) acceptWindow.addstr(1, 1, "Got connection from %s" % self.client.getHostname()) pos = ACCEPT while True: if pos == ACCEPT: acceptWindow.addstr(3, 2, "Accept", curses.color_pair(4)) acceptWindow.addstr(4, 2, "Reject") else: acceptWindow.addstr(3, 2, "Accept") acceptWindow.addstr(4, 2, "Reject", curses.color_pair(4)) self.screen.refresh() key = acceptWindow.getch() # Enter key if key == ord('\n'): break elif pos == ACCEPT: pos = REJECT elif pos == REJECT: pos = ACCEPT # Re-enable the cursor curses.curs_set(2) # Get rid of the accept window acceptWindow.clear() acceptWindow.refresh() return pos def makeChatWindow(self): self.chatWindow = self.screen.subwin(self.height-4, self.width-2, 1, 1) self.chatWindow.scrollok(True) def makeStatusWindow(self): self.statusWindow = self.screen.subwin(self.height-3, self.width-23) self.statusWindow.border(0) self.statusWindow.addstr(1, 1, "Disconnected") def makeChatInputWindow(self): self.textboxWindow = self.screen.subwin(1, self.width-25, self.height-2, 1) self.textbox = curses.textpad.Textbox(self.textboxWindow, insert_mode=True) curses.textpad.rectangle(self.screen, self.height-3, 0, self.height-1, self.width-24) self.textboxWindow.move(0, 0) def getHost(self): self.hostWindow = self.screen.subwin(3, 26, self.height/2 - 1, self.width/2 - 13) self.hostWindow.border(0) self.hostWindow.addstr(1, 1, "Host: ") self.hostWindow.refresh() # Turn on echo and wait for enter key to read buffer curses.echo() curses.nocbreak() self.host = self.hostWindow.getstr(1, 7) # Turn off echo and disable buffering curses.cbreak() curses.noecho() # Get rid of the host window self.hostWindow.clear() self.screen.refresh() def setStatusWindow(self): self.statusWindow.clear() self.statusWindow.border(0) self.statusWindow.addstr(1, 1, self.client.getHostname()) self.statusWindow.refresh() def startServer(self): try: self.server = Server() self.server.start(int(self.port)) except exceptions.NetworkError as ne: CursesDialog(screen, errors.FAILED_TO_START_SERVER, str(ne), isError=True).show() def showOptionsMenuWindow(self, showStartOption=False): menuWindow = self.screen.subwin((9 if showStartOption else 8), 40, 3, self.width/2 - 20) menuWindow.border(0) # Enable arrow key detection for this window menuWindow.keypad(True) pos = 1 while True: # Disable the cursor curses.curs_set(0) while True: menuItem = 1 if showStartOption: menuWindow.addstr(menuItem, 1, str(menuItem) + ".| Start chat", curses.color_pair(4) if pos == menuItem else curses.color_pair(1)) menuItem += 1 menuWindow.addstr(menuItem, 1, str(menuItem) + ".| Show public key fingerprints", curses.color_pair(4) if pos == menuItem else curses.color_pair(1)) menuItem += 1 menuWindow.addstr(menuItem, 1, str(menuItem) + ".| Save current keypair", curses.color_pair(4) if pos == menuItem else curses.color_pair(1)) menuItem += 1 menuWindow.addstr(menuItem, 1, str(menuItem) + ".| Clear saved keypair", curses.color_pair(4) if pos == menuItem else curses.color_pair(1)) menuItem += 1 menuWindow.addstr(menuItem, 1, str(menuItem) + ".| Show help", curses.color_pair(4) if pos == menuItem else curses.color_pair(1)) menuItem += 1 menuWindow.addstr(menuItem, 1, str(menuItem) + ".| Close menu", curses.color_pair(4) if pos == menuItem else curses.color_pair(1)) menuItem += 1 menuWindow.addstr(menuItem, 1, str(menuItem) + ".| Quit application", curses.color_pair(4) if pos == menuItem else curses.color_pair(1)) menuWindow.refresh() key = menuWindow.getch() if key == curses.KEY_DOWN and pos < (7 if showStartOption else 6): pos += 1 elif key == curses.KEY_UP and pos > 1: pos -= 1 # Wrap around from top of menu elif key == curses.KEY_UP and pos == 1: pos = (7 if showStartOption else 6) # Wrap around from bottom of menu elif key == curses.KEY_DOWN and pos == (7 if showStartOption else 6): pos = 1 # Enter key elif key == ord('\n'): break # Move the selected item by 1 to adjust for the lack of a start option if not showStartOption: pos += 1 # Process the selected option if pos == 1: break if pos == 2: try: CursesFingerprintDialog(self.screen, self.crypto.getLocalFingerprint(), self.crypto.getRemoteFingerprint()).show() except exceptions.CryptoError: CursesDialog(self.screen, "Public key(s) not generated/received yet.", isBlocking=True).show() elif pos == 3: passphrase = self.getKeypairPassphrase(True) utils.saveKeypair(self.crypto, passphrase) CursesDialog(self.screen, "This keypair will be used for all subsequent chats", "Keypair Saved", isBlocking=True).show() elif pos == 4: utils.clearKeypair() CursesDialog(self.screen, "Keypair cleared", isBlocking=True).show() elif pos == 5: CursesDialog(self.screen, "Read the docs at https://cryptully.readthedocs.org/en/latest/", isBlocking=True).show() elif pos == 6: break elif pos == 7: os.kill(os.getpid(), signal.SIGINT) # Shift the selected item position back if not showStartOption: pos -= 1 # Re-enable the cursor curses.curs_set(2) # Get rid of the accept window menuWindow.clear() menuWindow.refresh() def getKeypairPassphrase(self, verify=False): passphraseWindow = self.screen.subwin(3, 36, self.height/2 - 1, self.width/2 - 18) # Turn on echo and wait for enter key to read buffer curses.echo() curses.nocbreak() while True: passphraseWindow.border(0) passphraseWindow.addstr(1, 1, "Passphrase: ") passphraseWindow.refresh() passphrase = getpass('') if not verify: break passphraseWindow.clear() passphraseWindow.border(0) passphraseWindow.addstr(1, 1, "Verify: ") passphraseWindow.refresh() verifyPassphrase = getpass('') if passphrase == verifyPassphrase: break else: curses.cbreak() CursesDialog(self.screen, errors.VERIFY_PASSPHRASE_FAILED, '', isBlocking=True).show() curses.nocbreak() # Turn off echo and disable buffering curses.cbreak() curses.noecho() # Get rid of the passphrase window passphraseWindow.clear() passphraseWindow.refresh() return passphrase def loadOrGenerateKepair(self): self.crypto = Crypto() if utils.doesSavedKeypairExist(): while(True): passphrase = self.getKeypairPassphrase() try: utils.loadKeypair(self.crypto, passphrase) break except exceptions.CryptoError: CursesDialog(self.screen, errors.BAD_PASSPHRASE, '', isBlocking=True).show() # We still need to generate an AES key self.crypto.generateAESKey() else: self.crypto.generateKeys()
class EncSocket(object): RSA = 0 AES = 1 def __init__(self, addr, sock=None, crypto=None): self.addr = addr self.isEncrypted = False self.encryptType = None # Create a new socket if one was not given if sock is None: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.isConnected = False else: self.sock = sock self.isConnected = True # Create a crypto object if one was not given if crypto is None: self.crypto = Crypto() self.crypto.generateKeys() else: self.crypto = crypto def connect(self): try: self.sock.connect(self.addr) self.isConnected = True except socket.error as se: raise exceptions.GenericError(str(se)) def disconnect(self): try: self.sock.shutdown(socket.SHUT_RDWR) self.socket.close() except Exception: pass finally: self.isConnected = False def send(self, data): if type(data) is not str: raise TypeError() # Encrypt all outgoing data if self.encryptType is not None: if self.encryptType == self.RSA: data = self.crypto.rsaEncrypt(data) elif self.encryptType == self.AES: data = self.crypto.aesEncrypt(data) else: raise exceptions.ServerError(errors.UNKNOWN_ENCRYPTION_TYPE) dataLength = len(data) # Send the length of the message (int converted to network byte order and padded to 32 bytes) self._send(str('%32s' % socket.htonl(dataLength)), 32) # Send the actual data self._send(data, dataLength) def _send(self, data, length): sentLen = 0 while sentLen < length: try: amountSent = self.sock.send(data[sentLen:]) except socket.error, IOError: raise exceptions.NetworkError(errors.UNEXPECTED_CLOSE_CONNECTION) if amountSent == 0: raise exceptions.NetworkError(errors.UNEXPECTED_CLOSE_CONNECTION) sentLen += amountSent