|
| 1 | +/* hex variants removed -- RR */ |
| 2 | +#include <connectd/sha1.h> |
| 3 | + |
| 4 | +/******************************************************************************* |
| 5 | + * Teeny SHA-1 |
| 6 | + * |
| 7 | + * The below sha1digest() calculates a SHA-1 hash value for a |
| 8 | + * specified data buffer and generates a hex representation of the |
| 9 | + * result. This implementation is a re-forming of the SHA-1 code at |
| 10 | + * https://github.com/jinqiangshou/EncryptionLibrary. |
| 11 | + * |
| 12 | + * Copyright (c) 2017 CTrabant |
| 13 | + * |
| 14 | + * License: MIT, see included LICENSE file for details. |
| 15 | + * |
| 16 | + * To use the sha1digest() function either copy it into an existing |
| 17 | + * project source code file or include this file in a project and put |
| 18 | + * the declaration (example below) in the sources files where needed. |
| 19 | + ******************************************************************************/ |
| 20 | + |
| 21 | +#include <string.h> |
| 22 | + |
| 23 | +/* Declaration: |
| 24 | +extern int sha1digest(uint8_t *digest, const uint8_t *data, size_t databytes); |
| 25 | +*/ |
| 26 | + |
| 27 | +/******************************************************************************* |
| 28 | + * sha1digest: https://github.com/CTrabant/teeny-sha1 |
| 29 | + * |
| 30 | + * Calculate the SHA-1 value for supplied data buffer and generate a |
| 31 | + * text representation in hexadecimal. |
| 32 | + * |
| 33 | + * Based on https://github.com/jinqiangshou/EncryptionLibrary, credit |
| 34 | + * goes to @jinqiangshou, all new bugs are mine. |
| 35 | + * |
| 36 | + * @input: |
| 37 | + * data -- data to be hashed |
| 38 | + * databytes -- bytes in data buffer to be hashed |
| 39 | + * |
| 40 | + * @output: |
| 41 | + * digest -- the result, MUST be at least 20 bytes |
| 42 | + * |
| 43 | + * @return: 0 on success and non-zero on error. |
| 44 | + ******************************************************************************/ |
| 45 | +int |
| 46 | +sha1digest(uint8_t *digest, const uint8_t *data, size_t databytes) |
| 47 | +{ |
| 48 | +#define SHA1ROTATELEFT(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) |
| 49 | + |
| 50 | + uint32_t W[80]; |
| 51 | + uint32_t H[] = {0x67452301, |
| 52 | + 0xEFCDAB89, |
| 53 | + 0x98BADCFE, |
| 54 | + 0x10325476, |
| 55 | + 0xC3D2E1F0}; |
| 56 | + uint32_t a; |
| 57 | + uint32_t b; |
| 58 | + uint32_t c; |
| 59 | + uint32_t d; |
| 60 | + uint32_t e; |
| 61 | + uint32_t f = 0; |
| 62 | + uint32_t k = 0; |
| 63 | + |
| 64 | + uint32_t idx; |
| 65 | + uint32_t lidx; |
| 66 | + uint32_t widx; |
| 67 | + uint32_t didx = 0; |
| 68 | + |
| 69 | + int32_t wcount; |
| 70 | + uint32_t temp; |
| 71 | + uint64_t databits = ((uint64_t)databytes) * 8; |
| 72 | + uint32_t loopcount = (databytes + 8) / 64 + 1; |
| 73 | + uint32_t tailbytes = 64 * loopcount - databytes; |
| 74 | + uint8_t datatail[128] = {0}; |
| 75 | + |
| 76 | + if (!digest) |
| 77 | + return -1; |
| 78 | + |
| 79 | + if (!data) |
| 80 | + return -1; |
| 81 | + |
| 82 | + /* Pre-processing of data tail (includes padding to fill out 512-bit chunk): |
| 83 | + Add bit '1' to end of message (big-endian) |
| 84 | + Add 64-bit message length in bits at very end (big-endian) */ |
| 85 | + datatail[0] = 0x80; |
| 86 | + datatail[tailbytes - 8] = (uint8_t) (databits >> 56 & 0xFF); |
| 87 | + datatail[tailbytes - 7] = (uint8_t) (databits >> 48 & 0xFF); |
| 88 | + datatail[tailbytes - 6] = (uint8_t) (databits >> 40 & 0xFF); |
| 89 | + datatail[tailbytes - 5] = (uint8_t) (databits >> 32 & 0xFF); |
| 90 | + datatail[tailbytes - 4] = (uint8_t) (databits >> 24 & 0xFF); |
| 91 | + datatail[tailbytes - 3] = (uint8_t) (databits >> 16 & 0xFF); |
| 92 | + datatail[tailbytes - 2] = (uint8_t) (databits >> 8 & 0xFF); |
| 93 | + datatail[tailbytes - 1] = (uint8_t) (databits >> 0 & 0xFF); |
| 94 | + |
| 95 | + /* Process each 512-bit chunk */ |
| 96 | + for (lidx = 0; lidx < loopcount; lidx++) |
| 97 | + { |
| 98 | + /* Compute all elements in W */ |
| 99 | + memset (W, 0, 80 * sizeof (uint32_t)); |
| 100 | + |
| 101 | + /* Break 512-bit chunk into sixteen 32-bit, big endian words */ |
| 102 | + for (widx = 0; widx <= 15; widx++) |
| 103 | + { |
| 104 | + wcount = 24; |
| 105 | + |
| 106 | + /* Copy byte-per byte from specified buffer */ |
| 107 | + while (didx < databytes && wcount >= 0) |
| 108 | + { |
| 109 | + W[widx] += (((uint32_t)data[didx]) << wcount); |
| 110 | + didx++; |
| 111 | + wcount -= 8; |
| 112 | + } |
| 113 | + /* Fill out W with padding as needed */ |
| 114 | + while (wcount >= 0) |
| 115 | + { |
| 116 | + W[widx] += (((uint32_t)datatail[didx - databytes]) << wcount); |
| 117 | + didx++; |
| 118 | + wcount -= 8; |
| 119 | + } |
| 120 | + } |
| 121 | + |
| 122 | + /* Extend the sixteen 32-bit words into eighty 32-bit words, with potential optimization from: |
| 123 | + "Improving the Performance of the Secure Hash Algorithm (SHA-1)" by Max Locktyukhin */ |
| 124 | + for (widx = 16; widx <= 31; widx++) |
| 125 | + { |
| 126 | + W[widx] = SHA1ROTATELEFT ((W[widx - 3] ^ W[widx - 8] ^ W[widx - 14] ^ W[widx - 16]), 1); |
| 127 | + } |
| 128 | + for (widx = 32; widx <= 79; widx++) |
| 129 | + { |
| 130 | + W[widx] = SHA1ROTATELEFT ((W[widx - 6] ^ W[widx - 16] ^ W[widx - 28] ^ W[widx - 32]), 2); |
| 131 | + } |
| 132 | + |
| 133 | + /* Main loop */ |
| 134 | + a = H[0]; |
| 135 | + b = H[1]; |
| 136 | + c = H[2]; |
| 137 | + d = H[3]; |
| 138 | + e = H[4]; |
| 139 | + |
| 140 | + for (idx = 0; idx <= 79; idx++) |
| 141 | + { |
| 142 | + if (idx <= 19) |
| 143 | + { |
| 144 | + f = (b & c) | ((~b) & d); |
| 145 | + k = 0x5A827999; |
| 146 | + } |
| 147 | + else if (idx >= 20 && idx <= 39) |
| 148 | + { |
| 149 | + f = b ^ c ^ d; |
| 150 | + k = 0x6ED9EBA1; |
| 151 | + } |
| 152 | + else if (idx >= 40 && idx <= 59) |
| 153 | + { |
| 154 | + f = (b & c) | (b & d) | (c & d); |
| 155 | + k = 0x8F1BBCDC; |
| 156 | + } |
| 157 | + else if (idx >= 60 && idx <= 79) |
| 158 | + { |
| 159 | + f = b ^ c ^ d; |
| 160 | + k = 0xCA62C1D6; |
| 161 | + } |
| 162 | + temp = SHA1ROTATELEFT (a, 5) + f + e + k + W[idx]; |
| 163 | + e = d; |
| 164 | + d = c; |
| 165 | + c = SHA1ROTATELEFT (b, 30); |
| 166 | + b = a; |
| 167 | + a = temp; |
| 168 | + } |
| 169 | + |
| 170 | + H[0] += a; |
| 171 | + H[1] += b; |
| 172 | + H[2] += c; |
| 173 | + H[3] += d; |
| 174 | + H[4] += e; |
| 175 | + } |
| 176 | + |
| 177 | + /* Store binary digest in supplied buffer */ |
| 178 | + if (digest) |
| 179 | + { |
| 180 | + for (idx = 0; idx < 5; idx++) |
| 181 | + { |
| 182 | + digest[idx * 4 + 0] = (uint8_t) (H[idx] >> 24); |
| 183 | + digest[idx * 4 + 1] = (uint8_t) (H[idx] >> 16); |
| 184 | + digest[idx * 4 + 2] = (uint8_t) (H[idx] >> 8); |
| 185 | + digest[idx * 4 + 3] = (uint8_t) (H[idx]); |
| 186 | + } |
| 187 | + } |
| 188 | + |
| 189 | + return 0; |
| 190 | +} /* End of sha1digest() */ |
0 commit comments