Skip to content

Commit

Permalink
remove PyNaCl optional dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
glyph committed Jun 9, 2023
1 parent 34b161e commit 1716d31
Show file tree
Hide file tree
Showing 7 changed files with 6 additions and 278 deletions.
3 changes: 0 additions & 3 deletions docs/installation/howto/optional.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ The following optional dependencies are supported:

* `cryptography`_

* **conch-nacl** - **conch** options and `PyNaCl`_ to support Ed25519 keys on systems with OpenSSL < 1.1.1b.

* **soap** - the `SOAPpy`_ package to work with SOAP.

* **serial** - the `pyserial`_ package to work with serial data.
Expand Down Expand Up @@ -65,7 +63,6 @@ The following optional dependencies are supported:
.. _pyOpenSSL: https://pypi.python.org/pypi/pyOpenSSL
.. _service_identity: https://pypi.python.org/pypi/service_identity
.. _cryptography: https://pypi.python.org/pypi/cryptography
.. _PyNaCl: https://pypi.python.org/pypi/PyNaCl
.. _SOAPpy: https://pypi.python.org/pypi/SOAPpy
.. _pyserial: https://pypi.python.org/pypi/pyserial
.. _pyobjc: https://pypi.python.org/pypi/pyobjc
Expand Down
6 changes: 0 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,6 @@ conch = [
"bcrypt >= 3.1.3",
]

conch-nacl = [
"twisted[conch]",
# Used to support Ed25519 keys on systems with OpenSSL < 1.1.1b
"PyNaCl",
]

serial = [
"pyserial >= 3.0",
"pywin32 != 226; platform_system == 'Windows'",
Expand Down
1 change: 1 addition & 0 deletions src/twisted/conch/newsfragments/11871.removal
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Due to changes in the way raw private key byte serialization are handled in Cryptography, and widespread support for Ed25519 in current versions of OpenSSL, we no longer support PyNaCl as a fallback for Ed25519 keys in Conch.
104 changes: 0 additions & 104 deletions src/twisted/conch/ssh/_keys_pynacl.py

This file was deleted.

9 changes: 3 additions & 6 deletions src/twisted/conch/ssh/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,9 @@
if default_backend().ed25519_supported():
Ed25519PublicKey = ed25519.Ed25519PublicKey
Ed25519PrivateKey = ed25519.Ed25519PrivateKey
else: # pragma: no cover
try:
from twisted.conch.ssh._keys_pynacl import Ed25519PrivateKey, Ed25519PublicKey
except ImportError:
Ed25519PublicKey = None
Ed25519PrivateKey = None
else:
Ed25519PublicKey = None
Ed25519PrivateKey = None

Check warning on line 72 in src/twisted/conch/ssh/keys.py

View check run for this annotation

Codecov / codecov/patch

src/twisted/conch/ssh/keys.py#L71-L72

Added lines #L71 - L72 were not covered by tests


class BadKeyError(Exception):
Expand Down
157 changes: 1 addition & 156 deletions src/twisted/conch/test/test_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,15 @@
if cryptography is None:
skipCryptography = "Cannot run without cryptography."

_keys_pynacl = requireModule("twisted.conch.ssh._keys_pynacl")


if cryptography:
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

from twisted.conch.ssh import common, keys, sexpy

ED25519_SUPPORTED = (
default_backend().ed25519_supported() or _keys_pynacl is not None
)
ED25519_SUPPORTED = default_backend().ed25519_supported()
else:
ED25519_SUPPORTED = False

Expand Down Expand Up @@ -1665,156 +1660,6 @@ def test_reprPrivateEd25519(self):
)


class PyNaClKeyTests(KeyTests):
"""
Key tests, but forcing the use of C{PyNaCl}.
"""

if cryptography is None:
skip = skipCryptography
if _keys_pynacl is None:
skip = "Cannot run without PyNaCl"

def setUp(self):
super().setUp()
self.patch(keys, "Ed25519PublicKey", _keys_pynacl.Ed25519PublicKey)
self.patch(keys, "Ed25519PrivateKey", _keys_pynacl.Ed25519PrivateKey)

def test_naclPrivateBytes(self):
"""
L{_keys_pynacl.Ed25519PrivateKey.private_bytes} and
L{_keys_pynacl.Ed25519PrivateKey.from_private_bytes} round-trip.
"""
from cryptography.hazmat.primitives import serialization

key = _keys_pynacl.Ed25519PrivateKey.generate()
key_bytes = key.private_bytes(
serialization.Encoding.Raw,
serialization.PrivateFormat.Raw,
serialization.NoEncryption(),
)
self.assertIsInstance(key_bytes, bytes)
self.assertEqual(
key, _keys_pynacl.Ed25519PrivateKey.from_private_bytes(key_bytes)
)

def test_naclPrivateBytesInvalidParameters(self):
"""
L{_keys_pynacl.Ed25519PrivateKey.private_bytes} only accepts certain parameters.
"""
from cryptography.hazmat.primitives import serialization

key = _keys_pynacl.Ed25519PrivateKey.generate()
self.assertRaises(
ValueError,
key.private_bytes,
serialization.Encoding.PEM,
serialization.PrivateFormat.Raw,
serialization.NoEncryption(),
)
self.assertRaises(
ValueError,
key.private_bytes,
serialization.Encoding.Raw,
serialization.PrivateFormat.PKCS8,
serialization.NoEncryption(),
)
self.assertRaises(
ValueError,
key.private_bytes,
serialization.Encoding.Raw,
serialization.PrivateFormat.Raw,
serialization.BestAvailableEncryption(b"password"),
)

def test_naclPrivateHash(self):
"""
L{_keys_pynacl.Ed25519PrivateKey.__hash__} allows instances to be hashed.
"""
key = _keys_pynacl.Ed25519PrivateKey.generate()
d = {key: True}
self.assertTrue(d[key])

def test_naclPrivateEquality(self):
"""
L{_keys_pynacl.Ed25519PrivateKey} implements equality test methods.
"""
key1 = _keys_pynacl.Ed25519PrivateKey.generate()
key2 = _keys_pynacl.Ed25519PrivateKey.generate()
self.assertEqual(key1, key1)
self.assertNotEqual(key1, key2)
self.assertNotEqual(key1, bytes(key1))

def test_naclPublicBytes(self):
"""
L{_keys_pynacl.Ed25519PublicKey.public_bytes} and
L{_keys_pynacl.Ed25519PublicKey.from_public_bytes} round-trip.
"""
from cryptography.hazmat.primitives import serialization

key = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
key_bytes = key.public_bytes(
serialization.Encoding.Raw, serialization.PublicFormat.Raw
)
self.assertIsInstance(key_bytes, bytes)
self.assertEqual(
key, _keys_pynacl.Ed25519PublicKey.from_public_bytes(key_bytes)
)

def test_naclPublicBytesInvalidParameters(self):
"""
L{_keys_pynacl.Ed25519PublicKey.public_bytes} only accepts certain parameters.
"""
from cryptography.hazmat.primitives import serialization

key = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
self.assertRaises(
ValueError,
key.public_bytes,
serialization.Encoding.PEM,
serialization.PublicFormat.Raw,
)
self.assertRaises(
ValueError,
key.public_bytes,
serialization.Encoding.Raw,
serialization.PublicFormat.PKCS1,
)

def test_naclPublicHash(self):
"""
L{_keys_pynacl.Ed25519PublicKey.__hash__} allows instances to be hashed.
"""
key = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
d = {key: True}
self.assertTrue(d[key])

def test_naclPublicEquality(self):
"""
L{_keys_pynacl.Ed25519PublicKey} implements equality test methods.
"""
key1 = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
key2 = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
self.assertEqual(key1, key1)
self.assertNotEqual(key1, key2)
self.assertNotEqual(key1, bytes(key1))

def test_naclVerify(self):
"""
L{_keys_pynacl.Ed25519PublicKey.verify} raises appropriate exceptions.
"""
key = _keys_pynacl.Ed25519PrivateKey.generate()
self.assertIsInstance(key, keys.Ed25519PrivateKey)
signature = key.sign(b"test data")
self.assertIsNone(key.public_key().verify(signature, b"test data"))
self.assertRaises(
InvalidSignature, key.public_key().verify, signature, b"wrong data"
)
self.assertRaises(
InvalidSignature, key.public_key().verify, b"0" * 64, b"test data"
)


class PersistentRSAKeyTests(unittest.TestCase):
"""
Tests for L{keys._getPersistentRSAKey}.
Expand Down
4 changes: 1 addition & 3 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ extras =
; can be removed.
; We also need to include `dev_release` so that we can test our
; release helpers or documentation generation.
; `conch_nacl` is added so that we can test conch fallbacks to PyNaCl
; without requiring most users to install it.
alldeps: all_non_platform, dev_release, conch_nacl
alldeps: all_non_platform, dev_release

windows: windows_platform

Expand Down

0 comments on commit 1716d31

Please sign in to comment.