xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/fuzzer/FuzzerSHA1.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
10b57cec5SDimitry Andric //===- FuzzerSHA1.h - Private copy of the SHA1 implementation ---*- C++ -* ===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric // This code is taken from public domain
90b57cec5SDimitry Andric // (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c)
100b57cec5SDimitry Andric // and modified by adding anonymous namespace, adding an interface
110b57cec5SDimitry Andric // function fuzzer::ComputeSHA1() and removing unnecessary code.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric // lib/Fuzzer can not use SHA1 implementation from openssl because
140b57cec5SDimitry Andric // openssl may not be available and because we may be fuzzing openssl itself.
150b57cec5SDimitry Andric // For the same reason we do not want to depend on SHA1 from LLVM tree.
160b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #include "FuzzerSHA1.h"
190b57cec5SDimitry Andric #include "FuzzerDefs.h"
205ffd83dbSDimitry Andric #include "FuzzerPlatform.h"
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric /* This code is public-domain - it is based on libcrypt
230b57cec5SDimitry Andric  * placed in the public domain by Wei Dai and other contributors.
240b57cec5SDimitry Andric  */
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric #include <iomanip>
270b57cec5SDimitry Andric #include <sstream>
280b57cec5SDimitry Andric #include <stdint.h>
290b57cec5SDimitry Andric #include <string.h>
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric namespace {  // Added for LibFuzzer
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric #ifdef __BIG_ENDIAN__
340b57cec5SDimitry Andric # define SHA_BIG_ENDIAN
350b57cec5SDimitry Andric // Windows is always little endian and MSVC doesn't have <endian.h>
360b57cec5SDimitry Andric #elif defined __LITTLE_ENDIAN__ || LIBFUZZER_WINDOWS
370b57cec5SDimitry Andric /* override */
380b57cec5SDimitry Andric #elif defined __BYTE_ORDER
390b57cec5SDimitry Andric # if __BYTE_ORDER__ ==  __ORDER_BIG_ENDIAN__
400b57cec5SDimitry Andric # define SHA_BIG_ENDIAN
410b57cec5SDimitry Andric # endif
420b57cec5SDimitry Andric #else // ! defined __LITTLE_ENDIAN__
430b57cec5SDimitry Andric # include <endian.h> // machine/endian.h
440b57cec5SDimitry Andric # if __BYTE_ORDER__ ==  __ORDER_BIG_ENDIAN__
450b57cec5SDimitry Andric #  define SHA_BIG_ENDIAN
460b57cec5SDimitry Andric # endif
470b57cec5SDimitry Andric #endif
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric /* header */
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric #define HASH_LENGTH 20
530b57cec5SDimitry Andric #define BLOCK_LENGTH 64
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric typedef struct sha1nfo {
560b57cec5SDimitry Andric 	uint32_t buffer[BLOCK_LENGTH/4];
570b57cec5SDimitry Andric 	uint32_t state[HASH_LENGTH/4];
580b57cec5SDimitry Andric 	uint32_t byteCount;
590b57cec5SDimitry Andric 	uint8_t bufferOffset;
600b57cec5SDimitry Andric 	uint8_t keyBuffer[BLOCK_LENGTH];
610b57cec5SDimitry Andric 	uint8_t innerHash[HASH_LENGTH];
620b57cec5SDimitry Andric } sha1nfo;
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric /* public API - prototypes - TODO: doxygen*/
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric /**
670b57cec5SDimitry Andric  */
680b57cec5SDimitry Andric void sha1_init(sha1nfo *s);
690b57cec5SDimitry Andric /**
700b57cec5SDimitry Andric  */
710b57cec5SDimitry Andric void sha1_writebyte(sha1nfo *s, uint8_t data);
720b57cec5SDimitry Andric /**
730b57cec5SDimitry Andric  */
740b57cec5SDimitry Andric void sha1_write(sha1nfo *s, const char *data, size_t len);
750b57cec5SDimitry Andric /**
760b57cec5SDimitry Andric  */
770b57cec5SDimitry Andric uint8_t* sha1_result(sha1nfo *s);
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric /* code */
810b57cec5SDimitry Andric #define SHA1_K0  0x5a827999
820b57cec5SDimitry Andric #define SHA1_K20 0x6ed9eba1
830b57cec5SDimitry Andric #define SHA1_K40 0x8f1bbcdc
840b57cec5SDimitry Andric #define SHA1_K60 0xca62c1d6
850b57cec5SDimitry Andric 
sha1_init(sha1nfo * s)860b57cec5SDimitry Andric void sha1_init(sha1nfo *s) {
870b57cec5SDimitry Andric 	s->state[0] = 0x67452301;
880b57cec5SDimitry Andric 	s->state[1] = 0xefcdab89;
890b57cec5SDimitry Andric 	s->state[2] = 0x98badcfe;
900b57cec5SDimitry Andric 	s->state[3] = 0x10325476;
910b57cec5SDimitry Andric 	s->state[4] = 0xc3d2e1f0;
920b57cec5SDimitry Andric 	s->byteCount = 0;
930b57cec5SDimitry Andric 	s->bufferOffset = 0;
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
sha1_rol32(uint32_t number,uint8_t bits)960b57cec5SDimitry Andric uint32_t sha1_rol32(uint32_t number, uint8_t bits) {
970b57cec5SDimitry Andric 	return ((number << bits) | (number >> (32-bits)));
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric 
sha1_hashBlock(sha1nfo * s)1000b57cec5SDimitry Andric void sha1_hashBlock(sha1nfo *s) {
1010b57cec5SDimitry Andric 	uint8_t i;
1020b57cec5SDimitry Andric 	uint32_t a,b,c,d,e,t;
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric 	a=s->state[0];
1050b57cec5SDimitry Andric 	b=s->state[1];
1060b57cec5SDimitry Andric 	c=s->state[2];
1070b57cec5SDimitry Andric 	d=s->state[3];
1080b57cec5SDimitry Andric 	e=s->state[4];
1090b57cec5SDimitry Andric 	for (i=0; i<80; i++) {
1100b57cec5SDimitry Andric 		if (i>=16) {
1110b57cec5SDimitry Andric 			t = s->buffer[(i+13)&15] ^ s->buffer[(i+8)&15] ^ s->buffer[(i+2)&15] ^ s->buffer[i&15];
1120b57cec5SDimitry Andric 			s->buffer[i&15] = sha1_rol32(t,1);
1130b57cec5SDimitry Andric 		}
1140b57cec5SDimitry Andric 		if (i<20) {
1150b57cec5SDimitry Andric 			t = (d ^ (b & (c ^ d))) + SHA1_K0;
1160b57cec5SDimitry Andric 		} else if (i<40) {
1170b57cec5SDimitry Andric 			t = (b ^ c ^ d) + SHA1_K20;
1180b57cec5SDimitry Andric 		} else if (i<60) {
1190b57cec5SDimitry Andric 			t = ((b & c) | (d & (b | c))) + SHA1_K40;
1200b57cec5SDimitry Andric 		} else {
1210b57cec5SDimitry Andric 			t = (b ^ c ^ d) + SHA1_K60;
1220b57cec5SDimitry Andric 		}
1230b57cec5SDimitry Andric 		t+=sha1_rol32(a,5) + e + s->buffer[i&15];
1240b57cec5SDimitry Andric 		e=d;
1250b57cec5SDimitry Andric 		d=c;
1260b57cec5SDimitry Andric 		c=sha1_rol32(b,30);
1270b57cec5SDimitry Andric 		b=a;
1280b57cec5SDimitry Andric 		a=t;
1290b57cec5SDimitry Andric 	}
1300b57cec5SDimitry Andric 	s->state[0] += a;
1310b57cec5SDimitry Andric 	s->state[1] += b;
1320b57cec5SDimitry Andric 	s->state[2] += c;
1330b57cec5SDimitry Andric 	s->state[3] += d;
1340b57cec5SDimitry Andric 	s->state[4] += e;
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric 
137*fe6060f1SDimitry Andric // Adds the least significant byte of |data|.
sha1_addUncounted(sha1nfo * s,uint32_t data)138*fe6060f1SDimitry Andric void sha1_addUncounted(sha1nfo *s, uint32_t data) {
1390b57cec5SDimitry Andric   uint8_t *const b = (uint8_t *)s->buffer;
1400b57cec5SDimitry Andric #ifdef SHA_BIG_ENDIAN
141*fe6060f1SDimitry Andric   b[s->bufferOffset] = static_cast<uint8_t>(data);
1420b57cec5SDimitry Andric #else
143*fe6060f1SDimitry Andric   b[s->bufferOffset ^ 3] = static_cast<uint8_t>(data);
1440b57cec5SDimitry Andric #endif
1450b57cec5SDimitry Andric 	s->bufferOffset++;
1460b57cec5SDimitry Andric 	if (s->bufferOffset == BLOCK_LENGTH) {
1470b57cec5SDimitry Andric 		sha1_hashBlock(s);
1480b57cec5SDimitry Andric 		s->bufferOffset = 0;
1490b57cec5SDimitry Andric 	}
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric 
sha1_writebyte(sha1nfo * s,uint8_t data)1520b57cec5SDimitry Andric void sha1_writebyte(sha1nfo *s, uint8_t data) {
1530b57cec5SDimitry Andric 	++s->byteCount;
1540b57cec5SDimitry Andric 	sha1_addUncounted(s, data);
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric 
sha1_write(sha1nfo * s,const char * data,size_t len)1570b57cec5SDimitry Andric void sha1_write(sha1nfo *s, const char *data, size_t len) {
1580b57cec5SDimitry Andric 	for (;len--;) sha1_writebyte(s, (uint8_t) *data++);
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric 
sha1_pad(sha1nfo * s)1610b57cec5SDimitry Andric void sha1_pad(sha1nfo *s) {
1620b57cec5SDimitry Andric 	// Implement SHA-1 padding (fips180-2 §5.1.1)
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric 	// Pad with 0x80 followed by 0x00 until the end of the block
1650b57cec5SDimitry Andric 	sha1_addUncounted(s, 0x80);
1660b57cec5SDimitry Andric 	while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00);
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric 	// Append length in the last 8 bytes
1690b57cec5SDimitry Andric 	sha1_addUncounted(s, 0); // We're only using 32 bit lengths
1700b57cec5SDimitry Andric 	sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths
1710b57cec5SDimitry Andric 	sha1_addUncounted(s, 0); // So zero pad the top bits
1720b57cec5SDimitry Andric 	sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8
1730b57cec5SDimitry Andric 	sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as
1740b57cec5SDimitry Andric 	sha1_addUncounted(s, s->byteCount >> 13); // byte.
1750b57cec5SDimitry Andric 	sha1_addUncounted(s, s->byteCount >> 5);
1760b57cec5SDimitry Andric 	sha1_addUncounted(s, s->byteCount << 3);
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
sha1_result(sha1nfo * s)1790b57cec5SDimitry Andric uint8_t* sha1_result(sha1nfo *s) {
1800b57cec5SDimitry Andric 	// Pad to complete the last block
1810b57cec5SDimitry Andric 	sha1_pad(s);
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric #ifndef SHA_BIG_ENDIAN
1840b57cec5SDimitry Andric 	// Swap byte order back
1850b57cec5SDimitry Andric 	int i;
1860b57cec5SDimitry Andric 	for (i=0; i<5; i++) {
1870b57cec5SDimitry Andric 		s->state[i]=
1880b57cec5SDimitry Andric 			  (((s->state[i])<<24)& 0xff000000)
1890b57cec5SDimitry Andric 			| (((s->state[i])<<8) & 0x00ff0000)
1900b57cec5SDimitry Andric 			| (((s->state[i])>>8) & 0x0000ff00)
1910b57cec5SDimitry Andric 			| (((s->state[i])>>24)& 0x000000ff);
1920b57cec5SDimitry Andric 	}
1930b57cec5SDimitry Andric #endif
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric 	// Return pointer to hash (20 characters)
1960b57cec5SDimitry Andric 	return (uint8_t*) s->state;
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric }  // namespace; Added for LibFuzzer
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric namespace fuzzer {
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric // The rest is added for LibFuzzer
ComputeSHA1(const uint8_t * Data,size_t Len,uint8_t * Out)2040b57cec5SDimitry Andric void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out) {
2050b57cec5SDimitry Andric   sha1nfo s;
2060b57cec5SDimitry Andric   sha1_init(&s);
2070b57cec5SDimitry Andric   sha1_write(&s, (const char*)Data, Len);
2080b57cec5SDimitry Andric   memcpy(Out, sha1_result(&s), HASH_LENGTH);
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric 
Sha1ToString(const uint8_t Sha1[kSHA1NumBytes])2110b57cec5SDimitry Andric std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]) {
2120b57cec5SDimitry Andric   std::stringstream SS;
2130b57cec5SDimitry Andric   for (int i = 0; i < kSHA1NumBytes; i++)
2140b57cec5SDimitry Andric     SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Sha1[i];
2150b57cec5SDimitry Andric   return SS.str();
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric 
Hash(const Unit & U)2180b57cec5SDimitry Andric std::string Hash(const Unit &U) {
2190b57cec5SDimitry Andric   uint8_t Hash[kSHA1NumBytes];
2200b57cec5SDimitry Andric   ComputeSHA1(U.data(), U.size(), Hash);
2210b57cec5SDimitry Andric   return Sha1ToString(Hash);
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric }
225