1 /*
2  * C++ covers for md5, sha1, and sha256 (and sha512 if present)
3  *
4  * hash representation classes: md5_t, sha1_t, sha256_t (sha512_t)
5  * has generators: md5_generator(), sha1_generator(), sha256_generator()
6  *
7  * Generating a hash:
8  * sha1_t val = sha1_generator::hash_buf(buf,bufsize)
9  * sha1_t generator hasher;
10  *       hasher.update(buf,bufsize)
11  *       hasher.update(buf,bufsize)
12  *       hasher.update(buf,bufsize)
13  * sha1_t val = hasher.final()
14  *
15  * Using the values:
16  * string val.hexdigest()   --- return a hext digest
17  * val.size()		    --- the size of the hash in bytes
18  * uint8_t val.digest[SIZE] --- the buffer of the raw bytes
19  * uint8_t val.final()        --- synonym for md.digest
20  *
21  * This can be updated in the future for Mac so that the hash__ class
22  * is then subclassed by a hash__openssl or a hash__commonCrypto class.
23  *
24  *
25  * Revision History:
26  * 2012 - Simson L. Garfinkel - Created for bulk_extractor.
27  *
28  * This file is public domain
29  */
30 
31 #ifndef  HASH_T_H
32 #define  HASH_T_H
33 
34 #include <cstring>
35 #include <cstdlib>
36 
37 /**
38  * For reasons that defy explanation (at the moment), this is required.
39  */
40 
41 
42 #ifdef __APPLE__
43 #include <AvailabilityMacros.h>
44 #undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
45 #define  DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
46 #endif
47 
48 #include <stdint.h>
49 #include <assert.h>
50 #include <fcntl.h>
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <iostream>
54 #include <unistd.h>
55 
56 #if defined(HAVE_OPENSSL_HMAC_H) && defined(HAVE_OPENSSL_EVP_H)
57 #include <openssl/hmac.h>
58 #include <openssl/evp.h>
59 #else
60 #error OpenSSL required for hash_t.h
61 #endif
62 
63 #ifdef HAVE_SYS_MMAN_H
64 #include <sys/mman.h>
65 #endif
66 
67 #ifdef HAVE_SYS_MMAP_H
68 #include <sys/mmap.h>
69 #endif
70 
71 template<const EVP_MD *md(),size_t SIZE>
72 class hash__
73 {
74 public:
75     uint8_t digest[SIZE];
size()76     static size_t size() {
77         return(SIZE);
78     }
hash__()79     hash__(){
80     }
hash__(const uint8_t * provided)81     hash__(const uint8_t *provided){
82 	memcpy(this->digest,provided,size());
83     }
final()84     const uint8_t *final() const {
85 	return this->digest;
86     }
87     /* python like interface for hexdigest */
hex2int(char ch)88     static unsigned int hex2int(char ch){
89 	if(ch>='0' && ch<='9') return ch-'0';
90 	if(ch>='a' && ch<='f') return ch-'a'+10;
91 	if(ch>='A' && ch<='F') return ch-'A'+10;
92 	return 0;
93     }
hex2int(char ch0,char ch1)94     static unsigned int hex2int(char ch0,char ch1){
95         return (hex2int(ch0)<<4) | hex2int(ch1);
96     }
fromhex(const std::string & hexbuf)97     static hash__ fromhex(const std::string &hexbuf) {
98 	hash__ res;
99         assert(hexbuf.size()==SIZE*2);
100 	for(unsigned int i=0;i+1<hexbuf.size() && (i/2)<size();i+=2){
101 	    res.digest[i/2] = hex2int(hexbuf[i],hexbuf[i+1]);
102 	}
103 	return res;
104     }
hexdigest(char * hexbuf,size_t bufsize)105     const char *hexdigest(char *hexbuf,size_t bufsize) const {
106 	const char *hexbuf_start = hexbuf;
107 	for(unsigned int i=0;i<SIZE && bufsize>=3;i++){
108 	    snprintf(hexbuf,bufsize,"%02x",this->digest[i]);
109 	    hexbuf  += 2;
110 	    bufsize -= 2;
111 	}
112 	return hexbuf_start;
113     }
hexdigest()114     std::string hexdigest() const {
115 	std::string ret;
116 	char buf[SIZE*2+1];
117 	return std::string(hexdigest(buf,sizeof(buf)));
118     }
119     /**
120      * Convert a hex representation to binary, and return
121      * the number of bits converted.
122      * @param binbuf output buffer
123      * @param binbuf_size size of output buffer in bytes.
124      * @param hex    input buffer (in hex)
125      * @return the number of converted bits.
126      */
hex2bin(uint8_t * binbuf,size_t binbuf_size,const char * hex)127     static int hex2bin(uint8_t *binbuf,size_t binbuf_size,const char *hex)
128     {
129 	int bits = 0;
130 	while(hex[0] && hex[1] && binbuf_size>0){
131 	    *binbuf++ = hex2int(hex[0],hex[1]);
132 	    hex  += 2;
133 	    bits += 8;
134 	    binbuf_size -= 1;
135 	}
136 	return bits;
137     }
new_from_hex(const char * hex)138     static const hash__ *new_from_hex(const char *hex) {
139 	hash__ *val = new hash__();
140 	if(hex2bin(val->digest,sizeof(val->digest),hex)!=SIZE*8){
141 	    std::cerr << "invalid input " << hex << "(" << SIZE*8 << ")\n";
142 	    exit(1);
143 	}
144 	return val;
145     }
146     bool operator<(const hash__ &s2) const {
147 	/* Check the first byte manually as a performance hack */
148 	if(this->digest[0] < s2.digest[0]) return true;
149 	if(this->digest[0] > s2.digest[0]) return false;
150 	return memcmp(this->digest,s2.digest, SIZE) < 0;
151     }
152     bool operator==(const hash__ &s2) const {
153 	if(this->digest[0] != s2.digest[0]) return false;
154 	return memcmp(this->digest,s2.digest, SIZE) == 0;
155     }
156     friend std::ostream& operator<<(std::ostream& os,const hash__ &s2) {
157         os << s2.hexdigest();
158         return os;
159     }
160 };
161 
162 typedef hash__<EVP_md5,16> md5_t;
163 typedef hash__<EVP_sha1,20> sha1_t;
164 typedef hash__<EVP_sha256,32> sha256_t;
165 #ifdef HAVE_EVP_SHA512
166 typedef hash__<EVP_sha512,64> sha512_t;
167 #endif
168 
169 template<typename T>
170 inline std::string digest_name();
171 template<>
172 inline std::string digest_name<md5_t>() {
173     return "MD5";
174 }
175 template<>
176 inline std::string digest_name<sha1_t>() {
177     return "SHA1";
178 }
179 template<>
180 inline std::string digest_name<sha256_t>() {
181     return "SHA256";
182 }
183 #ifdef HAVE_EVP_SHA512
184 template<>
185 inline std::string digest_name<sha512_t>() {
186     return "SHA512";
187 }
188 #endif
189 
190 template<const EVP_MD *md(),size_t SIZE>
191 class hash_generator__ { 			/* generates the hash */
192  private:
193     EVP_MD_CTX* mdctx;	     /* the context for computing the value */
194     bool initialized;	       /* has the context been initialized? */
195     bool finalized;
196     /* Static function to determine if something is zero */
iszero(const uint8_t * buf,size_t bufsize)197     static bool iszero(const uint8_t *buf,size_t bufsize){
198 	for(unsigned int i=0;i<bufsize;i++){
199 	    if(buf[i]!=0) return false;
200 	}
201 	return true;
202     }
203     /* Not allowed to copy; these are prototyped but not defined, so any attempt to use them will fail, but we won't get the -Weffc++ warnings  */
204     hash_generator__ & operator=(const hash_generator__ &);
205     hash_generator__(const hash_generator__ &);
206 public:
207     int64_t hashed_bytes;
208     /* This function takes advantage of the fact that different hash functions produce residues with different sizes */
hash_generator__()209     hash_generator__():mdctx(NULL),initialized(false),finalized(false),hashed_bytes(0){ }
~hash_generator__()210     ~hash_generator__(){
211 	release();
212     }
release()213     void release(){			/* free allocated memory */
214 	if(initialized){
215 #ifdef HAVE_EVP_MD_CTX_FREE
216 	    EVP_MD_CTX_free(mdctx);
217 #else
218 	    EVP_MD_CTX_destroy(mdctx);
219 #endif
220 	    initialized = false;
221 	    hashed_bytes = 0;
222 	}
223     }
init()224     void init(){
225 	if(initialized==false){
226 #ifdef HAVE_EVP_MD_CTX_NEW
227 	    mdctx = EVP_MD_CTX_new();
228 #else
229 	    mdctx = EVP_MD_CTX_create();
230 #endif
231             if (!mdctx) throw std::bad_alloc();
232 	    EVP_DigestInit_ex(mdctx, md(), NULL);
233 	    initialized = true;
234 	    finalized = false;
235 	    hashed_bytes = 0;
236 	}
237     }
update(const uint8_t * buf,size_t bufsize)238     void update(const uint8_t *buf,size_t bufsize){
239 	if(!initialized) init();
240 	if(finalized){
241 	    std::cerr << "hashgen_t::update called after finalized\n";
242 	    exit(1);
243 	}
244 	EVP_DigestUpdate(mdctx,buf,bufsize);
245 	hashed_bytes += bufsize;
246     }
final()247     hash__<md,SIZE> final() {
248 	if(finalized){
249 	  std::cerr << "currently friendly_geneator does not cache the final value\n";
250 	  assert(0);
251           exit(1);                      // in case compiled with assertions disabled
252 	}
253 	if(!initialized){
254 	  init();			/* do it now! */
255 	}
256 	hash__<md,SIZE> val;
257 	unsigned int len = sizeof(val.digest);
258 	EVP_DigestFinal(mdctx,val.digest,&len);
259 	finalized = true;
260 	return val;
261     }
262 
263     /** Compute a sha1 from a buffer and return the hash */
hash_buf(const uint8_t * buf,size_t bufsize)264     static hash__<md,SIZE>  hash_buf(const uint8_t *buf,size_t bufsize){
265 	/* First time through find the SHA1 of 512 NULLs */
266 	hash_generator__ g;
267 	g.update(buf,bufsize);
268 	return g.final();
269     }
270 
271 #ifdef HAVE_MMAP
272     /** Static method allocateor */
hash_file(const char * fname)273     static hash__<md,SIZE> hash_file(const char *fname){
274 	int fd = open(fname,O_RDONLY
275 #ifdef O_BINARY
276 		      |O_BINARY
277 #endif
278 		      );
279 	if(fd<0) throw fname;
280 	struct stat st;
281 	if(fstat(fd,&st)<0){
282 	    close(fd);
283 	    throw fname;
284 	}
285 	const uint8_t *buf = (const uint8_t *)mmap(0,st.st_size,PROT_READ,MAP_FILE|MAP_SHARED,fd,0);
286 	if(buf==0){
287 	    close(fd);
288 	    throw fname;
289 	}
290 	hash__<md,SIZE> s = hash_buf(buf,st.st_size);
291 	munmap((void *)buf,st.st_size);
292 	close(fd);
293 	return s;
294     }
295 #endif
296 };
297 
298 typedef hash_generator__<EVP_md5,16> md5_generator;
299 typedef hash_generator__<EVP_sha1,20> sha1_generator;
300 typedef hash_generator__<EVP_sha256,32> sha256_generator;
301 
302 #ifdef HAVE_EVP_SHA512
303 typedef hash_generator__<EVP_sha512,64> sha512_generator;
304 #define HAVE_SHA512_T
305 #endif
306 
307 #endif
308