Switched hash functions from PyCrypto to hashlib.
There's a few advantages to this: 1) It's probably fast, OpenSSL, which typically backs hashlib, receives far more attention for optimizaitons than PyCrypto. 2) It's the first step to supporting PyPy, where PyCrypto doesn't run.
This commit is contained in:
parent
5a430def22
commit
4d3e0b711a
|
@ -20,8 +20,9 @@
|
|||
DSS keys.
|
||||
"""
|
||||
|
||||
from hashlib import sha1
|
||||
|
||||
from Crypto.PublicKey import DSA
|
||||
from Crypto.Hash import SHA
|
||||
|
||||
from paramiko import util
|
||||
from paramiko.common import zero_byte, rng
|
||||
|
@ -96,7 +97,7 @@ class DSSKey (PKey):
|
|||
return self.x is not None
|
||||
|
||||
def sign_ssh_data(self, rng, data):
|
||||
digest = SHA.new(data).digest()
|
||||
digest = sha1(data).digest()
|
||||
dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q), long(self.x)))
|
||||
# generate a suitable k
|
||||
qsize = len(util.deflate_long(self.q, 0))
|
||||
|
@ -130,7 +131,7 @@ class DSSKey (PKey):
|
|||
# pull out (r, s) which are NOT encoded as mpints
|
||||
sigR = util.inflate_long(sig[:20], 1)
|
||||
sigS = util.inflate_long(sig[20:], 1)
|
||||
sigM = util.inflate_long(SHA.new(data).digest(), 1)
|
||||
sigM = util.inflate_long(sha1(data).digest(), 1)
|
||||
|
||||
dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q)))
|
||||
return dss.verify(sigM, (sigR, sigS))
|
||||
|
|
|
@ -21,11 +21,12 @@ L{ECDSAKey}
|
|||
"""
|
||||
|
||||
import binascii
|
||||
from ecdsa import SigningKey, VerifyingKey, der, curves
|
||||
from Crypto.Hash import SHA256
|
||||
from ecdsa.test_pyecdsa import ECDSA
|
||||
from paramiko.common import four_byte, one_byte
|
||||
from hashlib import sha256
|
||||
|
||||
from ecdsa import SigningKey, VerifyingKey, der, curves
|
||||
from ecdsa.test_pyecdsa import ECDSA
|
||||
|
||||
from paramiko.common import four_byte, one_byte
|
||||
from paramiko.message import Message
|
||||
from paramiko.pkey import PKey
|
||||
from paramiko.py3compat import byte_chr, u
|
||||
|
@ -98,7 +99,7 @@ class ECDSAKey (PKey):
|
|||
return self.signing_key is not None
|
||||
|
||||
def sign_ssh_data(self, rpool, data):
|
||||
digest = SHA256.new(data).digest()
|
||||
digest = sha256(data).digest()
|
||||
sig = self.signing_key.sign_digest(digest, entropy=rpool.read,
|
||||
sigencode=self._sigencode)
|
||||
m = Message()
|
||||
|
@ -113,7 +114,7 @@ class ECDSAKey (PKey):
|
|||
|
||||
# verify the signature by SHA'ing the data and encrypting it
|
||||
# using the public key.
|
||||
hash_obj = SHA256.new(data).digest()
|
||||
hash_obj = sha256(data).digest()
|
||||
return self.verifying_key.verify_digest(sig, hash_obj,
|
||||
sigdecode=self._sigdecode)
|
||||
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
|
||||
|
||||
import binascii
|
||||
from Crypto.Hash import SHA, HMAC
|
||||
from hashlib import sha1
|
||||
from hmac import HMAC
|
||||
|
||||
from paramiko.common import rng
|
||||
from paramiko.py3compat import b, u, encodebytes, decodebytes
|
||||
|
||||
|
@ -262,13 +264,13 @@ class HostKeys (MutableMapping):
|
|||
:return: the hashed hostname as a `str`
|
||||
"""
|
||||
if salt is None:
|
||||
salt = rng.read(SHA.digest_size)
|
||||
salt = rng.read(sha1().digest_size)
|
||||
else:
|
||||
if salt.startswith('|1|'):
|
||||
salt = salt.split('|')[2]
|
||||
salt = decodebytes(b(salt))
|
||||
assert len(salt) == SHA.digest_size
|
||||
hmac = HMAC.HMAC(salt, b(hostname), SHA).digest()
|
||||
assert len(salt) == sha1().digest_size
|
||||
hmac = HMAC(salt, b(hostname), sha1).digest()
|
||||
hostkey = '|1|%s|%s' % (u(encodebytes(salt)), u(encodebytes(hmac)))
|
||||
return hostkey.replace('\n', '')
|
||||
hash_host = staticmethod(hash_host)
|
||||
|
|
|
@ -22,7 +22,7 @@ generator "g" are provided by the server. A bit more work is required on the
|
|||
client side, and a B{lot} more on the server side.
|
||||
"""
|
||||
|
||||
from Crypto.Hash import SHA
|
||||
from hashlib import sha1
|
||||
|
||||
from paramiko import util
|
||||
from paramiko.common import DEBUG
|
||||
|
@ -203,7 +203,7 @@ class KexGex (object):
|
|||
hm.add_mpint(self.e)
|
||||
hm.add_mpint(self.f)
|
||||
hm.add_mpint(K)
|
||||
H = SHA.new(hm.asbytes()).digest()
|
||||
H = sha1(hm.asbytes()).digest()
|
||||
self.transport._set_K_H(K, H)
|
||||
# sign it
|
||||
sig = self.transport.get_server_key().sign_ssh_data(self.transport.rng, H)
|
||||
|
@ -238,6 +238,6 @@ class KexGex (object):
|
|||
hm.add_mpint(self.e)
|
||||
hm.add_mpint(self.f)
|
||||
hm.add_mpint(K)
|
||||
self.transport._set_K_H(K, SHA.new(hm.asbytes()).digest())
|
||||
self.transport._set_K_H(K, sha1(hm.asbytes()).digest())
|
||||
self.transport._verify_key(host_key, sig)
|
||||
self.transport._activate_outbound()
|
||||
|
|
|
@ -21,7 +21,7 @@ Standard SSH key exchange ("kex" if you wanna sound cool). Diffie-Hellman of
|
|||
1024 bit key halves, using a known "p" prime and "g" generator.
|
||||
"""
|
||||
|
||||
from Crypto.Hash import SHA
|
||||
from hashlib import sha1
|
||||
|
||||
from paramiko import util
|
||||
from paramiko.common import max_byte, zero_byte
|
||||
|
@ -105,7 +105,7 @@ class KexGroup1(object):
|
|||
hm.add_mpint(self.e)
|
||||
hm.add_mpint(self.f)
|
||||
hm.add_mpint(K)
|
||||
self.transport._set_K_H(K, SHA.new(hm.asbytes()).digest())
|
||||
self.transport._set_K_H(K, sha1(hm.asbytes()).digest())
|
||||
self.transport._verify_key(host_key, sig)
|
||||
self.transport._activate_outbound()
|
||||
|
||||
|
@ -124,7 +124,7 @@ class KexGroup1(object):
|
|||
hm.add_mpint(self.e)
|
||||
hm.add_mpint(self.f)
|
||||
hm.add_mpint(K)
|
||||
H = SHA.new(hm.asbytes()).digest()
|
||||
H = sha1(hm.asbytes()).digest()
|
||||
self.transport._set_K_H(K, H)
|
||||
# sign it
|
||||
sig = self.transport.get_server_key().sign_ssh_data(self.transport.rng, H)
|
||||
|
|
|
@ -25,6 +25,7 @@ import socket
|
|||
import struct
|
||||
import threading
|
||||
import time
|
||||
from hmac import HMAC
|
||||
|
||||
from paramiko import util
|
||||
from paramiko.common import linefeed_byte, cr_byte_value, asbytes, MSG_NAMES, \
|
||||
|
@ -34,12 +35,6 @@ from paramiko.ssh_exception import SSHException, ProxyCommandFailure
|
|||
from paramiko.message import Message
|
||||
|
||||
|
||||
try:
|
||||
from r_hmac import HMAC
|
||||
except ImportError:
|
||||
from Crypto.Hash.HMAC import HMAC
|
||||
|
||||
|
||||
def compute_hmac(key, message, digest_class):
|
||||
return HMAC(key, message, digest_class).digest()
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ Common API for all public keys.
|
|||
import base64
|
||||
from binascii import hexlify, unhexlify
|
||||
import os
|
||||
from hashlib import md5
|
||||
|
||||
from Crypto.Hash import MD5
|
||||
from Crypto.Cipher import DES3, AES
|
||||
|
||||
from paramiko import util
|
||||
|
@ -126,7 +126,7 @@ class PKey (object):
|
|||
a 16-byte `string <str>` (binary) of the MD5 fingerprint, in SSH
|
||||
format.
|
||||
"""
|
||||
return MD5.new(self.asbytes()).digest()
|
||||
return md5(self.asbytes()).digest()
|
||||
|
||||
def get_base64(self):
|
||||
"""
|
||||
|
@ -300,7 +300,7 @@ class PKey (object):
|
|||
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)
|
||||
key = util.generate_key_bytes(md5, salt, password, keysize)
|
||||
return cipher.new(key, mode, salt).decrypt(data)
|
||||
|
||||
def _write_private_key_file(self, tag, filename, data, password=None):
|
||||
|
@ -332,7 +332,7 @@ class PKey (object):
|
|||
blocksize = self._CIPHER_TABLE[cipher_name]['blocksize']
|
||||
mode = self._CIPHER_TABLE[cipher_name]['mode']
|
||||
salt = rng.read(16)
|
||||
key = util.generate_key_bytes(MD5, salt, password, keysize)
|
||||
key = util.generate_key_bytes(md5, salt, password, keysize)
|
||||
if len(data) % blocksize != 0:
|
||||
n = blocksize - len(data) % blocksize
|
||||
#data += rng.read(n)
|
||||
|
|
|
@ -20,8 +20,9 @@
|
|||
RSA keys.
|
||||
"""
|
||||
|
||||
from hashlib import sha1
|
||||
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.Hash import SHA
|
||||
|
||||
from paramiko import util
|
||||
from paramiko.common import rng, max_byte, zero_byte, one_byte
|
||||
|
@ -91,7 +92,7 @@ class RSAKey (PKey):
|
|||
return self.d is not None
|
||||
|
||||
def sign_ssh_data(self, rpool, data):
|
||||
digest = SHA.new(data).digest()
|
||||
digest = sha1(data).digest()
|
||||
rsa = RSA.construct((long(self.n), long(self.e), long(self.d)))
|
||||
sig = util.deflate_long(rsa.sign(self._pkcs1imify(digest), bytes())[0], 0)
|
||||
m = Message()
|
||||
|
@ -106,7 +107,7 @@ class RSAKey (PKey):
|
|||
# verify the signature by SHA'ing the data and encrypting it using the
|
||||
# public key. some wackiness ensues where we "pkcs1imify" the 20-byte
|
||||
# hash into a string as long as the RSA key.
|
||||
hash_obj = util.inflate_long(self._pkcs1imify(SHA.new(data).digest()), True)
|
||||
hash_obj = util.inflate_long(self._pkcs1imify(sha1(data).digest()), True)
|
||||
rsa = RSA.construct((long(self.n), long(self.e)))
|
||||
return rsa.verify(hash_obj, (sig,))
|
||||
|
||||
|
|
|
@ -22,9 +22,9 @@ Server-mode SFTP support.
|
|||
|
||||
import os
|
||||
import errno
|
||||
|
||||
from Crypto.Hash import MD5, SHA
|
||||
import sys
|
||||
from hashlib import md5, sha1
|
||||
|
||||
from paramiko import util
|
||||
from paramiko.sftp import BaseSFTP, Message, SFTP_FAILURE, \
|
||||
SFTP_PERMISSION_DENIED, SFTP_NO_SUCH_FILE
|
||||
|
@ -45,8 +45,8 @@ from paramiko.sftp import CMD_HANDLE, SFTP_DESC, CMD_STATUS, SFTP_EOF, CMD_NAME,
|
|||
CMD_READLINK, CMD_SYMLINK, CMD_REALPATH, CMD_EXTENDED, SFTP_OP_UNSUPPORTED
|
||||
|
||||
_hash_class = {
|
||||
'sha1': SHA,
|
||||
'md5': MD5,
|
||||
'sha1': sha1,
|
||||
'md5': md5,
|
||||
}
|
||||
|
||||
|
||||
|
@ -281,7 +281,7 @@ class SFTPServer (BaseSFTP, SubsystemHandler):
|
|||
# don't try to read more than about 64KB at a time
|
||||
chunklen = min(blocklen, 65536)
|
||||
count = 0
|
||||
hash_obj = alg.new()
|
||||
hash_obj = alg()
|
||||
while count < blocklen:
|
||||
data = f.read(offset, chunklen)
|
||||
if not isinstance(data, bytes_types):
|
||||
|
|
|
@ -25,6 +25,7 @@ import sys
|
|||
import threading
|
||||
import time
|
||||
import weakref
|
||||
from hashlib import md5, sha1
|
||||
|
||||
import paramiko
|
||||
from paramiko import util
|
||||
|
@ -59,7 +60,6 @@ from paramiko.util import retry_on_signal
|
|||
|
||||
from Crypto import Random
|
||||
from Crypto.Cipher import Blowfish, AES, DES3, ARC4
|
||||
from Crypto.Hash import SHA, MD5
|
||||
try:
|
||||
from Crypto.Util import Counter
|
||||
except ImportError:
|
||||
|
@ -107,10 +107,10 @@ class Transport (threading.Thread):
|
|||
}
|
||||
|
||||
_mac_info = {
|
||||
'hmac-sha1': {'class': SHA, 'size': 20},
|
||||
'hmac-sha1-96': {'class': SHA, 'size': 12},
|
||||
'hmac-md5': {'class': MD5, 'size': 16},
|
||||
'hmac-md5-96': {'class': MD5, 'size': 12},
|
||||
'hmac-sha1': {'class': sha1, 'size': 20},
|
||||
'hmac-sha1-96': {'class': sha1, 'size': 12},
|
||||
'hmac-md5': {'class': md5, 'size': 16},
|
||||
'hmac-md5-96': {'class': md5, 'size': 12},
|
||||
}
|
||||
|
||||
_key_info = {
|
||||
|
@ -1338,13 +1338,13 @@ class Transport (threading.Thread):
|
|||
m.add_bytes(self.H)
|
||||
m.add_byte(b(id))
|
||||
m.add_bytes(self.session_id)
|
||||
out = sofar = SHA.new(m.asbytes()).digest()
|
||||
out = sofar = sha1(m.asbytes()).digest()
|
||||
while len(out) < nbytes:
|
||||
m = Message()
|
||||
m.add_mpint(self.K)
|
||||
m.add_bytes(self.H)
|
||||
m.add_bytes(sofar)
|
||||
digest = SHA.new(m.asbytes()).digest()
|
||||
digest = sha1(m.asbytes()).digest()
|
||||
out += digest
|
||||
sofar += digest
|
||||
return out[:nbytes]
|
||||
|
@ -1719,9 +1719,9 @@ class Transport (threading.Thread):
|
|||
# initial mac keys are done in the hash's natural size (not the potentially truncated
|
||||
# transmission size)
|
||||
if self.server_mode:
|
||||
mac_key = self._compute_key('E', mac_engine.digest_size)
|
||||
mac_key = self._compute_key('E', mac_engine().digest_size)
|
||||
else:
|
||||
mac_key = self._compute_key('F', mac_engine.digest_size)
|
||||
mac_key = self._compute_key('F', mac_engine().digest_size)
|
||||
self.packetizer.set_inbound_cipher(engine, block_size, mac_engine, mac_size, mac_key)
|
||||
compress_in = self._compression_info[self.remote_compression][1]
|
||||
if (compress_in is not None) and ((self.remote_compression != 'zlib@openssh.com') or self.authenticated):
|
||||
|
@ -1746,9 +1746,9 @@ class Transport (threading.Thread):
|
|||
# initial mac keys are done in the hash's natural size (not the potentially truncated
|
||||
# transmission size)
|
||||
if self.server_mode:
|
||||
mac_key = self._compute_key('F', mac_engine.digest_size)
|
||||
mac_key = self._compute_key('F', mac_engine().digest_size)
|
||||
else:
|
||||
mac_key = self._compute_key('E', mac_engine.digest_size)
|
||||
mac_key = self._compute_key('E', mac_engine().digest_size)
|
||||
sdctr = self.local_cipher.endswith('-ctr')
|
||||
self.packetizer.set_outbound_cipher(engine, block_size, mac_engine, mac_size, mac_key, sdctr)
|
||||
compress_out = self._compression_info[self.local_compression][0]
|
||||
|
|
|
@ -143,15 +143,14 @@ def tb_strings():
|
|||
return ''.join(traceback.format_exception(*sys.exc_info())).split('\n')
|
||||
|
||||
|
||||
def generate_key_bytes(hashclass, salt, key, nbytes):
|
||||
def generate_key_bytes(hash_alg, salt, key, nbytes):
|
||||
"""
|
||||
Given a password, passphrase, or other human-source key, scramble it
|
||||
through a secure hash into some keyworthy bytes. This specific algorithm
|
||||
is used for encrypting/decrypting private key files.
|
||||
|
||||
:param class hashclass:
|
||||
class from `Crypto.Hash` that can be used as a secure hashing function
|
||||
(like ``MD5`` or ``SHA``).
|
||||
:param function hash_alg: A function which creates a new hash object, such
|
||||
as ``hashlib.sha256``.
|
||||
:param salt: data to salt the hash with.
|
||||
:type salt: byte string
|
||||
:param str key: human-entered password or passphrase.
|
||||
|
@ -163,7 +162,7 @@ def generate_key_bytes(hashclass, salt, key, nbytes):
|
|||
if len(salt) > 8:
|
||||
salt = salt[:8]
|
||||
while nbytes > 0:
|
||||
hash_obj = hashclass.new()
|
||||
hash_obj = hash_alg()
|
||||
if len(digest) > 0:
|
||||
hash_obj.update(digest)
|
||||
hash_obj.update(b(key))
|
||||
|
|
|
@ -21,9 +21,12 @@ Some unit tests for the ssh2 protocol in Transport.
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from hashlib import sha1
|
||||
|
||||
from tests.loop import LoopSocket
|
||||
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Hash import SHA
|
||||
|
||||
from paramiko import Message, Packetizer, util
|
||||
from paramiko.common import byte_chr, zero_byte
|
||||
|
||||
|
@ -41,7 +44,7 @@ class PacketizerTest (unittest.TestCase):
|
|||
p.set_log(util.get_logger('paramiko.transport'))
|
||||
p.set_hexdump(True)
|
||||
cipher = AES.new(zero_byte * 16, AES.MODE_CBC, x55 * 16)
|
||||
p.set_outbound_cipher(cipher, 16, SHA, 12, x1f * 20)
|
||||
p.set_outbound_cipher(cipher, 16, sha1, 12, x1f * 20)
|
||||
|
||||
# message has to be at least 16 bytes long, so we'll have at least one
|
||||
# block of data encrypted that contains zero random padding bytes
|
||||
|
@ -64,7 +67,7 @@ class PacketizerTest (unittest.TestCase):
|
|||
p.set_log(util.get_logger('paramiko.transport'))
|
||||
p.set_hexdump(True)
|
||||
cipher = AES.new(zero_byte * 16, AES.MODE_CBC, x55 * 16)
|
||||
p.set_inbound_cipher(cipher, 16, SHA, 12, x1f * 20)
|
||||
p.set_inbound_cipher(cipher, 16, sha1, 12, x1f * 20)
|
||||
wsock.send(b'\x43\x91\x97\xbd\x5b\x50\xac\x25\x87\xc2\xc4\x6b\xc7\xe9\x38\xc0\x90\xd2\x16\x56\x0d\x71\x73\x61\x38\x7c\x4c\x3d\xfb\x97\x7d\xe2\x6e\x03\xb1\xa0\xc2\x1c\xd6\x41\x41\x4c\xb4\x59')
|
||||
cmd, m = p.read_message()
|
||||
self.assertEqual(100, cmd)
|
||||
|
|
|
@ -20,11 +20,14 @@
|
|||
Some unit tests for public/private key objects.
|
||||
"""
|
||||
|
||||
from binascii import hexlify
|
||||
import unittest
|
||||
from binascii import hexlify
|
||||
from hashlib import md5
|
||||
|
||||
from paramiko import RSAKey, DSSKey, ECDSAKey, Message, util
|
||||
from paramiko.py3compat import StringIO, byte_chr, b, bytes
|
||||
from paramiko.common import rng
|
||||
|
||||
from tests.util import test_path
|
||||
|
||||
# from openssh's ssh-keygen
|
||||
|
@ -90,8 +93,7 @@ class KeyTest (unittest.TestCase):
|
|||
pass
|
||||
|
||||
def test_1_generate_key_bytes(self):
|
||||
from Crypto.Hash import MD5
|
||||
key = util.generate_key_bytes(MD5, x1234, 'happy birthday', 30)
|
||||
key = util.generate_key_bytes(md5, x1234, 'happy birthday', 30)
|
||||
exp = b'\x61\xE1\xF2\x72\xF4\xC1\xC4\x56\x15\x86\xBD\x32\x24\x98\xC0\xE9\x24\x67\x27\x80\xF4\x7B\xB3\x7D\xDA\x7D\x54\x01\x9E\x64'
|
||||
self.assertEqual(exp, key)
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ Some unit tests for utility functions.
|
|||
from binascii import hexlify
|
||||
import errno
|
||||
import os
|
||||
from Crypto.Hash import SHA
|
||||
from hashlib import sha1
|
||||
|
||||
import paramiko.util
|
||||
from paramiko.util import lookup_ssh_host_config as host_config
|
||||
from paramiko.py3compat import StringIO, byte_ord
|
||||
|
@ -136,7 +137,7 @@ class UtilTest(ParamikoTest):
|
|||
)
|
||||
|
||||
def test_4_generate_key_bytes(self):
|
||||
x = paramiko.util.generate_key_bytes(SHA, b'ABCDEFGH', 'This is my secret passphrase.', 64)
|
||||
x = paramiko.util.generate_key_bytes(sha1, b'ABCDEFGH', 'This is my secret passphrase.', 64)
|
||||
hex = ''.join(['%02x' % byte_ord(c) for c in x])
|
||||
self.assertEqual(hex, '9110e2f6793b69363e58173e9436b13a5a4b339005741d5c680e505f57d871347b4239f14fb5c46e857d5e100424873ba849ac699cea98d729e57b3e84378e8b')
|
||||
|
||||
|
|
Loading…
Reference in New Issue