Closed vsafonin closed 1 year ago
This likely has the same cause as https://github.com/pyca/cryptography/issues/9063, and will be fixed in our next release.
Ahh, wait, alternatively, this may be caused by the fact that cryptography 37 begins to use OpenSSL 3.
I'm not aware of a specific regression that may be at work here, so some more profiling may be required.
I attempted to reproduce this locally, and the tests run in about 10 seconds. However, if I run under a profiler, basically none of the time is spent in cryptography.
What key type are you using for my_test_key
?
I attempted to reproduce this locally, and the tests run in about 10 seconds. However, if I run under a profiler, basically none of the time is spent in cryptography.
What key type are you using for
my_test_key
?
i'm using this:
3072 SHA256:v97YqUHeH3JIkbi3QhDlcIQzTw0IisvR9rselXDIJAg vldmr@workvm (RSA)
update, i checked now: this happen only with rsa key...
This is very very likely to be a performance regression in OpenSSL, but let's see.
I'm not sure what's going on with @alex's profiler results, but RSA key loading is substantially slower in 37+ due to changes in the way it performs key checks when calling RSA_check_key
. unsafe_skip_rsa_key_validation=True
as a kwarg when loading will skip this (at the cost of being potentially unsafe!) but I think you'll have to patch asyncio to test and see if that recovers/even improves performance.
I also do not know what's going on with the profiler, with an RSA key I see this takes 4.5x longer, but the profiler results don't show where it's spending that time.
Nonetheless: the best choice is almost certainly to find a way to load the key a single time, right now each connection re-parses the key from disk, if you can reuse the same key object, it will be much faster. I'm not sure how to do that with asyncssh's APIs.
Yes - I think this is caused by the extra RSA checks in OpenSSL 3 mentioned above. If you want to disable those extra checks, it can be done as follows:
from cryptography.hazmat.backends.openssl import backend
backend._rsa_skip_check_key = True
This made a substantial difference in the runtime on the AsyncSSH unit tests. You can see an example of that at https://github.com/ronf/asyncssh/blob/8dba2b17f0cae4929bb5f2f4f8e888745fde1013/tests/util.py#L80-L85. I think this will be especially noticeable with larger (4K) RSA keys.
I'm not sure if there's a better way to do this that doesn't involve violating protected access.
The various key loading APIs now have a public API for it: https://cryptography.io/en/latest/hazmat/primitives/asymmetric/serialization/#cryptography.hazmat.primitives.serialization.load_pem_private_key, please note the caveats though.
The best solution, if possible, would be to avoid re-loading the key on each connection.
On Fri, Jun 23, 2023 at 9:49 AM Ron Frederick @.***> wrote:
Yes - I think this is caused by the extra RSA checks in OpenSSL 3 mentioned above. If you want to disable those extra checks, it can be done as follows:
from cryptography.hazmat.backends.openssl import backendbackend._rsa_skip_check_key = True
This made a substantial difference in the runtime on the AsyncSSH unit tests. You can see an example of that at https://github.com/ronf/asyncssh/blob/8dba2b17f0cae4929bb5f2f4f8e888745fde1013/tests/util.py#L80-L85. I think this will be especially noticeable with larger (4K) RSA keys.
I'm not sure if there's a better way to do this that doesn't involve violating protected access.
— Reply to this email directly, view it on GitHub https://github.com/pyca/cryptography/issues/9122#issuecomment-1604313477, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAAGBAUEIHJYGVIYVCSOF3XMWNHPANCNFSM6AAAAAAZROPW3Q . You are receiving this because you were mentioned.Message ID: @.***>
-- All that is necessary for evil to succeed is for good people to do nothing.
Ok, Thank you.
Now, I have enabled unsafe_skip_rsa_key_validation
in the RSAPrivateKey
class:
class RSAPrivateKey(_RSAKey):
"""A shim around PyCA for RSA private keys"""
@classmethod
def construct(cls, n: int, e: int, d: int, p: int, q: int,
dmp1: int, dmq1: int, iqmp: int) -> 'RSAPrivateKey':
"""Construct an RSA private key"""
pub = rsa.RSAPublicNumbers(e, n)
priv = rsa.RSAPrivateNumbers(p, q, d, dmp1, dmq1, iqmp, pub)
priv_key = priv.private_key(unsafe_skip_rsa_key_validation=True)
return cls(priv_key, pub, priv)
This code is located in the asyncssh/crypto/rsa.py
file.
This solution resolves my problem for now, but I acknowledge that it is not an ideal solution. I will continue to explore alternative approaches to avoid reloading the key. However, at the moment, it seems to be impossible to achieve.
I think any future follow-ups here are in asyncssh, so I'm going to close this for now. If there ends up being future action items we can take in cryptography please file a new bug!
Hello, I have noticed that my app, which uses asyncssh, has become much slower when I use a version cryptography newer than 36.0.2. This issue only occurs when I utilize an SSH key file for authentication. My app connects to 56 thousand devices simultaneously. When I use a version newer than 36.0.2, my app takes over an hour to complete and heavily burdens the processor.
To describe this problem, I have written a small test module.
Where 'client_keys' is the actual SSH authentication key (it should be located in the directory with the test).
This is result: if i'm using cryptography 36.0.2
if i'm using cryptography=37.0.0
if i'm using cryptography 41.0.0
Why this happen? this is possible to fix it? Thank you