diff options
author | Alex Gaynor <alex.gaynor@gmail.com> | 2015-03-18 07:54:23 -0400 |
---|---|---|
committer | Alex Gaynor <alex.gaynor@gmail.com> | 2015-03-18 07:54:23 -0400 |
commit | ffcbc09d314d710f5db87573b398be1c8c5f177c (patch) | |
tree | a33105d9d10079b749d54dbab204baadcb0ae8d8 | |
parent | 6ed173a4606e404a3908926beabc02b50a5ad8a8 (diff) |
More progress towards cleanup
-rw-r--r-- | paramiko/dsskey.py | 51 | ||||
-rw-r--r-- | paramiko/ecdsakey.py | 27 | ||||
-rw-r--r-- | paramiko/pkey.py | 51 | ||||
-rw-r--r-- | paramiko/rsakey.py | 51 |
4 files changed, 99 insertions, 81 deletions
diff --git a/paramiko/dsskey.py b/paramiko/dsskey.py index 8e0c2ba9..2f1c1ec8 100644 --- a/paramiko/dsskey.py +++ b/paramiko/dsskey.py @@ -22,7 +22,7 @@ DSS keys. from cryptography.exceptions import InvalidSignature from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import dsa from cryptography.hazmat.primitives.asymmetric.utils import ( decode_rfc6979_signature, encode_rfc6979_signature @@ -160,22 +160,45 @@ class DSSKey(PKey): else: return True - def _encode_key(self): - if self.x is None: - raise SSHException('Not enough key information') - keylist = [0, self.p, self.q, self.g, self.y, self.x] - try: - b = BER() - b.encode(keylist) - except BERException: - raise SSHException('Unable to create ber encoding of key') - return b.asbytes() - def write_private_key_file(self, filename, password=None): - self._write_private_key_file('DSA', filename, self._encode_key(), password) + key = dsa.DSAPrivateNumbers( + x=self.x, + public_numbers=dsa.DSAPublicNumbers( + y=self.y, + parameter_numbers=dsa.DSAParameterNumbers( + p=self.p, + q=self.q, + g=self.g + ) + ) + ).private_key(backend=default_backend()) + + self._write_private_key_file( + filename, + key, + serialization.Format.TraditionalOpenSSL, + password=password + ) def write_private_key(self, file_obj, password=None): - self._write_private_key('DSA', file_obj, self._encode_key(), password) + key = dsa.DSAPrivateNumbers( + x=self.x, + public_numbers=dsa.DSAPublicNumbers( + y=self.y, + parameter_numbers=dsa.DSAParameterNumbers( + p=self.p, + q=self.q, + g=self.g + ) + ) + ).private_key(backend=default_backend()) + + self._write_private_key( + file_obj, + key, + serialization.Format.TraditionalOpenSSL, + password=password + ) @staticmethod def generate(bits=1024, progress_func=None): diff --git a/paramiko/ecdsakey.py b/paramiko/ecdsakey.py index af9200c0..16a2c3db 100644 --- a/paramiko/ecdsakey.py +++ b/paramiko/ecdsakey.py @@ -144,12 +144,20 @@ class ECDSAKey(PKey): return True def write_private_key_file(self, filename, password=None): - with open(filename, "w") as f: - self.write_private_key(f, password=password) + self._write_private_key_file( + filename, + self.signing_key, + serialization.Format.TraditionalOpenSSL, + password=password + ) def write_private_key(self, file_obj, password=None): - key = self.signing_key or self.verifying_key - file_obj.write(self._to_pem(key, password=password).decode()) + self._write_private_key( + file_obj, + self.signing_key, + serialization.Format.TraditionalOpenSSL, + password=password + ) @staticmethod def generate(curve=ec.SECP256R1(), progress_func=None): @@ -182,17 +190,6 @@ class ECDSAKey(PKey): self.verifying_key = key.public_key() self.size = key.curve.key_size - def _to_pem(self, key, password): - if password is None: - encryption = serialization.NoEncryption() - else: - encryption = serialization.BestEncryption(password) - return key.private_bytes( - serialization.Encoding.PEM, - serialization.PrivateFormat.TraditionalOpenSSL, - encryption - ) - def _sigencode(self, r, s): msg = Message() msg.add_mpint(r) diff --git a/paramiko/pkey.py b/paramiko/pkey.py index 24fb0d60..b21a867c 100644 --- a/paramiko/pkey.py +++ b/paramiko/pkey.py @@ -21,15 +21,16 @@ Common API for all public keys. """ import base64 -from binascii import hexlify, unhexlify +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, zero_byte +from paramiko.common import o600 from paramiko.py3compat import u, encodebytes, decodebytes, b from paramiko.ssh_exception import SSHException, PasswordRequiredException @@ -316,7 +317,7 @@ class PKey(object): ).decryptor() return decryptor.update(data) + decryptor.finalize() - def _write_private_key_file(self, tag, filename, data, password=None): + 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 @@ -333,34 +334,16 @@ class PKey(object): with open(filename, 'w', o600) as f: # grrr... the mode doesn't always take hold os.chmod(filename, o600) - self._write_private_key(tag, f, data, password) - - def _write_private_key(self, tag, f, data, password=None): - f.write('-----BEGIN %s PRIVATE KEY-----\n' % tag) - if password is not None: - cipher_name = list(self._CIPHER_TABLE.keys())[0] - cipher = self._CIPHER_TABLE[cipher_name]['cipher'] - keysize = self._CIPHER_TABLE[cipher_name]['keysize'] - blocksize = self._CIPHER_TABLE[cipher_name]['blocksize'] - mode = self._CIPHER_TABLE[cipher_name]['mode'] - salt = os.urandom(blocksize) - key = util.generate_key_bytes(md5, salt, password, keysize) - if len(data) % blocksize != 0: - n = blocksize - len(data) % blocksize - #data += os.urandom(n) - # that would make more sense ^, but it confuses openssh. - data += zero_byte * n - encryptor = Cipher( - cipher(key), mode(salt), backend=default_backend() - ).encryptor() - data = encryptor.update(data) + encryptor.finalize() - f.write('Proc-Type: 4,ENCRYPTED\n') - f.write('DEK-Info: %s,%s\n' % (cipher_name, u(hexlify(salt)).upper())) - f.write('\n') - s = u(encodebytes(data)) - # re-wrap to 64-char lines - s = ''.join(s.split('\n')) - s = '\n'.join([s[i: i + 64] for i in range(0, len(s), 64)]) - f.write(s) - f.write('\n') - f.write('-----END %s PRIVATE KEY-----\n' % tag) + 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 + )) diff --git a/paramiko/rsakey.py b/paramiko/rsakey.py index aac57f91..17fa6104 100644 --- a/paramiko/rsakey.py +++ b/paramiko/rsakey.py @@ -20,11 +20,9 @@ RSA keys. """ -import os - from cryptography.exceptions import InvalidSignature from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import rsa, padding from paramiko import util @@ -136,24 +134,41 @@ class RSAKey(PKey): else: return True - def _encode_key(self): - if (self.p is None) or (self.q is None): - raise SSHException('Not enough key info to write private key file') - keylist = [0, self.n, self.e, self.d, self.p, self.q, - self.d % (self.p - 1), self.d % (self.q - 1), - util.mod_inverse(self.q, self.p)] - try: - b = BER() - b.encode(keylist) - except BERException: - raise SSHException('Unable to create ber encoding of key') - return b.asbytes() - def write_private_key_file(self, filename, password=None): - self._write_private_key_file('RSA', filename, self._encode_key(), password) + key = rsa.RSAPrivateNumbers( + p=self.p, + q=self.q, + d=self.d, + dmp1=self.dmp1, + dmq1=self.dmq1, + iqmp=self.iqmp, + public_numbers=rsa.RSAPublicNumbers(self.e, self.n) + ).private_key(backend=default_backend()) + + self._write_private_key_file( + filename, + key, + serialization.Format.TraditionalOpenSSL, + password=password + ) def write_private_key(self, file_obj, password=None): - self._write_private_key('RSA', file_obj, self._encode_key(), password) + key = rsa.RSAPrivateNumbers( + p=self.p, + q=self.q, + d=self.d, + dmp1=self.dmp1, + dmq1=self.dmq1, + iqmp=self.iqmp, + public_numbers=rsa.RSAPublicNumbers(self.e, self.n) + ).private_key(backend=default_backend()) + + self._write_private_key( + file_obj, + key, + serialization.Format.TraditionalOpenSSL, + password=password + ) @staticmethod def generate(bits, progress_func=None): |