/** * Cloned from https://github.com/CTrabant/teeny-sha1 * in commit f05a2d0019e12850bb482274c1a21ae7a4fb84bd */ /******************************************************************************* * Teeny SHA-1 * * The below sha1digest() calculates a SHA-1 hash value for a * specified data buffer and generates a hex representation of the * result. This implementation is a re-forming of the SHA-1 code at * https://github.com/jinqiangshou/EncryptionLibrary. * * Copyright (c) 2017 CTrabant * * License: MIT, see included LICENSE file for details. * * To use the sha1digest() function either copy it into an existing * project source code file or include this file in a project and put * the declaration (example below) in the sources files where needed. ******************************************************************************/ #include #include #include #include /* Declaration: extern int sha1digest(uint8_t *digest, char *hexdigest, const uint8_t *data, size_t databytes); */ /******************************************************************************* * sha1digest: https://github.com/CTrabant/teeny-sha1 * * Calculate the SHA-1 value for supplied data buffer and generate a * text representation in hexadecimal. * * Based on https://github.com/jinqiangshou/EncryptionLibrary, credit * goes to @jinqiangshou, all new bugs are mine. * * @input: * data -- data to be hashed * databytes -- bytes in data buffer to be hashed * * @output: * digest -- the result, MUST be at least 20 bytes * hexdigest -- the result in hex, MUST be at least 41 bytes * * At least one of the output buffers must be supplied. The other, if not * desired, may be set to NULL. * * @return: 0 on success and non-zero on error. ******************************************************************************/ int sha1digest(uint8_t *digest, char *hexdigest, const uint8_t *data, size_t databytes) { #define SHA1ROTATELEFT(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) uint32_t W[80]; uint32_t H[] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0}; uint32_t a; uint32_t b; uint32_t c; uint32_t d; uint32_t e; uint32_t f = 0; uint32_t k = 0; uint32_t idx; uint32_t lidx; uint32_t widx; uint32_t didx = 0; int32_t wcount; uint32_t temp; uint64_t databits = ((uint64_t)databytes) * 8; uint32_t loopcount = (databytes + 8) / 64 + 1; uint32_t tailbytes = 64 * loopcount - databytes; uint8_t datatail[128] = {0}; if (!digest && !hexdigest) return -1; if (!data) return -1; /* Pre-processing of data tail (includes padding to fill out 512-bit chunk): Add bit '1' to end of message (big-endian) Add 64-bit message length in bits at very end (big-endian) */ datatail[0] = 0x80; datatail[tailbytes - 8] = (uint8_t) (databits >> 56 & 0xFF); datatail[tailbytes - 7] = (uint8_t) (databits >> 48 & 0xFF); datatail[tailbytes - 6] = (uint8_t) (databits >> 40 & 0xFF); datatail[tailbytes - 5] = (uint8_t) (databits >> 32 & 0xFF); datatail[tailbytes - 4] = (uint8_t) (databits >> 24 & 0xFF); datatail[tailbytes - 3] = (uint8_t) (databits >> 16 & 0xFF); datatail[tailbytes - 2] = (uint8_t) (databits >> 8 & 0xFF); datatail[tailbytes - 1] = (uint8_t) (databits >> 0 & 0xFF); /* Process each 512-bit chunk */ for (lidx = 0; lidx < loopcount; lidx++) { /* Compute all elements in W */ memset (W, 0, 80 * sizeof (uint32_t)); /* Break 512-bit chunk into sixteen 32-bit, big endian words */ for (widx = 0; widx <= 15; widx++) { wcount = 24; /* Copy byte-per byte from specified buffer */ while (didx < databytes && wcount >= 0) { W[widx] += (((uint32_t)data[didx]) << wcount); didx++; wcount -= 8; } /* Fill out W with padding as needed */ while (wcount >= 0) { W[widx] += (((uint32_t)datatail[didx - databytes]) << wcount); didx++; wcount -= 8; } } /* Extend the sixteen 32-bit words into eighty 32-bit words, with potential optimization from: "Improving the Performance of the Secure Hash Algorithm (SHA-1)" by Max Locktyukhin */ for (widx = 16; widx <= 31; widx++) { W[widx] = SHA1ROTATELEFT ((W[widx - 3] ^ W[widx - 8] ^ W[widx - 14] ^ W[widx - 16]), 1); } for (widx = 32; widx <= 79; widx++) { W[widx] = SHA1ROTATELEFT ((W[widx - 6] ^ W[widx - 16] ^ W[widx - 28] ^ W[widx - 32]), 2); } /* Main loop */ a = H[0]; b = H[1]; c = H[2]; d = H[3]; e = H[4]; for (idx = 0; idx <= 79; idx++) { if (idx <= 19) { f = (b & c) | ((~b) & d); k = 0x5A827999; } else if (idx >= 20 && idx <= 39) { f = b ^ c ^ d; k = 0x6ED9EBA1; } else if (idx >= 40 && idx <= 59) { f = (b & c) | (b & d) | (c & d); k = 0x8F1BBCDC; } else if (idx >= 60 && idx <= 79) { f = b ^ c ^ d; k = 0xCA62C1D6; } temp = SHA1ROTATELEFT (a, 5) + f + e + k + W[idx]; e = d; d = c; c = SHA1ROTATELEFT (b, 30); b = a; a = temp; } H[0] += a; H[1] += b; H[2] += c; H[3] += d; H[4] += e; } /* Store binary digest in supplied buffer */ if (digest) { for (idx = 0; idx < 5; idx++) { digest[idx * 4 + 0] = (uint8_t) (H[idx] >> 24); digest[idx * 4 + 1] = (uint8_t) (H[idx] >> 16); digest[idx * 4 + 2] = (uint8_t) (H[idx] >> 8); digest[idx * 4 + 3] = (uint8_t) (H[idx]); } } /* Store hex version of digest in supplied buffer */ if (hexdigest) { snprintf (hexdigest, 41, "%08x%08x%08x%08x%08x", H[0],H[1],H[2],H[3],H[4]); } return 0; } /* End of sha1digest() */