Package paramiko :: Module ecdsakey
[frames] | no frames]

Source Code for Module paramiko.ecdsakey

  1  # Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com> 
  2  # 
  3  # This file is part of paramiko. 
  4  # 
  5  # Paramiko is free software; you can redistribute it and/or modify it under the 
  6  # terms of the GNU Lesser General Public License as published by the Free 
  7  # Software Foundation; either version 2.1 of the License, or (at your option) 
  8  # any later version. 
  9  # 
 10  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY 
 11  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 
 12  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
 13  # details. 
 14  # 
 15  # You should have received a copy of the GNU Lesser General Public License 
 16  # along with Paramiko; if not, write to the Free Software Foundation, Inc., 
 17  # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. 
 18   
 19  """ 
 20  L{ECDSAKey} 
 21  """ 
 22   
 23  import binascii 
 24  from hashlib import sha256 
 25   
 26  from ecdsa import SigningKey, VerifyingKey, der, curves 
 27  from ecdsa.test_pyecdsa import ECDSA 
 28   
 29  from paramiko.common import four_byte, one_byte 
 30  from paramiko.message import Message 
 31  from paramiko.pkey import PKey 
 32  from paramiko.py3compat import byte_chr, u 
 33  from paramiko.ssh_exception import SSHException 
 34   
 35   
36 -class ECDSAKey (PKey):
37 """ 38 Representation of an ECDSA key which can be used to sign and verify SSH2 39 data. 40 """ 41
42 - def __init__(self, msg=None, data=None, filename=None, password=None, vals=None, file_obj=None):
43 self.verifying_key = None 44 self.signing_key = None 45 if file_obj is not None: 46 self._from_private_key(file_obj, password) 47 return 48 if filename is not None: 49 self._from_private_key_file(filename, password) 50 return 51 if (msg is None) and (data is not None): 52 msg = Message(data) 53 if vals is not None: 54 self.verifying_key, self.signing_key = vals 55 else: 56 if msg is None: 57 raise SSHException('Key object may not be empty') 58 if msg.get_text() != 'ecdsa-sha2-nistp256': 59 raise SSHException('Invalid key') 60 curvename = msg.get_text() 61 if curvename != 'nistp256': 62 raise SSHException("Can't handle curve of type %s" % curvename) 63 64 pointinfo = msg.get_binary() 65 if pointinfo[0:1] != four_byte: 66 raise SSHException('Point compression is being used: %s' % 67 binascii.hexlify(pointinfo)) 68 self.verifying_key = VerifyingKey.from_string(pointinfo[1:], 69 curve=curves.NIST256p) 70 self.size = 256
71
72 - def asbytes(self):
73 key = self.verifying_key 74 m = Message() 75 m.add_string('ecdsa-sha2-nistp256') 76 m.add_string('nistp256') 77 78 point_str = four_byte + key.to_string() 79 80 m.add_string(point_str) 81 return m.asbytes()
82
83 - def __str__(self):
84 return self.asbytes()
85
86 - def __hash__(self):
87 h = hash(self.get_name()) 88 h = h * 37 + hash(self.verifying_key.pubkey.point.x()) 89 h = h * 37 + hash(self.verifying_key.pubkey.point.y()) 90 return hash(h)
91
92 - def get_name(self):
93 return 'ecdsa-sha2-nistp256'
94
95 - def get_bits(self):
96 return self.size
97
98 - def can_sign(self):
99 return self.signing_key is not None
100
101 - def sign_ssh_data(self, data):
102 sig = self.signing_key.sign_deterministic( 103 data, sigencode=self._sigencode, hashfunc=sha256) 104 m = Message() 105 m.add_string('ecdsa-sha2-nistp256') 106 m.add_string(sig) 107 return m
108
109 - def verify_ssh_sig(self, data, msg):
110 if msg.get_text() != 'ecdsa-sha2-nistp256': 111 return False 112 sig = msg.get_binary() 113 114 # verify the signature by SHA'ing the data and encrypting it 115 # using the public key. 116 hash_obj = sha256(data).digest() 117 return self.verifying_key.verify_digest(sig, hash_obj, 118 sigdecode=self._sigdecode)
119
120 - def write_private_key_file(self, filename, password=None):
121 key = self.signing_key or self.verifying_key 122 self._write_private_key_file('EC', filename, key.to_der(), password)
123
124 - def write_private_key(self, file_obj, password=None):
125 key = self.signing_key or self.verifying_key 126 self._write_private_key('EC', file_obj, key.to_der(), password)
127
128 - def generate(bits, progress_func=None):
129 """ 130 Generate a new private RSA key. This factory function can be used to 131 generate a new host key or authentication key. 132 133 @param bits: number of bits the generated key should be. 134 @type bits: int 135 @param progress_func: an optional function to call at key points in 136 key generation (used by C{pyCrypto.PublicKey}). 137 @type progress_func: function 138 @return: new private key 139 @rtype: L{RSAKey} 140 """ 141 signing_key = ECDSA.generate() 142 key = ECDSAKey(vals=(signing_key, signing_key.get_verifying_key())) 143 return key
144 generate = staticmethod(generate) 145 146 ### internals... 147
148 - def _from_private_key_file(self, filename, password):
149 data = self._read_private_key_file('EC', filename, password) 150 self._decode_key(data)
151
152 - def _from_private_key(self, file_obj, password):
153 data = self._read_private_key('EC', file_obj, password) 154 self._decode_key(data)
155 156 ALLOWED_PADDINGS = [one_byte, byte_chr(2) * 2, byte_chr(3) * 3, byte_chr(4) * 4, 157 byte_chr(5) * 5, byte_chr(6) * 6, byte_chr(7) * 7] 158
159 - def _decode_key(self, data):
160 s, padding = der.remove_sequence(data) 161 if padding: 162 if padding not in self.ALLOWED_PADDINGS: 163 raise ValueError("weird padding: %s" % u(binascii.hexlify(data))) 164 data = data[:-len(padding)] 165 key = SigningKey.from_der(data) 166 self.signing_key = key 167 self.verifying_key = key.get_verifying_key() 168 self.size = 256
169
170 - def _sigencode(self, r, s, order):
171 msg = Message() 172 msg.add_mpint(r) 173 msg.add_mpint(s) 174 return msg.asbytes()
175
176 - def _sigdecode(self, sig, order):
177 msg = Message(sig) 178 r = msg.get_mpint() 179 s = msg.get_mpint() 180 return r, s
181