Crypto-View

paramiko/paramiko

Cryptographic posture

381 cryptographic locations: 6 already broken, 305 quantum-vulnerable, 19 reduced-margin, 31 undetermined, 20 quantum-safe

50 establish keys, so traffic protected by them and recorded today becomes readable once the algorithm falls. 1 imported cryptographic library is listed separately. 109 files analysed.

Quantum-vulnerable 305 Already broken 6 Reduced margin 19 Could not be determined 31 Quantum-safe 20
To address271
Key establishment50
Inventory only1
Total findings382
What was analysed
Branch main
Commit 142f593e40ad767c5e3556cbace66dc84589620c Add annotations future for type hint
Committed 2026-08-29 20:44 UTC
Scanned 2026-09-21 10:57 UTC 9 hours ago
Coverage 109 files, 70 python

List of cryptographic assets

SHA-1 Already broken Renamed import 3 places See details

Broken hash function

`hashlib.md5()` or `hashlib.sha1()`. Both have practical collisions. Where the call is annotated `usedforsecurity=False` the finding is recorded as inventory instead.

This is already unsafe today, with no quantum computer involved. SHAttered and subsequent work produced practical collisions; NIST withdrew SHA-1 in 2030 guidance and it is already unacceptable for signatures.

What to do. SHA-256, or SHA-384 for long-lived signatures.

  1. paramiko/config.py:449 "%C": sha1(tohash.encode()).hexdigest(),
  2. paramiko/hostkeys.py:294 salt = os.urandom(sha1().digest_size)
  3. paramiko/hostkeys.py:299 assert len(salt) == sha1().digest_size
py.hashlib.weak · CWE-328
RSAES-PKCS1v15 Already broken Recorded traffic 2 places See details

PKCS#1 v1.5 padding

`padding.PKCS1v15()`. For encryption this is vulnerable to Bleichenbacher-style padding oracles today; for signatures it is acceptable but the key is still RSA.

This is already unsafe today, with no quantum computer involved. PKCS#1 v1.5 encryption padding is vulnerable to Bleichenbacher oracles today, and the underlying RSA is broken by Shor.

What to do. For encryption, OAEP immediately and ML-KEM-768 as the destination.

  1. paramiko/rsakey.py:139 padding=padding.PKCS1v15(),
  2. paramiko/rsakey.py:167 sign, data, padding.PKCS1v15(), self.HASHES[sig_algorithm]()
py.cryptography.pkcs1v15 · CWE-327
MD5 Already broken Renamed import 1 place See details

Broken hash function

`hashlib.md5()` or `hashlib.sha1()`. Both have practical collisions. Where the call is annotated `usedforsecurity=False` the finding is recorded as inventory instead.

This is already unsafe today, with no quantum computer involved. Practical chosen-prefix collisions exist; MD5 has no remaining security as a digest.

What to do. SHA-256, or SHA-384 for long-lived signatures.

  1. paramiko/pkey.py:390 return md5(self.asbytes()).digest()
py.hashlib.weak · CWE-328
RSASSA-PKCS1v15 Quantum-vulnerable From a constant 102 places See details

SSH algorithms pinned in configuration

A `KexAlgorithms`, `HostKeyAlgorithms` or `Ciphers` directive in an SSH configuration. `KexAlgorithms` is the line that decides whether recorded sessions stay confidential.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer. The v1.5 signature scheme of RFC 8017 section 8.2 has no classical break of its own; RSA-PSS is preferred for new work, but the quantum exposure is the same for both.

What to do. Put `sntrup761x25519-sha512@openssh.com` first in `KexAlgorithms`. It is a hybrid, so it is no weaker than the classical exchange it replaces.

  1. paramiko/agent.py:53 "rsa-sha2-256": SSH_AGENT_RSA_SHA2_256,
  2. paramiko/agent.py:54 "rsa-sha2-512": SSH_AGENT_RSA_SHA2_512,
  3. paramiko/client.py:430 if keytype == "ssh-rsa":
  4. paramiko/client.py:431 if "rsa-sha2-512" in sec_opts.key_types:
  5. paramiko/client.py:432 keytype = "rsa-sha2-512"
  6. paramiko/client.py:433 elif "rsa-sha2-256" in sec_opts.key_types:
  7. paramiko/client.py:434 keytype = "rsa-sha2-256"
  8. paramiko/pkey.py:338 example, ``"ssh-rsa"``).
  9. paramiko/pkey.py:948 :param str type_: Type indicator, eg ``ssh-rsa``.
  10. paramiko/rsakey.py:41 name = "ssh-rsa"
  11. paramiko/rsakey.py:43 "rsa-sha2-256": hashes.SHA256,
  12. paramiko/rsakey.py:44 "rsa-sha2-256-cert-v01@openssh.com": hashes.SHA256,
  13. paramiko/rsakey.py:45 "rsa-sha2-512": hashes.SHA512,
  14. paramiko/rsakey.py:46 "rsa-sha2-512-cert-v01@openssh.com": hashes.SHA512,
  15. paramiko/rsakey.py:76 cert_type="ssh-rsa-cert-v01@openssh.com",
  16. paramiko/rsakey.py:89 "ssh-rsa",
  17. paramiko/rsakey.py:90 "ssh-rsa-cert-v01@openssh.com",
  18. paramiko/transport.py:203 "rsa-sha2-512",
  19. paramiko/transport.py:204 "rsa-sha2-256",
  20. paramiko/transport.py:212 "rsa-sha2-512",
  21. paramiko/transport.py:213 "rsa-sha2-256",
  22. paramiko/transport.py:312 "rsa-sha2-256": RSAKey,
  23. paramiko/transport.py:313 "rsa-sha2-256-cert-v01@openssh.com": RSAKey,
  24. paramiko/transport.py:314 "rsa-sha2-512": RSAKey,
  25. paramiko/transport.py:315 "rsa-sha2-512-cert-v01@openssh.com": RSAKey,
  26. paramiko/transport.py:795 self.server_key_dict["rsa-sha2-256"] = key
  27. paramiko/transport.py:796 self.server_key_dict["rsa-sha2-512"] = key
  28. paramiko/transport.py:1322 "rsa-sha2-512",
  29. paramiko/transport.py:1323 "rsa-sha2-256",
  30. tests/_support/rsa-missing.key-cert.pub:1 test path ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgsZlXTd5NE4uzGAn6TyAqQj+IPbsTEFGap2x5pTRwQR8AAAABIwAAAIEA049W6geFpmsljTwfvI1UmKWWJPNFI74+vNKTk4dmzkQY2yAMs6FhlvhlI8ysU4oj71ZsRYMecHbBbxdN79+JRFVYTKaLqjwGENeTd+yv4q+
  31. tests/_support/rsa.key-cert.pub:1 test path ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgsZlXTd5NE4uzGAn6TyAqQj+IPbsTEFGap2x5pTRwQR8AAAABIwAAAIEA049W6geFpmsljTwfvI1UmKWWJPNFI74+vNKTk4dmzkQY2yAMs6FhlvhlI8ysU4oj71ZsRYMecHbBbxdN79+JRFVYTKaLqjwGENeTd+yv4q+
  32. tests/agent.py:103 test path (dict(algorithm="rsa-sha2-256"), SSH_AGENT_RSA_SHA2_256),
  33. tests/agent.py:104 test path (dict(algorithm="rsa-sha2-512"), SSH_AGENT_RSA_SHA2_512),
  34. tests/agent.py:109 test path dict(algorithm="rsa-sha2-256-cert-v01@openssh.com"),
  35. tests/agent.py:113 test path dict(algorithm="rsa-sha2-512-cert-v01@openssh.com"),
  36. tests/auth.py:160 test path pubkeys=["rsa-sha2-256", "rsa-sha2-512"]
  37. tests/auth.py:178 test path pubkeys=["rsa-sha2-256", "rsa-sha2-512"]
  38. tests/auth.py:187 test path disabled_algorithms=dict(pubkeys=["rsa-sha2-512"])
  39. tests/auth.py:196 test path assert tc._agreed_pubkey_algorithm == "rsa-sha2-256"
  40. tests/auth.py:203 test path init=dict(disabled_algorithms=dict(pubkeys=["rsa-sha2-256"])),
  41. tests/auth.py:206 test path assert tc._agreed_pubkey_algorithm == "rsa-sha2-512"
  42. tests/auth.py:213 test path init=dict(disabled_algorithms=dict(pubkeys=["rsa-sha2-512"])),
  43. tests/auth.py:216 test path assert tc._agreed_pubkey_algorithm == "rsa-sha2-256"
  44. tests/conftest.py:125 test path "ssh-rsa",
  45. tests/conftest.py:132 test path "rsa-sha2-512",
  46. tests/conftest.py:162 test path - ``full_type``: the "message style" key identifier, eg ``ssh-rsa``, or
  47. tests/pkey.py:94 test path key.public_blob.key_type == "ssh-rsa-cert-v01@openssh.com"
  48. tests/pkey.py:108 test path key.public_blob.key_type == "ssh-rsa-cert-v01@openssh.com"
  49. tests/pkey.py:138 test path msg = key.sign_ssh_data(data, "rsa-sha2-256")
  50. tests/pkey.py:140 test path assert "rsa-sha2-256" == msg.get_text()
  51. tests/pkey.py:146 test path assert key.public_blob.key_type == "ssh-rsa-cert-v01@openssh.com"
  52. tests/pkey.py:150 test path assert msg.get_text() == "ssh-rsa-cert-v01@openssh.com"
  53. tests/pkey.py:165 test path msg = key.sign_ssh_data(data, "rsa-sha2-256-cert-v01@openssh.com")
  54. tests/pkey.py:167 test path assert "rsa-sha2-256" == msg.get_text()
  55. tests/pkey.py:174 test path err = "PublicBlob type ssh-rsa-cert-v01@openssh.com incompatible with key type ssh-ed25519" # noqa
  56. tests/pkey.py:221 test path "rsa-sha2-256",
  57. tests/pkey.py:222 test path "rsa-sha2-256-cert-v01@openssh.com",
  58. tests/pkey.py:223 test path "rsa-sha2-512",
  59. tests/pkey.py:224 test path "rsa-sha2-512-cert-v01@openssh.com",
  60. tests/pkey.py:227 test path "ssh-rsa",
  61. tests/pkey.py:228 test path "ssh-rsa-cert-v01@openssh.com",
  62. tests/test_client.py:48 test path "ssh-rsa": b"\x60\x73\x38\x44\xcb\x51\x86\x65\x7f\xde\xda\xa2\x2b\x5a\x57\xd5", # noqa
  63. tests/test_client.py:204 test path "ssh-rsa",
  64. tests/test_client.py:274 test path "rsa": "ssh-rsa",
  65. tests/test_client.py:395 test path client.get_host_keys().add(host_id, "ssh-rsa", public_host_key)
  66. tests/test_client.py:397 test path assert public_host_key == client.get_host_keys()[host_id]["ssh-rsa"]
  67. tests/test_client.py:493 test path "ssh-rsa",
  68. tests/test_hostkeys.py:34 test path secure.example.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1PD6U2/TVxET6lkpKhOk5r\
  69. tests/test_hostkeys.py:37 test path broken.example.com ssh-rsa AAAA
  70. tests/test_hostkeys.py:38 test path happy.example.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA8bP1ZA7DCZDB9J0s50l31M\
  71. tests/test_hostkeys.py:82 test path hostdict["secure.example.com"]["ssh-rsa"].get_fingerprint()
  72. tests/test_hostkeys.py:90 test path hostdict.add(hh, "ssh-rsa", key)
  73. tests/test_hostkeys.py:93 test path fp = hexlify(x["ssh-rsa"].get_fingerprint()).upper()
  74. tests/test_hostkeys.py:105 test path fp = hexlify(x["ssh-rsa"].get_fingerprint()).upper()
  75. tests/test_hostkeys.py:117 test path "ssh-rsa": key,
  76. tests/test_hostkeys.py:121 test path hostdict["fake.example.com"]["ssh-rsa"] = key
  77. tests/test_hostkeys.py:128 test path hostdict["secure.example.com"]["ssh-rsa"].get_fingerprint()
  78. tests/test_pkey.py:50 test path PUB_RSA = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA049W6geFpmsljTwfvI1UmKWWJPNFI74+vNKTk4dmzkQY2yAMs6FhlvhlI8ysU4oj71ZsRYMecHbBbxdN79+JRFVYTKaLqjwGENeTd+yv4q+V2PvZv3fLnzApI3l7EJCqhWwJUHJ1jAkZzqDx0tyOL4uoZpww3nmE0kb3y21tH4c=" # noqa
  79. tests/test_pkey.py:54 test path PUB_RSA_2K_OPENSSH = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDF+Dpr54DX0WdeTDpNAMdkCWEkl3OXtNgf58qlN1gX572OLBqLf0zT4bHstUEpU3piazph/rSWcUMuBoD46tZ6jiH7H9b9Pem2eYQWaELDDkM+v9BMbEy5rMbFRLol5OtEvPFqneyEAanPOgvd8t3yyhSev9QVusakzJ8j8LGgrA8huYZ+Sr
  80. tests/test_pkey.py:138 test path self.assertEqual("ssh-rsa", key.get_name())
  81. tests/test_pkey.py:171 test path self.assertEqual("ssh-rsa", key.get_name())
  82. tests/test_pkey.py:202 test path self._sign_and_verify_rsa("rsa-sha2-512", SIGNED_RSA_512)
  83. tests/test_pkey.py:205 test path self._sign_and_verify_rsa("rsa-sha2-256", SIGNED_RSA_256)
  84. tests/test_pkey.py:210 test path msg = key.sign_ssh_data(b"jerri blank", algorithm="rsa-sha2-256")
  85. tests/test_pkey.py:414 test path self.assertEqual("ssh-rsa", key.get_name())
  86. tests/test_rsa.key.pub:1 test path ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA049W6geFpmsljTwfvI1UmKWWJPNFI74+vNKTk4dmzkQY2yAMs6FhlvhlI8ysU4oj71ZsRYMecHbBbxdN79+JRFVYTKaLqjwGENeTd+yv4q+V2PvZv3fLnzApI3l7EJCqhWwJUHJ1jAkZzqDx0tyOL4uoZpww3nmE0kb3y21tH4c=
  87. tests/test_transport.py:1110 test path "keys": ["rsa-sha2-512"],
  88. tests/test_transport.py:1118 test path assert "rsa-sha2-512" in t._preferred_keys
  89. tests/test_transport.py:1119 test path assert "rsa-sha2-512" not in t.preferred_keys
  90. tests/test_transport.py:1121 test path assert "rsa-sha2-512-cert-v01@openssh.com" not in t.preferred_keys
  91. tests/test_transport.py:1131 test path "keys": ["rsa-sha2-256"],
  92. tests/test_transport.py:1160 test path assert "rsa-sha2-256" not in server_keys
  93. tests/test_transport.py:1176 test path assert tc.host_key_type == "rsa-sha2-512"
  94. tests/test_transport.py:1181 test path init=dict(disabled_algorithms=dict(keys=["rsa-sha2-512"]))
  95. tests/test_transport.py:1183 test path assert tc.host_key_type == "rsa-sha2-256"
  96. tests/test_transport.py:1215 test path assert tc.host_key_type == "rsa-sha2-512"
  97. tests/test_transport.py:1228 test path "server-sig-algs": b"ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,rsa-sha2-512,rsa-sha2-256" # noqa
  98. tests/test_transport.py:1237 test path disabled_algorithms=dict(pubkeys=["rsa-sha2-512"])
  99. tests/test_transport.py:1243 test path assert tc._agreed_pubkey_algorithm == "rsa-sha2-256"
  100. tests/test_util.py:35 test path secure.example.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1PD6U2/TVxET6lkpKhOk5r\
  101. tests/test_util.py:38 test path happy.example.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA8bP1ZA7DCZDB9J0s50l31M\
  102. tests/test_util.py:120 test path hostdict["secure.example.com"]["ssh-rsa"].get_fingerprint()
config.ssh-algorithms · CWE-757
ECDSA Quantum-vulnerable 41 places See details

SSH algorithms pinned in configuration

A `KexAlgorithms`, `HostKeyAlgorithms` or `Ciphers` directive in an SSH configuration. `KexAlgorithms` is the line that decides whether recorded sessions stay confidential.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Put `sntrup761x25519-sha512@openssh.com` first in `KexAlgorithms`. It is a hybrid, so it is no weaker than the classical exchange it replaces.

  1. paramiko/transport.py:200 "ecdsa-sha2-nistp256",
  2. paramiko/transport.py:201 "ecdsa-sha2-nistp384",
  3. paramiko/transport.py:202 "ecdsa-sha2-nistp521",
  4. paramiko/transport.py:209 "ecdsa-sha2-nistp256",
  5. paramiko/transport.py:210 "ecdsa-sha2-nistp384",
  6. paramiko/transport.py:211 "ecdsa-sha2-nistp521",
  7. paramiko/transport.py:316 "ecdsa-sha2-nistp256": ECDSAKey,
  8. paramiko/transport.py:317 "ecdsa-sha2-nistp256-cert-v01@openssh.com": ECDSAKey,
  9. paramiko/transport.py:318 "ecdsa-sha2-nistp384": ECDSAKey,
  10. paramiko/transport.py:319 "ecdsa-sha2-nistp384-cert-v01@openssh.com": ECDSAKey,
  11. paramiko/transport.py:320 "ecdsa-sha2-nistp521": ECDSAKey,
  12. paramiko/transport.py:321 "ecdsa-sha2-nistp521-cert-v01@openssh.com": ECDSAKey,
  13. tests/_support/ecdsa-256.key-cert.pub:1 test path ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgJ+ZkRXedIWPl9y6fvel60p47ys5WgwMSjiwzJ2Ho+4MAAAAIbmlzdHAyNTYAAABBBJSPZm3ZWkvk/Zx8WP+fZRZ5/NBBHnGQwR6uIC6XHGPDIHuWUzIjAwA0bzqkOUffEsbLe+u
  14. tests/conftest.py:146 test path "ecdsa-sha2-nistp256",
  15. tests/conftest.py:163 test path ``ecdsa-sha2-nistp256``.
  16. tests/pkey.py:236 test path "ecdsa-sha2-nistp256",
  17. tests/pkey.py:237 test path "ecdsa-sha2-nistp384",
  18. tests/pkey.py:238 test path "ecdsa-sha2-nistp521",
  19. tests/test_client.py:49 test path "ecdsa-sha2-nistp256": b"\x25\x19\xeb\x55\xe6\xa1\x47\xff\x4f\x38\xd2\x75\x6f\xa5\xd5\x60", # noqa
  20. tests/test_client.py:276 test path "ecdsa": "ecdsa-sha2-nistp256",
  21. tests/test_client.py:319 test path allowed_keys=["ecdsa-sha2-nistp256"],
  22. tests/test_hostkeys.py:43 test path curvy.example.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlz\
  23. tests/test_pkey.py:51 test path PUB_ECDSA_256 = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJSPZm3ZWkvk/Zx8WP+fZRZ5/NBBHnGQwR6uIC6XHGPDIHuWUzIjAwA0bzqkOUffEsbLe+uQgKl5kbc/L8KA/eo=" # noqa
  24. tests/test_pkey.py:52 test path PUB_ECDSA_384 = "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBBbGibQLW9AAZiGN2hEQxWYYoFaWKwN3PKSaDJSMqmIn1Z9sgRUuw8Y/w502OGvXL/wFk0i2z50l3pWZjD7gfMH7gX5TUiCzwrQkS+Hn1U2S9aF5WJp0NcIzYxXw2r4M2A==" # noqa
  25. tests/test_pkey.py:53 test path PUB_ECDSA_521 = "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACaOaFLZGuxa5AW16qj6VLypFbLrEWrt9AZUloCMefxO8bNLjK/O5g0rAVasar1TnyHE9qj4NwzANZASWjQNbc4MAG8vzqezFwLIn/kNyNTsXNfqEko9OgHZknlj2Z79dwTJcRAL4QLcT5aND0EHZL
  26. tests/test_pkey.py:57 test path PUB_EC_384_OPENSSH = "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBIch5LXTq/L/TWsTGG6dIktxD8DIMh7EfvoRmWsks6CuNDTvFvbQNtY4QO1mn5OXegHbS0M5DPIS++wpKGFP3suDEH08O35vZQasLNrL0tO2jyyEnzB2ZEx3PPYci811yg==" # noqa
  27. tests/test_pkey.py:220 test path self.assertEqual(key.get_name(), "ecdsa-sha2-nistp256")
  28. tests/test_pkey.py:227 test path self.assertEqual(key.get_name(), "ecdsa-sha2-nistp256")
  29. tests/test_pkey.py:234 test path self.assertEqual(key.get_name(), "ecdsa-sha2-nistp384")
  30. tests/test_pkey.py:241 test path self.assertEqual(key.get_name(), "ecdsa-sha2-nistp521")
  31. tests/test_pkey.py:245 test path self.assertEqual("ecdsa-sha2-nistp256", key.get_name())
  32. tests/test_pkey.py:263 test path self.assertEqual("ecdsa-sha2-nistp256", key.get_name())
  33. tests/test_pkey.py:285 test path self.assertEqual("ecdsa-sha2-nistp256", msg.get_text())
  34. tests/test_pkey.py:296 test path self.assertEqual("ecdsa-sha2-nistp384", key.get_name())
  35. tests/test_pkey.py:314 test path self.assertEqual("ecdsa-sha2-nistp384", key.get_name())
  36. tests/test_pkey.py:347 test path self.assertEqual("ecdsa-sha2-nistp384", msg.get_text())
  37. tests/test_pkey.py:358 test path self.assertEqual("ecdsa-sha2-nistp521", key.get_name())
  38. tests/test_pkey.py:379 test path self.assertEqual("ecdsa-sha2-nistp521", key.get_name())
  39. tests/test_pkey.py:401 test path self.assertEqual("ecdsa-sha2-nistp521", msg.get_text())
  40. tests/test_pkey.py:440 test path self.assertEqual("ecdsa-sha2-nistp384", key.get_name())
  41. tests/test_transport.py:1228 test path "server-sig-algs": b"ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,rsa-sha2-512,rsa-sha2-256" # noqa
config.ssh-algorithms · CWE-757
Ed25519255-bitother/Ed25519 Quantum-vulnerable 18 places See details

SSH algorithms pinned in configuration

A `KexAlgorithms`, `HostKeyAlgorithms` or `Ciphers` directive in an SSH configuration. `KexAlgorithms` is the line that decides whether recorded sessions stay confidential.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Put `sntrup761x25519-sha512@openssh.com` first in `KexAlgorithms`. It is a hybrid, so it is no weaker than the classical exchange it replaces.

  1. paramiko/ed25519key.py:42 name = "ssh-ed25519"
  2. paramiko/ed25519key.py:55 cert_type="ssh-ed25519-cert-v01@openssh.com",
  3. paramiko/pkey.py:234 For example, ``PKey.from_type_string("ssh-ed25519", <public bytes>)``
  4. paramiko/pkey.py:238 The key type, eg ``"ssh-ed25519"``.
  5. paramiko/transport.py:199 "ssh-ed25519",
  6. paramiko/transport.py:208 "ssh-ed25519",
  7. paramiko/transport.py:322 "ssh-ed25519": Ed25519Key,
  8. paramiko/transport.py:323 "ssh-ed25519-cert-v01@openssh.com": Ed25519Key,
  9. tests/_support/ed25519.key-cert.pub:1 test path ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIIjBkc8l1X887CLBHraU+d6/74Hxr9oa+3HC0iioecZ6AAAAIHr1K9komH/1WBIvQbbtvnFVhryd62EfcgRFuLRiokNfAAAAAAAAAAAAAAABAAAACXVzZXJfdGVzdAAAAAgAAAAEdGVzdAAAAAAAAAAA///
  10. tests/conftest.py:139 test path "ssh-ed25519",
  11. tests/pkey.py:174 test path err = "PublicBlob type ssh-rsa-cert-v01@openssh.com incompatible with key type ssh-ed25519" # noqa
  12. tests/pkey.py:232 test path assert Ed25519Key.identifiers() == ["ssh-ed25519"]
  13. tests/test_client.py:50 test path "ssh-ed25519": b'\xb3\xd5"\xaa\xf9u^\xe8\xcd\x0e\xea\x02\xb9)\xa2\x80',
  14. tests/test_client.py:275 test path "ed25519": "ssh-ed25519",
  15. tests/test_hostkeys.py:41 test path modern.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKHEChAIxsh2hr8Q\
  16. tests/test_hostkeys.py:118 test path "ssh-ed25519": key_ed25519,
  17. tests/test_hostkeys.py:132 test path hostdict["secure.example.com"]["ssh-ed25519"].get_fingerprint()
  18. tests/test_transport.py:1228 test path "server-sig-algs": b"ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,rsa-sha2-512,rsa-sha2-256" # noqa
config.ssh-algorithms · CWE-757
DH Quantum-vulnerable Recorded traffic 17 places See details

SSH algorithms pinned in configuration

A `KexAlgorithms`, `HostKeyAlgorithms` or `Ciphers` directive in an SSH configuration. `KexAlgorithms` is the line that decides whether recorded sessions stay confidential.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Put `sntrup761x25519-sha512@openssh.com` first in `KexAlgorithms`. It is a hybrid, so it is no weaker than the classical exchange it replaces.

  1. paramiko/kex_gex.py:51 name = "diffie-hellman-group-exchange-sha256"
  2. paramiko/kex_group14.py:45 name = "diffie-hellman-group14-sha256"
  3. paramiko/kex_group16.py:30 name = "diffie-hellman-group16-sha512"
  4. paramiko/kex_group16.py:35 name = "diffie-hellman-group16-sha512"
  5. paramiko/transport.py:219 "diffie-hellman-group16-sha512",
  6. paramiko/transport.py:220 "diffie-hellman-group-exchange-sha256",
  7. paramiko/transport.py:221 "diffie-hellman-group14-sha256",
  8. paramiko/transport.py:327 "diffie-hellman-group-exchange-sha256": KexGexSHA256,
  9. paramiko/transport.py:328 "diffie-hellman-group14-sha256": KexGroup14SHA256,
  10. paramiko/transport.py:329 "diffie-hellman-group16-sha512": KexGroup16SHA512,
  11. paramiko/transport.py:412 ``diffie-hellman-group16-sha512`` key exchange (perhaps because
  12. paramiko/transport.py:415 ["diffie-hellman-group16-sha512"]}``.
  13. tests/test_transport.py:1111 test path "kex": ["diffie-hellman-group14-sha256"],
  14. tests/test_transport.py:1122 test path assert "diffie-hellman-group14-sha256" in t._preferred_kex
  15. tests/test_transport.py:1123 test path assert "diffie-hellman-group14-sha256" not in t.preferred_kex
  16. tests/test_transport.py:1132 test path "kex": ["diffie-hellman-group14-sha256"],
  17. tests/test_transport.py:1161 test path assert "diffie-hellman-group14-sha256" not in kexen
config.ssh-algorithms · CWE-757
RSA Quantum-vulnerable Recorded traffic 10 places See details

RSA key generated with pyca/cryptography

`rsa.generate_private_key()`. The `key_size` argument is read where it is a literal and reported on the finding; it does not change the classification, because Shor is polynomial in the modulus size.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. ML-KEM-768 for encryption and ML-DSA-65 for signatures.

  1. paramiko/pkey.py:103 PrivateKey = Union[RSAPrivateKey, EllipticCurvePrivateKey, Ed25519PrivateKey]
  2. paramiko/pkey.py:212 if isinstance(loaded, asymmetric.rsa.RSAPrivateKey):
  3. paramiko/rsakey.py:98 def private_key(self) -> Optional[rsa.RSAPrivateKey]:
  4. paramiko/rsakey.py:99 return self.key if isinstance(self.key, rsa.RSAPrivateKey) else None
  5. paramiko/rsakey.py:103 if isinstance(self.key, rsa.RSAPrivateKey):
  6. paramiko/rsakey.py:132 return isinstance(self.key, rsa.RSAPrivateKey)
  7. paramiko/rsakey.py:155 if isinstance(key, rsa.RSAPrivateKey):
  8. paramiko/rsakey.py:184 key = rsa.generate_private_key(
  9. paramiko/rsakey.py:222 assert isinstance(key, rsa.RSAPrivateKey)
  10. tests/pkey.py:245 test path ("rsa.key", RSAPrivateKey),
py.cryptography.rsa · CWE-327
ECDH Quantum-vulnerable Recorded traffic 9 places See details

SSH algorithms pinned in configuration

A `KexAlgorithms`, `HostKeyAlgorithms` or `Ciphers` directive in an SSH configuration. `KexAlgorithms` is the line that decides whether recorded sessions stay confidential.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Put `sntrup761x25519-sha512@openssh.com` first in `KexAlgorithms`. It is a hybrid, so it is no weaker than the classical exchange it replaces.

  1. paramiko/kex_ecdh_nist.py:21 name = "ecdh-sha2-nistp256"
  2. paramiko/kex_ecdh_nist.py:143 name = "ecdh-sha2-nistp384"
  3. paramiko/kex_ecdh_nist.py:149 name = "ecdh-sha2-nistp521"
  4. paramiko/transport.py:216 "ecdh-sha2-nistp256",
  5. paramiko/transport.py:217 "ecdh-sha2-nistp384",
  6. paramiko/transport.py:218 "ecdh-sha2-nistp521",
  7. paramiko/transport.py:330 "ecdh-sha2-nistp256": KexNistp256,
  8. paramiko/transport.py:331 "ecdh-sha2-nistp384": KexNistp384,
  9. paramiko/transport.py:332 "ecdh-sha2-nistp521": KexNistp521,
config.ssh-algorithms · CWE-757
ECDSA Quantum-vulnerable 9 places See details

Private key committed to the repository

A PEM private-key block. The header names the algorithm where the format is the legacy one; for PKCS#8 the algorithm OID is read out of the DER. A private key in version control is a present-day incident before it is a quantum question.

A secret key is stored in this repository's files. Anyone who can read the repository can use it. This needs attention today, regardless of quantum computers.

What to do. Revoke and rotate the key, then keep key material out of the repository. Record the algorithm in the inventory.

  1. tests/_support/ecdsa-256.key:1 test path -----BEGIN EC PRIVATE KEY-----
  2. tests/test_ecdsa_384.key:1 test path -----BEGIN EC PRIVATE KEY-----
  3. tests/test_ecdsa_521.key:1 test path -----BEGIN EC PRIVATE KEY-----
  4. tests/test_ecdsa_password_256.key:1 test path -----BEGIN EC PRIVATE KEY-----
  5. tests/test_ecdsa_password_384.key:1 test path -----BEGIN EC PRIVATE KEY-----
  6. tests/test_ecdsa_password_521.key:1 test path -----BEGIN EC PRIVATE KEY-----
  7. tests/test_pkey.py:88 test path -----BEGIN EC PRIVATE KEY-----
  8. tests/test_pkey.py:96 test path -----BEGIN EC PRIVATE KEY-----
  9. tests/test_pkey.py:105 test path -----BEGIN EC PRIVATE KEY-----
pem.private-key · CWE-321, CWE-327
RSA Quantum-vulnerable 7 places See details

SSH public key

An `ssh-rsa`, `ecdsa-sha2-*`, `ssh-ed25519` or `ssh-dss` key. `ssh-dss` is disabled by default in current OpenSSH and is reported as broken.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Replace `ssh-dss` now. For the rest, enable the `sntrup761x25519-sha512` key exchange, which protects recorded sessions even while host keys stay classical.

  1. tests/test_hostkeys.py:34 test path secure.example.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1PD6U2/TVxET6lkpKhOk5r\
  2. tests/test_hostkeys.py:38 test path happy.example.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA8bP1ZA7DCZDB9J0s50l31M\
  3. tests/test_pkey.py:50 test path PUB_RSA = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA049W6geFpmsljTwfvI1UmKWWJPNFI74+v
  4. tests/test_pkey.py:54 test path PUB_RSA_2K_OPENSSH = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDF+Dpr54DX0WdeTDpNAM
  5. tests/test_rsa.key.pub:1 test path ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA049W6geFpmsljTwfvI1UmKWWJPNFI74+vNKTk4dmzkQY
  6. tests/test_util.py:35 test path secure.example.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1PD6U2/TVxET6lkpKhOk5r\
  7. tests/test_util.py:38 test path happy.example.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA8bP1ZA7DCZDB9J0s50l31M\
ssh.public-key · CWE-327
RSA Quantum-vulnerable Recorded traffic 4 places See details

Private key committed to the repository

A PEM private-key block. The header names the algorithm where the format is the legacy one; for PKCS#8 the algorithm OID is read out of the DER. A private key in version control is a present-day incident before it is a quantum question.

A secret key is stored in this repository's files. Anyone who can read the repository can use it. This needs attention today, regardless of quantum computers.

What to do. Revoke and rotate the key, then keep key material out of the repository. Record the algorithm in the inventory.

  1. tests/_support/rsa-lonely.key:1 test path -----BEGIN RSA PRIVATE KEY-----
  2. tests/_support/rsa.key:1 test path -----BEGIN RSA PRIVATE KEY-----
  3. tests/test_pkey.py:70 test path -----BEGIN RSA PRIVATE KEY-----
  4. tests/test_rsa_password.key:1 test path -----BEGIN RSA PRIVATE KEY-----
pem.private-key · CWE-321, CWE-327
X25519255-bitother/Curve25519 Quantum-vulnerable Recorded traffic 4 places See details

X25519 key agreement

`X25519PrivateKey.generate()`. X25519 is the best classical key exchange available and is still a discrete-logarithm problem, so Shor solves it.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Hybrid X25519+ML-KEM-768 keeps this exact code as the classical half.

  1. paramiko/kex_curve25519.py:30 X25519PrivateKey.generate()
  2. paramiko/kex_curve25519.py:45 self.key = X25519PrivateKey.generate()
  3. paramiko/kex_mlkem.py:76 X25519PrivateKey.generate()
  4. paramiko/kex_mlkem.py:84 self.x25519_key = X25519PrivateKey.generate()
py.cryptography.x25519 · CWE-327
ECDH Quantum-vulnerable Recorded traffic 2 places See details

ECDH key agreement

`ec.ECDH()` passed to `exchange()`. Any traffic protected by this exchange and recorded now is readable once the curve is broken.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. ML-KEM-768, or hybrid X25519+ML-KEM-768.

  1. paramiko/kex_ecdh_nist.py:71 K = self.P.exchange(ec.ECDH(), self.Q_C)
  2. paramiko/kex_ecdh_nist.py:117 K = self.P.exchange(ec.ECDH(), self.Q_S)
py.cryptography.ecdh · CWE-327
ECDSA Quantum-vulnerable 2 places See details

Elliptic-curve key generated with pyca/cryptography

`ec.generate_private_key()`. The curve is read from the argument and normalised onto the CycloneDX 1.7 curve registry.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. ML-DSA-65 for signatures. If the key feeds ECDH, treat it as key establishment and prioritise it above signatures.

  1. paramiko/ecdsakey.py:268 private_key = ec.generate_private_key(curve, backend=default_backend())
  2. paramiko/kex_ecdh_nist.py:59 self.P = ec.generate_private_key(self.curve, default_backend())
py.cryptography.ec · CWE-327
ECDSAsecp256r1 Quantum-vulnerable 2 places See details

SSH public key

An `ssh-rsa`, `ecdsa-sha2-*`, `ssh-ed25519` or `ssh-dss` key. `ssh-dss` is disabled by default in current OpenSSH and is reported as broken.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Replace `ssh-dss` now. For the rest, enable the `sntrup761x25519-sha512` key exchange, which protects recorded sessions even while host keys stay classical.

  1. tests/test_hostkeys.py:43 test path curvy.example.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlz\
  2. tests/test_pkey.py:51 test path PUB_ECDSA_256 = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHA
ssh.public-key · CWE-327
ECDSAsecp384r1 Quantum-vulnerable 2 places See details

SSH public key

An `ssh-rsa`, `ecdsa-sha2-*`, `ssh-ed25519` or `ssh-dss` key. `ssh-dss` is disabled by default in current OpenSSH and is reported as broken.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Replace `ssh-dss` now. For the rest, enable the `sntrup761x25519-sha512` key exchange, which protects recorded sessions even while host keys stay classical.

  1. tests/test_pkey.py:52 test path PUB_ECDSA_384 = "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHA
  2. tests/test_pkey.py:57 test path PUB_EC_384_OPENSSH = "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbm
ssh.public-key · CWE-327
X25519255-bitother/Curve25519 Quantum-vulnerable Recorded traffic 2 places See details

SSH algorithms pinned in configuration

A `KexAlgorithms`, `HostKeyAlgorithms` or `Ciphers` directive in an SSH configuration. `KexAlgorithms` is the line that decides whether recorded sessions stay confidential.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Put `sntrup761x25519-sha512@openssh.com` first in `KexAlgorithms`. It is a hybrid, so it is no weaker than the classical exchange it replaces.

  1. paramiko/transport.py:224 _preferred_kex = ("curve25519-sha256@libssh.org",) + _preferred_kex
  2. paramiko/transport.py:335 _kex_info["curve25519-sha256@libssh.org"] = KexCurve25519
config.ssh-algorithms · CWE-757
ECDSAsecp521r1 Quantum-vulnerable 1 place See details

SSH public key

An `ssh-rsa`, `ecdsa-sha2-*`, `ssh-ed25519` or `ssh-dss` key. `ssh-dss` is disabled by default in current OpenSSH and is reported as broken.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Replace `ssh-dss` now. For the rest, enable the `sntrup761x25519-sha512` key exchange, which protects recorded sessions even while host keys stay classical.

  1. tests/test_pkey.py:53 test path PUB_ECDSA_521 = "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA
ssh.public-key · CWE-327
Ed25519ed25519 Quantum-vulnerable 1 place See details

SSH public key

An `ssh-rsa`, `ecdsa-sha2-*`, `ssh-ed25519` or `ssh-dss` key. `ssh-dss` is disabled by default in current OpenSSH and is reported as broken.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Replace `ssh-dss` now. For the rest, enable the `sntrup761x25519-sha512` key exchange, which protects recorded sessions even while host keys stay classical.

  1. tests/test_hostkeys.py:41 test path modern.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKHEChAIxsh2hr8Q\
ssh.public-key · CWE-327
EdDSA Quantum-vulnerable 1 place See details

Private key committed to the repository

A PEM private-key block. The header names the algorithm where the format is the legacy one; for PKCS#8 the algorithm OID is read out of the DER. A private key in version control is a present-day incident before it is a quantum question.

A secret key is stored in this repository's files. Anyone who can read the repository can use it. This needs attention today, regardless of quantum computers.

What to do. Revoke and rotate the key, then keep key material out of the repository. Record the algorithm in the inventory.

  1. tests/_support/ed448.key:1 test path -----BEGIN PRIVATE KEY-----
pem.private-key · CWE-321, CWE-327
AES Reduced margin 4 places See details

AES block cipher

`algorithms.AES(key)`. Symmetric encryption is not broken by a quantum computer; the key length is what matters. The key size is reported where it can be read.

This is the kind of encryption that quantum computers do not break. Using a longer key is enough.

What to do. Use a 256-bit key. No change of algorithm is required.

  1. paramiko/pkey.py:727 algorithms.AES(key), mode(iv), default_backend()
  2. tests/test_packetizer.py:49 test path algorithms.AES(zero_byte * 16),
  3. tests/test_packetizer.py:79 test path algorithms.AES(zero_byte * 16),
  4. tests/test_packetizer.py:103 test path algorithms.AES(zero_byte * 16),
py.cryptography.aes
SHA-256 Reduced margin Renamed import 1 place See details

Hash function in use

`hashlib.sha256()` and friends. The digest is read from the call, so SHA-384 and above are inventory while the broken ones are reported separately.

A quantum computer weakens this but does not break it. Increasing the key or digest size restores the margin. Pre-image resistance falls to about 128 bits of quantum work. Adequate for most uses; SHA-384 restores the full margin where a signature must last decades.

What to do. SHA-256 as the floor, SHA-384 where the digest protects something long-lived.

  1. paramiko/pkey.py:401 hashy = sha256(bytes(self))
py.hashlib
unknown Could not be determined Renamed import 21 places See details

SSH key handled by paramiko

`paramiko.RSAKey`, `ECDSAKey` or `Ed25519Key`. SSH host and user keys are long-lived, which makes them a slow and awkward thing to rotate later.

The algorithm could not be established from the source. Usually it is selected while the program runs, but it may equally be that the call gives no clue, or that it is decided somewhere this scan does not reach. Somebody has to check.

What to do. No post-quantum SSH signature is standardised yet. OpenSSH already supports the `sntrup761x25519` hybrid key exchange, which addresses the recorded-traffic half.

  1. tests/agent.py:143 test path inner_key = RSAKey.from_private_key_file(_support("rsa.key"))
  2. tests/test_client.py:126 test path host_key = paramiko.RSAKey.from_private_key_file(_support("rsa.key"))
  3. tests/test_client.py:127 test path self.public_host_key = paramiko.RSAKey(data=host_key.asbytes())
  4. tests/test_client.py:172 test path host_key = paramiko.RSAKey.from_private_key_file(keypath)
  5. tests/test_client.py:175 test path host_key = paramiko.ECDSAKey.from_private_key_file(keypath)
  6. tests/test_client.py:361 test path public_host_key = paramiko.ECDSAKey.from_private_key_file(key_file)
  7. tests/test_client.py:383 test path host_key = paramiko.RSAKey.from_private_key_file(_support("rsa.key"))
  8. tests/test_client.py:384 test path public_host_key = paramiko.RSAKey(data=host_key.asbytes())
  9. tests/test_client.py:486 test path host_key = paramiko.RSAKey.from_private_key_file(_support("rsa.key"))
  10. tests/test_client.py:487 test path public_host_key = paramiko.RSAKey(data=host_key.asbytes())
  11. tests/test_client.py:606 test path host_key = paramiko.ECDSAKey.generate()
  12. tests/test_client.py:611 test path host_key = paramiko.RSAKey.generate(2048)
  13. tests/test_client.py:615 test path self._client_host_key_good(paramiko.ECDSAKey, "ecdsa-256.key")
  14. tests/test_client.py:618 test path self._client_host_key_good(paramiko.RSAKey, "rsa.key")
  15. tests/test_hostkeys.py:89 test path key = paramiko.RSAKey(data=decodebytes(keyblob))
  16. tests/test_hostkeys.py:112 test path key = paramiko.RSAKey(data=decodebytes(keyblob))
  17. tests/test_hostkeys.py:113 test path key_ed25519 = paramiko.Ed25519Key.from_private_key_file(
  18. tests/test_kex.py:503 test path host_key = RSAKey.from_private_key_file(_support("rsa.key"))
  19. tests/test_kex.py:517 test path hostkey=RSAKey(data=host_key.asbytes()),
  20. tests/test_ssh_exception.py:60 test path got_key = RSAKey.generate(2048)
  21. tests/test_ssh_exception.py:61 test path wanted_key = RSAKey.generate(2048)
py.paramiko.key · CWE-327
unknown Could not be determined 10 places See details

Private key committed to the repository

A PEM private-key block. The header names the algorithm where the format is the legacy one; for PKCS#8 the algorithm OID is read out of the DER. A private key in version control is a present-day incident before it is a quantum question.

A secret key is stored in this repository's files. Anyone who can read the repository can use it. This needs attention today, regardless of quantum computers.

What to do. Revoke and rotate the key, then keep key material out of the repository. Record the algorithm in the inventory.

  1. tests/_support/ed25519.key:1 test path -----BEGIN OPENSSH PRIVATE KEY-----
  2. tests/_support/rsa-passphrased.key:1 test path -----BEGIN OPENSSH PRIVATE KEY-----
  3. tests/badhash_key1.ed25519.key:1 test path -----BEGIN OPENSSH PRIVATE KEY-----
  4. tests/badhash_key2.ed25519.key:1 test path -----BEGIN OPENSSH PRIVATE KEY-----
  5. tests/test_ecdsa_384_openssh.key:1 test path -----BEGIN OPENSSH PRIVATE KEY-----
  6. tests/test_ed25519-funky-padding.key:1 test path -----BEGIN OPENSSH PRIVATE KEY-----
  7. tests/test_ed25519-funky-padding_password.key:1 test path -----BEGIN OPENSSH PRIVATE KEY-----
  8. tests/test_ed25519_password.key:1 test path -----BEGIN OPENSSH PRIVATE KEY-----
  9. tests/test_rsa_openssh.key:1 test path -----BEGIN OPENSSH PRIVATE KEY-----
  10. tests/test_rsa_openssh_nopad.key:1 test path -----BEGIN OPENSSH PRIVATE KEY-----
pem.private-key · CWE-321, CWE-327
unknown Could not be determined 1 place See details

Cryptographic library in the dependency manifest

A dependency known to implement classical asymmetric cryptography. Its presence is inventory, not a finding about this codebase: the library may never be called with a quantum-vulnerable algorithm.

The project depends on a cryptography library. Listed so the inventory is complete; it is not by itself a problem.

What to do. Check the version. Several of these libraries have shipped ML-KEM and ML-DSA support since 2024, so the migration may need an upgrade rather than a replacement.

  1. pyproject.toml:2 name = "paramiko"
dep.crypto-library
CSPRNG Quantum-safe Renamed import 7 places See details

Random number generation

`secrets.token_bytes()`, `os.urandom()` or `ssl.RAND_bytes()`. Recorded so the inventory names its randomness source.

This is where the software gets its random numbers. Quantum computers do not weaken it.

What to do. No action. `random.random()` is a separate, present-day defect if it reaches key material.

  1. paramiko/channel.py:475 auth_cookie = binascii.hexlify(os.urandom(16))
  2. paramiko/hostkeys.py:294 salt = os.urandom(sha1().digest_size)
  3. paramiko/kex_gex.py:116 x_bytes = os.urandom(byte_count)
  4. paramiko/kex_group14.py:87 x_bytes = os.urandom(128)
  5. paramiko/packet.py:691 packet += os.urandom(padding)
  6. paramiko/primes.py:43 x = os.urandom(byte_count)
  7. paramiko/transport.py:1164 byte_count = (byte_ord(os.urandom(1)) % 32) + 10
py.rng
ML-KEM-768 Quantum-safe 6 places See details

SSH algorithms pinned in configuration

A `KexAlgorithms`, `HostKeyAlgorithms` or `Ciphers` directive in an SSH configuration. `KexAlgorithms` is the line that decides whether recorded sessions stay confidential.

No known quantum attack changes how strong this is. No known quantum algorithm changes the security margin.

What to do. Put `sntrup761x25519-sha512@openssh.com` first in `KexAlgorithms`. It is a hybrid, so it is no weaker than the classical exchange it replaces.

  1. paramiko/kex_mlkem.py:6 ``mlkem768x25519-sha256``).
  2. paramiko/kex_mlkem.py:47 ``mlkem768x25519-sha256`` hybrid key exchange.
  3. paramiko/kex_mlkem.py:54 name = "mlkem768x25519-sha256"
  4. paramiko/transport.py:226 _preferred_kex = ("mlkem768x25519-sha256",) + _preferred_kex
  5. paramiko/transport.py:337 _kex_info["mlkem768x25519-sha256"] = KexMLKEM768X25519
  6. tests/test_kex.py:489 test path NAME = "mlkem768x25519-sha256"
config.ssh-algorithms · CWE-757
HMAC Quantum-safe Renamed import 2 places See details

Keyed hash in use

`hmac.new()` or `hmac.digest()`. Not broken by Shor and only marginally affected by Grover. Recorded so the inventory is complete.

This is a fingerprint proving a message was not altered. Quantum computers do not break it.

What to do. No action, unless the digest is MD5 or SHA-1.

  1. paramiko/hostkeys.py:300 hmac = HMAC(salt, b(hostname), sha1).digest()
  2. paramiko/packet.py:47 return HMAC(key, message, digest_class).digest()
py.hmac
ML-KEM-768 Quantum-safe 1 place See details

Post-quantum algorithm in use

`cryptography.hazmat.primitives.asymmetric.mlkem` and its ML-DSA and SLH-DSA siblings, or a call into liboqs, `pqcrypto` or `kyber`/`dilithium` bindings. The class names carry the parameter set - `MLKEM768PrivateKey` is ML-KEM-768 - so the finding names the concrete algorithm rather than the family. Recorded so the inventory shows completed migration work.

This is already a quantum-safe algorithm.

What to do. None. Confirm the parameter set matches the required NIST category.

  1. paramiko/kex_mlkem.py:75 mlkem.MLKEM768PrivateKey.generate()
py.pqc

Cryptographic assets

Algorithm Assessment What it means Occurrences
RSASSA-PKCS1v15 Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. The v1.5 signature scheme of RFC 8017 section 8.2 has no classical break of its own; RSA-PSS is preferred for new work, but the quantum exposure is the same for both. 102
Ed25519 Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 77
ECDSA Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 57
RSA Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 33
unknown Could not be determined The algorithm could not be established from the source - chosen at runtime, or decided somewhere this scan does not reach. 31
DH Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 17
SHA-256 Reduced margin Pre-image resistance falls to about 128 bits of quantum work. Adequate for most uses; SHA-384 restores the full margin where a signature must last decades. 15
ECDH Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 11
CSPRNG Quantum-safe A cryptographically secure random number generator provided by the platform. Not weakened by a quantum computer. 7
X25519 Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 7
ML-KEM-768 Quantum-safe No known quantum algorithm changes the security margin. 7
AES Reduced margin Grover's algorithm halves the effective strength; the parameter, not the design, is the problem. The key size was not visible at this call site, so the weaker case is assumed. 4
HMAC Quantum-safe A keyed MAC is not affected by Shor and only marginally by Grover. 4
SHA-1 Already broken SHAttered and subsequent work produced practical collisions; NIST withdrew SHA-1 in 2030 guidance and it is already unacceptable for signatures. 3
bcrypt Quantum-safe A password hashing function. Grover offers only a marginal speed-up against a deliberately slow function, so quantum computing is not the concern here. 2
RSAES-PKCS1v15 Already broken PKCS#1 v1.5 encryption padding is vulnerable to Bleichenbacher oracles today, and the underlying RSA is broken by Shor. 2
MD5 Already broken Practical chosen-prefix collisions exist; MD5 has no remaining security as a digest. 1
EdDSA Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 1

Imported cryptographic libraries

Library Files
paramiko an SSH client and server 58
cryptography pyca/cryptography 12
nacl PyNaCl 1
hashlib the standard digests, including the broken ones 14
hmac keyed message authentication 2
bcrypt password hashing 2