Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/Crypto/Hash/HMAC.py: 62%
58 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 07:03 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 07:03 +0000
1# HMAC.py - Implements the HMAC algorithm as described by RFC 2104.
2#
3# ===================================================================
4# Portions Copyright (c) 2001, 2002, 2003 Python Software Foundation;
5# All Rights Reserved
6#
7# This file contains code from the Python 2.2 hmac.py module (the
8# "Original Code"), with modifications made after it was incorporated
9# into PyCrypto (the "Modifications").
10#
11# To the best of our knowledge, the Python Software Foundation is the
12# copyright holder of the Original Code, and has licensed it under the
13# Python 2.2 license. See the file LEGAL/copy/LICENSE.python-2.2 for
14# details.
15#
16# The Modifications to this file are dedicated to the public domain.
17# To the extent that dedication to the public domain is not available,
18# everyone is granted a worldwide, perpetual, royalty-free,
19# non-exclusive license to exercise all rights associated with the
20# contents of this file for any purpose whatsoever. No rights are
21# reserved.
22#
23# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30# SOFTWARE.
31# ===================================================================
34"""HMAC (Hash-based Message Authentication Code) algorithm
36HMAC is a MAC defined in RFC2104_ and FIPS-198_ and constructed using
37a cryptograpic hash algorithm.
38It is usually named *HMAC-X*, where *X* is the hash algorithm; for
39instance *HMAC-SHA1* or *HMAC-MD5*.
41The strength of an HMAC depends on:
43 - the strength of the hash algorithm
44 - the length and entropy of the secret key
46This is an example showing how to *create* a MAC:
48 >>> from Crypto.Hash import HMAC
49 >>>
50 >>> secret = b'Swordfish'
51 >>> h = HMAC.new(secret)
52 >>> h.update(b'Hello')
53 >>> print h.hexdigest()
55This is an example showing how to *check* a MAC:
57 >>> from Crypto.Hash import HMAC
58 >>>
59 >>> # We have received a message 'msg' together
60 >>> # with its MAC 'mac'
61 >>>
62 >>> secret = b'Swordfish'
63 >>> h = HMAC.new(secret)
64 >>> h.update(msg)
65 >>> try:
66 >>> h.verify(mac)
67 >>> print "The message '%s' is authentic" % msg
68 >>> except ValueError:
69 >>> print "The message or the key is wrong"
71.. _RFC2104: http://www.ietf.org/rfc/rfc2104.txt
72.. _FIPS-198: http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
73"""
75# This is just a copy of the Python 2.2 HMAC module, modified to work when
76# used on versions of Python before 2.2.
78__revision__ = "$Id$"
80__all__ = ['new', 'digest_size', 'HMAC' ]
82from binascii import unhexlify
84from Crypto.Util.strxor import strxor_c
85from Crypto.Util.py3compat import *
87#: The size of the authentication tag produced by the MAC.
88#: It matches the digest size on the underlying
89#: hashing module used.
90digest_size = None
92class HMAC:
93 """Class that implements HMAC"""
95 #: The size of the authentication tag produced by the MAC.
96 #: It matches the digest size on the underlying
97 #: hashing module used.
98 digest_size = None
100 def __init__(self, key, msg = None, digestmod = None):
101 """Create a new HMAC object.
103 :Parameters:
104 key : byte string
105 secret key for the MAC object.
106 It must be long enough to match the expected security level of the
107 MAC. However, there is no benefit in using keys longer than the
108 `digest_size` of the underlying hash algorithm.
109 msg : byte string
110 The very first chunk of the message to authenticate.
111 It is equivalent to an early call to `update()`. Optional.
112 :Parameter digestmod:
113 The hash algorithm the HMAC is based on.
114 Default is `Crypto.Hash.MD5`.
115 :Type digestmod:
116 A hash module or object instantiated from `Crypto.Hash`
117 """
118 if digestmod is None:
119 from . import MD5
120 digestmod = MD5
122 self.digestmod = digestmod
123 self.outer = digestmod.new()
124 self.inner = digestmod.new()
125 try:
126 self.digest_size = digestmod.digest_size
127 except AttributeError:
128 self.digest_size = len(self.outer.digest())
130 try:
131 # The block size is 128 bytes for SHA384 and SHA512 and 64 bytes
132 # for the others hash function
133 blocksize = digestmod.block_size
134 except AttributeError:
135 blocksize = 64
137 ipad = 0x36
138 opad = 0x5C
140 if len(key) > blocksize:
141 key = digestmod.new(key).digest()
143 key = key + bchr(0) * (blocksize - len(key))
144 self.outer.update(strxor_c(key, opad))
145 self.inner.update(strxor_c(key, ipad))
146 if (msg):
147 self.update(msg)
149 def update(self, msg):
150 """Continue authentication of a message by consuming the next chunk of data.
152 Repeated calls are equivalent to a single call with the concatenation
153 of all the arguments. In other words:
155 >>> m.update(a); m.update(b)
157 is equivalent to:
159 >>> m.update(a+b)
161 :Parameters:
162 msg : byte string
163 The next chunk of the message being authenticated
164 """
166 self.inner.update(msg)
168 def copy(self):
169 """Return a copy ("clone") of the MAC object.
171 The copy will have the same internal state as the original MAC
172 object.
173 This can be used to efficiently compute the MAC of strings that
174 share a common initial substring.
176 :Returns: An `HMAC` object
177 """
178 other = HMAC(b(""))
179 other.digestmod = self.digestmod
180 other.inner = self.inner.copy()
181 other.outer = self.outer.copy()
182 return other
184 def digest(self):
185 """Return the **binary** (non-printable) MAC of the message that has
186 been authenticated so far.
188 This method does not change the state of the MAC object.
189 You can continue updating the object after calling this function.
191 :Return: A byte string of `digest_size` bytes. It may contain non-ASCII
192 characters, including null bytes.
193 """
195 h = self.outer.copy()
196 h.update(self.inner.digest())
197 return h.digest()
199 def verify(self, mac_tag):
200 """Verify that a given **binary** MAC (computed by another party) is valid.
202 :Parameters:
203 mac_tag : byte string
204 The expected MAC of the message.
205 :Raises ValueError:
206 if the MAC does not match. It means that the message
207 has been tampered with or that the MAC key is incorrect.
208 """
210 mac = self.digest()
211 res = 0
212 # Constant-time comparison
213 for x,y in zip(mac, mac_tag):
214 res |= bord(x) ^ bord(y)
215 if res or len(mac_tag)!=self.digest_size:
216 raise ValueError("MAC check failed")
218 def hexdigest(self):
219 """Return the **printable** MAC of the message that has been
220 authenticated so far.
222 This method does not change the state of the MAC object.
224 :Return: A string of 2* `digest_size` bytes. It contains only
225 hexadecimal ASCII digits.
226 """
227 return "".join(["%02x" % bord(x)
228 for x in tuple(self.digest())])
230 def hexverify(self, hex_mac_tag):
231 """Verify that a given **printable** MAC (computed by another party) is valid.
233 :Parameters:
234 hex_mac_tag : string
235 The expected MAC of the message, as a hexadecimal string.
236 :Raises ValueError:
237 if the MAC does not match. It means that the message
238 has been tampered with or that the MAC key is incorrect.
239 """
241 self.verify(unhexlify(tobytes(hex_mac_tag)))
243def new(key, msg = None, digestmod = None):
244 """Create a new HMAC object.
246 :Parameters:
247 key : byte string
248 key for the MAC object.
249 It must be long enough to match the expected security level of the
250 MAC. However, there is no benefit in using keys longer than the
251 `digest_size` of the underlying hash algorithm.
252 msg : byte string
253 The very first chunk of the message to authenticate.
254 It is equivalent to an early call to `HMAC.update()`.
255 Optional.
256 :Parameter digestmod:
257 The hash to use to implement the HMAC. Default is `Crypto.Hash.MD5`.
258 :Type digestmod:
259 A hash module or instantiated object from `Crypto.Hash`
260 :Returns: An `HMAC` object
261 """
262 return HMAC(key, msg, digestmod)