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