diff options
35 files changed, 602 insertions, 949 deletions
diff --git a/lib/Crypto/Hash/MD2.py b/lib/Crypto/Hash/MD2.py deleted file mode 100644 index dac959e..0000000 --- a/lib/Crypto/Hash/MD2.py +++ /dev/null @@ -1,91 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""MD2 cryptographic hash algorithm. - -MD2 is specified in RFC1319_ and it produces the 128 bit digest of a message. - - >>> from Crypto.Hash import MD2 - >>> - >>> h = MD2.new() - >>> h.update(b'Hello') - >>> print h.hexdigest() - -MD2 stand for Message Digest version 2, and it was invented by Rivest in 1989. - -This algorithm is both slow and insecure. Do not use it for new designs. - -.. _RFC1319: http://tools.ietf.org/html/rfc1319 -""" - -_revision__ = "$Id$" - -__all__ = ['new', 'digest_size', 'MD2Hash' ] - -from Crypto.Util.py3compat import * -from Crypto.Hash.hashalgo import HashAlgo - -import Crypto.Hash._MD2 as _MD2 -hashFactory = _MD2 - -class MD2Hash(HashAlgo): - """Class that implements an MD2 hash - - :undocumented: block_size - """ - - #: ASN.1 Object identifier (OID):: - #: - #: id-md2 OBJECT IDENTIFIER ::= { - #: iso(1) member-body(2) us(840) rsadsi(113549) - #: digestAlgorithm(2) 2 - #: } - #: - #: This value uniquely identifies the MD2 algorithm. - oid = b('\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x02') - - digest_size = 16 - block_size = 16 - - def __init__(self, data=None): - HashAlgo.__init__(self, hashFactory, data) - - def new(self, data=None): - return MD2Hash(data) - -def new(data=None): - """Return a fresh instance of the hash object. - - :Parameters: - data : byte string - The very first chunk of the message to hash. - It is equivalent to an early call to `MD2Hash.update()`. - Optional. - - :Return: An `MD2Hash` object - """ - return MD2Hash().new(data) - -#: The size of the resulting hash in bytes. -digest_size = MD2Hash.digest_size - -#: The internal block size of the hash algorithm in bytes. -block_size = MD2Hash.block_size - diff --git a/lib/Crypto/Hash/MD4.py b/lib/Crypto/Hash/MD4.py deleted file mode 100644 index e28a201..0000000 --- a/lib/Crypto/Hash/MD4.py +++ /dev/null @@ -1,91 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""MD4 cryptographic hash algorithm. - -MD4 is specified in RFC1320_ and produces the 128 bit digest of a message. - - >>> from Crypto.Hash import MD4 - >>> - >>> h = MD4.new() - >>> h.update(b'Hello') - >>> print h.hexdigest() - -MD4 stand for Message Digest version 4, and it was invented by Rivest in 1990. - -This algorithm is insecure. Do not use it for new designs. - -.. _RFC1320: http://tools.ietf.org/html/rfc1320 -""" - -_revision__ = "$Id$" - -__all__ = ['new', 'digest_size', 'MD4Hash' ] - -from Crypto.Util.py3compat import * -from Crypto.Hash.hashalgo import HashAlgo - -import Crypto.Hash._MD4 as _MD4 -hashFactory = _MD4 - -class MD4Hash(HashAlgo): - """Class that implements an MD4 hash - - :undocumented: block_size - """ - - #: ASN.1 Object identifier (OID):: - #: - #: id-md2 OBJECT IDENTIFIER ::= { - #: iso(1) member-body(2) us(840) rsadsi(113549) - #: digestAlgorithm(2) 4 - #: } - #: - #: This value uniquely identifies the MD4 algorithm. - oid = b('\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x04') - - digest_size = 16 - block_size = 64 - - def __init__(self, data=None): - HashAlgo.__init__(self, hashFactory, data) - - def new(self, data=None): - return MD4Hash(data) - -def new(data=None): - """Return a fresh instance of the hash object. - - :Parameters: - data : byte string - The very first chunk of the message to hash. - It is equivalent to an early call to `MD4Hash.update()`. - Optional. - - :Return: A `MD4Hash` object - """ - return MD4Hash().new(data) - -#: The size of the resulting hash in bytes. -digest_size = MD4Hash.digest_size - -#: The internal block size of the hash algorithm in bytes. -block_size = MD4Hash.block_size - diff --git a/lib/Crypto/Hash/MD5.py b/lib/Crypto/Hash/MD5.py index 18e9e7b..c5df793 100644 --- a/lib/Crypto/Hash/MD5.py +++ b/lib/Crypto/Hash/MD5.py @@ -35,63 +35,58 @@ This algorithm is insecure. Do not use it for new designs. .. _RFC1321: http://tools.ietf.org/html/rfc1321 """ +from __future__ import nested_scopes + _revision__ = "$Id$" -__all__ = ['new', 'digest_size', 'MD5Hash' ] +__all__ = ['new', 'block_size', 'digest_size'] from Crypto.Util.py3compat import * -from Crypto.Hash.hashalgo import HashAlgo - -try: - # The md5 module is deprecated in Python 2.6, so use hashlib when possible. - import hashlib - hashFactory = hashlib.md5 - -except ImportError: - import md5 - hashFactory = md5 - -class MD5Hash(HashAlgo): - """Class that implements an MD5 hash - - :undocumented: block_size - """ - - #: ASN.1 Object identifier (OID):: - #: - #: id-md5 OBJECT IDENTIFIER ::= { - #: iso(1) member-body(2) us(840) rsadsi(113549) - #: digestAlgorithm(2) 5 - #: } - #: - #: This value uniquely identifies the MD5 algorithm. - oid = b('\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05') - - digest_size = 16 - block_size = 64 - - def __init__(self, data=None): - HashAlgo.__init__(self, hashFactory, data) - - def new(self, data=None): - return MD5Hash(data) - -def new(data=None): - """Return a fresh instance of the hash object. - - :Parameters: - data : byte string - The very first chunk of the message to hash. - It is equivalent to an early call to `MD5Hash.update()`. - Optional. - - :Return: A `MD5Hash` object - """ - return MD5Hash().new(data) +if sys.version_info[0] == 2 and sys.version_info[1] == 1: + from Crypto.Util.py21compat import * + +def __make_constructor(): + try: + # The md5 module is deprecated in Python 2.6, so use hashlib when possible. + from hashlib import md5 as _hash_new + except ImportError: + from md5 import new as _hash_new + + h = _hash_new() + if hasattr(h, 'new') and hasattr(h, 'name') and hasattr(h, 'digest_size') and hasattr(h, 'block_size'): + # The module from stdlib has the API that we need. Just use it. + return _hash_new + else: + # Wrap the hash object in something that gives us the expected API. + _copy_sentinel = object() + class _MD5(object): + digest_size = 16 + block_size = 64 + name = "md5" + def __init__(self, *args): + if args and args[0] is _copy_sentinel: + self._h = args[1] + else: + self._h = _hash_new(*args) + def copy(self): + return _MD5(_copy_sentinel, self._h.copy()) + def update(self, *args): + f = self.update = self._h.update + f(*args) + def digest(self): + f = self.digest = self._h.digest + return f() + def hexdigest(self): + f = self.hexdigest = self._h.hexdigest + return f() + _MD5.new = _MD5 + return _MD5 + +new = __make_constructor() +del __make_constructor #: The size of the resulting hash in bytes. -digest_size = MD5Hash.digest_size +digest_size = new().digest_size #: The internal block size of the hash algorithm in bytes. -block_size = MD5Hash.block_size - +block_size = new().block_size diff --git a/lib/Crypto/Hash/RIPEMD160.py b/lib/Crypto/Hash/RIPEMD160.py deleted file mode 100644 index 3abed5d..0000000 --- a/lib/Crypto/Hash/RIPEMD160.py +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""RIPEMD-160 cryptographic hash algorithm. - -RIPEMD-160_ produces the 160 bit digest of a message. - - >>> from Crypto.Hash import RIPEMD160 - >>> - >>> h = RIPEMD160.new() - >>> h.update(b'Hello') - >>> print h.hexdigest() - -RIPEMD-160 stands for RACE Integrity Primitives Evaluation Message Digest -with a 160 bit digest. It was invented by Dobbertin, Bosselaers, and Preneel. - -This algorithm is considered secure, although it has not been scrutinized as -extensively as SHA-1. Moreover, it provides an informal security level of just -80bits. - -.. _RIPEMD-160: http://homes.esat.kuleuven.be/~bosselae/ripemd160.html -""" - -_revision__ = "$Id$" - -__all__ = ['new', 'digest_size', 'RIPEMD160Hash' ] - -from Crypto.Util.py3compat import * -from Crypto.Hash.hashalgo import HashAlgo - -import Crypto.Hash._RIPEMD160 as _RIPEMD160 -hashFactory = _RIPEMD160 - -class RIPEMD160Hash(HashAlgo): - """Class that implements a RIPMD-160 hash - - :undocumented: block_size - """ - - #: ASN.1 Object identifier (OID):: - #: - #: id-ripemd160 OBJECT IDENTIFIER ::= { - #: iso(1) identified-organization(3) teletrust(36) - #: algorithm(3) hashAlgorithm(2) ripemd160(1) - #: } - #: - #: This value uniquely identifies the RIPMD-160 algorithm. - oid = b("\x06\x05\x2b\x24\x03\x02\x01") - - digest_size = 20 - block_size = 64 - - def __init__(self, data=None): - HashAlgo.__init__(self, hashFactory, data) - - def new(self, data=None): - return RIPEMD160Hash(data) - -def new(data=None): - """Return a fresh instance of the hash object. - - :Parameters: - data : byte string - The very first chunk of the message to hash. - It is equivalent to an early call to `RIPEMD160Hash.update()`. - Optional. - - :Return: A `RIPEMD160Hash` object - """ - return RIPEMD160Hash().new(data) - -#: The size of the resulting hash in bytes. -digest_size = RIPEMD160Hash.digest_size - -#: The internal block size of the hash algorithm in bytes. -block_size = RIPEMD160Hash.block_size - diff --git a/lib/Crypto/Hash/SHA1.py b/lib/Crypto/Hash/SHA1.py index 334ae18..9ad9f1e 100644 --- a/lib/Crypto/Hash/SHA1.py +++ b/lib/Crypto/Hash/SHA1.py @@ -35,64 +35,58 @@ This algorithm is not considered secure. Do not use it for new designs. .. _SHA-1: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf """ +from __future__ import nested_scopes + _revision__ = "$Id$" -__all__ = ['new', 'digest_size', 'SHA1Hash' ] +__all__ = ['new', 'block_size', 'digest_size'] from Crypto.Util.py3compat import * -from Crypto.Hash.hashalgo import HashAlgo - -try: - # The sha module is deprecated in Python 2.6, so use hashlib when possible. - import hashlib - hashFactory = hashlib.sha1 - -except ImportError: - import sha - hashFactory = sha - -class SHA1Hash(HashAlgo): - """Class that implements a SHA-1 hash - - :undocumented: block_size - """ - - #: ASN.1 Object identifier (OID):: - #: - #: id-sha1 OBJECT IDENTIFIER ::= { - #: iso(1) identified-organization(3) oiw(14) secsig(3) - #: algorithms(2) 26 - #: } - #: - #: This value uniquely identifies the SHA-1 algorithm. - oid = b('\x06\x05\x2b\x0e\x03\x02\x1a') - - digest_size = 20 - block_size = 64 - - def __init__(self, data=None): - HashAlgo.__init__(self, hashFactory, data) - - def new(self, data=None): - return SHA1Hash(data) - -def new(data=None): - """Return a fresh instance of the hash object. - - :Parameters: - data : byte string - The very first chunk of the message to hash. - It is equivalent to an early call to `SHA1Hash.update()`. - Optional. - - :Return: A `SHA1Hash` object - """ - return SHA1Hash().new(data) +if sys.version_info[0] == 2 and sys.version_info[1] == 1: + from Crypto.Util.py21compat import * + +def __make_constructor(): + try: + # The sha module is deprecated in Python 2.6, so use hashlib when possible. + from hashlib import sha1 as _hash_new + except ImportError: + from sha import new as _hash_new + + h = _hash_new() + if hasattr(h, 'new') and hasattr(h, 'name') and hasattr(h, 'digest_size') and hasattr(h, 'block_size'): + # The module from stdlib has the API that we need. Just use it. + return _hash_new + else: + # Wrap the hash object in something that gives us the expected API. + _copy_sentinel = object() + class _SHA1(object): + digest_size = 20 + block_size = 64 + name = "sha1" + def __init__(self, *args): + if args and args[0] is _copy_sentinel: + self._h = args[1] + else: + self._h = _hash_new(*args) + def copy(self): + return _SHA1(_copy_sentinel, self._h.copy()) + def update(self, *args): + f = self.update = self._h.update + f(*args) + def digest(self): + f = self.digest = self._h.digest + return f() + def hexdigest(self): + f = self.hexdigest = self._h.hexdigest + return f() + _SHA1.new = _SHA1 + return _SHA1 + +new = __make_constructor() +del __make_constructor #: The size of the resulting hash in bytes. -digest_size = SHA1Hash.digest_size +digest_size = new().digest_size #: The internal block size of the hash algorithm in bytes. -block_size = SHA1Hash.block_size - - +block_size = new().block_size diff --git a/lib/Crypto/Hash/SHA224.py b/lib/Crypto/Hash/SHA224.py deleted file mode 100644 index 959b56d..0000000 --- a/lib/Crypto/Hash/SHA224.py +++ /dev/null @@ -1,95 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""SHA-224 cryptographic hash algorithm. - -SHA-224 belongs to the SHA-2_ family of cryptographic hashes. -It produces the 224 bit digest of a message. - - >>> from Crypto.Hash import SHA224 - >>> - >>> h = SHA224.new() - >>> h.update(b'Hello') - >>> print h.hexdigest() - -*SHA* stands for Secure Hash Algorithm. - -.. _SHA-2: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf -""" - -_revision__ = "$Id$" - -__all__ = ['new', 'digest_size', 'SHA224Hash' ] - -from Crypto.Util.py3compat import * -from Crypto.Hash.hashalgo import HashAlgo - -try: - import hashlib - hashFactory = hashlib.sha224 - -except ImportError: - from Crypto.Hash import _SHA224 - hashFactory = _SHA224 - -class SHA224Hash(HashAlgo): - """Class that implements a SHA-224 hash - - :undocumented: block_size - """ - - #: ASN.1 Object identifier (OID):: - #: - #: id-sha224 OBJECT IDENTIFIER ::= { - #: joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) - #: nistalgorithm(4) hashalgs(2) 4 - #: } - #: - #: This value uniquely identifies the SHA-224 algorithm. - oid = b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04') - - digest_size = 28 - block_size = 64 - - def __init__(self, data=None): - HashAlgo.__init__(self, hashFactory, data) - - def new(self, data=None): - return SHA224Hash(data) - -def new(data=None): - """Return a fresh instance of the hash object. - - :Parameters: - data : byte string - The very first chunk of the message to hash. - It is equivalent to an early call to `SHA224Hash.update()`. - Optional. - - :Return: A `SHA224Hash` object - """ - return SHA224Hash().new(data) - -#: The size of the resulting hash in bytes. -digest_size = SHA224Hash.digest_size - -#: The internal block size of the hash algorithm in bytes. -block_size = SHA224Hash.block_size - diff --git a/lib/Crypto/Hash/SHA256.py b/lib/Crypto/Hash/SHA256.py deleted file mode 100644 index b0a99b3..0000000 --- a/lib/Crypto/Hash/SHA256.py +++ /dev/null @@ -1,95 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""SHA-256 cryptographic hash algorithm. - -SHA-256 belongs to the SHA-2_ family of cryptographic hashes. -It produces the 256 bit digest of a message. - - >>> from Crypto.Hash import SHA256 - >>> - >>> h = SHA256.new() - >>> h.update(b'Hello') - >>> print h.hexdigest() - -*SHA* stands for Secure Hash Algorithm. - -.. _SHA-2: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf -""" - -_revision__ = "$Id$" - -__all__ = ['new', 'digest_size', 'SHA256Hash' ] - -from Crypto.Util.py3compat import * -from Crypto.Hash.hashalgo import HashAlgo - -try: - import hashlib - hashFactory = hashlib.sha256 - -except ImportError: - from Crypto.Hash import _SHA256 - hashFactory = _SHA256 - -class SHA256Hash(HashAlgo): - """Class that implements a SHA-256 hash - - :undocumented: block_size - """ - - #: ASN.1 Object identifier (OID):: - #: - #: id-sha256 OBJECT IDENTIFIER ::= { - #: joint-iso-itu-t(2) country(16) us(840) organization(1) - #: gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1 - #: } - #: - #: This value uniquely identifies the SHA-256 algorithm. - oid = b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01') - - digest_size = 32 - block_size = 64 - - def __init__(self, data=None): - HashAlgo.__init__(self, hashFactory, data) - - def new(self, data=None): - return SHA256Hash(data) - -def new(data=None): - """Return a fresh instance of the hash object. - - :Parameters: - data : byte string - The very first chunk of the message to hash. - It is equivalent to an early call to `SHA256Hash.update()`. - Optional. - - :Return: A `SHA256Hash` object - """ - return SHA256Hash().new(data) - -#: The size of the resulting hash in bytes. -digest_size = SHA256Hash.digest_size - -#: The internal block size of the hash algorithm in bytes. -block_size = SHA256Hash.block_size - diff --git a/lib/Crypto/Hash/SHA384.py b/lib/Crypto/Hash/SHA384.py deleted file mode 100644 index 3490b02..0000000 --- a/lib/Crypto/Hash/SHA384.py +++ /dev/null @@ -1,96 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""SHA-384 cryptographic hash algorithm. - -SHA-384 belongs to the SHA-2_ family of cryptographic hashes. -It produces the 384 bit digest of a message. - - >>> from Crypto.Hash import SHA384 - >>> - >>> h = SHA384.new() - >>> h.update(b'Hello') - >>> print h.hexdigest() - -*SHA* stands for Secure Hash Algorithm. - -.. _SHA-2: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf -""" - -_revision__ = "$Id$" - -__all__ = ['new', 'digest_size', 'SHA384Hash' ] - -from Crypto.Util.py3compat import * -from Crypto.Hash.hashalgo import HashAlgo - -try: - import hashlib - hashFactory = hashlib.sha384 - -except ImportError: - from Crypto.Hash import _SHA384 - hashFactory = _SHA384 - -class SHA384Hash(HashAlgo): - """Class that implements a SHA-384 hash - - :undocumented: block_size - """ - - #: ASN.1 Object identifier (OID):: - #: - #: id-sha384 OBJECT IDENTIFIER ::= { - #: joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) - #: nistalgorithm(4) hashalgs(2) 2 - #: } - #: - #: This value uniquely identifies the SHA-384 algorithm. - oid = b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02') - - digest_size = 48 - block_size = 128 - - def __init__(self, data=None): - HashAlgo.__init__(self, hashFactory, data) - - def new(self, data=None): - return SHA384Hash(data) - -def new(data=None): - """Return a fresh instance of the hash object. - - :Parameters: - data : byte string - The very first chunk of the message to hash. - It is equivalent to an early call to `SHA384Hash.update()`. - Optional. - - :Return: A `SHA384Hash` object - """ - return SHA384Hash().new(data) - -#: The size of the resulting hash in bytes. -digest_size = SHA384Hash.digest_size - -#: The internal block size of the hash algorithm in bytes. -block_size = SHA384Hash.block_size - - diff --git a/lib/Crypto/Hash/SHA512.py b/lib/Crypto/Hash/SHA512.py deleted file mode 100644 index d57548d..0000000 --- a/lib/Crypto/Hash/SHA512.py +++ /dev/null @@ -1,95 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""SHA-512 cryptographic hash algorithm. - -SHA-512 belongs to the SHA-2_ family of cryptographic hashes. -It produces the 512 bit digest of a message. - - >>> from Crypto.Hash import SHA512 - >>> - >>> h = SHA512.new() - >>> h.update(b'Hello') - >>> print h.hexdigest() - -*SHA* stands for Secure Hash Algorithm. - -.. _SHA-2: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf -""" - -_revision__ = "$Id$" - -__all__ = ['new', 'digest_size', 'SHA512Hash' ] - -from Crypto.Util.py3compat import * -from Crypto.Hash.hashalgo import HashAlgo - -try: - import hashlib - hashFactory = hashlib.sha512 - -except ImportError: - from Crypto.Hash import _SHA512 - hashFactory = _SHA512 - -class SHA512Hash(HashAlgo): - """Class that implements a SHA-512 hash - - :undocumented: block_size - """ - - #: ASN.1 Object identifier (OID):: - #: - #: id-sha512 OBJECT IDENTIFIER ::= { - #: joint-iso-itu-t(2) - #: country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3 - #: } - #: - #: This value uniquely identifies the SHA-512 algorithm. - oid = b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03') - - digest_size = 64 - block_size = 128 - - def __init__(self, data=None): - HashAlgo.__init__(self, hashFactory, data) - - def new(self, data=None): - return SHA512Hash(data) - -def new(data=None): - """Return a fresh instance of the hash object. - - :Parameters: - data : byte string - The very first chunk of the message to hash. - It is equivalent to an early call to `SHA512Hash.update()`. - Optional. - - :Return: A `SHA512Hash` object - """ - return SHA512Hash().new(data) - -#: The size of the resulting hash in bytes. -digest_size = SHA512Hash.digest_size - -#: The internal block size of the hash algorithm in bytes. -block_size = SHA512Hash.block_size - diff --git a/lib/Crypto/Hash/__init__.py b/lib/Crypto/Hash/__init__.py index b9f9525..1050c78 100644 --- a/lib/Crypto/Hash/__init__.py +++ b/lib/Crypto/Hash/__init__.py @@ -53,4 +53,123 @@ __all__ = ['HMAC', 'MD2', 'MD4', 'MD5', 'RIPEMD160', 'SHA1', 'SHA224', 'SHA256', 'SHA384', 'SHA512'] __revision__ = "$Id$" +import sys +if sys.version_info[0] == 2 and sys.version_info[1] == 1: + from Crypto.Util.py21compat import * +from Crypto.Util.py3compat import * +def new(algo, *args): + """Initialize a new hash object. + + The first argument to this function may be an algorithm name or another + hash object. + + This function has significant overhead. It's recommended that you instead + import and use the individual hash modules directly. + """ + + # Try just invoking algo.new() + # We do this first so that this is the fastest. + try: + new_func = algo.new + except AttributeError: + pass + else: + return new_func(*args) + + # Try getting the algorithm name. + if isinstance(algo, str): + name = algo + else: + try: + name = algo.name + except AttributeError: + raise ValueError("unsupported hash type %r" % (algo,)) + + # Got the name. Let's see if we have a PyCrypto implementation. + try: + new_func = _new_funcs[name] + except KeyError: + # No PyCrypto implementation. Try hashlib. + try: + import hashlib + except ImportError: + # There is no hashlib. + raise ValueError("unsupported hash type %s" % (name,)) + return hashlib.new(name, *args) + else: + # We have a PyCrypto implementation. Instantiate it. + return new_func(*args) + +# This dict originally gets the following _*_new methods, but its members get +# replaced with the real new() methods of the various hash modules as they are +# used. We do it without locks to improve performance, which is safe in +# CPython because dict access is atomic in CPython. This might break PyPI. +_new_funcs = {} + +def _md2_new(*args): + from Crypto.Hash import MD2 + _new_funcs['MD2'] = _new_funcs['md2'] = MD2.new + return MD2.new(*args) +_new_funcs['MD2'] = _new_funcs['md2'] = _md2_new +del _md2_new + +def _md4_new(*args): + from Crypto.Hash import MD4 + _new_funcs['MD4'] = _new_funcs['md4'] = MD4.new + return MD4.new(*args) +_new_funcs['MD4'] = _new_funcs['md4'] = _md4_new +del _md4_new + +def _md5_new(*args): + from Crypto.Hash import MD5 + _new_funcs['MD5'] = _new_funcs['md5'] = MD5.new + return MD5.new(*args) +_new_funcs['MD5'] = _new_funcs['md5'] = _md5_new +del _md5_new + +def _ripemd160_new(*args): + from Crypto.Hash import RIPEMD160 + _new_funcs['RIPEMD160'] = _new_funcs['ripemd160'] = \ + _new_funcs['RIPEMD'] = _new_funcs['ripemd'] = RIPEMD160.new + return RIPEMD160.new(*args) +_new_funcs['RIPEMD160'] = _new_funcs['ripemd160'] = \ + _new_funcs['RIPEMD'] = _new_funcs['ripemd'] = _ripemd160_new +del _ripemd160_new + +def _sha1_new(*args): + from Crypto.Hash import SHA1 + _new_funcs['SHA1'] = _new_funcs['sha1'] = \ + _new_funcs['SHA'] = _new_funcs['sha'] = SHA1.new + return SHA1.new(*args) +_new_funcs['SHA1'] = _new_funcs['sha1'] = \ + _new_funcs['SHA'] = _new_funcs['sha'] = _sha1_new +del _sha1_new + +def _sha224_new(*args): + from Crypto.Hash import SHA224 + _new_funcs['SHA224'] = _new_funcs['sha224'] = SHA224.new + return SHA224.new(*args) +_new_funcs['SHA224'] = _new_funcs['sha224'] = _sha224_new +del _sha224_new + +def _sha256_new(*args): + from Crypto.Hash import SHA256 + _new_funcs['SHA256'] = _new_funcs['sha256'] = SHA256.new + return SHA256.new(*args) +_new_funcs['SHA256'] = _new_funcs['sha256'] = _sha256_new +del _sha256_new + +def _sha384_new(*args): + from Crypto.Hash import SHA384 + _new_funcs['SHA384'] = _new_funcs['sha384'] = SHA384.new + return SHA384.new(*args) +_new_funcs['SHA384'] = _new_funcs['sha384'] = _sha384_new +del _sha384_new + +def _sha512_new(*args): + from Crypto.Hash import SHA512 + _new_funcs['SHA512'] = _new_funcs['sha512'] = SHA512.new + return SHA512.new(*args) +_new_funcs['SHA512'] = _new_funcs['sha512'] = _sha512_new +del _sha512_new diff --git a/lib/Crypto/Hash/hashalgo.py b/lib/Crypto/Hash/hashalgo.py deleted file mode 100644 index b38b3a6..0000000 --- a/lib/Crypto/Hash/hashalgo.py +++ /dev/null @@ -1,116 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from binascii import hexlify - -class HashAlgo: - """A generic class for an abstract cryptographic hash algorithm. - - :undocumented: block_size - """ - - #: The size of the resulting hash in bytes. - digest_size = None - #: The internal block size of the hash algorithm in bytes. - block_size = None - - def __init__(self, hashFactory, data=None): - """Initialize the hash object. - - :Parameters: - hashFactory : callable - An object that will generate the actual hash implementation. - *hashFactory* must have a *new()* method, or must be directly - callable. - data : byte string - The very first chunk of the message to hash. - It is equivalent to an early call to `update()`. - """ - if hasattr(hashFactory, 'new'): - self._hash = hashFactory.new() - else: - self._hash = hashFactory() - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Repeated calls are equivalent to a single call with the concatenation - of all the arguments. In other words: - - >>> m.update(a); m.update(b) - - is equivalent to: - - >>> m.update(a+b) - - :Parameters: - data : byte string - The next chunk of the message being hashed. - """ - return self._hash.update(data) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - This method does not change the state of the hash object. - You can continue updating the object after calling this function. - - :Return: A byte string of `digest_size` bytes. It may contain non-ASCII - characters, including null bytes. - """ - return self._hash.digest() - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - This method does not change the state of the hash object. - - :Return: A string of 2* `digest_size` characters. It contains only - hexadecimal ASCII digits. - """ - return self._hash.hexdigest() - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :Return: A hash object of the same type - """ - return self._hash.copy() - - def new(self, data=None): - """Return a fresh instance of the hash object. - - Unlike the `copy` method, the internal state of the object is empty. - - :Parameters: - data : byte string - The next chunk of the message being hashed. - - :Return: A hash object of the same type - """ - pass - diff --git a/lib/Crypto/Random/Fortuna/FortunaGenerator.py b/lib/Crypto/Random/Fortuna/FortunaGenerator.py index 723fa63..09351fc 100644 --- a/lib/Crypto/Random/Fortuna/FortunaGenerator.py +++ b/lib/Crypto/Random/Fortuna/FortunaGenerator.py @@ -25,7 +25,7 @@ __revision__ = "$Id$" import sys -if sys.version_info[0] is 2 and sys.version_info[1] is 1: +if sys.version_info[0] == 2 and sys.version_info[1] == 1: from Crypto.Util.py21compat import * from Crypto.Util.py3compat import * diff --git a/lib/Crypto/SelfTest/Hash/common.py b/lib/Crypto/SelfTest/Hash/common.py index f77fb0f..e722800 100644 --- a/lib/Crypto/SelfTest/Hash/common.py +++ b/lib/Crypto/SelfTest/Hash/common.py @@ -29,7 +29,10 @@ __revision__ = "$Id$" import sys import unittest import binascii +import Crypto.Hash from Crypto.Util.py3compat import * +if sys.version_info[0] == 2 and sys.version_info[1] == 1: + from Crypto.Util.py21compat import * # For compatibility with Python 2.1 and Python 2.2 if sys.hexversion < 0x02030000: @@ -94,11 +97,27 @@ class HashSelfTest(unittest.TestCase): self.assertEqual(self.expected.decode(), out3) # h = .new(data); h.hexdigest() self.assertEqual(self.expected, out4) # h = .new(data); h.digest() - # Verify that new() object method produces a fresh hash object - h2 = h.new() - h2.update(self.input) - out5 = binascii.b2a_hex(h2.digest()) - self.assertEqual(self.expected, out5) + # Verify that the .new() method produces a fresh hash object, except + # for MD5 and SHA1, which are hashlib objects. (But test any .new() + # method that does exist.) + if self.hashmod.__name__ not in ('Crypto.Hash.MD5', 'Crypto.Hash.SHA1') or hasattr(h, 'new'): + h2 = h.new() + h2.update(self.input) + out5 = binascii.b2a_hex(h2.digest()) + self.assertEqual(self.expected, out5) + + # Verify that Crypto.Hash.new(h) produces a fresh hash object + h3 = Crypto.Hash.new(h) + h3.update(self.input) + out6 = binascii.b2a_hex(h3.digest()) + self.assertEqual(self.expected, out6) + + if hasattr(h, 'name'): + # Verify that Crypto.Hash.new(h.name) produces a fresh hash object + h4 = Crypto.Hash.new(h.name) + h4.update(self.input) + out7 = binascii.b2a_hex(h4.digest()) + self.assertEqual(self.expected, out7) class HashTestOID(unittest.TestCase): def __init__(self, hashmod, oid): @@ -107,16 +126,38 @@ class HashTestOID(unittest.TestCase): self.oid = oid def runTest(self): + from Crypto.Signature import PKCS1_v1_5 h = self.hashmod.new() - if self.oid==None: - try: - raised = 0 - a = h.oid - except AttributeError: - raised = 1 - self.assertEqual(raised,1) - else: - self.assertEqual(h.oid, self.oid) + self.assertEqual(PKCS1_v1_5._HASH_OIDS[h.name], self.oid) + +class HashDocStringTest(unittest.TestCase): + def __init__(self, hashmod): + unittest.TestCase.__init__(self) + self.hashmod = hashmod + + def runTest(self): + docstring = self.hashmod.__doc__ + self.assert_(hasattr(self.hashmod, '__doc__')) + self.assert_(isinstance(self.hashmod.__doc__, str)) + +class GenericHashConstructorTest(unittest.TestCase): + def __init__(self, hashmod): + unittest.TestCase.__init__(self) + self.hashmod = hashmod + + def runTest(self): + obj1 = self.hashmod.new("foo") + obj2 = self.hashmod.new() + obj3 = Crypto.Hash.new(obj1.name, "foo") + obj4 = Crypto.Hash.new(obj1.name) + obj5 = Crypto.Hash.new(obj1, "foo") + obj6 = Crypto.Hash.new(obj1) + self.assert_(isinstance(self.hashmod, obj1)) + self.assert_(isinstance(self.hashmod, obj2)) + self.assert_(isinstance(self.hashmod, obj3)) + self.assert_(isinstance(self.hashmod, obj4)) + self.assert_(isinstance(self.hashmod, obj5)) + self.assert_(isinstance(self.hashmod, obj6)) class MACSelfTest(unittest.TestCase): @@ -178,11 +219,13 @@ def make_hash_tests(module, module_name, test_data, digest_size, oid=None): description = row[2].encode('latin-1') name = "%s #%d: %s" % (module_name, i+1, description) tests.append(HashSelfTest(module, name, expected, input)) - if oid is not None: - oid = b(oid) name = "%s #%d: digest_size" % (module_name, i+1) tests.append(HashDigestSizeSelfTest(module, name, digest_size)) - tests.append(HashTestOID(module, oid)) + if oid is not None: + tests.append(HashTestOID(module, b(oid))) + tests.append(HashDocStringTest(module)) + if getattr(module, 'name', None) is not None: + tests.append(GenericHashConstructorTest(module)) return tests def make_mac_tests(module, module_name, test_data, hashmods): diff --git a/lib/Crypto/Signature/PKCS1_PSS.py b/lib/Crypto/Signature/PKCS1_PSS.py index cd9eaf3..3840959 100644 --- a/lib/Crypto/Signature/PKCS1_PSS.py +++ b/lib/Crypto/Signature/PKCS1_PSS.py @@ -72,6 +72,7 @@ if sys.version_info[0] == 2 and sys.version_info[1] == 1: import Crypto.Util.number from Crypto.Util.number import ceil_shift, ceil_div, long_to_bytes from Crypto.Util.strxor import strxor +from Crypto.Hash import new as Hash_new class PSS_SigScheme: """This signature scheme can perform PKCS#1 PSS RSA signature or verification.""" @@ -203,7 +204,11 @@ def MGF1(mgfSeed, maskLen, hash): T = b("") for counter in xrange(ceil_div(maskLen, hash.digest_size)): c = long_to_bytes(counter, 4) - T = T + hash.new(mgfSeed + c).digest() + try: + T = T + hash.new(mgfSeed + c).digest() + except AttributeError: + # hash object doesn't have a "new" method. Use Crypto.Hash.new() to instantiate it + T = T + Hash_new(hash, mgfSeed + c).digest() assert(len(T)>=maskLen) return T[:maskLen] @@ -253,7 +258,11 @@ def EMSA_PSS_ENCODE(mhash, emBits, randFunc, mgf, sLen): if randFunc and sLen>0: salt = randFunc(sLen) # Step 5 and 6 - h = mhash.new(bchr(0x00)*8 + mhash.digest() + salt) + try: + h = mhash.new(bchr(0x00)*8 + mhash.digest() + salt) + except AttributeError: + # hash object doesn't have a "new" method. Use Crypto.Hash.new() to instantiate it + h = Hash_new(mhash, bchr(0x00)*8 + mhash.digest() + salt) # Step 7 and 8 db = bchr(0x00)*(emLen-sLen-mhash.digest_size-2) + bchr(0x01) + salt # Step 9 @@ -328,7 +337,11 @@ def EMSA_PSS_VERIFY(mhash, em, emBits, mgf, sLen): salt = b("") if sLen: salt = db[-sLen:] # Step 12 and 13 - hp = mhash.new(bchr(0x00)*8 + mhash.digest() + salt).digest() + try: + hp = mhash.new(bchr(0x00)*8 + mhash.digest() + salt).digest() + except AttributeError: + # hash object doesn't have a "new" method. Use Crypto.Hash.new() to instantiate it + hp = Hash_new(mhash, bchr(0x00)*8 + mhash.digest() + salt).digest() # Step 14 if h!=hp: return False diff --git a/lib/Crypto/Signature/PKCS1_v1_5.py b/lib/Crypto/Signature/PKCS1_v1_5.py index 73ac251..22bb340 100644 --- a/lib/Crypto/Signature/PKCS1_v1_5.py +++ b/lib/Crypto/Signature/PKCS1_v1_5.py @@ -208,7 +208,7 @@ def EMSA_PKCS1_V1_5_ENCODE(hash, emLen): # { OID id-sha512 PARAMETERS NULL } # } # - digestAlgo = DerSequence([hash.oid, DerNull().encode()]) + digestAlgo = DerSequence([_HASH_OIDS[hash.name], DerNull().encode()]) digest = DerOctetString(hash.digest()) digestInfo = DerSequence([ digestAlgo.encode(), @@ -234,3 +234,73 @@ def new(key): """ return PKCS115_SigScheme(key) +# AlgorithmIdentifier OIDs for use with PKCS#1 v1.5. +# +# These map names to the associated OIDs. We should try to be compatible +# with the standard library's hashlib modules, where possible. +# +# XXX - These will probably be moved somewhere else soon. +_HASH_OIDS = { + #: id-md2 OBJECT IDENTIFIER ::= { + #: iso(1) member-body(2) us(840) rsadsi(113549) + #: digestAlgorithm(2) 2 + #: } + "MD2": b('\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x02'), + "md2": b('\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x02'), + + #: id-md4 OBJECT IDENTIFIER ::= { + #: iso(1) member-body(2) us(840) rsadsi(113549) + #: digestAlgorithm(2) 4 + #: } + "MD4": b('\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x04'), + "md4": b('\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x04'), + + #: id-md5 OBJECT IDENTIFIER ::= { + #: iso(1) member-body(2) us(840) rsadsi(113549) + #: digestAlgorithm(2) 5 + #: } + "MD5": b('\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05'), + "md5": b('\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05'), + + #: id-ripemd160 OBJECT IDENTIFIER ::= { + #: iso(1) identified-organization(3) teletrust(36) + #: algorithm(3) hashAlgorithm(2) ripemd160(1) + #: } + "RIPEMD160": b("\x06\x05\x2b\x24\x03\x02\x01"), + "ripemd160": b("\x06\x05\x2b\x24\x03\x02\x01"), + + #: id-sha1 OBJECT IDENTIFIER ::= { + #: iso(1) identified-organization(3) oiw(14) secsig(3) + #: algorithms(2) 26 + #: } + "SHA1": b('\x06\x05\x2b\x0e\x03\x02\x1a'), + "sha1": b('\x06\x05\x2b\x0e\x03\x02\x1a'), + + #: id-sha224 OBJECT IDENTIFIER ::= { + #: joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) + #: nistalgorithm(4) hashalgs(2) 4 + #: } + "SHA224": b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04'), + "sha224": b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04'), + + #: id-sha256 OBJECT IDENTIFIER ::= { + #: joint-iso-itu-t(2) country(16) us(840) organization(1) + #: gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1 + #: } + "SHA256": b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01'), + "sha256": b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01'), + + #: id-sha384 OBJECT IDENTIFIER ::= { + #: joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) + #: nistalgorithm(4) hashalgs(2) 2 + #: } + "SHA384": b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02'), + "sha384": b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02'), + + #: id-sha512 OBJECT IDENTIFIER ::= { + #: joint-iso-itu-t(2) + #: country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3 + #: } + "SHA512": b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03'), + "sha512": b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03'), +} diff --git a/pct-speedtest.py b/pct-speedtest.py index eb2778f..bd099ce 100644 --- a/pct-speedtest.py +++ b/pct-speedtest.py @@ -28,10 +28,17 @@ import os import sys from Crypto.PublicKey import RSA +from Crypto.Cipher import PKCS1_OAEP, PKCS1_v1_5 as RSAES_PKCS1_v1_5 +from Crypto.Signature import PKCS1_PSS, PKCS1_v1_5 as RSASSA_PKCS1_v1_5 from Crypto.Cipher import AES, ARC2, ARC4, Blowfish, CAST, DES3, DES, XOR -from Crypto.Hash import HMAC, MD2, MD4, MD5, SHA, SHA224, SHA256, SHA384, SHA512 +from Crypto.Hash import HMAC, MD2, MD4, MD5, SHA224, SHA256, SHA384, SHA512 from Crypto.Random import get_random_bytes try: + from Crypto.Hash import SHA1 +except ImportError: + # Maybe it's called SHA + from Crypto.Hash import SHA as SHA1 +try: from Crypto.Hash import RIPEMD160 except ImportError: # Maybe it's called RIPEMD @@ -194,6 +201,59 @@ class Benchmark: mac_constructor = lambda data=None: hmac_constructor(key, data, digestmod) self.test_hash_large(mac_name, mac_constructor, digest_size) + def test_pkcs1_sign(self, scheme_name, scheme_constructor, hash_name, hash_constructor, digest_size): + self.announce_start("%s signing %s (%d-byte inputs)" % (scheme_name, hash_name, digest_size)) + + # Make a key + k = RSA.generate(2048) + sigscheme = scheme_constructor(k) + + # Make some hashes + blocks = self.random_blocks(digest_size, 50) + hashes = [] + for b in blocks: + hashes.append(hash_constructor(b)) + + # Perform signing + t0 = time.time() + for h in hashes: + sigscheme.sign(h) + t = time.time() + + speed = len(hashes) / (t - t0) + self.announce_result(speed, "sigs/sec") + + def test_pkcs1_verify(self, scheme_name, scheme_constructor, hash_name, hash_constructor, digest_size): + self.announce_start("%s verification %s (%d-byte inputs)" % (scheme_name, hash_name, digest_size)) + + # Make a key + k = RSA.generate(2048) + sigscheme = scheme_constructor(k) + + # Make some hashes + blocks = self.random_blocks(digest_size, 50) + hashes = [] + for b in blocks: + hashes.append(hash_constructor(b)) + + # Make some signatures + signatures = [] + for h in hashes: + signatures.append(sigscheme.sign(h)) + + # Double the list, to make timing better + hashes = hashes + hashes + signatures = signatures + signatures + + # Perform verification + t0 = time.time() + for h, s in zip(hashes, signatures): + sigscheme.verify(h, s) + t = time.time() + + speed = len(hashes) / (t - t0) + self.announce_result(speed, "sigs/sec") + def run(self): pubkey_specs = [ ("RSA(1024)", RSA, int(1024/8)), @@ -221,7 +281,7 @@ class Benchmark: ("MD2", MD2), ("MD4", MD4), ("MD5", MD5), - ("SHA", SHA), + ("SHA1", SHA1), ("SHA224", SHA224), ("SHA256", SHA256), ("SHA384", SHA384), @@ -277,6 +337,22 @@ class Benchmark: self.test_hmac_small("hmac+"+hash_name, hmac.HMAC, func, func().digest_size) self.test_hmac_large("hmac+"+hash_name, hmac.HMAC, func, func().digest_size) + # PKCS1_v1_5 (sign) + Crypto.Hash + for hash_name, module in hash_specs: + self.test_pkcs1_sign("PKCS#1-v1.5", RSASSA_PKCS1_v1_5.new, hash_name, module.new, module.digest_size) + + # PKCS1_PSS (sign) + Crypto.Hash + for hash_name, module in hash_specs: + self.test_pkcs1_sign("PKCS#1-PSS", PKCS1_PSS.new, hash_name, module.new, module.digest_size) + + # PKCS1_v1_5 (verify) + Crypto.Hash + for hash_name, module in hash_specs: + self.test_pkcs1_verify("PKCS#1-v1.5", RSASSA_PKCS1_v1_5.new, hash_name, module.new, module.digest_size) + + # PKCS1_PSS (verify) + Crypto.Hash + for hash_name, module in hash_specs: + self.test_pkcs1_verify("PKCS#1-PSS", PKCS1_PSS.new, hash_name, module.new, module.digest_size) + if __name__ == '__main__': Benchmark().run() @@ -399,25 +399,25 @@ kw = {'name':"pycrypto", sources=["src/_fastmath.c"]), # Hash functions - Extension("Crypto.Hash._MD2", + Extension("Crypto.Hash.MD2", include_dirs=['src/'], sources=["src/MD2.c"]), - Extension("Crypto.Hash._MD4", + Extension("Crypto.Hash.MD4", include_dirs=['src/'], sources=["src/MD4.c"]), - Extension("Crypto.Hash._SHA256", + Extension("Crypto.Hash.SHA256", include_dirs=['src/'], sources=["src/SHA256.c"]), - Extension("Crypto.Hash._SHA224", + Extension("Crypto.Hash.SHA224", include_dirs=['src/'], sources=["src/SHA224.c"]), - Extension("Crypto.Hash._SHA384", + Extension("Crypto.Hash.SHA384", include_dirs=['src/'], sources=["src/SHA384.c"]), - Extension("Crypto.Hash._SHA512", + Extension("Crypto.Hash.SHA512", include_dirs=['src/'], sources=["src/SHA512.c"]), - Extension("Crypto.Hash._RIPEMD160", + Extension("Crypto.Hash.RIPEMD160", include_dirs=['src/'], sources=["src/RIPEMD160.c"], define_macros=[endianness_macro()]), @@ -24,9 +24,9 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "Python.h" #include <assert.h> #include <stdlib.h> -#include "Python.h" #define MODULE_NAME _AES #define BLOCK_SIZE 16 @@ -41,8 +41,8 @@ * */ -#include <string.h> #include "Python.h" +#include <string.h> #define MODULE_NAME _ARC2 #define BLOCK_SIZE 8 diff --git a/src/Blowfish.c b/src/Blowfish.c index 94562bb..fd90fd7 100644 --- a/src/Blowfish.c +++ b/src/Blowfish.c @@ -26,6 +26,7 @@ * http://www.schneier.com/paper-blowfish-fse.html */ +#include "Python.h" #include "config.h" #if HAVE_STDINT_H # include <stdint.h> @@ -36,7 +37,6 @@ #endif #include <assert.h> #include <string.h> -#include "Python.h" #include "Blowfish-tables.h" @@ -24,6 +24,8 @@ * Country of origin: Canada */ +#include "Python.h" + /* Setting this will cause LibTomCrypt to return CRYPT_INVALID_ARG when its * assert-like LTC_ARGCHK macro fails. */ #define ARGTYPE 4 @@ -34,7 +36,6 @@ #undef DES /* this is needed because tomcrypt_custom.h defines DES to an empty string */ #include <assert.h> -#include "Python.h" typedef struct { symmetric_key sk; @@ -27,24 +27,30 @@ */ -#include <string.h> #include "Python.h" +#include <string.h> #include "pycrypto_compat.h" -#define MODULE_NAME _MD2 +#define MODULE_NAME MD2 #define DIGEST_SIZE 16 #define BLOCK_SIZE 64 -/** - * id-md2 OBJECT IDENTIFIER ::= { - * iso(1) member-body(2) us(840) rsadsi(113549) - * digestAlgorithm(2) 2 - * } - */ -static const char md2_oid[] = { 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x02 }; - -#define DER_OID ((void*)&md2_oid) -#define DER_OID_SIZE (sizeof md2_oid) +static char MODULE__doc__[] = + "MD2 cryptographic hash algorithm.\n" + "\n" + "MD2 is specified in RFC1319_ and it produces the 128 bit digest of a message.\n" + "\n" + " >>> from Crypto.Hash import MD2\n" + " >>>\n" + " >>> h = MD2.new()\n" + " >>> h.update(b'Hello')\n" + " >>> print h.hexdigest()\n" + "\n" + "MD2 stand for Message Digest version 2, and it was invented by Rivest in 1989.\n" + "\n" + "This algorithm is both slow and insecure. Do not use it for new designs.\n" + "\n" + ".. _RFC1319: http://tools.ietf.org/html/rfc1319\n"; typedef unsigned char U8; typedef unsigned int U32; @@ -27,14 +27,31 @@ */ -#include <string.h> #include "Python.h" +#include <string.h> #include "pycrypto_compat.h" -#define MODULE_NAME _MD4 +#define MODULE_NAME MD4 #define DIGEST_SIZE 16 #define BLOCK_SIZE 64 +static char MODULE__doc__[] = + "MD4 cryptographic hash algorithm.\n" + "\n" + "MD4 is specified in RFC1320_ and produces the 128 bit digest of a message.\n" + "\n" + " >>> from Crypto.Hash import MD4\n" + " >>>\n" + " >>> h = MD4.new()\n" + " >>> h.update(b'Hello')\n" + " >>> print h.hexdigest()\n" + "\n" + "MD4 stand for Message Digest version 4, and it was invented by Rivest in 1990.\n" + "\n" + "This algorithm is insecure. Do not use it for new designs.\n" + "\n" + ".. _RFC1320: http://tools.ietf.org/html/rfc1320\n"; + typedef unsigned int U32; typedef unsigned char U8; #define U32_MAX (U32)4294967295 diff --git a/src/RIPEMD160.c b/src/RIPEMD160.c index 9786af8..9593fc8 100644 --- a/src/RIPEMD160.c +++ b/src/RIPEMD160.c @@ -43,6 +43,8 @@ * "RIPEMD-160 is big-bit-endian, little-byte-endian, and left-justified." */ +#include "Python.h" + #include "config.h" #if HAVE_STDINT_H # include <stdint.h> @@ -54,12 +56,31 @@ #include <assert.h> #include <string.h> -#include "Python.h" #include "pycrypto_compat.h" #define RIPEMD160_DIGEST_SIZE 20 #define BLOCK_SIZE 64 +static char MODULE__doc__[] = + "RIPEMD-160 cryptographic hash algorithm.\n" + "\n" + "RIPEMD-160_ produces the 160 bit digest of a message.\n" + "\n" + " >>> from Crypto.Hash import RIPEMD160\n" + " >>>\n" + " >>> h = RIPEMD160.new()\n" + " >>> h.update(b'Hello')\n" + " >>> print h.hexdigest()\n" + "\n" + "RIPEMD-160 stands for RACE Integrity Primitives Evaluation Message Digest\n" + "with a 160 bit digest. It was invented by Dobbertin, Bosselaers, and Preneel.\n" + "\n" + "This algorithm is considered secure, although it has not been scrutinized as\n" + "extensively as SHA-1. Moreover, it provides an informal security level of just\n" + "80bits.\n" + "\n" + ".. _RIPEMD-160: http://homes.esat.kuleuven.be/~bosselae/ripemd160.html\n"; + #define RIPEMD160_MAGIC 0x9f19dd68u typedef struct { uint32_t magic; @@ -400,7 +421,7 @@ static int ripemd160_digest(const ripemd160_state *self, unsigned char *out) } /* Template definitions */ -#define MODULE_NAME _RIPEMD160 +#define MODULE_NAME RIPEMD160 #define DIGEST_SIZE RIPEMD160_DIGEST_SIZE #define hash_state ripemd160_state #define hash_init ripemd160_init diff --git a/src/SHA224.c b/src/SHA224.c index ca70fbd..86591cf 100644 --- a/src/SHA224.c +++ b/src/SHA224.c @@ -27,12 +27,28 @@ * */ -#define MODULE_NAME _SHA224 +#define MODULE_NAME SHA224 #define DIGEST_SIZE (224/8) #define BLOCK_SIZE (512/8) #define WORD_SIZE 4 #define SCHEDULE_SIZE 64 +static char MODULE__doc__[] = + "SHA-224 cryptographic hash algorithm.\n" + "\n" + "SHA-224 belongs to the SHA-2_ family of cryptographic hashes.\n" + "It produces the 224 bit digest of a message.\n" + "\n" + " >>> from Crypto.Hash import SHA224\n" + " >>>\n" + " >>> h = SHA224.new()\n" + " >>> h.update(b'Hello')\n" + " >>> print h.hexdigest()\n" + "\n" + "*SHA* stands for Secure Hash Algorithm.\n" + "\n" + ".. _SHA-2: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf\n"; + #include "hash_SHA2.h" /* Initial Values H */ diff --git a/src/SHA256.c b/src/SHA256.c index 61a2d74..9473abc 100644 --- a/src/SHA256.c +++ b/src/SHA256.c @@ -26,12 +26,28 @@ * =================================================================== * */ -#define MODULE_NAME _SHA256 +#define MODULE_NAME SHA256 #define DIGEST_SIZE (256/8) #define BLOCK_SIZE (512/8) #define WORD_SIZE 4 #define SCHEDULE_SIZE 64 - + +static char MODULE__doc__[] = + "SHA-256 cryptographic hash algorithm.\n" + "\n" + "SHA-256 belongs to the SHA-2_ family of cryptographic hashes.\n" + "It produces the 256 bit digest of a message.\n" + "\n" + " >>> from Crypto.Hash import SHA256\n" + " >>>\n" + " >>> h = SHA256.new()\n" + " >>> h.update(b'Hello')\n" + " >>> print h.hexdigest()\n" + "\n" + "*SHA* stands for Secure Hash Algorithm.\n" + "\n" + ".. _SHA-2: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf\n"; + #include "hash_SHA2.h" /* Initial Values H */ diff --git a/src/SHA384.c b/src/SHA384.c index 05dfe25..eb7051e 100644 --- a/src/SHA384.c +++ b/src/SHA384.c @@ -27,12 +27,28 @@ * */ -#define MODULE_NAME _SHA384 +#define MODULE_NAME SHA384 #define DIGEST_SIZE (384/8) #define BLOCK_SIZE (1024/8) #define WORD_SIZE 8 #define SCHEDULE_SIZE 80 +static char MODULE__doc__[] = + "SHA-384 cryptographic hash algorithm.\n" + "\n" + "SHA-384 belongs to the SHA-2_ family of cryptographic hashes.\n" + "It produces the 384 bit digest of a message.\n" + "\n" + " >>> from Crypto.Hash import SHA384\n" + " >>>\n" + " >>> h = SHA384.new()\n" + " >>> h.update(b'Hello')\n" + " >>> print h.hexdigest()\n" + "\n" + "*SHA* stands for Secure Hash Algorithm.\n" + "\n" + ".. _SHA-2: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf\n"; + #include "hash_SHA2.h" /* Initial Values H */ diff --git a/src/SHA512.c b/src/SHA512.c index 3370e8e..f12755c 100644 --- a/src/SHA512.c +++ b/src/SHA512.c @@ -27,12 +27,28 @@ * */ -#define MODULE_NAME _SHA512 +#define MODULE_NAME SHA512 #define DIGEST_SIZE (512/8) #define BLOCK_SIZE (1024/8) #define WORD_SIZE 8 #define SCHEDULE_SIZE 80 +static char MODULE__doc__[] = + "SHA-512 cryptographic hash algorithm.\n" + "\n" + "SHA-512 belongs to the SHA-2_ family of cryptographic hashes.\n" + "It produces the 512 bit digest of a message.\n" + "\n" + " >>> from Crypto.Hash import SHA512\n" + " >>>\n" + " >>> h = SHA512.new()\n" + " >>> h.update(b'Hello')\n" + " >>> print h.hexdigest()\n" + "\n" + "*SHA* stands for Secure Hash Algorithm.\n" + "\n" + ".. _SHA-2: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf\n"; + #include "hash_SHA2.h" /* Initial Values H */ diff --git a/src/_counter.c b/src/_counter.c index 9b396e4..6579a5f 100644 --- a/src/_counter.c +++ b/src/_counter.c @@ -22,10 +22,10 @@ * =================================================================== */ +#include "Python.h" #include <assert.h> #include <stddef.h> #include <string.h> -#include "Python.h" #include "pycrypto_compat.h" #include "_counter.h" @@ -106,6 +106,7 @@ CounterObject_init(PCT_CounterObject *self, PyObject *args, PyObject *kwargs) /* Sanity-check pointers */ assert(self->val <= self->p); + assert(self->buf_size >= 0); assert(self->p + self->nbytes <= self->val + self->buf_size); assert(self->val + PyBytes_GET_SIZE(self->prefix) == self->p); assert(PyBytes_GET_SIZE(self->prefix) + self->nbytes + PyBytes_GET_SIZE(self->suffix) == self->buf_size); diff --git a/src/_counter.h b/src/_counter.h index fc3e24e..f671094 100644 --- a/src/_counter.h +++ b/src/_counter.h @@ -38,7 +38,7 @@ typedef struct { PyBytesObject *prefix; /* Prefix (useful for a nonce) */ PyBytesObject *suffix; /* Suffix (useful for a nonce) */ uint8_t *val; /* Buffer for our output string */ - uint32_t buf_size; /* Size of the buffer */ + Py_ssize_t buf_size;/* Size of the buffer */ uint8_t *p; /* Pointer to the part of the buffer that we're allowed to update */ uint16_t nbytes; /* The number of bytes that from .p that are part of the counter */ void (*inc_func)(void *); /* Pointer to the counter increment function */ diff --git a/src/_fastmath.c b/src/_fastmath.c index 99b1c43..bd2651d 100644 --- a/src/_fastmath.c +++ b/src/_fastmath.c @@ -26,9 +26,9 @@ * $Id$ */ +#include "Python.h" #include <stdio.h> #include <string.h> -#include "Python.h" #include "pycrypto_compat.h" #include <longintrepr.h> /* for conversions */ #include "config.h" diff --git a/src/block_template.c b/src/block_template.c index c36b316..2cfee1b 100644 --- a/src/block_template.c +++ b/src/block_template.c @@ -24,6 +24,7 @@ * =================================================================== */ +#include "Python.h" #ifdef HAVE_CONFIG_H #include "config.h" @@ -33,7 +34,6 @@ #include <string.h> #endif -#include "Python.h" #include "pycrypto_compat.h" #include "modsupport.h" diff --git a/src/hash_SHA2.h b/src/hash_SHA2.h index 5867191..02991bd 100644 --- a/src/hash_SHA2.h +++ b/src/hash_SHA2.h @@ -26,6 +26,8 @@ #ifndef __HASH_SHA2_H #define __HASH_SHA2_H +#include "Python.h" + /* check if implementation set the correct macros */ #ifndef MODULE_NAME #error SHA2 Implementation must define MODULE_NAME before including this header diff --git a/src/hash_template.c b/src/hash_template.c index eb27e9f..d085bb8 100644 --- a/src/hash_template.c +++ b/src/hash_template.c @@ -24,13 +24,13 @@ /* Basic object type */ +#include "Python.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef _HAVE_STDC_HEADERS #include <string.h> #endif -#include "Python.h" #include "pycrypto_compat.h" #define _STR(x) #x @@ -209,9 +209,13 @@ ALG_getattr(PyObject *self, char *name) if (PyUnicode_CompareWithASCIIString(attr, "digest_size")==0) return PyLong_FromLong(DIGEST_SIZE); + if (PyUnicode_CompareWithASCIIString(attr, "name")==0) + return PyUnicode_FromString(_MODULE_STRING); /* we should try to be compatible with hashlib here */ #else if (strcmp(name, "digest_size")==0) return PyInt_FromLong(DIGEST_SIZE); + if (strcmp(name, "name")==0) + return PyString_FromString(_MODULE_STRING); /* we should try to be compatible with hashlib here */ #endif #ifdef IS_PY3K @@ -309,14 +313,14 @@ static struct PyMethodDef ALG_functions[] = { #ifdef IS_PY3K static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, - "Crypto.Hash." _MODULE_STRING, - NULL, - -1, - ALG_functions, - NULL, - NULL, - NULL, - NULL + "Crypto.Hash." _MODULE_STRING, /* m_name */ + MODULE__doc__, /* m_doc */ + -1, /* m_size */ + ALG_functions, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ }; #endif @@ -349,7 +353,7 @@ _MODULE_NAME (void) return NULL; #else ALGtype.ob_type = &PyType_Type; - m = Py_InitModule("Crypto.Hash." _MODULE_STRING, ALG_functions); + m = Py_InitModule3("Crypto.Hash." _MODULE_STRING, ALG_functions, MODULE__doc__); #endif /* Add some symbolic constants to the module */ diff --git a/src/stream_template.c b/src/stream_template.c index c3effa4..a74d18d 100644 --- a/src/stream_template.c +++ b/src/stream_template.c @@ -24,6 +24,7 @@ * =================================================================== */ +#include "Python.h" #ifdef HAVE_CONFIG_H #include "config.h" @@ -33,7 +34,6 @@ #include <string.h> #endif -#include "Python.h" #include "pycrypto_compat.h" #include "modsupport.h" |