Revonzy Mini Shell
# Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com>
#
# This file is part of paramiko.
#
# Paramiko is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2.1 of the License, or (at your option)
# any later version.
#
# Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
"""
Common API for all public keys.
"""
import base64
from binascii import unhexlify
import os
from hashlib import md5
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.ciphers import algorithms, modes, Cipher
from paramiko import util
from paramiko.common import o600
from paramiko.py3compat import u, encodebytes, decodebytes, b
from paramiko.ssh_exception import SSHException, PasswordRequiredException
class PKey(object):
"""
Base class for public keys.
"""
# known encryption types for private key files:
_CIPHER_TABLE = {
'AES-128-CBC': {
'cipher': algorithms.AES,
'keysize': 16,
'blocksize': 16,
'mode': modes.CBC
},
'DES-EDE3-CBC': {
'cipher': algorithms.TripleDES,
'keysize': 24,
'blocksize': 8,
'mode': modes.CBC
},
}
def __init__(self, msg=None, data=None):
"""
Create a new instance of this public key type. If ``msg`` is given,
the key's public part(s) will be filled in from the message. If
``data`` is given, the key's public part(s) will be filled in from
the string.
:param .Message msg:
an optional SSH `.Message` containing a public key of this type.
:param str data: an optional string containing a public key of this type
:raises SSHException:
if a key cannot be created from the ``data`` or ``msg`` given, or
no key was passed in.
"""
pass
def asbytes(self):
"""
Return a string of an SSH `.Message` made up of the public part(s) of
this key. This string is suitable for passing to `__init__` to
re-create the key object later.
"""
return bytes()
def __str__(self):
return self.asbytes()
# noinspection PyUnresolvedReferences
def __cmp__(self, other):
"""
Compare this key to another. Returns 0 if this key is equivalent to
the given key, or non-0 if they are different. Only the public parts
of the key are compared, so a public key will compare equal to its
corresponding private key.
:param .Pkey other: key to compare to.
"""
hs = hash(self)
ho = hash(other)
if hs != ho:
return cmp(hs, ho)
return cmp(self.asbytes(), other.asbytes())
def __eq__(self, other):
return hash(self) == hash(other)
def get_name(self):
"""
Return the name of this private key implementation.
:return:
name of this private key type, in SSH terminology, as a `str` (for
example, ``"ssh-rsa"``).
"""
return ''
def get_bits(self):
"""
Return the number of significant bits in this key. This is useful
for judging the relative security of a key.
:return: bits in the key (as an `int`)
"""
return 0
def can_sign(self):
"""
Return ``True`` if this key has the private part necessary for signing
data.
"""
return False
def get_fingerprint(self):
"""
Return an MD5 fingerprint of the public part of this key. Nothing
secret is revealed.
:return:
a 16-byte `string <str>` (binary) of the MD5 fingerprint, in SSH
format.
"""
return md5(self.asbytes()).digest()
def get_base64(self):
"""
Return a base64 string containing the public part of this key. Nothing
secret is revealed. This format is compatible with that used to store
public key files or recognized host keys.
:return: a base64 `string <str>` containing the public part of the key.
"""
return u(encodebytes(self.asbytes())).replace('\n', '')
def sign_ssh_data(self, data):
"""
Sign a blob of data with this private key, and return a `.Message`
representing an SSH signature message.
:param str data: the data to sign.
:return: an SSH signature `message <.Message>`.
"""
return bytes()
def verify_ssh_sig(self, data, msg):
"""
Given a blob of data, and an SSH message representing a signature of
that data, verify that it was signed with this key.
:param str data: the data that was signed.
:param .Message msg: an SSH signature message
:return:
``True`` if the signature verifies correctly; ``False`` otherwise.
"""
return False
@classmethod
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 ``password`` is not ``None``, the given password
will be used to decrypt the key (otherwise `.PasswordRequiredException`
is thrown). Through the magic of Python, this factory method will
exist in all subclasses of PKey (such as `.RSAKey` or `.DSSKey`), but
is useless on the abstract PKey class.
:param str filename: name of the file to read
:param str password:
an optional password to use to decrypt the key file, if it's
encrypted
:return: a new `.PKey` based on the given private key
:raises IOError: if there was an error reading the file
:raises PasswordRequiredException: if the private key file is
encrypted, and ``password`` is ``None``
:raises SSHException: if the key file is invalid
"""
key = cls(filename=filename, password=password)
return key
@classmethod
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 ``password`` is not
``None``, the given password will be used to decrypt the key (otherwise
`.PasswordRequiredException` is thrown).
:param file_obj: the file-like object to read from
:param str password:
an optional password to use to decrypt the key, if it's encrypted
:return: a new `.PKey` based on the given private key
:raises IOError: if there was an error reading the key
:raises PasswordRequiredException:
if the private key file is encrypted, and ``password`` is ``None``
:raises SSHException: if the key file is invalid
"""
key = cls(file_obj=file_obj, password=password)
return key
def write_private_key_file(self, filename, password=None):
"""
Write private key contents into a file. If the password is not
``None``, the key is encrypted before writing.
:param str filename: name of the file to write
:param str password:
an optional password to use to encrypt the key file
:raises IOError: if there was an error writing the file
:raises SSHException: if the key is invalid
"""
raise Exception('Not implemented in PKey')
def write_private_key(self, file_obj, password=None):
"""
Write private key contents into a file (or file-like) object. If the
password is not ``None``, the key is encrypted before writing.
:param file_obj: the file-like object to write into
:param str password: an optional password to use to encrypt the key
:raises IOError: if there was an error writing to the file
:raises SSHException: if the key is invalid
"""
raise Exception('Not implemented in PKey')
def _read_private_key_file(self, tag, filename, password=None):
"""
Read an SSH2-format private key file, looking for a string of the type
``"BEGIN xxx PRIVATE KEY"`` for some ``xxx``, base64-decode the text we
find, and return it as a string. If the private key is encrypted and
``password`` is not ``None``, the given password will be used to decrypt
the key (otherwise `.PasswordRequiredException` is thrown).
:param str tag: ``"RSA"`` or ``"DSA"``, the tag used to mark the data block.
:param str filename: name of the file to read.
:param str password:
an optional password to use to decrypt the key file, if it's
encrypted.
:return: data blob (`str`) that makes up the private key.
:raises IOError: if there was an error reading the file.
:raises PasswordRequiredException: if the private key file is
encrypted, and ``password`` is ``None``.
:raises SSHException: if the key file is invalid.
"""
with open(filename, 'r') as f:
data = self._read_private_key(tag, f, password)
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
if start >= len(lines):
raise SSHException('not a valid ' + tag + ' private key file')
# parse any headers first
headers = {}
start += 1
while start < len(lines):
l = lines[start].split(': ')
if len(l) == 1:
break
headers[l[0].lower()] = l[1].strip()
start += 1
# find end
end = start
while end < len(lines) and lines[end].strip() != '-----END ' + tag + ' PRIVATE KEY-----':
end += 1
# if we trudged to the end of the file, just try to cope.
try:
data = decodebytes(b(''.join(lines[start:end])))
except base64.binascii.Error as e:
raise SSHException('base64 decoding error: ' + str(e))
if 'proc-type' not in headers:
# unencryped: done
return data
# encrypted keyfile: will need a password
if headers['proc-type'] != '4,ENCRYPTED':
raise SSHException('Unknown private key structure "%s"' % headers['proc-type'])
try:
encryption_type, saltstr = headers['dek-info'].split(',')
except:
raise SSHException("Can't parse DEK-info in private key file")
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:
raise PasswordRequiredException('Private key file is encrypted')
cipher = self._CIPHER_TABLE[encryption_type]['cipher']
keysize = self._CIPHER_TABLE[encryption_type]['keysize']
mode = self._CIPHER_TABLE[encryption_type]['mode']
salt = unhexlify(b(saltstr))
key = util.generate_key_bytes(md5, salt, password, keysize)
decryptor = Cipher(
cipher(key), mode(salt), backend=default_backend()
).decryptor()
return decryptor.update(data) + decryptor.finalize()
def _write_private_key_file(self, filename, key, format, password=None):
"""
Write an SSH2-format private key file in a form that can be read by
paramiko or openssh. If no password is given, the key is written in
a trivially-encoded format (base64) which is completely insecure. If
a password is given, DES-EDE3-CBC is used.
:param str tag:
``"RSA"`` or ``"DSA"``, the tag used to mark the data block.
:param filename: name of the file to write.
:param str data: data blob that makes up the private key.
:param str password: an optional password to use to encrypt the file.
:raises IOError: if there was an error writing the file.
"""
with open(filename, 'w') as f:
os.chmod(filename, o600)
self._write_private_key(f, key, format)
def _write_private_key(self, f, key, format, password=None):
if password is None:
encryption = serialization.NoEncryption()
else:
encryption = serialization.BestEncryption(password)
f.write(key.private_bytes(
serialization.Encoding.PEM,
format,
encryption
).decode())
EliteHackz.ORG
Revonzy Mini Shell
root@revonzy.com