Ejemplo n.º 1
0
    def encrypt(self, plaintext):
        # type: (AnyStr) -> _OlmMessage
        """Encrypts a message using the session. Returns the ciphertext as a
        base64 encoded string on success. Raises OlmSessionError on failure.

        Args:
            plaintext(str): The plaintext message that will be encrypted.
        """
        byte_plaintext = to_bytearray(plaintext)

        r_length = lib.olm_encrypt_random_length(self._session)
        random = URANDOM(r_length)

        try:
            message_type = lib.olm_encrypt_message_type(self._session)

            self._check_error(message_type)

            ciphertext_length = lib.olm_encrypt_message_length(
                self._session, len(byte_plaintext))
            ciphertext_buffer = ffi.new("char[]", ciphertext_length)

            self._check_error(
                lib.olm_encrypt(
                    self._session,
                    ffi.from_buffer(byte_plaintext),
                    len(byte_plaintext),
                    ffi.from_buffer(random),
                    r_length,
                    ciphertext_buffer,
                    ciphertext_length,
                ))
        finally:
            # clear out copies of plaintext
            if byte_plaintext is not plaintext:
                for i in range(0, len(byte_plaintext)):
                    byte_plaintext[i] = 0

        if message_type == lib.OLM_MESSAGE_TYPE_PRE_KEY:
            return OlmPreKeyMessage(
                bytes_to_native_str(
                    ffi.unpack(ciphertext_buffer, ciphertext_length)))
        elif message_type == lib.OLM_MESSAGE_TYPE_MESSAGE:
            return OlmMessage(
                bytes_to_native_str(
                    ffi.unpack(ciphertext_buffer, ciphertext_length)))
        else:  # pragma: no cover
            raise ValueError("Unknown message type")
Ejemplo n.º 2
0
    def encrypt(self, plaintext):
        # type: (AnyStr) -> _OlmMessage
        """Encrypts a message using the session. Returns the ciphertext as an
        base64 encoded strin on success. Raises OlmSessionError on failure. If
        there weren't enough random bytes to encrypt the message the error
        message for the exception will be NOT_ENOUGH_RANDOM.

        Args:
            plaintext(str): The plaintext message that will be encrypted.
        """
        byte_plaintext = to_bytes(plaintext)

        r_length = lib.olm_encrypt_random_length(self._session)
        random = URANDOM(r_length)
        random_buffer = ffi.new("char[]", random)

        message_type = lib.olm_encrypt_message_type(self._session)

        self._check_error(message_type)

        ciphertext_length = lib.olm_encrypt_message_length(
            self._session, len(plaintext)
        )
        ciphertext_buffer = ffi.new("char[]", ciphertext_length)

        plaintext_buffer = ffi.new("char[]", byte_plaintext)

        self._check_error(lib.olm_encrypt(
            self._session,
            plaintext_buffer, len(byte_plaintext),
            random_buffer, r_length,
            ciphertext_buffer, ciphertext_length,
        ))

        if message_type == lib.OLM_MESSAGE_TYPE_PRE_KEY:
            return OlmPreKeyMessage(
                bytes_to_native_str(ffi.unpack(
                    ciphertext_buffer,
                    ciphertext_length
                )))
        elif message_type == lib.OLM_MESSAGE_TYPE_MESSAGE:
            return OlmMessage(
                bytes_to_native_str(ffi.unpack(
                    ciphertext_buffer,
                    ciphertext_length
                )))
        else:  # pragma: no cover
            raise ValueError("Unknown message type")
Ejemplo n.º 3
0
    def __init__(self, seed):
        # type: (bytes) -> None
        """Create a new signing object.

        Args:
            seed(bytes): the seed to use as the private key for signing.  The
                seed must have the same length as the seeds generated by
                PkSigning.generate_seed().
        """
        if not seed:
            raise ValueError("seed can't be empty")

        self._buf = ffi.new("char[]", lib.olm_pk_signing_size())
        self._pk_signing = lib.olm_pk_signing(self._buf)
        track_for_finalization(self, self._pk_signing, _clear_pk_signing)

        seed_buffer = ffi.new("char[]", seed)

        pubkey_length = lib.olm_pk_signing_public_key_length()
        pubkey_buffer = ffi.new("char[]", pubkey_length)

        ret = lib.olm_pk_signing_key_from_seed(self._pk_signing, pubkey_buffer,
                                               pubkey_length, seed_buffer,
                                               len(seed))

        # zero out copies of the seed
        lib.memset(seed_buffer, 0, len(seed))

        self._check_error(ret)

        self.public_key = bytes_to_native_str(
            ffi.unpack(pubkey_buffer, pubkey_length))
Ejemplo n.º 4
0
    def pickle(self, passphrase=""):
        # type: (str) -> bytes
        """Store a PkDecryption object.

        Stores a PkDecryption object as a base64 string. Encrypts the object
        using the supplied passphrase. Returns a byte object containing the
        base64 encoded string of the pickled session.

        Args:
            passphrase(str, optional): The passphrase to be used to encrypt
                the object.
        """
        byte_key = to_bytearray(passphrase)

        pickle_length = lib.olm_pickle_pk_decryption_length(
            self._pk_decryption)
        pickle_buffer = ffi.new("char[]", pickle_length)

        ret = lib.olm_pickle_pk_decryption(self._pk_decryption,
                                           ffi.from_buffer(byte_key),
                                           len(byte_key), pickle_buffer,
                                           pickle_length)
        try:
            self._check_error(ret)
        finally:
            # zero out copies of the passphrase
            for i in range(0, len(byte_key)):
                byte_key[i] = 0

        return ffi.unpack(pickle_buffer, pickle_length)
Ejemplo n.º 5
0
    def decrypt(self, message):
        # type: (_OlmMessage) -> str
        """Decrypts a message using the session. Returns the plaintext string
        on success. Raises OlmSessionError on failure. If the base64 couldn't
        be decoded then the error message will be "INVALID_BASE64". If the
        message is for an unsupported version of the protocol the error message
        will be "BAD_MESSAGE_VERSION". If the message couldn't be decoded then
        the error message will be "BAD_MESSAGE_FORMAT". If the MAC on the
        message was invalid then the error message will be "BAD_MESSAGE_MAC".

        Args:
            message(OlmMessage): The Olm message that will be decrypted. It can
            be either an OlmPreKeyMessage or an OlmMessage.
        """
        if not message.ciphertext:
            raise ValueError("Ciphertext can't be empty")

        byte_ciphertext = to_bytes(message.ciphertext)
        ciphertext_buffer = ffi.new("char[]", byte_ciphertext)

        max_plaintext_length = lib.olm_decrypt_max_plaintext_length(
            self._session, message.message_type, ciphertext_buffer,
            len(byte_ciphertext))
        plaintext_buffer = ffi.new("char[]", max_plaintext_length)
        ciphertext_buffer = ffi.new("char[]", byte_ciphertext)
        plaintext_length = lib.olm_decrypt(self._session, message.message_type,
                                           ciphertext_buffer,
                                           len(byte_ciphertext),
                                           plaintext_buffer,
                                           max_plaintext_length)
        self._check_error(plaintext_length)
        return bytes_to_native_str(
            ffi.unpack(plaintext_buffer, plaintext_length))
Ejemplo n.º 6
0
    def pickle(self, passphrase=""):
        # type: (Optional[str]) -> bytes
        """Store an inbound group session.

        Stores a group session as a base64 string. Encrypts the session using
        the supplied passphrase. Returns a byte object containing the base64
        encoded string of the pickled session.

        Args:
            passphrase(str, optional): The passphrase to be used to encrypt
                the session.
        """
        byte_passphrase = bytes(passphrase, "utf-8") if passphrase else b""

        passphrase_buffer = ffi.new("char[]", byte_passphrase)
        pickle_length = lib.olm_pickle_inbound_group_session_length(
            self._session)
        pickle_buffer = ffi.new("char[]", pickle_length)

        ret = lib.olm_pickle_inbound_group_session(self._session,
                                                   passphrase_buffer,
                                                   len(byte_passphrase),
                                                   pickle_buffer,
                                                   pickle_length)

        self._check_error(ret)

        return ffi.unpack(pickle_buffer, pickle_length)
Ejemplo n.º 7
0
    def pickle(self, passphrase=""):
        # type: (Optional[str]) -> bytes
        """Store an Olm account.

        Stores an account as a base64 string. Encrypts the account using the
        supplied passphrase. Returns a byte object containing the base64
        encoded string of the pickled account. Raises OlmAccountError on
        failure.

        Args:
            passphrase(str, optional): The passphrase to be used to encrypt
                the account.
        """
        byte_key = bytearray(passphrase, "utf-8") if passphrase else b""

        pickle_length = lib.olm_pickle_account_length(self._account)
        pickle_buffer = ffi.new("char[]", pickle_length)

        try:
            self._check_error(
                lib.olm_pickle_account(self._account,
                                       ffi.from_buffer(byte_key),
                                       len(byte_key),
                                       pickle_buffer,
                                       pickle_length))
        finally:
            # zero out copies of the passphrase
            for i in range(0, len(byte_key)):
                byte_key[i] = 0

        return ffi.unpack(pickle_buffer, pickle_length)
Ejemplo n.º 8
0
    def from_pickle(cls, pickle, passphrase=""):
        # types: (bytes, str) -> PkDecryption
        if not pickle:
            raise ValueError("Pickle can't be empty")

        byte_key = to_bytes(passphrase)
        key_buffer = ffi.new("char[]", byte_key)
        pickle_buffer = ffi.new("char[]", pickle)

        pubkey_length = lib.olm_pk_key_length()
        pubkey_buffer = ffi.new("char[]", pubkey_length)

        obj = cls.__new__(cls)

        ret = lib.olm_unpickle_pk_decryption(
            obj._pk_decryption,
            key_buffer, len(byte_key),
            pickle_buffer, len(pickle),
            pubkey_buffer, pubkey_length)

        obj._check_error(ret)

        obj.public_key = bytes_to_native_str(ffi.unpack(
            pubkey_buffer,
            pubkey_length
        ))

        return obj
Ejemplo n.º 9
0
Archivo: sas.py Proyecto: bitcard/olm2
    def generate_bytes(self, extra_info, length):
        # type: (str, int) -> bytes
        """Generate bytes to use for the short authentication string.

        Args:
            extra_info (str): Extra information to mix in when generating the
                bytes.
            length (int): The number of bytes to generate.

        Raises OlmSasError if the other users persons public key isn't set or
        an internal Olm error happens.

        """
        if length < 1:
            raise ValueError("The length needs to be a positive integer value")

        byte_info = to_bytearray(extra_info)
        out_buffer = ffi.new("char[]", length)

        self._check_error(
            lib.olm_sas_generate_bytes(
                self._sas,
                ffi.from_buffer(byte_info),
                len(byte_info),
                out_buffer,
                length
            )
        )

        return ffi.unpack(out_buffer, length)
Ejemplo n.º 10
0
    def export_session(self, message_index):
        # type: (int) -> str
        """Export an inbound group session

        Export the base64-encoded ratchet key for this session, at the given
        index, in a format which can be used by import_session().

        Raises OlmGroupSessionError on failure. The error message for the
        exception will be:

        * OLM_UNKNOWN_MESSAGE_INDEX if we do not have a session key
            corresponding to the given index (ie, it was sent before the
            session key was shared with us)

        Args:
            message_index(int): The message index at which the session should
                be exported.
        """

        export_length = lib.olm_export_inbound_group_session_length(
            self._session)

        export_buffer = ffi.new("char[]", export_length)
        ret = lib.olm_export_inbound_group_session(self._session,
                                                   export_buffer,
                                                   export_length,
                                                   message_index)
        self._check_error(ret)
        return bytes_to_native_str(ffi.unpack(export_buffer, export_length))
Ejemplo n.º 11
0
    def encrypt(self, plaintext):
        # type: (AnyStr) -> str
        """Encrypt a message.

        Returns the encrypted ciphertext.

        Args:
            plaintext(str): A string that will be encrypted using the group
                session.
        """
        byte_plaintext = to_bytes(plaintext)
        message_length = lib.olm_group_encrypt_message_length(
            self._session, len(byte_plaintext))

        message_buffer = ffi.new("char[]", message_length)

        plaintext_buffer = ffi.new("char[]", byte_plaintext)

        ret = lib.olm_group_encrypt(
            self._session,
            plaintext_buffer,
            len(byte_plaintext),
            message_buffer,
            message_length,
        )
        self._check_error(ret)
        return bytes_to_native_str(ffi.unpack(message_buffer, message_length))
Ejemplo n.º 12
0
Archivo: sas.py Proyecto: bitcard/olm2
    def calculate_mac(self, message, extra_info):
        # type: (str, str) -> str
        """Generate a message authentication code based on the shared secret.

        Args:
            message (str): The message to produce the authentication code for.
            extra_info (str): Extra information to mix in when generating the
                MAC

        Raises OlmSasError on failure.

        """
        byte_message = to_bytes(message)
        byte_info = to_bytes(extra_info)

        mac_length = lib.olm_sas_mac_length(self._sas)
        mac_buffer = ffi.new("char[]", mac_length)

        self._check_error(
            lib.olm_sas_calculate_mac(
                self._sas,
                ffi.from_buffer(byte_message),
                len(byte_message),
                ffi.from_buffer(byte_info),
                len(byte_info),
                mac_buffer,
                mac_length
            )
        )
        return bytes_to_native_str(ffi.unpack(mac_buffer, mac_length))
Ejemplo n.º 13
0
Archivo: sas.py Proyecto: bitcard/olm2
    def calculate_mac_long_kdf(self, message, extra_info):
        # type: (str, str) -> str
        """Generate a message authentication code based on the shared secret.

        This function should not be used unless compatibility with an older
        non-tagged Olm version is required.

        Args:
            message (str): The message to produce the authentication code for.
            extra_info (str): Extra information to mix in when generating the
                MAC

        Raises OlmSasError on failure.

        """
        byte_message = to_bytes(message)
        byte_info = to_bytes(extra_info)

        mac_length = lib.olm_sas_mac_length(self._sas)
        mac_buffer = ffi.new("char[]", mac_length)

        self._check_error(
            lib.olm_sas_calculate_mac_long_kdf(
                self._sas,
                ffi.from_buffer(byte_message),
                len(byte_message),
                ffi.from_buffer(byte_info),
                len(byte_info),
                mac_buffer,
                mac_length
            )
        )
        return bytes_to_native_str(ffi.unpack(mac_buffer, mac_length))
Ejemplo n.º 14
0
    def sign(self, message):
        # type: (AnyStr) -> str
        """Signs a message with this account.

        Signs a message with the private ed25519 identity key of this account.
        Returns the signature.
        Raises OlmAccountError on failure.

        Args:
            message(str): The message to sign.
        """
        bytes_message = to_bytearray(message)
        out_length = lib.olm_account_signature_length(self._account)
        out_buffer = ffi.new("char[]", out_length)

        try:
            self._check_error(
                lib.olm_account_sign(self._account,
                                     ffi.from_buffer(bytes_message),
                                     len(bytes_message), out_buffer,
                                     out_length))
        finally:
            # clear out copies of the message, which may be plaintext
            if bytes_message is not message:
                for i in range(0, len(bytes_message)):
                    bytes_message[i] = 0

        return bytes_to_native_str(ffi.unpack(out_buffer, out_length))
Ejemplo n.º 15
0
    def pickle(self, passphrase=""):
        # type: (Optional[str]) -> bytes
        """Store an outbound group session.

        Stores a group session as a base64 string. Encrypts the session using
        the supplied passphrase. Returns a byte object containing the base64
        encoded string of the pickled session.

        Args:
            passphrase(str, optional): The passphrase to be used to encrypt
                the session.
        """
        byte_passphrase = bytearray(passphrase, "utf-8") if passphrase else b""
        pickle_length = lib.olm_pickle_outbound_group_session_length(
            self._session)
        pickle_buffer = ffi.new("char[]", pickle_length)

        try:
            ret = lib.olm_pickle_outbound_group_session(
                self._session, ffi.from_buffer(byte_passphrase),
                len(byte_passphrase), pickle_buffer, pickle_length)
            self._check_error(ret)
        finally:
            # clear out copies of the passphrase
            for i in range(0, len(byte_passphrase)):
                byte_passphrase[i] = 0

        return ffi.unpack(pickle_buffer, pickle_length)
Ejemplo n.º 16
0
    def decrypt(self, message):
        # type (PkMessage) -> str
        ephermal_key = to_bytes(message.ephermal_key)
        ephermal_key_size = len(ephermal_key)

        mac = to_bytes(message.mac)
        mac_length = len(mac)

        ciphertext = to_bytes(message.ciphertext)
        ciphertext_length = len(ciphertext)

        max_plaintext_length = lib.olm_pk_max_plaintext_length(
            self._pk_decryption,
            ciphertext_length
        )
        plaintext = ffi.new("char[]", max_plaintext_length)

        ret = lib.olm_pk_decrypt(
            self._pk_decryption,
            ephermal_key, ephermal_key_size,
            mac, mac_length,
            ciphertext, ciphertext_length,
            plaintext, max_plaintext_length)
        self._check_error(ret)

        unpacked_plaintext = (ffi.unpack(
            plaintext,
            ret
        ))

        return bytes_to_native_str(unpacked_plaintext)
Ejemplo n.º 17
0
    def encrypt(self, plaintext):
        # type: (AnyStr) -> str
        """Encrypt a message.

        Returns the encrypted ciphertext.

        Args:
            plaintext(str): A string that will be encrypted using the group
                session.
        """
        byte_plaintext = to_bytearray(plaintext)
        message_length = lib.olm_group_encrypt_message_length(
            self._session, len(byte_plaintext))

        message_buffer = ffi.new("char[]", message_length)

        try:
            ret = lib.olm_group_encrypt(
                self._session,
                ffi.from_buffer(byte_plaintext),
                len(byte_plaintext),
                message_buffer,
                message_length,
            )
            self._check_error(ret)
        finally:
            # clear out copies of plaintext
            if byte_plaintext is not plaintext:
                for i in range(0, len(byte_plaintext)):
                    byte_plaintext[i] = 0

        return bytes_to_native_str(ffi.unpack(message_buffer, message_length))
Ejemplo n.º 18
0
    def encrypt(self, plaintext):
        # type: (AnyStr) -> PkMessage
        """Encrypt a message.

        Returns the encrypted PkMessage.

        Args:
            plaintext(str): A string that will be encrypted using the
            PkEncryption object.
        """
        byte_plaintext = to_bytearray(plaintext)

        r_length = lib.olm_pk_encrypt_random_length(self._pk_encryption)
        random = URANDOM(r_length)
        random_buffer = ffi.new("char[]", random)

        ciphertext_length = lib.olm_pk_ciphertext_length(
            self._pk_encryption, len(byte_plaintext))
        ciphertext = ffi.new("char[]", ciphertext_length)

        mac_length = lib.olm_pk_mac_length(self._pk_encryption)
        mac = ffi.new("char[]", mac_length)

        ephemeral_key_size = lib.olm_pk_key_length()
        ephemeral_key = ffi.new("char[]", ephemeral_key_size)

        ret = lib.olm_pk_encrypt(self._pk_encryption,
                                 ffi.from_buffer(byte_plaintext),
                                 len(byte_plaintext), ciphertext,
                                 ciphertext_length, mac, mac_length,
                                 ephemeral_key, ephemeral_key_size,
                                 random_buffer, r_length)

        try:
            self._check_error(ret)
        finally:  # pragma: no cover
            # clear out copies of plaintext
            if byte_plaintext is not plaintext:
                for i in range(0, len(byte_plaintext)):
                    byte_plaintext[i] = 0

        message = PkMessage(
            bytes_to_native_str(ffi.unpack(ephemeral_key, ephemeral_key_size)),
            bytes_to_native_str(ffi.unpack(mac, mac_length)),
            bytes_to_native_str(ffi.unpack(ciphertext, ciphertext_length)))
        return message
Ejemplo n.º 19
0
 def id(self):
     # type: () -> str
     """str: A base64 encoded identifier for this session."""
     id_length = lib.olm_inbound_group_session_id_length(self._session)
     id_buffer = ffi.new("char[]", id_length)
     ret = lib.olm_inbound_group_session_id(self._session, id_buffer,
                                            id_length)
     self._check_error(ret)
     return bytes_to_native_str(ffi.unpack(id_buffer, id_length))
Ejemplo n.º 20
0
    def identity_keys(self):
        # type: () -> Dict[str, str]
        """dict: Public part of the identity keys of the account."""
        out_length = lib.olm_account_identity_keys_length(self._account)
        out_buffer = ffi.new("char[]", out_length)

        self._check_error(
            lib.olm_account_identity_keys(self._account, out_buffer,
                                          out_length))
        return json.loads(ffi.unpack(out_buffer, out_length).decode("utf-8"))
Ejemplo n.º 21
0
    def decrypt(self, ciphertext):
        # type: (AnyStr) -> Tuple[str, int]
        """Decrypt a message

        Returns a tuple of the decrypted plain-text and the message index of
        the decrypted message or raises OlmGroupSessionError on failure.
        On failure the error message of the exception  will be:

        * OLM_INVALID_BASE64         if the message is not valid base64
        * OLM_BAD_MESSAGE_VERSION    if the message was encrypted with an
            unsupported version of the protocol
        * OLM_BAD_MESSAGE_FORMAT     if the message headers could not be
            decoded
        * OLM_BAD_MESSAGE_MAC        if the message could not be verified
        * OLM_UNKNOWN_MESSAGE_INDEX  if we do not have a session key
            corresponding to the message's index (i.e., it was sent before
            the session key was shared with us)

        Args:
            ciphertext(str): Base64 encoded ciphertext containing the encrypted
                message
        """
        if not ciphertext:
            raise ValueError("Ciphertext can't be empty.")

        byte_ciphertext = to_bytes(ciphertext)

        # copy because max_plaintext_length will destroy the buffer
        ciphertext_buffer = ffi.new("char[]", byte_ciphertext)

        max_plaintext_length = lib.olm_group_decrypt_max_plaintext_length(
            self._session, ciphertext_buffer, len(byte_ciphertext))
        self._check_error(max_plaintext_length)
        plaintext_buffer = ffi.new("char[]", max_plaintext_length)
        # copy because max_plaintext_length will destroy the buffer
        ciphertext_buffer = ffi.new("char[]", byte_ciphertext)

        message_index = ffi.new("uint32_t*")
        plaintext_length = lib.olm_group_decrypt(self._session,
                                                 ciphertext_buffer,
                                                 len(byte_ciphertext),
                                                 plaintext_buffer,
                                                 max_plaintext_length,
                                                 message_index)

        self._check_error(plaintext_length)

        plaintext = bytes_to_native_str(
            ffi.unpack(plaintext_buffer, plaintext_length))

        # clear out copies of the plaintext
        lib.memset(plaintext_buffer, 0, max_plaintext_length)

        return plaintext, message_index[0]
Ejemplo n.º 22
0
    def one_time_keys(self):
        # type: () -> Dict[str, Dict[str, str]]
        """dict: The public part of the one-time keys for this account."""
        out_length = lib.olm_account_one_time_keys_length(self._account)
        out_buffer = ffi.new("char[]", out_length)

        self._check_error(
            lib.olm_account_one_time_keys(self._account, out_buffer,
                                          out_length))

        return json.loads(ffi.unpack(out_buffer, out_length).decode("utf-8"))
Ejemplo n.º 23
0
    def id(self):
        # type: () -> str
        """str: An identifier for this session. Will be the same for both
        ends of the conversation.
        """
        id_length = lib.olm_session_id_length(self._session)
        id_buffer = ffi.new("char[]", id_length)

        self._check_error(
            lib.olm_session_id(self._session, id_buffer, id_length))
        return bytes_to_native_str(ffi.unpack(id_buffer, id_length))
Ejemplo n.º 24
0
    def decrypt(self, message, unicode_errors="replace"):
        # type: (_OlmMessage, str) -> str
        """Decrypts a message using the session. Returns the plaintext string
        on success. Raises OlmSessionError on failure. If the base64 couldn't
        be decoded then the error message will be "INVALID_BASE64". If the
        message is for an unsupported version of the protocol the error message
        will be "BAD_MESSAGE_VERSION". If the message couldn't be decoded then
        the error message will be "BAD_MESSAGE_FORMAT". If the MAC on the
        message was invalid then the error message will be "BAD_MESSAGE_MAC".

        Args:
            message(OlmMessage): The Olm message that will be decrypted. It can
                be either an OlmPreKeyMessage or an OlmMessage.
            unicode_errors(str, optional): The error handling scheme to use for
                unicode decoding errors. The default is "replace" meaning that
                the character that was unable to decode will be replaced with
                the unicode replacement character (U+FFFD). Other possible
                values are "strict", "ignore" and "xmlcharrefreplace" as well
                as any other name registered with codecs.register_error that
                can handle UnicodeEncodeErrors.
        """
        if not message.ciphertext:
            raise ValueError("Ciphertext can't be empty")

        byte_ciphertext = to_bytes(message.ciphertext)
        # make a copy the ciphertext buffer, because
        # olm_decrypt_max_plaintext_length wants to destroy something
        ciphertext_buffer = ffi.new("char[]", byte_ciphertext)

        max_plaintext_length = lib.olm_decrypt_max_plaintext_length(
            self._session, message.message_type, ciphertext_buffer,
            len(byte_ciphertext))
        self._check_error(max_plaintext_length)
        plaintext_buffer = ffi.new("char[]", max_plaintext_length)

        # make a copy the ciphertext buffer, because
        # olm_decrypt_max_plaintext_length wants to destroy something
        ciphertext_buffer = ffi.new("char[]", byte_ciphertext)
        plaintext_length = lib.olm_decrypt(self._session, message.message_type,
                                           ciphertext_buffer,
                                           len(byte_ciphertext),
                                           plaintext_buffer,
                                           max_plaintext_length)
        self._check_error(plaintext_length)
        plaintext = to_unicode_str(ffi.unpack(plaintext_buffer,
                                              plaintext_length),
                                   errors=unicode_errors)

        # clear out copies of the plaintext
        lib.memset(plaintext_buffer, 0, max_plaintext_length)

        return plaintext
Ejemplo n.º 25
0
    def encrypt(self, plaintext):
        # type: (AnyStr) -> PkMessage
        byte_plaintext = to_bytes(plaintext)

        r_length = lib.olm_pk_encrypt_random_length(self._pk_encryption)
        random = URANDOM(r_length)
        random_buffer = ffi.new("char[]", random)

        ciphertext_length = lib.olm_pk_ciphertext_length(
            self._pk_encryption, len(byte_plaintext)
        )
        ciphertext = ffi.new("char[]", ciphertext_length)

        mac_length = lib.olm_pk_mac_length(self._pk_encryption)
        mac = ffi.new("char[]", mac_length)

        ephermal_key_size = lib.olm_pk_key_length()
        ephermal_key = ffi.new("char[]", ephermal_key_size)

        ret = lib.olm_pk_encrypt(
            self._pk_encryption,
            byte_plaintext, len(byte_plaintext),
            ciphertext, ciphertext_length,
            mac, mac_length,
            ephermal_key, ephermal_key_size,
            random_buffer, r_length
        )
        self._check_error(ret)

        message = PkMessage(
            bytes_to_native_str(
                ffi.unpack(ephermal_key, ephermal_key_size)),
            bytes_to_native_str(
                ffi.unpack(mac, mac_length)),
            bytes_to_native_str(
                ffi.unpack(ciphertext, ciphertext_length))
        )
        return message
Ejemplo n.º 26
0
    def _sha256(cls, input):
        # type: (Type[_Utility], AnyStr) -> str
        if not cls._utility:
            cls._allocate()

        byte_input = to_bytes(input)
        hash_length = lib.olm_sha256_length(cls._utility)
        hash = ffi.new("char[]", hash_length)

        ret = lib.olm_sha256(cls._utility, byte_input, len(byte_input), hash,
                             hash_length)

        cls._check_error(ret, OlmHashError)

        return bytes_to_native_str(ffi.unpack(hash, hash_length))
Ejemplo n.º 27
0
    def session_key(self):
        # type: () -> str
        """The base64-encoded current ratchet key for this session.

        Each message is encrypted with a different ratchet key. This function
        returns the ratchet key that will be used for the next message.
        """
        key_length = lib.olm_outbound_group_session_key_length(self._session)
        key_buffer = ffi.new("char[]", key_length)

        ret = lib.olm_outbound_group_session_key(self._session, key_buffer,
                                                 key_length)
        self._check_error(ret)

        return bytes_to_native_str(ffi.unpack(key_buffer, key_length))
Ejemplo n.º 28
0
    def __init__(self):
        if False:  # pragma: no cover
            self._pk_decryption = self._pk_decryption  # type: ffi.cdata

        random_length = lib.olm_pk_private_key_length()
        random = URANDOM(random_length)
        random_buffer = ffi.new("char[]", random)

        key_length = lib.olm_pk_key_length()
        key_buffer = ffi.new("char[]", key_length)

        ret = lib.olm_pk_key_from_private(self._pk_decryption, key_buffer,
                                          key_length, random_buffer,
                                          random_length)
        self._check_error(ret)
        self.public_key = bytes_to_native_str(
            ffi.unpack(key_buffer, key_length))
Ejemplo n.º 29
0
    def pubkey(self):
        # type: () -> str
        """Get the public key for the SAS object.

        This returns the public key of the SAS object that can then be shared
        with another user to perform the authentication process.

        Raises OlmSasError on failure.

        """
        pubkey_length = lib.olm_sas_pubkey_length(self._sas)
        pubkey_buffer = ffi.new("char[]", pubkey_length)

        self._check_error(
            lib.olm_sas_get_pubkey(self._sas, pubkey_buffer, pubkey_length))

        return bytes_to_native_str(ffi.unpack(pubkey_buffer, pubkey_length))
Ejemplo n.º 30
0
    def pickle(self, passphrase=""):
        # type: (str) -> bytes
        byte_key = to_bytes(passphrase)
        key_buffer = ffi.new("char[]", byte_key)

        pickle_length = lib.olm_pickle_pk_decryption_length(
            self._pk_decryption
        )
        pickle_buffer = ffi.new("char[]", pickle_length)

        ret = lib.olm_pickle_pk_decryption(
            self._pk_decryption,
            key_buffer, len(byte_key),
            pickle_buffer, pickle_length
        )
        self._check_error(ret)

        return ffi.unpack(pickle_buffer, pickle_length)