summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README1
-rw-r--r--paramiko/dsskey.py2
-rw-r--r--paramiko/ecdsakey.py87
-rw-r--r--paramiko/util.py3
-rw-r--r--setup.py1
5 files changed, 60 insertions, 34 deletions
diff --git a/README b/README
index b6c2c957..7be87eff 100644
--- a/README
+++ b/README
@@ -37,7 +37,6 @@ Requirements
- Python 2.6 or better <http://www.python.org/> - this includes Python
3.2 and higher as well.
- Cryptography 0.6 or better <https://cryptography.io>
- - ecdsa 0.9 or better <https://pypi.python.org/pypi/ecdsa>
- pyasn1 0.1.7 or better <https://pypi.python.org/pypi/pyasn1>
If you have setuptools, you can build and install paramiko and all its
diff --git a/paramiko/dsskey.py b/paramiko/dsskey.py
index 87293e3c..496e8527 100644
--- a/paramiko/dsskey.py
+++ b/paramiko/dsskey.py
@@ -20,8 +20,6 @@
DSS keys.
"""
-import os
-
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
diff --git a/paramiko/ecdsakey.py b/paramiko/ecdsakey.py
index fefd5eb5..831fa003 100644
--- a/paramiko/ecdsakey.py
+++ b/paramiko/ecdsakey.py
@@ -20,19 +20,28 @@
ECDSA keys
"""
+import base64
import binascii
+import textwrap
from hashlib import sha256
-from ecdsa import SigningKey, VerifyingKey, der, curves
+from cryptography.exceptions import InvalidSignature
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives import hashes, serialization
+from cryptography.hazmat.primitives.asymmetric import ec
+
+from pyasn1.codec.der import decoder, encoder
from paramiko.common import four_byte, one_byte
+from paramiko.dsskey import _DSSSigValue
from paramiko.message import Message
from paramiko.pkey import PKey
from paramiko.py3compat import byte_chr, u
from paramiko.ssh_exception import SSHException
+from paramiko.util import deflate_long, inflate_long
-class ECDSAKey (PKey):
+class ECDSAKey(PKey):
"""
Representation of an ECDSA key which can be used to sign and verify SSH2
data.
@@ -65,9 +74,13 @@ class ECDSAKey (PKey):
if pointinfo[0:1] != four_byte:
raise SSHException('Point compression is being used: %s' %
binascii.hexlify(pointinfo))
- self.verifying_key = VerifyingKey.from_string(pointinfo[1:],
- curve=curves.NIST256p,
- validate_point=validate_point)
+ curve = ec.SECP256R1()
+ numbers = ec.EllipticCurvePublicNumbers(
+ x=inflate_long(pointinfo[1:1 + curve.key_size // 8], always_positive=True),
+ y=inflate_long(pointinfo[1 + curve.key_size // 8:], always_positive=True),
+ curve=curve
+ )
+ self.verifying_key = numbers.public_key(backend=default_backend())
self.size = 256
def asbytes(self):
@@ -76,8 +89,15 @@ class ECDSAKey (PKey):
m.add_string('ecdsa-sha2-nistp256')
m.add_string('nistp256')
- point_str = four_byte + key.to_string()
+ numbers = key.public_numbers()
+
+ x_bytes = deflate_long(numbers.x, add_sign_padding=False)
+ x_bytes = b'\x00' * (len(x_bytes) - key.curve.key_size // 8) + x_bytes
+ y_bytes = deflate_long(numbers.y, add_sign_padding=False)
+ y_bytes = b'\x00' * (len(y_bytes) - key.curve.key_size // 8) + y_bytes
+
+ point_str = four_byte + x_bytes + y_bytes
m.add_string(point_str)
return m.asbytes()
@@ -86,8 +106,8 @@ class ECDSAKey (PKey):
def __hash__(self):
h = hash(self.get_name())
- h = h * 37 + hash(self.verifying_key.pubkey.point.x())
- h = h * 37 + hash(self.verifying_key.pubkey.point.y())
+ h = h * 37 + hash(self.verifying_key.public_numbers().x)
+ h = h * 37 + hash(self.verifying_key.public_numbers().y)
return hash(h)
def get_name(self):
@@ -100,23 +120,34 @@ class ECDSAKey (PKey):
return self.signing_key is not None
def sign_ssh_data(self, data):
- sig = self.signing_key.sign_deterministic(
- data, sigencode=self._sigencode, hashfunc=sha256)
+ signer = self.signing_key.signer(ec.ECDSA(hashes.SHA256()))
+ signer.update(data)
+ sig = signer.finalize()
+ (r, s), _ = decoder.decode(sig)
+
m = Message()
m.add_string('ecdsa-sha2-nistp256')
- m.add_string(sig)
+ m.add_string(self._sigencode(r, s))
return m
def verify_ssh_sig(self, data, msg):
if msg.get_text() != 'ecdsa-sha2-nistp256':
return False
sig = msg.get_binary()
-
- # verify the signature by SHA'ing the data and encrypting it
- # using the public key.
- hash_obj = sha256(data).digest()
- return self.verifying_key.verify_digest(sig, hash_obj,
- sigdecode=self._sigdecode)
+ sigR, sigS = self._sigdecode(sig)
+ sig_asn1 = _DSSSigValue()
+ sig_asn1.setComponentByName('r', sigR)
+ sig_asn1.setComponentByName('s', sigS)
+ signature = encoder.encode(sig_asn1)
+
+ verifier = self.verifying_key.verifier(signature, ec.ECDSA(hashes.SHA256()))
+ verifier.update(data)
+ try:
+ verifier.verify()
+ except InvalidSignature:
+ return False
+ else:
+ return True
def write_private_key_file(self, filename, password=None):
key = self.signing_key or self.verifying_key
@@ -126,7 +157,7 @@ class ECDSAKey (PKey):
key = self.signing_key or self.verifying_key
self._write_private_key('EC', file_obj, key.to_der(), password)
- def generate(curve=curves.NIST256p, progress_func=None):
+ def generate(curve=ec.SECP256R1(), progress_func=None):
"""
Generate a new private RSA key. This factory function can be used to
generate a new host key or authentication key.
@@ -153,23 +184,23 @@ class ECDSAKey (PKey):
byte_chr(5) * 5, byte_chr(6) * 6, byte_chr(7) * 7]
def _decode_key(self, data):
- s, padding = der.remove_sequence(data)
- if padding:
- if padding not in self.ALLOWED_PADDINGS:
- raise ValueError("weird padding: %s" % u(binascii.hexlify(data)))
- data = data[:-len(padding)]
- key = SigningKey.from_der(data)
+ s = """
+-----BEGIN EC PRIVATE KEY-----
+%s
+-----END EC PRIVATE KEY-----
+""" % "\n".join(textwrap.wrap(base64.b64encode(data), 64))
+ key = serialization.load_pem_private_key(s, password=None, backend=default_backend())
self.signing_key = key
- self.verifying_key = key.get_verifying_key()
- self.size = 256
+ self.verifying_key = key.public_key()
+ self.size = key.curve.key_size
- def _sigencode(self, r, s, order):
+ def _sigencode(self, r, s):
msg = Message()
msg.add_mpint(r)
msg.add_mpint(s)
return msg.asbytes()
- def _sigdecode(self, sig, order):
+ def _sigdecode(self, sig):
msg = Message(sig)
r = msg.get_mpint()
s = msg.get_mpint()
diff --git a/paramiko/util.py b/paramiko/util.py
index 25062d00..d90fd981 100644
--- a/paramiko/util.py
+++ b/paramiko/util.py
@@ -22,7 +22,6 @@ Useful functions used by the rest of paramiko.
from __future__ import generators
-import array
from binascii import hexlify, unhexlify
import errno
import sys
@@ -32,7 +31,7 @@ import threading
import logging
from paramiko.common import DEBUG, zero_byte, xffffffff, max_byte
-from paramiko.py3compat import PY2, long, byte_ord, b, byte_chr
+from paramiko.py3compat import PY2, long, byte_ord, b
from paramiko.config import SSHConfig
diff --git a/setup.py b/setup.py
index 491f937d..e67cbd56 100644
--- a/setup.py
+++ b/setup.py
@@ -42,7 +42,6 @@ try:
kw = {
'install_requires': [
'cryptography >= 0.6',
- 'ecdsa >= 0.11',
'pyasn1 >= 0.1.7',
],
}