-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Add a Cobblestone recipe implementing c2sp.org/chunked-encryption #15144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
93fde7c
Add a chunked encryption recipe implementing c2sp.org/chunked-encryption
claude 0dc129b
Address review feedback on chunked encryption
claude 6d93eed
Add PiB to the docs spelling wordlist
claude 5b56421
Restructure chunked encryption for full test coverage
claude 83967cd
Address review feedback: drop overhead paragraph, document buffer inv…
claude a796398
Expose the Cobblestone-128 and Cobblestone-256 instantiations
claude b6029a2
Replace the variant macro with explicit class definitions
claude 5998166
Address review feedback: trim docs, drop Decryptor.generate_key, prun…
claude 2424c5e
Remove hasattr assert from test_generate_key
claude f56e037
Rename the module to cryptography.cobblestone, trim docs
claude 8f0b031
Add Wycheproof tests for Cobblestone
claude File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,185 @@ | ||
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # This file is dual licensed under the terms of the Apache License, Version | ||
| # 2.0, and the BSD License. See the LICENSE file in the root of this repository | ||
| # for complete details. | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from cryptography.hazmat.bindings._rust import ( | ||
| cobblestone as _cobblestone, | ||
| ) | ||
|
|
||
| Cobblestone128Decryptor = _cobblestone.Cobblestone128Decryptor | ||
| Cobblestone128Encryptor = _cobblestone.Cobblestone128Encryptor | ||
| Cobblestone256Decryptor = _cobblestone.Cobblestone256Decryptor | ||
| Cobblestone256Encryptor = _cobblestone.Cobblestone256Encryptor | ||
|
|
||
| __all__ = [ | ||
| "Cobblestone128Decryptor", | ||
| "Cobblestone128Encryptor", | ||
| "Cobblestone256Decryptor", | ||
| "Cobblestone256Encryptor", | ||
| ] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # This file is dual licensed under the terms of the Apache License, Version | ||
| # 2.0, and the BSD License. See the LICENSE file in the root of this repository | ||
| # for complete details. | ||
|
|
||
| from cryptography.utils import Buffer | ||
|
|
||
| class Cobblestone128Encryptor: | ||
| def __init__(self, key: Buffer, context: Buffer) -> None: ... | ||
| @staticmethod | ||
| def generate_key() -> bytes: ... | ||
| def update(self, data: Buffer) -> bytes: ... | ||
| def update_into(self, data: Buffer, buf: Buffer) -> int: ... | ||
| def finalize(self) -> bytes: ... | ||
|
|
||
| class Cobblestone128Decryptor: | ||
| def __init__(self, key: Buffer, context: Buffer) -> None: ... | ||
| def update(self, data: Buffer) -> bytes: ... | ||
| def update_into(self, data: Buffer, buf: Buffer) -> int: ... | ||
| def finalize(self) -> bytes: ... | ||
|
|
||
| class Cobblestone256Encryptor: | ||
| def __init__(self, key: Buffer, context: Buffer) -> None: ... | ||
| @staticmethod | ||
| def generate_key() -> bytes: ... | ||
| def update(self, data: Buffer) -> bytes: ... | ||
| def update_into(self, data: Buffer, buf: Buffer) -> int: ... | ||
| def finalize(self) -> bytes: ... | ||
|
|
||
| class Cobblestone256Decryptor: | ||
| def __init__(self, key: Buffer, context: Buffer) -> None: ... | ||
| def update(self, data: Buffer) -> bytes: ... | ||
| def update_into(self, data: Buffer, buf: Buffer) -> int: ... | ||
| def finalize(self) -> bytes: ... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.