Skip to content
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

add support for update_into on CipherContext #3190

Merged
merged 23 commits into from
Feb 17, 2017
Merged

Conversation

reaperhulk
Copy link
Member

This allows you to provide your own buffer (like recv_into) to improve performance when repeatedly calling encrypt/decrypt on large payloads.

Even if you're calling update millions of times this is not necessarily a performance win at very small sizes (e.g. 16 bytes per call). In testing it is 21% faster when calling update repeatedly with 32KB payloads.

This is still WIP as at least one branch will not be covered (update_into on OpenSSL 1.0.0 AES CTR) and I'm not sure I'm happy with testing yet.

fixes #3119

@mention-bot
Copy link

@reaperhulk, thanks for your PR! By analyzing the history of the files in this pull request, we identified @public, @alex and @Ayrx to be potential reviewers.

@reaperhulk reaperhulk force-pushed the update-into branch 2 times, most recently from e414eef to 3b875b5 Compare October 12, 2016 17:18
@reaperhulk
Copy link
Member Author

(I am considering this blocked until we drop 1.0.0 because I don't want to modify our CI to cover that branch, so this PR will languish until we start the dev cycle for 1.8)

@reaperhulk
Copy link
Member Author

Jenkins, retest this please

@codecov-io
Copy link

Current coverage is 99.94% (diff: 94.32%)

Merging #3190 into master will decrease coverage by 0.05%

@@           master      #3190   diff @@
========================================
  Files         134        134          
  Lines       15245      15380   +135   
  Methods         0          0          
  Messages        0          0          
  Branches     1570       1585    +15   
========================================
+ Hits        15245      15372   +127   
- Misses          0          5     +5   
- Partials        0          3     +3   

Powered by Codecov. Last update c7ab931...4b4ed14

@alex
Copy link
Member

alex commented Nov 13, 2016

Failing tests relevant.

@reaperhulk reaperhulk changed the title [WIP] add support for update_into on CipherContext add support for update_into on CipherContext Nov 14, 2016
@reaperhulk
Copy link
Member Author

To get full coverage on this I had to add a new tox target py35-cffi-min. This installs a cffi < 1.7 and runs on Mac so it can trigger the NotImplementedError branches in both openssl (which is actually covered by our pypy 4.0.1 linux job) and commoncrypto.

@@ -10,6 +10,8 @@
import sys
import warnings

from pkg_resources import parse_version
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing this will trigger the import side effects we tried to avoid in #3347. Maybe we should do a simpler version check?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any other not-hacky version parser lying around we can use?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @dstufft who might know

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dstufft! @sigmavirus24 also suggested it in IRC so that looks like the path to go.

.travis.yml Outdated
@@ -67,6 +67,10 @@ matrix:
env: TOXENV=py27 CRYPTOGRAPHY_OSX_NO_LINK_FLAGS=0
- language: generic
os: osx
osx_image: xcode8
env: TOXENV=py35-cffi-min CRYPTOGRAPHY_OSX_NO_LINK_FLAGS=1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be an OS X job?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but now that I look at the code that's because we have conditional branches for update_into on both the commoncrypto and openssl backends. We could just assume we have a sufficiently new version in those classes but then do the version check at the CipherContext layer in hazmat.primitives.ciphers.base. That would simplify this whole thing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(And it would make it so this doesn't have to be a macOS job)

This method allows you to avoid a memory copy by passing a writable
buffer and reading the resulting data. You are responsible for
correctly sizing the buffer and properly handling the data. Failure
to do so correctly can result in crashes. This method should only
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why crashes? Can't we check the buffer sizes and error cleanly?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We actually do, this msg should be updated


:param bytes data: The data you wish to pass into the context.
:param buf: A writable Python buffer that the data will be written
into. This buffer should be ``n - 1`` bytes bigger than the size of
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be clearer if you wrote it as len(data) + n - 1

@@ -10,6 +10,8 @@
import sys
import warnings

from pkg_resources import parse_version
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any other not-hacky version parser lying around we can use?

tox.ini Outdated
@@ -48,6 +48,14 @@ commands =
pip list
py.test --capture=no --strict {posargs}

# This target downgrades cffi to the minimum supported in setup.py
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment to setup.py saying this needs to be updated if the minimimum cffi version is changed.

tox.ini Outdated
coverage
./vectors
cffi==1.4.1
basepython = python3.5
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point if we want this to be a py3 build maybe it should be 3.6?

@alex
Copy link
Member

alex commented Feb 14, 2017 via email

@reaperhulk
Copy link
Member Author

Jenkins, retest this please

>>> iv = os.urandom(16)
>>> cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
>>> encryptor = cipher.encryptor()
>>> buf = bytearray(31)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add comments throughout this example?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a swing at adding some comments. Hopefully they're useful.

Copy link
Member

@alex alex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very close!

@@ -488,12 +488,12 @@ Interfaces
>>> iv = os.urandom(16)
>>> cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
>>> encryptor = cipher.encryptor()
>>> buf = bytearray(31)
>>> buf = bytearray(31) # size the buffer to b len(data) + n - 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

b len(data)?

>>> len_encrypted = encryptor.update_into(b"a secret message", buf)
>>> ct = bytes(buf[:len_encrypted]) + encryptor.finalize()
>>> ct = bytes(buf[:len_encrypted]) + encryptor.finalize() # get the ciphertext from the buffer reading only the bytes written to it (len_encrypted)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe put the comment on the line above the code, so it doesn't wrap so long?

>>> iv = os.urandom(16)
>>> cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
>>> encryptor = cipher.encryptor()
>>> buf = bytearray(31) # size the buffer to b len(data) + n - 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't understand this comment :-)

@alex alex merged commit 9b34ca9 into pyca:master Feb 17, 2017
@reaperhulk reaperhulk deleted the update-into branch February 18, 2017 14:46
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 21, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Allow use of bytearray buffers in cipher context calls
5 participants