summaryrefslogtreecommitdiff
path: root/paramiko/pkey.py
diff options
context:
space:
mode:
Diffstat (limited to 'paramiko/pkey.py')
-rw-r--r--paramiko/pkey.py93
1 files changed, 67 insertions, 26 deletions
diff --git a/paramiko/pkey.py b/paramiko/pkey.py
index 75db8e5..4e8b26b 100644
--- a/paramiko/pkey.py
+++ b/paramiko/pkey.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2003-2005 Robey Pointer <robey@lag.net>
+# Copyright (C) 2003-2007 Robey Pointer <robey@lag.net>
#
# This file is part of paramiko.
#
@@ -21,6 +21,7 @@ Common API for all public keys.
"""
import base64
+from binascii import hexlify, unhexlify
import os
from Crypto.Hash import MD5
@@ -139,8 +140,6 @@ class PKey (object):
@return: a base64 string containing the public part of the key.
@rtype: str
-
- @since: fearow
"""
return base64.encodestring(str(self)).replace('\n', '')
@@ -173,7 +172,7 @@ class PKey (object):
"""
return False
- def from_private_key_file(cl, filename, password=None):
+ def from_private_key_file(cls, filename, password=None):
"""
Create a key object by reading a private key file. If the private
key is encrypted and C{password} is not C{None}, the given password
@@ -182,41 +181,76 @@ class PKey (object):
exist in all subclasses of PKey (such as L{RSAKey} or L{DSSKey}), but
is useless on the abstract PKey class.
- @param filename: name of the file to read.
+ @param filename: name of the file to read
@type filename: str
@param password: an optional password to use to decrypt the key file,
if it's encrypted
@type password: str
- @return: a new key object based on the given private key.
+ @return: a new key object based on the given private key
@rtype: L{PKey}
- @raise IOError: if there was an error reading the file.
+ @raise IOError: if there was an error reading the file
@raise PasswordRequiredException: if the private key file is
- encrypted, and C{password} is C{None}.
- @raise SSHException: if the key file is invalid.
-
- @since: fearow
+ encrypted, and C{password} is C{None}
+ @raise SSHException: if the key file is invalid
"""
- key = cl(filename=filename, password=password)
+ key = cls(filename=filename, password=password)
return key
from_private_key_file = classmethod(from_private_key_file)
+ def from_private_key(cls, file_obj, password=None):
+ """
+ Create a key object by reading a private key from a file (or file-like)
+ object. If the private key is encrypted and C{password} is not C{None},
+ the given password will be used to decrypt the key (otherwise
+ L{PasswordRequiredException} is thrown).
+
+ @param file_obj: the file to read from
+ @type file_obj: file
+ @param password: an optional password to use to decrypt the key, if it's
+ encrypted
+ @type password: str
+ @return: a new key object based on the given private key
+ @rtype: L{PKey}
+
+ @raise IOError: if there was an error reading the key
+ @raise PasswordRequiredException: if the private key file is encrypted,
+ and C{password} is C{None}
+ @raise SSHException: if the key file is invalid
+ """
+ key = cls(file_obj=file_obj, password=password)
+ return key
+ from_private_key = classmethod(from_private_key)
+
def write_private_key_file(self, filename, password=None):
"""
Write private key contents into a file. If the password is not
C{None}, the key is encrypted before writing.
- @param filename: name of the file to write.
+ @param filename: name of the file to write
@type filename: str
- @param password: an optional password to use to encrypt the key file.
+ @param password: an optional password to use to encrypt the key file
@type password: str
- @raise IOError: if there was an error writing the file.
- @raise SSHException: if the key is invalid.
-
- @since: fearow
+ @raise IOError: if there was an error writing the file
+ @raise SSHException: if the key is invalid
+ """
+ raise Exception('Not implemented in PKey')
+
+ def write_private_key(self, file_obj, password=None):
"""
- raise exception('Not implemented in PKey')
+ Write private key contents into a file (or file-like) object. If the
+ password is not C{None}, the key is encrypted before writing.
+
+ @param file_obj: the file object to write into
+ @type file_obj: file
+ @param password: an optional password to use to encrypt the key
+ @type password: str
+
+ @raise IOError: if there was an error writing to the file
+ @raise SSHException: if the key is invalid
+ """
+ raise Exception('Not implemented in PKey')
def _read_private_key_file(self, tag, filename, password=None):
"""
@@ -242,8 +276,12 @@ class PKey (object):
@raise SSHException: if the key file is invalid.
"""
f = open(filename, 'r')
- lines = f.readlines()
+ data = self._read_private_key(tag, f, password)
f.close()
+ return data
+
+ def _read_private_key(self, tag, f, password=None):
+ lines = f.readlines()
start = 0
while (start < len(lines)) and (lines[start].strip() != '-----BEGIN ' + tag + ' PRIVATE KEY-----'):
start += 1
@@ -265,9 +303,9 @@ class PKey (object):
# if we trudged to the end of the file, just try to cope.
try:
data = base64.decodestring(''.join(lines[start:end]))
- except binascii.Error, e:
+ except base64.binascii.Error, e:
raise SSHException('base64 decoding error: ' + str(e))
- if not headers.has_key('proc-type'):
+ if 'proc-type' not in headers:
# unencryped: done
return data
# encrypted keyfile: will need a password
@@ -277,7 +315,7 @@ class PKey (object):
encryption_type, saltstr = headers['dek-info'].split(',')
except:
raise SSHException('Can\'t parse DEK-info in private key file')
- if not self._CIPHER_TABLE.has_key(encryption_type):
+ if encryption_type not in self._CIPHER_TABLE:
raise SSHException('Unknown private key cipher "%s"' % encryption_type)
# if no password was passed in, raise an exception pointing out that we need one
if password is None:
@@ -285,7 +323,7 @@ class PKey (object):
cipher = self._CIPHER_TABLE[encryption_type]['cipher']
keysize = self._CIPHER_TABLE[encryption_type]['keysize']
mode = self._CIPHER_TABLE[encryption_type]['mode']
- salt = util.unhexify(saltstr)
+ salt = unhexlify(saltstr)
key = util.generate_key_bytes(MD5, salt, password, keysize)
return cipher.new(key, mode, salt).decrypt(data)
@@ -310,6 +348,10 @@ class PKey (object):
f = open(filename, 'w', 0600)
# grrr... the mode doesn't always take hold
os.chmod(filename, 0600)
+ self._write_private_key(tag, f, data, password)
+ f.close()
+
+ def _write_private_key(self, tag, f, data, password=None):
f.write('-----BEGIN %s PRIVATE KEY-----\n' % tag)
if password is not None:
# since we only support one cipher here, use it
@@ -327,7 +369,7 @@ class PKey (object):
data += '\0' * n
data = cipher.new(key, mode, salt).encrypt(data)
f.write('Proc-Type: 4,ENCRYPTED\n')
- f.write('DEK-Info: %s,%s\n' % (cipher_name, util.hexify(salt)))
+ f.write('DEK-Info: %s,%s\n' % (cipher_name, hexlify(salt).upper()))
f.write('\n')
s = base64.encodestring(data)
# re-wrap to 64-char lines
@@ -336,4 +378,3 @@ class PKey (object):
f.write(s)
f.write('\n')
f.write('-----END %s PRIVATE KEY-----\n' % tag)
- f.close()