Skip to content

Commit

Permalink
chunked update_into (#5419)
Browse files Browse the repository at this point in the history
* chunked update_into

* all pointer arithmetic all the time

* review feedback
  • Loading branch information
reaperhulk committed Aug 24, 2020
1 parent bc4b956 commit f90ba18
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 13 deletions.
34 changes: 21 additions & 13 deletions src/cryptography/hazmat/backends/openssl/ciphers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
class _CipherContext(object):
_ENCRYPT = 1
_DECRYPT = 0
_MAX_CHUNK_SIZE = 2 ** 31

def __init__(self, backend, cipher, mode, operation):
self._backend = backend
Expand Down Expand Up @@ -124,25 +125,32 @@ def update(self, data):
return bytes(buf[:n])

def update_into(self, data, buf):
if len(buf) < (len(data) + self._block_size_bytes - 1):
total_data_len = len(data)
if len(buf) < (total_data_len + self._block_size_bytes - 1):
raise ValueError(
"buffer must be at least {} bytes for this "
"payload".format(len(data) + self._block_size_bytes - 1)
)

buf = self._backend._ffi.cast(
"unsigned char *", self._backend._ffi.from_buffer(buf)
)
data_processed = 0
total_out = 0
outlen = self._backend._ffi.new("int *")
res = self._backend._lib.EVP_CipherUpdate(
self._ctx,
buf,
outlen,
self._backend._ffi.from_buffer(data),
len(data),
)
self._backend.openssl_assert(res != 0)
return outlen[0]
baseoutbuf = self._backend._ffi.from_buffer(buf)
baseinbuf = self._backend._ffi.from_buffer(data)

while data_processed != total_data_len:
outbuf = baseoutbuf + total_out
inbuf = baseinbuf + data_processed
inlen = min(self._MAX_CHUNK_SIZE, total_data_len - data_processed)

res = self._backend._lib.EVP_CipherUpdate(
self._ctx, outbuf, outlen, inbuf, inlen
)
self._backend.openssl_assert(res != 0)
data_processed += inlen
total_out += outlen[0]

return total_out

def finalize(self):
if (
Expand Down
17 changes: 17 additions & 0 deletions tests/hazmat/primitives/test_ciphers.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,3 +316,20 @@ def test_update_into_buffer_too_small_gcm(self, backend):
buf = bytearray(5)
with pytest.raises(ValueError):
encryptor.update_into(b"testing", buf)

def test_update_into_auto_chunking(self, backend, monkeypatch):
key = b"\x00" * 16
c = ciphers.Cipher(AES(key), modes.ECB(), backend)
encryptor = c.encryptor()
# Lower max chunk size so we can test chunking
monkeypatch.setattr(encryptor._ctx, "_MAX_CHUNK_SIZE", 40)
buf = bytearray(527)
pt = b"abcdefghijklmnopqrstuvwxyz012345" * 16 # 512 bytes
processed = encryptor.update_into(pt, buf)
assert processed == 512
decryptor = c.decryptor()
# Change max chunk size to verify alternate boundaries don't matter
monkeypatch.setattr(decryptor._ctx, "_MAX_CHUNK_SIZE", 73)
decbuf = bytearray(527)
decprocessed = decryptor.update_into(buf[:processed], decbuf)
assert decbuf[:decprocessed] == pt

0 comments on commit f90ba18

Please sign in to comment.