paramiko.ecdsakey

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 ecdsa import SigningKey, VerifyingKey, der, curves
     25  from ecdsa.util import number_to_string, sigencode_string, sigencode_strings, sigdecode_strings
     26  from Crypto.Hash import SHA256, MD5
     27  from Crypto.Cipher import DES3
     28
     29  from paramiko.common import *
     30  from paramiko import util
     31  from paramiko.message import Message
     32  from paramiko.ber import BER, BERException
     33  from paramiko.pkey import PKey
     34  from paramiko.ssh_exception import SSHException
     35
     36
     37 -class ECDSAKey (PKey):
     38      """
     39      Representation of an ECDSA key which can be used to sign and verify SSH2
     40      data.
     41      """
     42
     43 -    def __init__(self, msg=None, data=None, filename=None, password=None, vals=None, file_obj=None):
     44          self.verifying_key = None
     45          self.signing_key = None
     46          if file_obj is not None:
     47              self._from_private_key(file_obj, password)
     48              return
     49          if filename is not None:
     50              self._from_private_key_file(filename, password)
     51              return
     52          if (msg is None) and (data is not None):
     53              msg = Message(data)
     54          if vals is not None:
     55              self.verifying_key, self.signing_key = vals
     56          else:
     57              if msg is None:
     58                  raise SSHException('Key object may not be empty')
     59              if msg.get_string() != 'ecdsa-sha2-nistp256':
     60                  raise SSHException('Invalid key')
     61              curvename = msg.get_string()
     62              if curvename != 'nistp256':
     63                  raise SSHException("Can't handle curve of type %s" % curvename)
     64
     65              pointinfo = msg.get_string()
     66              if pointinfo[0] != "\x04":
     67                  raise SSHException('Point compression is being used: %s'%
     68                                     binascii.hexlify(pointinfo))
     69              self.verifying_key = VerifyingKey.from_string(pointinfo[1:],
     70                  curve=curves.NIST256p)
     71          self.size = 256
     72
     73 -    def __str__(self):
     74          key = self.verifying_key
     75          m = Message()
     76          m.add_string('ecdsa-sha2-nistp256')
     77          m.add_string('nistp256')
     78
     79          point_str = "\x04" + key.to_string()
     80
     81          m.add_string(point_str)
     82          return str(m)
     83
     84 -    def __hash__(self):
     85          h = hash(self.get_name())
     86          h = h * 37 + hash(self.verifying_key.pubkey.point.x())
     87          h = h * 37 + hash(self.verifying_key.pubkey.point.y())
     88          return hash(h)
     89
     90 -    def get_name(self):
     91          return 'ecdsa-sha2-nistp256'
     92
     93 -    def get_bits(self):
     94          return self.size
     95
     96 -    def can_sign(self):
     97          return self.signing_key is not None
     98
     99 -    def sign_ssh_data(self, rpool, data):
    100          digest = SHA256.new(data).digest()
    101          sig = self.signing_key.sign_digest(digest, entropy=rpool.read,
    102                                             sigencode=self._sigencode)
    103          m = Message()
    104          m.add_string('ecdsa-sha2-nistp256')
    105          m.add_string(sig)
    106          return m
    107
    108 -    def verify_ssh_sig(self, data, msg):
    109          if msg.get_string() != 'ecdsa-sha2-nistp256':
    110              return False
    111          sig = msg.get_string()
    112
    113          # verify the signature by SHA'ing the data and encrypting it
    114          # using the public key.
    115          hash_obj = SHA256.new(data).digest()
    116          return self.verifying_key.verify_digest(sig, hash_obj,
    117                                                  sigdecode=self._sigdecode)
    118
    119 -    def write_private_key_file(self, filename, password=None):
    120          key = self.signing_key or self.verifying_key
    121          self._write_private_key_file('EC', filename, key.to_der(), password)
    122
    123 -    def write_private_key(self, file_obj, password=None):
    124          key = self.signing_key or self.verifying_key
    125          self._write_private_key('EC', file_obj, key.to_der(), password)
    126
    127 -    def generate(bits, progress_func=None):
    128          """
    129          Generate a new private RSA key.  This factory function can be used to
    130          generate a new host key or authentication key.
    131
    132          @param bits: number of bits the generated key should be.
    133          @type bits: int
    134          @param progress_func: an optional function to call at key points in
    135              key generation (used by C{pyCrypto.PublicKey}).
    136          @type progress_func: function
    137          @return: new private key
    138          @rtype: L{RSAKey}
    139          """
    140          signing_key = ECDSA.generate()
    141          key = ECDSAKey(vals=(signing_key, signing_key.get_verifying_key()))
    142          return key
    143      generate = staticmethod(generate)
    144
    145
    146      ###  internals...
    147
    148
    149 -    def _from_private_key_file(self, filename, password):
    150          data = self._read_private_key_file('EC', filename, password)
    151          self._decode_key(data)
    152
    153 -    def _from_private_key(self, file_obj, password):
    154          data = self._read_private_key('EC', file_obj, password)
    155          self._decode_key(data)
    156
    157      ALLOWED_PADDINGS = ['\x01', '\x02\x02', '\x03\x03\x03', '\x04\x04\x04\x04',
    158                          '\x05\x05\x05\x05\x05', '\x06\x06\x06\x06\x06\x06',
    159                          '\x07\x07\x07\x07\x07\x07\x07']
    160 -    def _decode_key(self, data):
    161          s, padding = der.remove_sequence(data)
    162          if padding:
    163              if padding not in self.ALLOWED_PADDINGS:
    164                  raise ValueError, "weird padding: %s" % (binascii.hexlify(empty))
    165              data = data[:-len(padding)]
    166          key = SigningKey.from_der(data)
    167          self.signing_key = key
    168          self.verifying_key = key.get_verifying_key()
    169          self.size = 256
    170
    171 -    def _sigencode(self, r, s, order):
    172          msg = Message()
    173          msg.add_mpint(r)
    174          msg.add_mpint(s)
    175          return str(msg)
    176
    177 -    def _sigdecode(self, sig, order):
    178          msg = Message(sig)
    179          r = msg.get_mpint()
    180          s = msg.get_mpint()
    181          return (r, s)
    182