Source code for bastio.ssh.crypto
# Copyright 2013 Databracket LLC
# See LICENSE file for details.
"""
:module: bastio.ssh.crypto
:synopsis: A module for miscellaneous cryptographic facilities.
:author: Amr Ali <amr@databracket.com>
.. autoclass:: RSAKey
:members:
"""
__author__ = "Amr Ali"
__copyright__ = "Copyright 2013 Databracket LLC"
__license__ = "GPLv3+"
import base64
import StringIO
import paramiko
from bastio.mixin import public
from bastio.excepts import BastioCryptoError, reraise
@public
[docs]class RSAKey(paramiko.RSAKey):
"""A class to add a few helper functions to :class:`paramiko.RSAKey`."""
@classmethod
[docs] def generate(cls, size):
"""A wrapper around paramiko's RSAKey generation interface to add this
class's methods to it.
:param size:
The size of the RSA key pair in bits you wish to generate.
:type size:
int
:returns:
:class:`RSAKey`
"""
try:
klass = paramiko.RSAKey.generate(size)
klass.__class__ = cls
return klass
except Exception:
reraise(BastioCryptoError)
@classmethod
[docs] def from_public_key(cls, public_key):
"""Load an instance of this class with ``public_key``.
:param public_key:
An OpenSSH formatted public key.
:type public_key:
str
:returns:
:class:`RSAKey`
"""
if not cls.validate_public_key(public_key):
raise BastioCryptoError("invalid public key")
vals = public_key.split(' ')
return cls(data=base64.decodestring(vals[1]))
@classmethod
[docs] def validate_public_key(cls, data):
"""Validate public key data.
:param data:
An OpenSSH formatted public key.
[ssh-][ALGO][ ][BASE64][ ][COMMENT]
:type data:
str
:returns:
Whether the key data is valid.
"""
try:
if not data.startswith('ssh-'):
return False
vals = data.split(' ')
if len(vals) < 2: # There must be at least 'ssh-algo' and 'base64'
return False
cls(data=base64.decodestring(vals[1]))
return True
except Exception:
return False
@classmethod
[docs] def validate_private_key(cls, data):
"""Validate private key data.
:param data:
A PEM formatted private key content.
:type data:
str
:returns:
Whether the key data is valid.
"""
try:
buf = StringIO.StringIO(data)
cls.from_private_key(buf)
return True
except Exception:
return False
@classmethod
[docs] def validate_private_key_file(cls, filename):
"""Validate private key file.
:param filename:
A filename that contains PEM formatted private key data.
:type filename:
str
:returns:
Whether the key file is valid.
"""
try:
cls.from_private_key_file(filename)
return True
except Exception:
return False
[docs] def get_private_key(self):
"""Return private key data in PEM format."""
buf = StringIO.StringIO()
self.write_private_key(buf)
buf.seek(0)
return buf.read()
[docs] def get_public_key(self):
"""Return the public key in OpenSSH authorized_keys line format."""
return self.get_name() + ' ' + self.get_base64()