1 //===- FuzzerSHA1.h - Private copy of the SHA1 implementation ---*- C++ -* ===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // This code is taken from public domain 9 // (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c) 10 // and modified by adding anonymous namespace, adding an interface 11 // function fuzzer::ComputeSHA1() and removing unnecessary code. 12 // 13 // lib/Fuzzer can not use SHA1 implementation from openssl because 14 // openssl may not be available and because we may be fuzzing openssl itself. 15 // For the same reason we do not want to depend on SHA1 from LLVM tree. 16 //===----------------------------------------------------------------------===// 17 18 #include "FuzzerSHA1.h" 19 #include "FuzzerDefs.h" 20 #include "FuzzerPlatform.h" 21 22 /* This code is public-domain - it is based on libcrypt 23 * placed in the public domain by Wei Dai and other contributors. 24 */ 25 26 #include <iomanip> 27 #include <sstream> 28 #include <stdint.h> 29 #include <string.h> 30 31 namespace { // Added for LibFuzzer 32 33 #ifdef __BIG_ENDIAN__ 34 # define SHA_BIG_ENDIAN 35 // Windows is always little endian and MSVC doesn't have <endian.h> 36 #elif defined __LITTLE_ENDIAN__ || LIBFUZZER_WINDOWS 37 /* override */ 38 #elif defined __BYTE_ORDER 39 # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 40 # define SHA_BIG_ENDIAN 41 # endif 42 #else // ! defined __LITTLE_ENDIAN__ 43 # include <endian.h> // machine/endian.h 44 # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 45 # define SHA_BIG_ENDIAN 46 # endif 47 #endif 48 49 50 /* header */ 51 52 #define HASH_LENGTH 20 53 #define BLOCK_LENGTH 64 54 55 typedef struct sha1nfo { 56 uint32_t buffer[BLOCK_LENGTH/4]; 57 uint32_t state[HASH_LENGTH/4]; 58 uint32_t byteCount; 59 uint8_t bufferOffset; 60 uint8_t keyBuffer[BLOCK_LENGTH]; 61 uint8_t innerHash[HASH_LENGTH]; 62 } sha1nfo; 63 64 /* public API - prototypes - TODO: doxygen*/ 65 66 /** 67 */ 68 void sha1_init(sha1nfo *s); 69 /** 70 */ 71 void sha1_writebyte(sha1nfo *s, uint8_t data); 72 /** 73 */ 74 void sha1_write(sha1nfo *s, const char *data, size_t len); 75 /** 76 */ 77 uint8_t* sha1_result(sha1nfo *s); 78 79 80 /* code */ 81 #define SHA1_K0 0x5a827999 82 #define SHA1_K20 0x6ed9eba1 83 #define SHA1_K40 0x8f1bbcdc 84 #define SHA1_K60 0xca62c1d6 85 86 void sha1_init(sha1nfo *s) { 87 s->state[0] = 0x67452301; 88 s->state[1] = 0xefcdab89; 89 s->state[2] = 0x98badcfe; 90 s->state[3] = 0x10325476; 91 s->state[4] = 0xc3d2e1f0; 92 s->byteCount = 0; 93 s->bufferOffset = 0; 94 } 95 96 uint32_t sha1_rol32(uint32_t number, uint8_t bits) { 97 return ((number << bits) | (number >> (32-bits))); 98 } 99 100 void sha1_hashBlock(sha1nfo *s) { 101 uint8_t i; 102 uint32_t a,b,c,d,e,t; 103 104 a=s->state[0]; 105 b=s->state[1]; 106 c=s->state[2]; 107 d=s->state[3]; 108 e=s->state[4]; 109 for (i=0; i<80; i++) { 110 if (i>=16) { 111 t = s->buffer[(i+13)&15] ^ s->buffer[(i+8)&15] ^ s->buffer[(i+2)&15] ^ s->buffer[i&15]; 112 s->buffer[i&15] = sha1_rol32(t,1); 113 } 114 if (i<20) { 115 t = (d ^ (b & (c ^ d))) + SHA1_K0; 116 } else if (i<40) { 117 t = (b ^ c ^ d) + SHA1_K20; 118 } else if (i<60) { 119 t = ((b & c) | (d & (b | c))) + SHA1_K40; 120 } else { 121 t = (b ^ c ^ d) + SHA1_K60; 122 } 123 t+=sha1_rol32(a,5) + e + s->buffer[i&15]; 124 e=d; 125 d=c; 126 c=sha1_rol32(b,30); 127 b=a; 128 a=t; 129 } 130 s->state[0] += a; 131 s->state[1] += b; 132 s->state[2] += c; 133 s->state[3] += d; 134 s->state[4] += e; 135 } 136 137 // Adds the least significant byte of |data|. 138 void sha1_addUncounted(sha1nfo *s, uint32_t data) { 139 uint8_t *const b = (uint8_t *)s->buffer; 140 #ifdef SHA_BIG_ENDIAN 141 b[s->bufferOffset] = static_cast<uint8_t>(data); 142 #else 143 b[s->bufferOffset ^ 3] = static_cast<uint8_t>(data); 144 #endif 145 s->bufferOffset++; 146 if (s->bufferOffset == BLOCK_LENGTH) { 147 sha1_hashBlock(s); 148 s->bufferOffset = 0; 149 } 150 } 151 152 void sha1_writebyte(sha1nfo *s, uint8_t data) { 153 ++s->byteCount; 154 sha1_addUncounted(s, data); 155 } 156 157 void sha1_write(sha1nfo *s, const char *data, size_t len) { 158 for (;len--;) sha1_writebyte(s, (uint8_t) *data++); 159 } 160 161 void sha1_pad(sha1nfo *s) { 162 // Implement SHA-1 padding (fips180-2 §5.1.1) 163 164 // Pad with 0x80 followed by 0x00 until the end of the block 165 sha1_addUncounted(s, 0x80); 166 while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00); 167 168 // Append length in the last 8 bytes 169 sha1_addUncounted(s, 0); // We're only using 32 bit lengths 170 sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths 171 sha1_addUncounted(s, 0); // So zero pad the top bits 172 sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8 173 sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as 174 sha1_addUncounted(s, s->byteCount >> 13); // byte. 175 sha1_addUncounted(s, s->byteCount >> 5); 176 sha1_addUncounted(s, s->byteCount << 3); 177 } 178 179 uint8_t* sha1_result(sha1nfo *s) { 180 // Pad to complete the last block 181 sha1_pad(s); 182 183 #ifndef SHA_BIG_ENDIAN 184 // Swap byte order back 185 int i; 186 for (i=0; i<5; i++) { 187 s->state[i]= 188 (((s->state[i])<<24)& 0xff000000) 189 | (((s->state[i])<<8) & 0x00ff0000) 190 | (((s->state[i])>>8) & 0x0000ff00) 191 | (((s->state[i])>>24)& 0x000000ff); 192 } 193 #endif 194 195 // Return pointer to hash (20 characters) 196 return (uint8_t*) s->state; 197 } 198 199 } // namespace; Added for LibFuzzer 200 201 namespace fuzzer { 202 203 // The rest is added for LibFuzzer 204 void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out) { 205 sha1nfo s; 206 sha1_init(&s); 207 sha1_write(&s, (const char*)Data, Len); 208 memcpy(Out, sha1_result(&s), HASH_LENGTH); 209 } 210 211 std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]) { 212 std::stringstream SS; 213 for (int i = 0; i < kSHA1NumBytes; i++) 214 SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Sha1[i]; 215 return SS.str(); 216 } 217 218 std::string Hash(const Unit &U) { 219 uint8_t Hash[kSHA1NumBytes]; 220 ComputeSHA1(U.data(), U.size(), Hash); 221 return Sha1ToString(Hash); 222 } 223 224 } 225