Skip to content

Commit 23ac152

Browse files
author
greg
committed
[ sf.net patch # 1121611 ]
A new hashlib module to replace the md5 and sha modules. It adds support for additional secure hashes such as SHA-256 and SHA-512. The hashlib module uses OpenSSL for fast platform optimized implementations of algorithms when available. The old md5 and sha modules still exist as wrappers around hashlib to preserve backwards compatibility. git-svn-id: http://svn.python.org/projects/python/trunk@39316 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 266618c commit 23ac152

21 files changed

Lines changed: 2587 additions & 51 deletions

Doc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ Joakim Sernbrant
164164
Justin Sheehy
165165
Michael Simcich
166166
Ionel Simionescu
167+
Gregory P. Smith
167168
Roy Smith
168169
Clay Spence
169170
Nicholas Spies

Doc/Makefile.deps

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ LIBFILES= $(MANSTYLES) $(INDEXSTYLES) $(COMMONTEX) \
202202
lib/librgbimg.tex \
203203
lib/libossaudiodev.tex \
204204
lib/libcrypto.tex \
205+
lib/libhashlib.tex \
205206
lib/libmd5.tex \
206207
lib/libsha.tex \
207208
lib/libhmac.tex \

Doc/lib/lib.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ \chapter*{Front Matter\label{front}}
303303

304304
\input{libcrypto} % Cryptographic Services
305305
\input{libhmac}
306+
\input{libhashlib}
306307
\input{libmd5}
307308
\input{libsha}
308309

Doc/lib/libhmac.tex

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ \section{\module{hmac} ---
1414
\begin{funcdesc}{new}{key\optional{, msg\optional{, digestmod}}}
1515
Return a new hmac object. If \var{msg} is present, the method call
1616
\code{update(\var{msg})} is made. \var{digestmod} is the digest
17-
module for the HMAC object to use. It defaults to the
18-
\refmodule{md5} module.
17+
constructor or module for the HMAC object to use. It defaults to
18+
the \code{\refmodule{hashlib}.md5} constructor. \note{The md5 hash
19+
has known weaknesses but remains the default for backwards compatibility.
20+
Choose a better one for your application.}
1921
\end{funcdesc}
2022

2123
An HMAC object has the following methods:
@@ -29,14 +31,14 @@ \section{\module{hmac} ---
2931

3032
\begin{methoddesc}[hmac]{digest}{}
3133
Return the digest of the strings passed to the \method{update()}
32-
method so far. This is a 16-byte string (for \refmodule{md5}) or a
33-
20-byte string (for \refmodule{sha}) which may contain non-\ASCII{}
34-
characters, including NUL bytes.
34+
method so far. This string will be the same length as the
35+
\var{digest_size} of the digest given to the constructor. It
36+
may contain non-\ASCII{} characters, including NUL bytes.
3537
\end{methoddesc}
3638

3739
\begin{methoddesc}[hmac]{hexdigest}{}
38-
Like \method{digest()} except the digest is returned as a string of
39-
length 32 for \refmodule{md5} (40 for \refmodule{sha}), containing
40+
Like \method{digest()} except the digest is returned as a string
41+
twice the length containing
4042
only hexadecimal digits. This may be used to exchange the value
4143
safely in email or other non-binary environments.
4244
\end{methoddesc}
@@ -46,3 +48,7 @@ \section{\module{hmac} ---
4648
efficiently compute the digests of strings that share a common
4749
initial substring.
4850
\end{methoddesc}
51+
52+
\begin{seealso}
53+
\seemodule{hashlib}{The python module providing secure hash functions.}
54+
\end{seealso}

Doc/lib/libmd5.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ \section{\module{md5} ---
44
\declaremodule{builtin}{md5}
55
\modulesynopsis{RSA's MD5 message digest algorithm.}
66

7+
\deprecated{2.5}{Use the \refmodule{hashlib} module instead.}
78

89
This module implements the interface to RSA's MD5 message digest
910
\index{message digest, MD5}

Doc/lib/libsha.tex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ \section{\module{sha} ---
55
\modulesynopsis{NIST's secure hash algorithm, SHA.}
66
\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org}
77

8+
\deprecated{2.5}{Use the \refmodule{hashlib} module instead.}
9+
810

911
This module implements the interface to NIST's\index{NIST} secure hash
1012
algorithm,\index{Secure Hash Algorithm} known as SHA-1. SHA-1 is an

Doc/whatsnew/whatsnew25.tex

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,15 @@ \section{New, Improved, and Deprecated Modules}
247247
a different directory as the extraction target, and to unpack only a
248248
subset of the archive's members. (Contributed by Lars Gust\"abel.)
249249

250+
\item A new \module{hashlib} module has been added to replace the
251+
\module{md5} and \module{sha} modules and adds support for additional
252+
secure hashes such as SHA-256 and SHA-512. The \module{hashlib} module
253+
uses OpenSSL for fast platform optimized implementations of algorithms
254+
when available. The old \module{md5} and \module{sha} modules still
255+
exist as wrappers around hashlib to preserve backwards compatibility.
256+
257+
(Contributed by Gregory P. Smith.)
258+
250259
\end{itemize}
251260

252261

Lib/hashlib.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# $Id$
2+
#
3+
# Copyright (C) 2005 Gregory P. Smith (greg@electricrain.com)
4+
# Licensed to PSF under a Contributor Agreement.
5+
#
6+
7+
__doc__ = """hashlib module - A common interface to many hash functions.
8+
9+
new(name, string='') - returns a new hash object implementing the
10+
given hash function; initializing the hash
11+
using the given string data.
12+
13+
Named constructor functions are also available, these are much faster
14+
than using new():
15+
16+
md5(), sha1(), sha224(), sha256(), sha384(), and sha512()
17+
18+
More algorithms may be available on your platform but the above are
19+
guaranteed to exist.
20+
21+
Choose your hash function wisely. Some have known weaknesses.
22+
sha384 and sha512 will be slow on 32 bit platforms.
23+
"""
24+
25+
26+
def __get_builtin_constructor(name):
27+
if name in ('SHA1', 'sha1'):
28+
import _sha
29+
return _sha.new
30+
elif name in ('MD5', 'md5'):
31+
import _md5
32+
return _md5.new
33+
elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'):
34+
import _sha256
35+
bs = name[3:]
36+
if bs == '256':
37+
return _sha256.sha256
38+
elif bs == '224':
39+
return _sha256.sha224
40+
elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'):
41+
import _sha512
42+
bs = name[3:]
43+
if bs == '512':
44+
return _sha512.sha512
45+
elif bs == '384':
46+
return _sha512.sha384
47+
48+
raise ValueError, "unsupported hash type"
49+
50+
51+
def __py_new(name, string=''):
52+
"""new(name, string='') - Return a new hashing object using the named algorithm;
53+
optionally initialized with a string.
54+
"""
55+
return __get_builtin_constructor(name)(string)
56+
57+
58+
def __hash_new(name, string=''):
59+
"""new(name, string='') - Return a new hashing object using the named algorithm;
60+
optionally initialized with a string.
61+
"""
62+
try:
63+
return _hashlib.new(name, string)
64+
except ValueError:
65+
# If the _hashlib module (OpenSSL) doesn't support the named
66+
# hash, try using our builtin implementations.
67+
# This allows for SHA224/256 and SHA384/512 support even though
68+
# the OpenSSL library prior to 0.9.8 doesn't provide them.
69+
return __get_builtin_constructor(name)(string)
70+
71+
72+
try:
73+
import _hashlib
74+
# use the wrapper of the C implementation
75+
new = __hash_new
76+
77+
for opensslFuncName in filter(lambda n: n.startswith('openssl_'), dir(_hashlib)):
78+
funcName = opensslFuncName[len('openssl_'):]
79+
try:
80+
# try them all, some may not work due to the OpenSSL
81+
# version not supporting that algorithm.
82+
f = getattr(_hashlib, opensslFuncName)
83+
f()
84+
# Use the C function directly (very fast)
85+
exec funcName + ' = f'
86+
except ValueError:
87+
try:
88+
# Use the builtin implementation directly (fast)
89+
exec funcName + ' = __get_builtin_constructor(funcName)'
90+
except ValueError:
91+
# this one has no builtin implementation, don't define it
92+
pass
93+
# clean up our locals
94+
del f
95+
del opensslFuncName
96+
del funcName
97+
98+
except ImportError:
99+
# We don't have the _hashlib OpenSSL module?
100+
# use the built in legacy interfaces via a wrapper function
101+
new = __py_new
102+
103+
# lookup the C function to use directly for the named constructors
104+
md5 = __get_builtin_constructor('md5')
105+
sha1 = __get_builtin_constructor('sha1')
106+
sha224 = __get_builtin_constructor('sha224')
107+
sha256 = __get_builtin_constructor('sha256')
108+
sha384 = __get_builtin_constructor('sha384')
109+
sha512 = __get_builtin_constructor('sha512')
110+

Lib/hmac.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,33 @@ def __init__(self, key, msg = None, digestmod = None):
2828
2929
key: key for the keyed hash object.
3030
msg: Initial input for the hash, if provided.
31-
digestmod: A module supporting PEP 247. Defaults to the md5 module.
31+
digestmod: A module supporting PEP 247. *OR*
32+
A hashlib constructor returning a new hash object.
33+
Defaults to hashlib.md5.
3234
"""
3335

3436
if key is _secret_backdoor_key: # cheap
3537
return
3638

3739
if digestmod is None:
38-
import md5
39-
digestmod = md5
40+
import hashlib
41+
digestmod = hashlib.md5
4042

41-
self.digestmod = digestmod
42-
self.outer = digestmod.new()
43-
self.inner = digestmod.new()
44-
self.digest_size = digestmod.digest_size
43+
if callable(digestmod):
44+
self.digest_cons = digestmod
45+
else:
46+
self.digest_cons = lambda d='': digestmod.new(d)
47+
48+
self.outer = self.digest_cons()
49+
self.inner = self.digest_cons()
50+
self.digest_size = self.inner.digest_size
4551

4652
blocksize = 64
4753
ipad = "\x36" * blocksize
4854
opad = "\x5C" * blocksize
4955

5056
if len(key) > blocksize:
51-
key = digestmod.new(key).digest()
57+
key = self.digest_cons(key).digest()
5258

5359
key = key + chr(0) * (blocksize - len(key))
5460
self.outer.update(_strxor(key, opad))
@@ -70,7 +76,7 @@ def copy(self):
7076
An update to this copy won't affect the original object.
7177
"""
7278
other = HMAC(_secret_backdoor_key)
73-
other.digestmod = self.digestmod
79+
other.digest_cons = self.digest_cons
7480
other.digest_size = self.digest_size
7581
other.inner = self.inner.copy()
7682
other.outer = self.outer.copy()

Lib/md5.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# $Id$
2+
#
3+
# Copyright (C) 2005 Gregory P. Smith (greg@electricrain.com)
4+
# Licensed to PSF under a Contributor Agreement.
5+
6+
from hashlib import md5
7+
new = md5
8+
9+
blocksize = 1 # legacy value (wrong in any useful sense)
10+
digest_size = 16

0 commit comments

Comments
 (0)