mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 14:21:53 +00:00

Part of #1646. ## Summary Implement `S505` ([`weak_cryptographic_key`](https://bandit.readthedocs.io/en/latest/plugins/b505_weak_cryptographic_key.html)) rule from `bandit`. For this rule, `bandit` [reports the issue with](https://github.com/PyCQA/bandit/blob/1.7.5/bandit/plugins/weak_cryptographic_key.py#L47-L56): - medium severity for DSA/RSA < 2048 bits and EC < 224 bits - high severity for DSA/RSA < 1024 bits and EC < 160 bits Since Ruff does not handle severities for `bandit`-related rules, we could either report the issue if we have lower values than medium severity, or lower values than high one. Two reasons led me to choose the first option: - a medium severity issue is still a security issue we would want to report to the user, who can then decide to either handle the issue or ignore it - `bandit` [maps the EC key algorithms to their respective key lengths in bits](https://github.com/PyCQA/bandit/blob/1.7.5/bandit/plugins/weak_cryptographic_key.py#L112-L133), but there is no value below 160 bits, so technically `bandit` would never report medium severity issues for EC keys, only high ones Another consideration is that as shared just above, for EC key algorithms, `bandit` has a mapping to map the algorithms to their respective key lengths. In the implementation in Ruff, I rather went with an explicit list of EC algorithms known to be vulnerable (which would thus be reported) rather than implementing a mapping to retrieve the associated key length and comparing it with the minimum value. ## Test Plan Snapshot tests from https://github.com/PyCQA/bandit/blob/1.7.5/examples/weak_cryptographic_key_sizes.py.
54 lines
2.2 KiB
Python
54 lines
2.2 KiB
Python
from cryptography.hazmat import backends
|
|
from cryptography.hazmat.primitives.asymmetric import dsa
|
|
from cryptography.hazmat.primitives.asymmetric import ec
|
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
from Crypto.PublicKey import DSA as pycrypto_dsa
|
|
from Crypto.PublicKey import RSA as pycrypto_rsa
|
|
from Cryptodome.PublicKey import DSA as pycryptodomex_dsa
|
|
from Cryptodome.PublicKey import RSA as pycryptodomex_rsa
|
|
|
|
# OK
|
|
dsa.generate_private_key(key_size=2048, backend=backends.default_backend())
|
|
ec.generate_private_key(curve=ec.SECP384R1, backend=backends.default_backend())
|
|
rsa.generate_private_key(
|
|
public_exponent=65537, key_size=2048, backend=backends.default_backend()
|
|
)
|
|
pycrypto_dsa.generate(bits=2048)
|
|
pycrypto_rsa.generate(bits=2048)
|
|
pycryptodomex_dsa.generate(bits=2048)
|
|
pycryptodomex_rsa.generate(bits=2048)
|
|
dsa.generate_private_key(2048, backends.default_backend())
|
|
ec.generate_private_key(ec.SECP256K1, backends.default_backend())
|
|
rsa.generate_private_key(3, 2048, backends.default_backend())
|
|
pycrypto_dsa.generate(2048)
|
|
pycrypto_rsa.generate(2048)
|
|
pycryptodomex_dsa.generate(2048)
|
|
pycryptodomex_rsa.generate(2048)
|
|
|
|
# Errors
|
|
dsa.generate_private_key(key_size=2047, backend=backends.default_backend())
|
|
ec.generate_private_key(curve=ec.SECT163R2, backend=backends.default_backend())
|
|
rsa.generate_private_key(
|
|
public_exponent=65537, key_size=2047, backend=backends.default_backend()
|
|
)
|
|
pycrypto_dsa.generate(bits=2047)
|
|
pycrypto_rsa.generate(bits=2047)
|
|
pycryptodomex_dsa.generate(bits=2047)
|
|
pycryptodomex_rsa.generate(bits=2047)
|
|
dsa.generate_private_key(2047, backends.default_backend())
|
|
ec.generate_private_key(ec.SECT163R2, backends.default_backend())
|
|
rsa.generate_private_key(3, 2047, backends.default_backend())
|
|
pycrypto_dsa.generate(2047)
|
|
pycrypto_rsa.generate(2047)
|
|
pycryptodomex_dsa.generate(2047)
|
|
pycryptodomex_rsa.generate(2047)
|
|
|
|
# Don't crash when the size is variable.
|
|
rsa.generate_private_key(
|
|
public_exponent=65537, key_size=some_key_size, backend=backends.default_backend()
|
|
)
|
|
|
|
# Can't reliably know which curve was passed, in some cases like below.
|
|
ec.generate_private_key(
|
|
curve=curves[self.curve]["create"](self.size), backend=backends.default_backend()
|
|
)
|