Cobblestone (streaming symmetric encryption)
=============================================

.. currentmodule:: cryptography.cobblestone

Cobblestone provides authenticated symmetric encryption of large
messages — up to 4 PiB — as a stream, without ever holding the whole
message in memory. It is an implementation of the `C2SP
chunked-encryption specification`_'s two named instantiations:
**Cobblestone-128** (SHA-512 and AES-128-GCM, the recommended choice)
and **Cobblestone-256** (SHA-512 and AES-256-GCM, for environments
that mandate 256-bit keys).

.. doctest::

    >>> from cryptography.cobblestone import (
    ...     Cobblestone128Decryptor, Cobblestone128Encryptor
    ... )
    >>> key = Cobblestone128Encryptor.generate_key()
    >>> encryptor = Cobblestone128Encryptor(
    ...     key, context=b"example-app file encryption"
    ... )
    >>> ciphertext = encryptor.update(b"a secret message")
    >>> ciphertext += encryptor.finalize()
    >>> decryptor = Cobblestone128Decryptor(
    ...     key, context=b"example-app file encryption"
    ... )
    >>> decryptor.update(ciphertext) + decryptor.finalize()
    b'a secret message'

.. class:: Cobblestone128Encryptor(key, context)

    .. versionadded:: 50.0.0

    Encrypts a single message under ``key`` with Cobblestone-128. Each
    instance must be used for exactly one message: call :meth:`update`
    (or :meth:`update_into`) any number of times, then call
    :meth:`finalize` exactly once. The concatenation of the returned
    bytes is the ciphertext.

    :param key: A 16-byte key. This **must** be kept secret, and
        **must** be uniformly random (e.g. the output of
        :meth:`generate_key` — never a password). A single key may be
        used to encrypt a practically unlimited number of messages.
    :type key: :term:`bytes-like`
    :param context: Application-provided context, bound to the
        ciphertext. Decryption fails unless the same value is passed to
        :class:`Cobblestone128Decryptor`. It is not secret, may be
        empty, and is not part of the ciphertext, so it must be
        available to the decrypting party independently. It can be used
        for domain separation, e.g. ``b"myapp v2 backup encryption"``.
    :type context: :term:`bytes-like`
    :raises ValueError: If ``key`` is not 16 bytes.

    .. staticmethod:: generate_key()

        Generates a fresh 16-byte key.

        :return bytes: A new key.

    .. method:: update(data)

        Encrypts ``data``. Data is internally buffered into 16 KiB
        chunks, so between 0 and ``len(data) + 16 KiB`` bytes of
        ciphertext are returned.

        :param data: The data to encrypt.
        :type data: :term:`bytes-like`
        :return bytes: The next portion of the ciphertext.

    .. method:: update_into(data, buf)

        Encrypts ``data``, writing the resulting ciphertext into
        ``buf``, and returns the number of bytes written. This avoids
        allocating a new buffer for each call.

        :param data: The data to encrypt.
        :type data: :term:`bytes-like`
        :param buf: A writable buffer to write the ciphertext into. A
            buffer of ``len(data) + len(data) // 1024 + 16456`` bytes
            is always large enough.
        :type buf: :term:`bytes-like`
        :return int: The number of bytes written to ``buf``.
        :raises ValueError: If ``buf`` is too small.

    .. method:: finalize()

        Encrypts the final chunk and returns the last portion of the
        ciphertext. This must always be called, and the instance cannot
        be used afterwards.

        :return bytes: The remainder of the ciphertext.
        :raises cryptography.exceptions.AlreadyFinalized: If
            ``finalize`` has already been called.

.. class:: Cobblestone128Decryptor(key, context)

    .. versionadded:: 50.0.0

    Decrypts a single message encrypted by
    :class:`Cobblestone128Encryptor` with the same ``key`` and
    ``context``. Call :meth:`update` (or :meth:`update_into`) with the
    ciphertext any number of times, then call :meth:`finalize` exactly
    once. The concatenation of the returned bytes is the plaintext.

    Any returned plaintext is authenticated, but until
    :meth:`finalize` returns successfully the message could still turn
    out to be truncated: an application acting on streamed plaintext
    before that point must be prepared to discard its work if a later
    call raises :class:`~cryptography.exceptions.InvalidTag`.

    Once any method raises
    :class:`~cryptography.exceptions.InvalidTag`, the instance is
    permanently unusable and all further calls raise
    :class:`~cryptography.exceptions.AlreadyFinalized`.

    :param key: The 16-byte key the message was encrypted with.
    :type key: :term:`bytes-like`
    :param context: The context value the message was encrypted with.
    :type context: :term:`bytes-like`
    :raises ValueError: If ``key`` is not 16 bytes.

    .. method:: update(data)

        Processes ``data``, which need not be aligned to any boundary,
        and returns the plaintext of all complete chunks that have been
        authenticated so far.

        :param data: The next portion of the ciphertext.
        :type data: :term:`bytes-like`
        :return bytes: The next portion of the plaintext.
        :raises cryptography.exceptions.InvalidTag: If the ciphertext
            was encrypted with a different key or context, or has been
            modified.

    .. method:: update_into(data, buf)

        Like ``update``, but writes the plaintext into ``buf`` and
        returns the number of bytes written.

        :param data: The next portion of the ciphertext.
        :type data: :term:`bytes-like`
        :param buf: A writable buffer to write the plaintext into. A
            buffer of ``len(data) + 16400`` bytes is always large
            enough.
        :type buf: :term:`bytes-like`
        :return int: The number of bytes written to ``buf``.
        :raises ValueError: If ``buf`` is too small.
        :raises cryptography.exceptions.InvalidTag: If the ciphertext
            was encrypted with a different key or context, or has been
            modified. Note that in this case unauthenticated data may
            have been written to ``buf`` and must not be used.

    .. method:: finalize()

        Decrypts and authenticates the final chunk, verifying that the
        entire message has been processed, and returns the final
        portion of the plaintext. This must always be called: a
        successful return is what guarantees the complete message was
        authentic and not truncated.

        :return bytes: The remainder of the plaintext.
        :raises cryptography.exceptions.InvalidTag: If the ciphertext
            was truncated or otherwise modified.
        :raises cryptography.exceptions.AlreadyFinalized: If
            ``finalize`` has already been called.

.. class:: Cobblestone256Encryptor(key, context)

    .. versionadded:: 50.0.0

    Exactly like :class:`Cobblestone128Encryptor`, but implements
    Cobblestone-256: the ``key`` is 32 bytes and messages are encrypted
    with AES-256-GCM. Use this when a 256-bit key is mandated;
    otherwise Cobblestone-128 is recommended.

.. class:: Cobblestone256Decryptor(key, context)

    .. versionadded:: 50.0.0

    Exactly like :class:`Cobblestone128Decryptor`, but decrypts
    messages produced by :class:`Cobblestone256Encryptor` with a
    32-byte key.

.. _`C2SP chunked-encryption specification`: https://c2sp.org/chunked-encryption
