Repository: pyca/cryptography

Issue:
key_size attribute not available on elliptic curve public keys?
I'm getting `'_EllipticCurvePublicKey' object has no attribute 'key_size'` when using `cryptography` -- it looks like RSA and DSA keys have this attribute defined. This looks like a potentially inconsistent API? Or, am I using it wrong?


Discussion:
On elliptic curves you have to call `key_size` on the `EllipticCurve` class (so it'd be `key.curve.key_size`). This is definitely an inconsistency, but also relates to #1478 in that `key_size` is an inappropriate term for the degree and order of the curve (which may, but do not have to be, the same). I'm not sure how to fix this, although it's clearly a confusing API as structured 😞 

Resolving patch:
diff --git a/src/cryptography/hazmat/backends/openssl/ec.py b/src/cryptography/hazmat/backends/openssl/ec.py
--- a/src/cryptography/hazmat/backends/openssl/ec.py
+++ b/src/cryptography/hazmat/backends/openssl/ec.py
@@ -135,6 +135,10 @@ def __init__(self, backend, ec_key_cdata, evp_pkey):
 
     curve = utils.read_only_property("_curve")
 
+    @property
+    def key_size(self):
+        return self.curve.key_size
+
     def signer(self, signature_algorithm):
         _check_signature_algorithm(signature_algorithm)
         return _ECDSASignatureContext(
@@ -231,6 +235,10 @@ def __init__(self, backend, ec_key_cdata, evp_pkey):
 
     curve = utils.read_only_property("_curve")
 
+    @property
+    def key_size(self):
+        return self.curve.key_size
+
     def verifier(self, signature, signature_algorithm):
         if not isinstance(signature, bytes):
             raise TypeError("signature must be bytes.")
diff --git a/src/cryptography/hazmat/primitives/asymmetric/ec.py b/src/cryptography/hazmat/primitives/asymmetric/ec.py
--- a/src/cryptography/hazmat/primitives/asymmetric/ec.py
+++ b/src/cryptography/hazmat/primitives/asymmetric/ec.py
@@ -22,7 +22,7 @@ def name(self):
     @abc.abstractproperty
     def key_size(self):
         """
-        The bit length of the base point of the curve.
+        Bit size of a secret scalar for the curve.
         """
 
 
@@ -62,6 +62,12 @@ def curve(self):
         The EllipticCurve that this key is on.
         """
 
+    @abc.abstractproperty
+    def key_size(self):
+        """
+        Bit size of a secret scalar for the curve.
+        """
+
     @abc.abstractproperty
     def sign(self, data, signature_algorithm):
         """
@@ -98,6 +104,12 @@ def curve(self):
         The EllipticCurve that this key is on.
         """
 
+    @abc.abstractproperty
+    def key_size(self):
+        """
+        Bit size of a secret scalar for the curve.
+        """
+
     @abc.abstractmethod
     def public_numbers(self):
         """


Test patch:
diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py
--- a/tests/hazmat/primitives/test_ec.py
+++ b/tests/hazmat/primitives/test_ec.py
@@ -276,6 +276,15 @@ def test_ec_private_numbers_hash():
     assert hash(numbers1) != hash(numbers3)
 
 
+@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
+def test_ec_key_key_size(backend):
+    curve = ec.SECP256R1()
+    _skip_curve_unsupported(backend, curve)
+    key = ec.generate_private_key(curve, backend)
+    assert key.key_size == 256
+    assert key.public_key().key_size == 256
+
+
 @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
 class TestECWithNumbers(object):
     @pytest.mark.parametrize(