/ adafruit_hashlib / _sha256.py
_sha256.py
1 # The MIT License (MIT) 2 # 3 # Copyright (c) 2017 Paul Sokolovsky 4 # Modified by Brent Rubell for Adafruit Industries, 2019 5 # 6 # Permission is hereby granted, free of charge, to any person obtaining a copy 7 # of this software and associated documentation files (the "Software"), to deal 8 # in the Software without restriction, including without limitation the rights 9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 # copies of the Software, and to permit persons to whom the Software is 11 # furnished to do so, subject to the following conditions: 12 # 13 # The above copyright notice and this permission notice shall be included in 14 # all copies or substantial portions of the Software. 15 # 16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 # THE SOFTWARE. 23 """ 24 `_sha256.py` 25 ====================================================== 26 SHA-256 Hash Algorithm. 27 * Author(s): Tom St Denis, Paul Sokolovsky, Brent Rubell 28 """ 29 # pylint: disable=invalid-name, unnecessary-lambda, missing-docstring 30 31 # SHA Block size and message digest sizes, in bytes. 32 SHA_BLOCKSIZE = 64 33 SHA_DIGESTSIZE = 32 34 35 36 def new_shaobject(): 37 """Struct. for storing SHA information.""" 38 return { 39 "digest": [0] * 8, 40 "count_lo": 0, 41 "count_hi": 0, 42 "data": [0] * SHA_BLOCKSIZE, 43 "local": 0, 44 "digestsize": 0, 45 } 46 47 48 # Various logical functions 49 ROR = ( 50 lambda x, y: (((x & 0xFFFFFFFF) >> (y & 31)) | (x << (32 - (y & 31)))) & 0xFFFFFFFF 51 ) 52 Ch = lambda x, y, z: (z ^ (x & (y ^ z))) 53 Maj = lambda x, y, z: (((x | y) & z) | (x & y)) 54 S = lambda x, n: ROR(x, n) 55 R = lambda x, n: (x & 0xFFFFFFFF) >> n 56 Sigma0 = lambda x: (S(x, 2) ^ S(x, 13) ^ S(x, 22)) 57 Sigma1 = lambda x: (S(x, 6) ^ S(x, 11) ^ S(x, 25)) 58 Gamma0 = lambda x: (S(x, 7) ^ S(x, 18) ^ R(x, 3)) 59 Gamma1 = lambda x: (S(x, 17) ^ S(x, 19) ^ R(x, 10)) 60 61 # pylint: disable=too-many-statements 62 def sha_transform(sha_info): 63 W = [] 64 65 d = sha_info["data"] 66 for i in range(0, 16): 67 W.append( 68 (d[4 * i] << 24) + (d[4 * i + 1] << 16) + (d[4 * i + 2] << 8) + d[4 * i + 3] 69 ) 70 71 for i in range(16, 64): 72 W.append( 73 (Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]) & 0xFFFFFFFF 74 ) 75 76 ss = sha_info["digest"][:] 77 78 # pylint: disable=too-many-arguments, line-too-long 79 def RND(a, b, c, d, e, f, g, h, i, ki): 80 """Compress""" 81 t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i] 82 t1 = Sigma0(a) + Maj(a, b, c) 83 d += t0 84 h = t0 + t1 85 return d & 0xFFFFFFFF, h & 0xFFFFFFFF 86 87 ss[3], ss[7] = RND( 88 ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], 0, 0x428A2F98 89 ) 90 ss[2], ss[6] = RND( 91 ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], 1, 0x71374491 92 ) 93 ss[1], ss[5] = RND( 94 ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], 2, 0xB5C0FBCF 95 ) 96 ss[0], ss[4] = RND( 97 ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], 3, 0xE9B5DBA5 98 ) 99 ss[7], ss[3] = RND( 100 ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], 4, 0x3956C25B 101 ) 102 ss[6], ss[2] = RND( 103 ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], 5, 0x59F111F1 104 ) 105 ss[5], ss[1] = RND( 106 ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], 6, 0x923F82A4 107 ) 108 ss[4], ss[0] = RND( 109 ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], 7, 0xAB1C5ED5 110 ) 111 ss[3], ss[7] = RND( 112 ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], 8, 0xD807AA98 113 ) 114 ss[2], ss[6] = RND( 115 ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], 9, 0x12835B01 116 ) 117 ss[1], ss[5] = RND( 118 ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], 10, 0x243185BE 119 ) 120 ss[0], ss[4] = RND( 121 ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], 11, 0x550C7DC3 122 ) 123 ss[7], ss[3] = RND( 124 ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], 12, 0x72BE5D74 125 ) 126 ss[6], ss[2] = RND( 127 ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], 13, 0x80DEB1FE 128 ) 129 ss[5], ss[1] = RND( 130 ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], 14, 0x9BDC06A7 131 ) 132 ss[4], ss[0] = RND( 133 ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], 15, 0xC19BF174 134 ) 135 ss[3], ss[7] = RND( 136 ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], 16, 0xE49B69C1 137 ) 138 ss[2], ss[6] = RND( 139 ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], 17, 0xEFBE4786 140 ) 141 ss[1], ss[5] = RND( 142 ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], 18, 0x0FC19DC6 143 ) 144 ss[0], ss[4] = RND( 145 ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], 19, 0x240CA1CC 146 ) 147 ss[7], ss[3] = RND( 148 ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], 20, 0x2DE92C6F 149 ) 150 ss[6], ss[2] = RND( 151 ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], 21, 0x4A7484AA 152 ) 153 ss[5], ss[1] = RND( 154 ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], 22, 0x5CB0A9DC 155 ) 156 ss[4], ss[0] = RND( 157 ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], 23, 0x76F988DA 158 ) 159 ss[3], ss[7] = RND( 160 ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], 24, 0x983E5152 161 ) 162 ss[2], ss[6] = RND( 163 ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], 25, 0xA831C66D 164 ) 165 ss[1], ss[5] = RND( 166 ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], 26, 0xB00327C8 167 ) 168 ss[0], ss[4] = RND( 169 ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], 27, 0xBF597FC7 170 ) 171 ss[7], ss[3] = RND( 172 ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], 28, 0xC6E00BF3 173 ) 174 ss[6], ss[2] = RND( 175 ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], 29, 0xD5A79147 176 ) 177 ss[5], ss[1] = RND( 178 ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], 30, 0x06CA6351 179 ) 180 ss[4], ss[0] = RND( 181 ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], 31, 0x14292967 182 ) 183 ss[3], ss[7] = RND( 184 ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], 32, 0x27B70A85 185 ) 186 ss[2], ss[6] = RND( 187 ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], 33, 0x2E1B2138 188 ) 189 ss[1], ss[5] = RND( 190 ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], 34, 0x4D2C6DFC 191 ) 192 ss[0], ss[4] = RND( 193 ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], 35, 0x53380D13 194 ) 195 ss[7], ss[3] = RND( 196 ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], 36, 0x650A7354 197 ) 198 ss[6], ss[2] = RND( 199 ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], 37, 0x766A0ABB 200 ) 201 ss[5], ss[1] = RND( 202 ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], 38, 0x81C2C92E 203 ) 204 ss[4], ss[0] = RND( 205 ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], 39, 0x92722C85 206 ) 207 ss[3], ss[7] = RND( 208 ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], 40, 0xA2BFE8A1 209 ) 210 ss[2], ss[6] = RND( 211 ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], 41, 0xA81A664B 212 ) 213 ss[1], ss[5] = RND( 214 ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], 42, 0xC24B8B70 215 ) 216 ss[0], ss[4] = RND( 217 ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], 43, 0xC76C51A3 218 ) 219 ss[7], ss[3] = RND( 220 ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], 44, 0xD192E819 221 ) 222 ss[6], ss[2] = RND( 223 ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], 45, 0xD6990624 224 ) 225 ss[5], ss[1] = RND( 226 ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], 46, 0xF40E3585 227 ) 228 ss[4], ss[0] = RND( 229 ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], 47, 0x106AA070 230 ) 231 ss[3], ss[7] = RND( 232 ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], 48, 0x19A4C116 233 ) 234 ss[2], ss[6] = RND( 235 ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], 49, 0x1E376C08 236 ) 237 ss[1], ss[5] = RND( 238 ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], 50, 0x2748774C 239 ) 240 ss[0], ss[4] = RND( 241 ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], 51, 0x34B0BCB5 242 ) 243 ss[7], ss[3] = RND( 244 ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], 52, 0x391C0CB3 245 ) 246 ss[6], ss[2] = RND( 247 ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], 53, 0x4ED8AA4A 248 ) 249 ss[5], ss[1] = RND( 250 ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], 54, 0x5B9CCA4F 251 ) 252 ss[4], ss[0] = RND( 253 ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], 55, 0x682E6FF3 254 ) 255 ss[3], ss[7] = RND( 256 ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], 56, 0x748F82EE 257 ) 258 ss[2], ss[6] = RND( 259 ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], 57, 0x78A5636F 260 ) 261 ss[1], ss[5] = RND( 262 ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], 58, 0x84C87814 263 ) 264 ss[0], ss[4] = RND( 265 ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], ss[4], 59, 0x8CC70208 266 ) 267 ss[7], ss[3] = RND( 268 ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], ss[3], 60, 0x90BEFFFA 269 ) 270 ss[6], ss[2] = RND( 271 ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], ss[2], 61, 0xA4506CEB 272 ) 273 ss[5], ss[1] = RND( 274 ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], ss[1], 62, 0xBEF9A3F7 275 ) 276 ss[4], ss[0] = RND( 277 ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[0], 63, 0xC67178F2 278 ) 279 280 # Feedback 281 dig = [] 282 for i, x in enumerate(sha_info["digest"]): 283 dig.append((x + ss[i]) & 0xFFFFFFFF) 284 sha_info["digest"] = dig 285 286 287 def sha_init(): 288 """Initialize the SHA digest.""" 289 sha_info = new_shaobject() 290 sha_info["digest"] = [ 291 0x6A09E667, 292 0xBB67AE85, 293 0x3C6EF372, 294 0xA54FF53A, 295 0x510E527F, 296 0x9B05688C, 297 0x1F83D9AB, 298 0x5BE0CD19, 299 ] 300 sha_info["count_lo"] = 0 301 sha_info["count_hi"] = 0 302 sha_info["local"] = 0 303 sha_info["digestsize"] = 32 304 return sha_info 305 306 307 def sha224_init(): 308 """Initialize a SHA224 digest.""" 309 sha_info = new_shaobject() 310 sha_info["digest"] = [ 311 0xC1059ED8, 312 0x367CD507, 313 0x3070DD17, 314 0xF70E5939, 315 0xFFC00B31, 316 0x68581511, 317 0x64F98FA7, 318 0xBEFA4FA4, 319 ] 320 sha_info["count_lo"] = 0 321 sha_info["count_hi"] = 0 322 sha_info["local"] = 0 323 sha_info["digestsize"] = 28 324 return sha_info 325 326 327 def getbuf(s): 328 if isinstance(s, str): 329 return s.encode("ascii") 330 return bytes(s) 331 332 333 def sha_update(sha_info, buffer): 334 """Update the SHA digest. 335 :param dict sha_info: SHA Digest. 336 :param str buffer: SHA buffer size. 337 """ 338 if isinstance(buffer, str): 339 raise TypeError("Unicode strings must be encoded before hashing") 340 count = len(buffer) 341 buffer_idx = 0 342 clo = (sha_info["count_lo"] + (count << 3)) & 0xFFFFFFFF 343 if clo < sha_info["count_lo"]: 344 sha_info["count_hi"] += 1 345 sha_info["count_lo"] = clo 346 347 sha_info["count_hi"] += count >> 29 348 349 if sha_info["local"]: 350 i = SHA_BLOCKSIZE - sha_info["local"] 351 if i > count: 352 i = count 353 354 # copy buffer 355 for x in enumerate(buffer[buffer_idx : buffer_idx + i]): 356 sha_info["data"][sha_info["local"] + x[0]] = x[1] 357 358 count -= i 359 buffer_idx += i 360 361 sha_info["local"] += i 362 if sha_info["local"] == SHA_BLOCKSIZE: 363 sha_transform(sha_info) 364 sha_info["local"] = 0 365 else: 366 return 367 368 while count >= SHA_BLOCKSIZE: 369 # copy buffer 370 sha_info["data"] = list(buffer[buffer_idx : buffer_idx + SHA_BLOCKSIZE]) 371 count -= SHA_BLOCKSIZE 372 buffer_idx += SHA_BLOCKSIZE 373 sha_transform(sha_info) 374 375 # copy buffer 376 pos = sha_info["local"] 377 sha_info["data"][pos : pos + count] = list(buffer[buffer_idx : buffer_idx + count]) 378 sha_info["local"] = count 379 380 381 def sha_final(sha_info): 382 """Finish computing the SHA Digest.""" 383 lo_bit_count = sha_info["count_lo"] 384 hi_bit_count = sha_info["count_hi"] 385 count = (lo_bit_count >> 3) & 0x3F 386 sha_info["data"][count] = 0x80 387 count += 1 388 if count > SHA_BLOCKSIZE - 8: 389 # zero the bytes in data after the count 390 sha_info["data"] = sha_info["data"][:count] + ([0] * (SHA_BLOCKSIZE - count)) 391 sha_transform(sha_info) 392 # zero bytes in data 393 sha_info["data"] = [0] * SHA_BLOCKSIZE 394 else: 395 sha_info["data"] = sha_info["data"][:count] + ([0] * (SHA_BLOCKSIZE - count)) 396 397 sha_info["data"][56] = (hi_bit_count >> 24) & 0xFF 398 sha_info["data"][57] = (hi_bit_count >> 16) & 0xFF 399 sha_info["data"][58] = (hi_bit_count >> 8) & 0xFF 400 sha_info["data"][59] = (hi_bit_count >> 0) & 0xFF 401 sha_info["data"][60] = (lo_bit_count >> 24) & 0xFF 402 sha_info["data"][61] = (lo_bit_count >> 16) & 0xFF 403 sha_info["data"][62] = (lo_bit_count >> 8) & 0xFF 404 sha_info["data"][63] = (lo_bit_count >> 0) & 0xFF 405 406 sha_transform(sha_info) 407 408 dig = [] 409 for i in sha_info["digest"]: 410 dig.extend( 411 [((i >> 24) & 0xFF), ((i >> 16) & 0xFF), ((i >> 8) & 0xFF), (i & 0xFF)] 412 ) 413 return bytes(dig) 414 415 416 # pylint: disable=protected-access 417 class sha256: 418 digest_size = digestsize = SHA_DIGESTSIZE 419 block_size = SHA_BLOCKSIZE 420 name = "sha256" 421 422 def __init__(self, s=None): 423 """Constructs a SHA256 hash object. 424 """ 425 self._sha = sha_init() 426 if s: 427 sha_update(self._sha, getbuf(s)) 428 429 def update(self, s): 430 """Updates the hash object with a bytes-like object, s.""" 431 sha_update(self._sha, getbuf(s)) 432 433 def digest(self): 434 """Returns the digest of the data passed to the update() 435 method so far.""" 436 return sha_final(self._sha.copy())[: self._sha["digestsize"]] 437 438 def hexdigest(self): 439 """Like digest() except the digest is returned as a string object of 440 double length, containing only hexadecimal digits. 441 """ 442 return "".join(["%.2x" % i for i in self.digest()]) 443 444 def copy(self): 445 """Return a copy (“clone”) of the hash object. 446 """ 447 new = sha256() 448 new._sha = self._sha.copy() 449 return new 450 451 452 # pylint: disable=protected-access, super-init-not-called 453 class sha224(sha256): 454 digest_size = digestsize = 28 455 name = "sha224" 456 457 def __init__(self, s=None): 458 """Constructs a SHA224 hash object. 459 """ 460 self._sha = sha224_init() 461 if s: 462 sha_update(self._sha, getbuf(s)) 463 464 def copy(self): 465 """Return a copy (“clone”) of the hash object. 466 """ 467 new = sha224() 468 new._sha = self._sha.copy() 469 return new