Exemple #1
0
 def _read_exact(fobj: io.BufferedIOBase, size: int) -> bytes:
     buf = bytearray(size)
     bufmv = memoryview(buf)
     while size > 0:
         bytes_read = fobj.readinto(bufmv[-size:])
         if bytes_read == 0:
             raise RuntimeError('EOF occurred')
         size -= bytes_read
     return bytes(buf)
Exemple #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)