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

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# =================================================================== 

32 

33 

34"""HMAC (Hash-based Message Authentication Code) algorithm 

35 

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*. 

40 

41The strength of an HMAC depends on: 

42 

43 - the strength of the hash algorithm 

44 - the length and entropy of the secret key 

45 

46This is an example showing how to *create* a MAC: 

47 

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() 

54 

55This is an example showing how to *check* a MAC: 

56 

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" 

70 

71.. _RFC2104: http://www.ietf.org/rfc/rfc2104.txt 

72.. _FIPS-198: http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf 

73""" 

74 

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. 

77 

78__revision__ = "$Id$" 

79 

80__all__ = ['new', 'digest_size', 'HMAC' ] 

81 

82from binascii import unhexlify 

83 

84from Crypto.Util.strxor import strxor_c 

85from Crypto.Util.py3compat import * 

86 

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 

91 

92class HMAC: 

93 """Class that implements HMAC""" 

94 

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 

99 

100 def __init__(self, key, msg = None, digestmod = None): 

101 """Create a new HMAC object. 

102 

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 

121 

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()) 

129 

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 

136 

137 ipad = 0x36 

138 opad = 0x5C 

139 

140 if len(key) > blocksize: 

141 key = digestmod.new(key).digest() 

142 

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) 

148 

149 def update(self, msg): 

150 """Continue authentication of a message by consuming the next chunk of data. 

151  

152 Repeated calls are equivalent to a single call with the concatenation 

153 of all the arguments. In other words: 

154 

155 >>> m.update(a); m.update(b) 

156  

157 is equivalent to: 

158  

159 >>> m.update(a+b) 

160 

161 :Parameters: 

162 msg : byte string 

163 The next chunk of the message being authenticated 

164 """ 

165 

166 self.inner.update(msg) 

167 

168 def copy(self): 

169 """Return a copy ("clone") of the MAC object. 

170 

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. 

175 

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 

183 

184 def digest(self): 

185 """Return the **binary** (non-printable) MAC of the message that has 

186 been authenticated so far. 

187 

188 This method does not change the state of the MAC object. 

189 You can continue updating the object after calling this function. 

190  

191 :Return: A byte string of `digest_size` bytes. It may contain non-ASCII 

192 characters, including null bytes. 

193 """ 

194 

195 h = self.outer.copy() 

196 h.update(self.inner.digest()) 

197 return h.digest() 

198 

199 def verify(self, mac_tag): 

200 """Verify that a given **binary** MAC (computed by another party) is valid. 

201 

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 """ 

209 

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") 

217 

218 def hexdigest(self): 

219 """Return the **printable** MAC of the message that has been 

220 authenticated so far. 

221 

222 This method does not change the state of the MAC object. 

223  

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())]) 

229 

230 def hexverify(self, hex_mac_tag): 

231 """Verify that a given **printable** MAC (computed by another party) is valid. 

232 

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 """ 

240 

241 self.verify(unhexlify(tobytes(hex_mac_tag))) 

242 

243def new(key, msg = None, digestmod = None): 

244 """Create a new HMAC object. 

245 

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) 

263