Opened at 2022-08-15T14:14:11Z
Closed at 2023-01-06T21:41:34Z
#3914 closed defect (fixed)
Loading a huge RSA key is _extremely_ slow on Ubuntu 22.04
Reported by: | itamarst | Owned by: | GitHub <noreply@…> |
---|---|---|---|
Priority: | normal | Milestone: | undecided |
Component: | unknown | Version: | n/a |
Keywords: | Cc: | ||
Launchpad Bug: |
Description
On Ubuntu 22.04, the test in test_crypto.py that loads a huge RSA key takes a ludicrous amount of time.
This is on my new, twice-as-fast-cores computer. Like, a minute, maybe more, it just sits there.
Maybe OpenSSL 3? Except OpenSSL is probably packaged in the relevant wheels?
I suggest either skipping the test on Ubuntu 22.04, or maybe just deleting it.
Change History (9)
comment:1 Changed at 2022-08-15T14:34:33Z by itamarst
comment:2 Changed at 2022-12-02T16:17:46Z by exarkun
On CircleCI, this is reported as the slowest test, taking more than 4 minutes to run on at least 95% of test runs.
I can reproduce this locally with tox where these versions are installed:
appdirs==1.4.4 attrs==22.1.0 autobahn==22.7.1 Automat==22.10.0 bcrypt==4.0.1 beautifulsoup4==4.11.1 boltons==21.0.0 cbor2==5.4.5 certifi==2022.9.24 cffi==1.15.1 cfgv==3.3.1 charset-normalizer==2.1.1 click==8.1.3 click-default-group==1.2.2 collections-extended==2.0.2 constantly==15.1.0 coverage==5.5 cryptography==38.0.4 decorator==5.1.1 distlib==0.3.6 distro==1.8.0 eliot==1.14.0 exceptiongroup==1.0.4 extras==1.0.0 filelock==3.8.0 fixtures==4.0.1 flake8==3.8.4 foolscap==21.7.0 future==0.18.2 greenlet==2.0.1 hkdf==0.0.3 html5lib==1.1 humanize==4.4.0 hyperlink==21.0.0 hypothesis==6.59.0 identify==2.5.9 idna==3.4 incremental==22.10.0 [30/129] iniconfig==1.1.1 Jinja2==3.1.2 junitxml==0.7 klein==21.8.0 magic-wormhole==0.12.0 MarkupSafe==2.1.1 mccabe==0.6.1 mock==4.0.3 netifaces==0.11.0 nodeenv==1.7.0 packaging==21.3 paramiko==2.8.1 Parsley==1.3 pbr==5.11.0 platformdirs==2.5.4 pluggy==1.0.0 pre-commit==2.20.0 prometheus-client==0.11.0 psutil==5.9.4 py==1.11.0 pyasn1==0.4.8 pyasn1-modules==0.2.8 pycddl==0.2.2 pycodestyle==2.6.0 pycparser==2.21 pyflakes==2.2.0 PyNaCl==1.5.0 pyOpenSSL==22.1.0 pyparsing==3.0.9 pyrsistent==0.19.2 pytest==7.2.0 pytest-timeout==2.1.0 pytest-twisted==1.14.0 python-subunit==1.4.2 pyutil==3.3.0 PyYAML==6.0 requests==2.28.1 service-identity==21.1.0 six==1.16.0 sortedcontainers==2.4.0 soupsieve==2.3.2.post1 spake2==0.8 subunitreporter==22.2.0 tahoe-lafs @ file:///home/exarkun/Work/python/tahoe-lafs/.tox/.tmp/package/1/tahoe-lafs-1.18.1.dev172%2Bgb56f53b77.zip tenacity==8.1.0 testtools==2.5.0 toml==0.10.2 tomli==2.0.1 towncrier==22.8.0 tox==3.27.1 tqdm==4.64.1 treq==22.2.0 Tubes==0.2.1 Twisted==22.10.0 txaio==22.2.1 txi2p-tahoe==0.3.7 txtorcon==22.0.0 typing_extensions==4.4.0 urllib3==1.26.13 virtualenv==20.17.0 webencodings==0.5.1 Werkzeug==2.2.2 zfec==1.5.7.2 zope.interface==5.5.2
but I fail to reproduce it in a different virtualenv (the test takes about 4 seconds there):
aniso8601==9.0.1 appdirs==1.4.4 attrs==21.4.0 autobahn==21.11.1 Automat==20.2.0 bcrypt==3.2.0 beautifulsoup4==4.10.0 black==22.3.0 boltons==21.0.0 build==0.9.0 cbor2==5.4.2 certifi==2021.10.8 cffi==1.15.0 characteristic==14.3.0 charset-normalizer==2.0.10 click==8.0.3 click-default-group==1.2.2 collections-extended==2.0.2 colorama==0.4.6 colored==1.4.3 compose==1.4.8 constantly==15.1.0 coverage==5.5 cryptography==36.0.1 decorator==4.4.2 distlib==0.3.4 distro==1.6.0 eliot==1.14.0 eliot-tree==21.0.0 execnet==1.9.0 extras==1.0.0 filelock==3.4.2 fixtures==3.0.0 flake8==3.8.4 foolscap==21.7.0 future==0.18.2 greenlet==1.1.2 hkdf==0.0.3 html5lib==1.1 humanize==3.13.1 hyperlink==21.0.0 hypothesis==6.36.0 idna==3.3 incremental==21.3.0 iniconfig==1.1.1 iso8601==1.0.2 isort==5.10.1 Jinja2==3.0.3 jmespath==1.0.1 junitxml==0.7 klein==21.8.0 magic-wormhole==0.12.0 MarkupSafe==2.0.1 mccabe==0.6.1 mock==4.0.3 mypy==0.981 mypy-clean-slate==0.1.5 mypy-extensions==0.4.3 mypy-zope==0.3.11 netifaces==0.11.0 packaging==21.3 paramiko==2.8.1 Parsley==1.3 pathspec==0.9.0 pbr==5.8.0 pep517==0.13.0 pip-tools==6.10.0 platformdirs==2.4.1 pluggy==1.0.0 prometheus-client==0.11.0 psutil==5.9.2 py==1.11.0 pyasn1==0.4.8 pyasn1-modules==0.2.8 pycddl==0.2.2 pycodestyle==2.6.0 pycparser==2.21 pyflakes==2.2.0 PyHamcrest==2.0.3 PyNaCl==1.5.0 pyOpenSSL==21.0.0 pyparsing==3.0.6 pyrsistent==0.18.1 pytest==6.2.5 pytest-forked==1.4.0 pytest-timeout==2.1.0 pytest-twisted==1.13.4 pytest-xdist==2.5.0 python-challenge-bypass-ristretto==2022.6.30 pytz==2022.6 pyutil==3.3.0 PyYAML==6.0 requests==2.27.1 service-identity==21.1.0 setuptools-scm==7.0.5 six==1.16.0 sortedcontainers==2.4.0 soupsieve==2.3.1 spake2==0.8 sqlparse==0.4.3 -e git+ssh://git@github.com/tahoe-lafs/tahoe-lafs@b56f53b77c7c5f4f184cd82dca5d03c96664389a#egg=tahoe_lafs tenacity==8.0.1 testtools==2.5.0 toml==0.10.2 tomli==2.0.1 toolz==0.12.0 towncrier==21.3.0 tox==3.24.5 tqdm==4.62.3 treq==21.5.0 Tubes==0.2.0 Twisted==22.10.0 txaio==21.2.1 -e git+ssh://git@github.com/tahoe-lafs/txi2p@a2e23a2a38f1bb110f90eb77b60fd9a6be62e42d#egg=txi2p_tahoe txtorcon==21.1.0 types-cryptography==3.3.23.2 types-mock==4.0.15.2 types-pkg-resources==0.1.3 types-pyOpenSSL==22.1.0.2 types-PyYAML==6.0.12.2 types-six==1.16.21.4 typing_extensions==4.0.1 urllib3==1.26.8 virtualenv==20.13.0 webencodings==0.5.1 Werkzeug==2.0.2 zero-knowledge-access-pass-authorizer==2022.8.21 zfec==1.5.5 zope.event==4.5.0 zope.interface==5.4.0 zope.schema==6.2.0
There's a *lot* that's different between the two envs. However, jumping straight to cryptography on the assumption that that's where a lot of the work is happening...
When I upgrade cryptography (36.0.1) and pyopenssl (21.0.0) in the fast env to the versions in the slow env (38.0.4 and 22.0.0 respectively), the fast env gets slow.
And with cryptography 37.0.0 it's still slow but with 36.0.2 it's fast again.
comment:3 Changed at 2022-12-02T16:19:39Z by exarkun
Reading the cryptography changelog, the headline item for 37.0.0 is...
Updated Windows, macOS, and Linux wheels to be compiled with OpenSSL 3.0.2.
:/
comment:4 Changed at 2022-12-02T18:56:37Z by exarkun
Here's a very narrow demonstration of the performance difference:
❯ time python -c 'from cryptography import __version__ print(__version__) from cryptography.hazmat.primitives.serialization import load_der_private_key from base64 import b64decode with open("src/allmydata/test/data/pycryptopp-rsa-32768-priv.txt", "rb") as f: load_der_private_key(b64decode(f.read()), password=None) ' 36.0.2 real 0m4.702s user 0m4.689s sys 0m0.012s ❯ pip install --upgrade cryptography==37.0 Collecting cryptography==37.0 Using cached cryptography-37.0.0-cp36-abi3-manylinux_2_24_x86_64.whl (4.0 MB) ... ❯ time python -c 'from cryptography import __version__ print(__version__) from cryptography.hazmat.primitives.serialization import load_der_private_key from base64 import b64decode with open("src/allmydata/test/data/pycryptopp-rsa-32768-priv.txt", "rb") as f: load_der_private_key(b64decode(f.read()), password=None) ' 37.0.0 real 3m8.899s user 3m8.556s sys 0m0.052s
OpenSSL 3 is basically 180x slower than OpenSSL 1.1.1 at decoding this key.
comment:5 Changed at 2022-12-02T20:39:57Z by exarkun
This is a known slowdown. OpenSSL 3 introduces some "primality" tests. It is possible to disable these (pass unsafe_skip_rsa_key_validation=True to the above API). As the parameter name suggests, this option is "unsafe" (in the sense that setting it and also taking untrusted key material exposes you to unspecified behavior from OpenSSL).
The *test suite* is not exposed to untrusted key material so it would probably be fine to set the option there (and reclaim about 4 minutes from each test run). However, I'm not entirely confident that we can say the same thing about all production uses of the function.
comment:6 Changed at 2022-12-14T13:46:27Z by exarkun
Oops, unsafe_skip_rsa_key_validation was added in the yet-to-be released cryptography 39. So hard to make use of it quite yet...
comment:7 Changed at 2022-12-14T13:48:43Z by exarkun
comment:8 Changed at 2023-01-02T16:48:24Z by exarkun
39 was released a couple days ago so we can now optionally take advantage of this feature, I think.
comment:9 Changed at 2023-01-06T21:41:34Z by GitHub <noreply@…>
- Owner set to GitHub <noreply@…>
- Resolution set to fixed
- Status changed from new to closed
In 3c3697d/trunk:
I'm using cryptography 37.0.4.