|
| 1 | +From 7dee5927eb528f7ddebd62fbab31232d505acc22 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Paul Kehrer < [email protected]> |
| 3 | +Date: Sun, 23 Aug 2020 23:41:33 -0500 |
| 4 | +Subject: [PATCH] chunked update_into (#5419) |
| 5 | + |
| 6 | +* chunked update_into |
| 7 | + |
| 8 | +* all pointer arithmetic all the time |
| 9 | + |
| 10 | +* review feedback |
| 11 | + |
| 12 | +Upstream-Status: Backport [https://github.com/pyca/cryptography/commit/f90ba1808ee9bd9a13c5673b776484644f29d7ba] |
| 13 | + |
| 14 | +Signed-off-by: Martin Jansa < [email protected]> |
| 15 | +--- |
| 16 | + .../hazmat/backends/openssl/ciphers.py | 31 +++++++++++++------ |
| 17 | + tests/hazmat/primitives/test_ciphers.py | 17 ++++++++++ |
| 18 | + 2 files changed, 38 insertions(+), 10 deletions(-) |
| 19 | + |
| 20 | +diff --git a/src/cryptography/hazmat/backends/openssl/ciphers.py b/src/cryptography/hazmat/backends/openssl/ciphers.py |
| 21 | +index 94b48f52..86bc94b3 100644 |
| 22 | +--- a/src/cryptography/hazmat/backends/openssl/ciphers.py |
| 23 | ++++ b/src/cryptography/hazmat/backends/openssl/ciphers.py |
| 24 | +@@ -17,6 +17,7 @@ from cryptography.hazmat.primitives.ciphers import modes |
| 25 | + class _CipherContext(object): |
| 26 | + _ENCRYPT = 1 |
| 27 | + _DECRYPT = 0 |
| 28 | ++ _MAX_CHUNK_SIZE = 2 ** 31 |
| 29 | + |
| 30 | + def __init__(self, backend, cipher, mode, operation): |
| 31 | + self._backend = backend |
| 32 | +@@ -125,22 +126,32 @@ class _CipherContext(object): |
| 33 | + return bytes(buf[:n]) |
| 34 | + |
| 35 | + def update_into(self, data, buf): |
| 36 | +- if len(buf) < (len(data) + self._block_size_bytes - 1): |
| 37 | ++ total_data_len = len(data) |
| 38 | ++ if len(buf) < (total_data_len + self._block_size_bytes - 1): |
| 39 | + raise ValueError( |
| 40 | + "buffer must be at least {} bytes for this " |
| 41 | + "payload".format(len(data) + self._block_size_bytes - 1) |
| 42 | + ) |
| 43 | + |
| 44 | +- buf = self._backend._ffi.cast( |
| 45 | +- "unsigned char *", self._backend._ffi.from_buffer(buf) |
| 46 | +- ) |
| 47 | ++ data_processed = 0 |
| 48 | ++ total_out = 0 |
| 49 | + outlen = self._backend._ffi.new("int *") |
| 50 | +- res = self._backend._lib.EVP_CipherUpdate( |
| 51 | +- self._ctx, buf, outlen, |
| 52 | +- self._backend._ffi.from_buffer(data), len(data) |
| 53 | +- ) |
| 54 | +- self._backend.openssl_assert(res != 0) |
| 55 | +- return outlen[0] |
| 56 | ++ baseoutbuf = self._backend._ffi.from_buffer(buf) |
| 57 | ++ baseinbuf = self._backend._ffi.from_buffer(data) |
| 58 | ++ |
| 59 | ++ while data_processed != total_data_len: |
| 60 | ++ outbuf = baseoutbuf + total_out |
| 61 | ++ inbuf = baseinbuf + data_processed |
| 62 | ++ inlen = min(self._MAX_CHUNK_SIZE, total_data_len - data_processed) |
| 63 | ++ |
| 64 | ++ res = self._backend._lib.EVP_CipherUpdate( |
| 65 | ++ self._ctx, outbuf, outlen, inbuf, inlen |
| 66 | ++ ) |
| 67 | ++ self._backend.openssl_assert(res != 0) |
| 68 | ++ data_processed += inlen |
| 69 | ++ total_out += outlen[0] |
| 70 | ++ |
| 71 | ++ return total_out |
| 72 | + |
| 73 | + def finalize(self): |
| 74 | + # OpenSSL 1.0.1 on Ubuntu 12.04 (and possibly other distributions) |
| 75 | +diff --git a/tests/hazmat/primitives/test_ciphers.py b/tests/hazmat/primitives/test_ciphers.py |
| 76 | +index f29ba9a9..b88610e7 100644 |
| 77 | +--- a/tests/hazmat/primitives/test_ciphers.py |
| 78 | ++++ b/tests/hazmat/primitives/test_ciphers.py |
| 79 | +@@ -309,3 +309,20 @@ class TestCipherUpdateInto(object): |
| 80 | + buf = bytearray(5) |
| 81 | + with pytest.raises(ValueError): |
| 82 | + encryptor.update_into(b"testing", buf) |
| 83 | ++ |
| 84 | ++ def test_update_into_auto_chunking(self, backend, monkeypatch): |
| 85 | ++ key = b"\x00" * 16 |
| 86 | ++ c = ciphers.Cipher(AES(key), modes.ECB(), backend) |
| 87 | ++ encryptor = c.encryptor() |
| 88 | ++ # Lower max chunk size so we can test chunking |
| 89 | ++ monkeypatch.setattr(encryptor._ctx, "_MAX_CHUNK_SIZE", 40) |
| 90 | ++ buf = bytearray(527) |
| 91 | ++ pt = b"abcdefghijklmnopqrstuvwxyz012345" * 16 # 512 bytes |
| 92 | ++ processed = encryptor.update_into(pt, buf) |
| 93 | ++ assert processed == 512 |
| 94 | ++ decryptor = c.decryptor() |
| 95 | ++ # Change max chunk size to verify alternate boundaries don't matter |
| 96 | ++ monkeypatch.setattr(decryptor._ctx, "_MAX_CHUNK_SIZE", 73) |
| 97 | ++ decbuf = bytearray(527) |
| 98 | ++ decprocessed = decryptor.update_into(buf[:processed], decbuf) |
| 99 | ++ assert decbuf[:decprocessed] == pt |
0 commit comments