Ejemplo n.º 1
0
	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)
Ejemplo n.º 2
0
 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)
Ejemplo n.º 3
0
 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
Ejemplo n.º 4
0
    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()
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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()
Ejemplo n.º 7
0
 def signup(self):
     return cryptoUtil.generateId(self.verify_key)
Ejemplo n.º 8
0
	def testEncDec(self):
		c = Crypto('some secret key_')
		plaintext = 'foo'
		ciphertext = c.enc(plaintext)
		plaintext2 = c.dec(ciphertext)
		assert plaintext == plaintext2
Ejemplo n.º 9
0
	def testEncidBad(self):
		# try encoding a non integer
		c = Crypto('some secret key_')
		plaintext = 'foo'
		with throwing(CryptoException):
			ciphertext = c.encid(plaintext)
Ejemplo n.º 10
0
	def testEncidDecid(self):
		c = Crypto('some secret key_')
		plaintext = 1
		ciphertext = c.encid(plaintext)
		plaintext2 = c.decid(ciphertext)
		assert plaintext == plaintext2
Ejemplo n.º 11
0
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()
Ejemplo n.º 12
0
 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))
Ejemplo n.º 13
0
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()
Ejemplo n.º 14
0
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