Ejemplo n.º 1
0
    def __init__(self,
                 peer_key: x25519.X25519PublicKey,
                 my_private_key: x25519.X25519PrivateKey = None,
                 min_peer_tag_len: int = MAX_TAG_LEN):
        """Initialize Glome class.

        Performs the handshake and generates keys.

        Args:
            peer_key: Your peer's public key.
            my_private_key: Your private key.
            min_peer_tag_len: Desired length (in bytes) for the tag.
              Must be an integer in range 1-32.
        Raises:
            ValueError: Raised whenever min_peer_tag_len is not in range 1-32.
            ExchangeError: Raised whenever null shared secret is derived from
              user/peer key pair.
        """

        if my_private_key is None:
            my_private_key, my_public_key = generate_keys()
        else:
            my_public_key = my_private_key.public_key()

        if not Glome.MIN_TAG_LEN < min_peer_tag_len <= Glome.MAX_TAG_LEN:
            raise ValueError('min_peer_tag_len must be in range {}-{}'.format(
                Glome.MIN_TAG_LEN, Glome.MAX_TAG_LEN))

        try:
            shared_secret = my_private_key.exchange(peer_key)
        except ValueError as value_error:
            raise ExchangeError(
                'Failed to deduce shared secret') from value_error

        self._send_key = shared_secret + _public_key_encode(
            peer_key) + _public_key_encode(my_public_key)
        self._receive_key = shared_secret + _public_key_encode(
            my_public_key) + _public_key_encode(peer_key)
        self._peer_key = peer_key
        self._my_keys = KeyPair(my_private_key, my_public_key)
        self._min_peer_tag_len = min_peer_tag_len
Ejemplo n.º 2
0
    def _decrypt(cls, fobj: io.BufferedIOBase,
                 input_size: typing.Optional[int],
                 privkey: x25519.X25519PrivateKey,
                 chunk_size: int) -> typing.Iterable[bytes]:
        if input_size is None:
            input_size = cls._get_size_till_eof(fobj)

        epubkey = x25519.X25519PublicKey.from_public_bytes(
            cls._read_exact(fobj, cls._PUBKEY_SIZE_BYTES))
        input_size -= cls._PUBKEY_SIZE_BYTES
        shared_secret = privkey.exchange(epubkey)
        iv = cls._read_exact(fobj, cls._IV_SIZE_BYTES)
        input_size -= cls._IV_SIZE_BYTES
        cipher_key = cls._derive_keys(shared_secret, iv)
        cipher_iv = iv[:cls._CIPHER_IV_SIZE_BYTES]
        decryptor = Cipher(algorithm=cls._CIPHER(cipher_key),
                           mode=GCM(cipher_iv),
                           backend=cls._CRYPTO_BACKEND).decryptor()

        if input_size < cls._AUTH_TAG_SIZE_BYTES:
            raise RuntimeError('input_size is too short')
        bufmv = memoryview(bytearray(chunk_size))
        auth_tag = b''
        while input_size > 0:
            bytes_read = fobj.readinto(bufmv)
            if bytes_read == 0:
                break
            input_size -= bytes_read
            if input_size <= cls._AUTH_TAG_SIZE_BYTES:
                auth_tag_part_len = cls._AUTH_TAG_SIZE_BYTES - input_size
                auth_tag += bufmv[bytes_read - auth_tag_part_len:bytes_read]
                auth_tag += fobj.read()
                yield decryptor.update(bufmv[:bytes_read - auth_tag_part_len])
            else:
                yield decryptor.update(bufmv[:bytes_read])
        yield decryptor.finalize_with_tag(auth_tag)