diff --git a/inc/hgl/util/hash/Hash.h b/inc/hgl/util/hash/Hash.h new file mode 100644 index 0000000..d49ed80 --- /dev/null +++ b/inc/hgl/util/hash/Hash.h @@ -0,0 +1,317 @@ +#ifndef HGL_UTIL_HASH_INCLUDE +#define HGL_UTIL_HASH_INCLUDE + +#include +namespace hgl +{ + namespace util + { + /** + * Hash算法枚举 + */ + enum class HASH ///Hash算法枚举 + { + Adler32, ///<一种较CRC32更为安全的快速HASH算法 + CRC32, ///<最快速的HASH算法,但最不安全,仅用于低安全性的简单验证 + MD4, ///<较MD5在安全性下稍弱。但仍未被攻破,且较MD5更快 + MD5, ///<最常用的HASH算法 + + SHA1, ///<较MD5更为安全,但计算较慢 + SHA1LE, /// struct HashCode + { + unsigned char code[SIZE]; + + public: + + template + using CharArray=T[(SIZE<<1)+1]; + + public: + + HashCode() + { + hgl_zero(code); + } + + static constexpr int size(){return SIZE;} + + const unsigned char operator[](int index)const + { + return code[index]; + } + + void CopyFrom(const void *ptr) + { + memcpy(code,ptr,SIZE); + } + + void FromString(const char *str) + { + ParseHexStr(code,str,SIZE); + } + + template + void ToUpperString(T *str,const T gap_char=0) const + { + ToUpperHexStr(str,code,SIZE,gap_char); + } + + template + void ToLowerString(T *str,const T gap_char=0) const + { + ToLowerHexStr(str,code,SIZE,gap_char); + } + + const int CompFunc(const HashCode &hash)const + { + const unsigned char *s=code; + const unsigned char *t=hash.code; + + for(int i=0;i &,CompFunc) + };//template struct HashCode + + using HashCodeCRC32 =HashCode<4> ; + using HashCodeAdler32 =HashCode<4> ; + using HashCodeMD5 =HashCode<16> ; + using HashCodeMD4 =HashCode<16> ; + using HashCodeSHA1 =HashCode<20> ; + using HashCodeSHA1LE =HashCode<20> ; + using HashCodeSHA256 =HashCode<32> ; + using HashCodeSHA512 =HashCode<64> ; + + const int hash_code_bytes[]={4,4,16,16,20,20,32,64}; //hash码长度 + + /** + * 散列值计算功能基类 + */ + class Hash ///散列值计算功能基类 + { + public: + + virtual ~Hash()=default; + + virtual void GetName(UTF8String &)const=0; ///<取得HASH算法的名称 + virtual void GetName(UTF16String &)const=0; ///<取得HASH算法的名称 + virtual const int GetHashBytes()const=0; ///<取得HASH码字节长度(MD4/MD5为16,SHA1为20) + + virtual void Init()=0; ///<初始化散列值计算 + virtual void Update(const void *,uint)=0; ///<提交新的数据 + virtual void Final(void *)=0; ///<结束并取得结果 + };//class Hash + + template Hash *CreateHash(); ///<创建一个hash值计算类实例 + +#define HGL_CREATE_HASH_FUNC(name) Hash *Create##name##Hash(); \ + template<> inline Hash *CreateHash(){return Create##name##Hash();} + + HGL_CREATE_HASH_FUNC(Adler32) + HGL_CREATE_HASH_FUNC(CRC32) + HGL_CREATE_HASH_FUNC(MD4) + HGL_CREATE_HASH_FUNC(MD5) + HGL_CREATE_HASH_FUNC(SHA1) + HGL_CREATE_HASH_FUNC(SHA1LE) + HGL_CREATE_HASH_FUNC(SHA256) + HGL_CREATE_HASH_FUNC(SHA512) + +#undef HGL_CREATE_HASH_FUNC + + inline Hash *CreateHash(HASH ha) + { + ENUM_CLASS_RANGE_ERROR_RETURN_NULLPTR(HASH,ha) + + using CreateHashFunc=Hash *(*)(); + + const CreateHashFunc func[(size_t)HASH::RANGE_SIZE]= + { + CreateAdler32Hash, + CreateCRC32Hash, + CreateMD4Hash, + CreateMD5Hash, + CreateSHA1Hash, + CreateSHA1LEHash, + CreateSHA256Hash, + CreateSHA512Hash + }; + + return func[(size_t)ha](); + } + + /** + * 计算一段数据的Hash值 + * @param data 数据指针 + * @param size 数据长度 + * @param ha hash算法 + * @param hash_code 计算后的hash值存放处 + * @return 是否计算成功 + */ + template bool CountHash(const void *data,int size,void *hash_code) + { + if(!data||size<=0||!hash_code)return(false); + + Hash *h=CreateHash(); + + if(!h)return(false); + + h->Init(); + h->Update(data,size); + h->Final(hash_code); + + delete h; + return(true); + } + + /** + * 计算一段数据的Hash值 + * @param data 数据指针 + * @param size 数据长度 + * @param ha hash算法 + * @param hash_code 计算后的hash值存放处 + * @return 是否计算成功 + */ + inline bool CountHash(const void *data,int size,HASH ha,void *hash_code) + { + ENUM_CLASS_RANGE_ERROR_RETURN_FALSE(HASH,ha) + if(!data||size<=0||!hash_code)return(false); + + using CountHashFunc=bool (*)(const void *,int size,void *); + + const CountHashFunc func[(size_t)HASH::RANGE_SIZE]= + { + CountHash, + CountHash, + CountHash, + CountHash, + CountHash, + CountHash, + CountHash, + CountHash + }; + + return func[(size_t)ha](data,size,hash_code); + } + + /** + * 计算一段数据的Hash值 + * @param data 数据指针 + * @param size 数据长度 + * @param ha hash算法 + * @param hash_str 计算后的hash值存放处 + * @param litter 小写字母 + * @return 是否计算成功 + */ + template bool CountHashStr(const void *data,int size,UTF8String &hash_str,bool litter=true) + { + if(!data||size<=0)return(false); + + Hash *h=CreateHash(); + + if(!h)return(false); + + const int hash_bytes=hash_code_bytes[(size_t)ha]; + + uint8 *hash_code=new uint8[hash_bytes]; + char *hash_code_str=new char[1+(hash_bytes<<1)]; + + h->Init(); + h->Update(data,size); + h->Final(hash_code); + + delete h; + + DataToHexStr(hash_code_str,hash_code,hash_bytes,litter?LowerHexChar:UpperHexChar); + + hash_str.SetInstance(hash_code_str,hash_bytes<<1); + + delete[] hash_code; + return(true); + } + + /** + * 计算一段数据的Hash值 + * @param data 数据指针 + * @param size 数据长度 + * @param ha hash算法 + * @param hash_str 计算后的hash值存放处 + * @param litter 小写字母 + * @return 是否计算成功 + */ + inline bool CountHash(const void *data,int size,HASH ha,UTF8String &hash_str,bool litter=true) + { + ENUM_CLASS_RANGE_ERROR_RETURN_FALSE(HASH,ha) + if(!data||size<=0)return(false); + + using CountHashFunc=bool (*)(const void *,int size,UTF8String &,bool); + + const CountHashFunc func[(size_t)HASH::RANGE_SIZE]= + { + CountHashStr, + CountHashStr, + CountHashStr, + CountHashStr, + CountHashStr, + CountHashStr, + CountHashStr, + CountHashStr + }; + + return func[(size_t)ha](data,size,hash_str,litter); + } + +#define HGL_COUNT_HASH_FUNC(name) inline bool Count##name(const void *data, int size, HashCode##name &hc) { return CountHash(data, size, &hc); } \ + inline bool Count##name(const void *data, int size, UTF8String &hash_str, bool litter = true) { return CountHashStr(data, size, hash_str, litter); } \ + inline bool Count##name(const UTF8String &str, UTF8String &hash_str, bool litter = true) { return CountHashStr(str.c_str(), str.Length(), hash_str, litter); } + + HGL_COUNT_HASH_FUNC(Adler32) + HGL_COUNT_HASH_FUNC(CRC32) + HGL_COUNT_HASH_FUNC(MD4) + HGL_COUNT_HASH_FUNC(MD5) + HGL_COUNT_HASH_FUNC(SHA1) + HGL_COUNT_HASH_FUNC(SHA1LE) + HGL_COUNT_HASH_FUNC(SHA256) + HGL_COUNT_HASH_FUNC(SHA512) + +#undef HGL_COUNT_HASH_FUNC + + /** + * 取得一个文件的hash值 + * @param filename 文件名 + * @param ha hash算法 + * @param hash_code 计算后的hash存放处 + * @return 是否计算成功 + */ + bool GetFileHash(const OSString &filename,HASH ha,void *hash_code); + + /** + * 取得一个文件的hash值 + * @param filename 文件名 + * @param ha hash算法 + * @param hash_str 计算后的hash值存放处 + * @param litter 小写字母 + * @return 是否计算成功 + */ + bool GetFileHash(const OSString &filename,HASH ha,UTF8String &hash_str,bool litter=true); + }//namespace util +}//namespace hgl +#endif//HGL_UTIL_HASH_INCLUDE diff --git a/inc/hgl/util/hash/SHA1LE.h b/inc/hgl/util/hash/SHA1LE.h new file mode 100644 index 0000000..fb6589f --- /dev/null +++ b/inc/hgl/util/hash/SHA1LE.h @@ -0,0 +1,55 @@ +#ifndef HGL_ALGORITHM_HASH_SHA1LE_INCLUDE +#define HGL_ALGORITHM_HASH_SHA1LE_INCLUDE + +#include +namespace hgl +{ + namespace util + { + /** + * SHA1-LE Hash算法
+ * 算法保持SHA1不变,改动如下:
+ * 1.去掉了因BigEndian设计造成的LittleEndian处理器需要做大小头转换的部分 + * 2.可自定义起始因子 + * 3.可动态修改扰乱因子 + */ + class SHA1LE:public Hash + { + enum + { + BLOCK_SIZE = 64, + DIGEST_SIZE = 20 + }; + + uint32 digest[5]; // Message digest + uint32 countLo; // 64-bit bit count + uint32 countHi; + uint32 data[16]; // SHA data buffer + uint32 slop; // # of bytes saved in data[] + + uint32 K[4]; + + uint32 W[80]; + + private: + + void sha1_transform(); + + public: + + void GetName(UTF8String &str)const override{str="SHA1LE";} + void GetName(UTF16String &str)const override{str=U16_TEXT("SHA1LE");} + + const int GetHashBytes()const override {return DIGEST_SIZE;} + + void Init(const uint32 *start_digest,const uint32 *mysterious_constants); ///<开始一次新的HASH计算,并指定初始因子和扰乱因子 + void Init()override; ///<开始一次新的HASH计算,并使用缺省初始因子和扰乱因子 + + void SetMark(const uint32 *mysterious_constants); ///<更新扰乱因子 + + void Update(const void *input,uint count)override; ///<添加新的HASH数据 + void Final(void *result)override; ///<结束本次HASH计算 + };//class SHA1LE + }//namespace util +}//namespace hgl +#endif//HGL_ALGORITHM_HASH_SHA1LE_INCLUDE diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e4df102..6df776b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -78,9 +78,32 @@ SET(CMD_SOURCE ${CMUTIL_ROOT_INCLUDE_PATH}/hgl/util/cmd/CmdParse.h SOURCE_GROUP("Command Line" FILES ${CMD_SOURCE}) #SOURCE_GROUP("Time" FILES ${TIME_SOURCE}) + +option(CM_UTIL_SUPPORT_HASH "Build HASH module" ON) + +IF(CM_UTIL_SUPPORT_HASH) + SET(HASH_HEADER_FILES ${CMUTIL_ROOT_INCLUDE_PATH}/hgl/util/hash/Hash.h + ${CMUTIL_ROOT_INCLUDE_PATH}/hgl/util/hash/SHA1LE.h) + + SET(HASH_SOURCE_FILES hash/adler32.cpp + hash/crc32.cpp + hash/Hash.cpp + hash/md4.cpp + hash/md5.cpp + hash/sha1.cpp + hash/sha1le.cpp + hash/sha256.cpp + hash/sha512.cpp) + + SOURCE_GROUP("HASH" FILES ${HASH_HEADER_FILES} ${HASH_SOURCE_FILES}) +ENDIF(CM_UTIL_SUPPORT_HASH) + add_cm_library(CMUtil "CM" ${CMD_SOURCE} # ${TIME_SOURCE} ${XML_PARSE_SOURCE} ${JSON_TOOL_SOURCE} + + ${HASH_HEADER_FILES} + ${HASH_SOURCE_FILES} ) diff --git a/src/hash/Hash.cpp b/src/hash/Hash.cpp new file mode 100644 index 0000000..4e34997 --- /dev/null +++ b/src/hash/Hash.cpp @@ -0,0 +1,43 @@ +#include +#include + +namespace hgl +{ + namespace util + { + bool GetFileHash(const OSString &filename,HASH ha,void *hash_code) + { + Hash *hash=CreateHash(ha); + + if(!hash)return(false); + + io::FileInputStream fp; + + if(fp.Open(filename)==false) + return(false); + + int filesize=fp.GetSize(); + int pos=0,size; + uint8 data[HGL_SIZE_1MB]; + + hash->Init(); + + while(posfilesize)size=filesize-pos; + + fp.Read(data,size); + + hash->Update(data,size); + pos+=size; + } + + hash->Final(hash_code); + fp.Close(); + delete hash; + + return(true); + } + }//namespace util +}//namespace hgl diff --git a/src/hash/adler32.cpp b/src/hash/adler32.cpp new file mode 100644 index 0000000..2e70026 --- /dev/null +++ b/src/hash/adler32.cpp @@ -0,0 +1,150 @@ +#include + +namespace hgl +{ + namespace + { + #define BASE 65521UL /* largest prime smaller than 65536 */ + #define NMAX 5552 + /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + #define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} + #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); + #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); + #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); + #define DO16(buf) DO8(buf,0); DO8(buf,8); + /* use NO_DIVIDE if your processor does not do division in hardware */ + #define NO_DIVIDE //不使用除法 + #ifdef NO_DIVIDE + # define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) + # define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) + #else + # define MOD(a) a %= BASE + # define MOD4(a) a %= BASE + #endif + }//namespace + + namespace util + { + /** + * Adler32校检码计算 + * @param adler 初始码 + * @param buf 待校验数据指针 + * @param len 待校验数据长度 + * @return 校检码 + */ + uint32 CountAdler32(uint32 adler,const uint8 *buf,uint32 len) + { + uint32 sum2; + uint32 n; + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == 0) + return 1L; + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + /* return recombined sums */ + return adler | (sum2 << 16); + } + + class Adler32:public Hash + { + uint32 result; + + public: + + void GetName(UTF8String &str)const override{str=U8_TEXT("Adler32");} + void GetName(UTF16String &str)const override{str=U16_TEXT("Adler32");} + + const int GetHashBytes()const override{return 4;} + + void Init()override + { + result=0; + } + + void Update(const void *input,uint inputLen)override + { + result=CountAdler32(result,(const uint8 *)input,inputLen); + } + + void Final(void *digest)override + { + *(uint32 *)digest=result; + } + };//class Adler32 + + Hash *CreateAdler32Hash(){return(new Adler32);} + }//namespace util +}//namespace hgl diff --git a/src/hash/crc32.cpp b/src/hash/crc32.cpp new file mode 100644 index 0000000..1ea5ec1 --- /dev/null +++ b/src/hash/crc32.cpp @@ -0,0 +1,98 @@ +#include + +namespace hgl +{ + namespace + { + const uint32 crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + }; + }//namespace + + namespace util + { + uint32 CountCRC32(uint32 crc, const uint8 *buf, uint32 size) + { + const uint8 *p; + + p = buf; + crc = crc ^ ~0U; + + while (size--) + crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + + return crc ^ ~0U; + } + + class CRC32:public Hash + { + uint32 result; + + public: + + void GetName(UTF8String &str)const override{str=U8_TEXT("CRC32");} + void GetName(UTF16String &str)const override{str=U16_TEXT("CRC32");} + + const int GetHashBytes()const override{return 4;} + + void Init()override + { + result=0; + } + + void Update(const void *input,uint inputLen)override + { + result=CountCRC32(result,(const uint8 *)input,inputLen); + } + + void Final(void *digest)override + { + *(uint32 *)digest=result; + } + };//class CRC32 + + Hash *CreateCRC32Hash(){return(new CRC32);} + }//namespace util +}//namepace hgl diff --git a/src/hash/md4.cpp b/src/hash/md4.cpp new file mode 100644 index 0000000..f453d49 --- /dev/null +++ b/src/hash/md4.cpp @@ -0,0 +1,227 @@ +#include +#include + +namespace hgl +{ + namespace util + { + namespace + { + /* Constants for MD4Transform routine. */ + #define S11 3 + #define S12 7 + #define S13 11 + #define S14 19 + #define S21 3 + #define S22 5 + #define S23 9 + #define S24 13 + #define S31 3 + #define S32 9 + #define S33 11 + #define S34 15 + + /* F, G and H are basic MD4 functions. */ + #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) + #define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) + #define H(x, y, z) ((x) ^ (y) ^ (z)) + + /* ROTATE_LEFT rotates x left n bits. */ + #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + + /* FF, GG and HH are transformations for rounds 1, 2 and 3 */ + /* Rotation is separate from addition to prevent recomputation */ + #define FF(a, b, c, d, x, s) { \ + (a) += F ((b), (c), (d)) + (x); \ + (a) = ROTATE_LEFT ((a), (s)); \ + } + #define GG(a, b, c, d, x, s) { \ + (a) += G ((b), (c), (d)) + (x) + (uint32)0x5a827999; \ + (a) = ROTATE_LEFT ((a), (s)); \ + } + #define HH(a, b, c, d, x, s) { \ + (a) += H ((b), (c), (d)) + (x) + (uint32)0x6ed9eba1; \ + (a) = ROTATE_LEFT ((a), (s)); \ + } + + void md4_encode(unsigned char* output, const uint32* input, unsigned int len) + { + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } + } + + void md4_decode(uint32* output, const unsigned char* input, unsigned int len) + { + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint32)input[j]) | (((uint32)input[j+1]) << 8) | + (((uint32)input[j+2]) << 16) | (((uint32)input[j+3]) << 24); + } + + void md4_transform (uint32 state[4], const unsigned char block[64]) + { + uint32 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + md4_decode(x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11); /* 1 */ + FF (d, a, b, c, x[ 1], S12); /* 2 */ + FF (c, d, a, b, x[ 2], S13); /* 3 */ + FF (b, c, d, a, x[ 3], S14); /* 4 */ + FF (a, b, c, d, x[ 4], S11); /* 5 */ + FF (d, a, b, c, x[ 5], S12); /* 6 */ + FF (c, d, a, b, x[ 6], S13); /* 7 */ + FF (b, c, d, a, x[ 7], S14); /* 8 */ + FF (a, b, c, d, x[ 8], S11); /* 9 */ + FF (d, a, b, c, x[ 9], S12); /* 10 */ + FF (c, d, a, b, x[10], S13); /* 11 */ + FF (b, c, d, a, x[11], S14); /* 12 */ + FF (a, b, c, d, x[12], S11); /* 13 */ + FF (d, a, b, c, x[13], S12); /* 14 */ + FF (c, d, a, b, x[14], S13); /* 15 */ + FF (b, c, d, a, x[15], S14); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 0], S21); /* 17 */ + GG (d, a, b, c, x[ 4], S22); /* 18 */ + GG (c, d, a, b, x[ 8], S23); /* 19 */ + GG (b, c, d, a, x[12], S24); /* 20 */ + GG (a, b, c, d, x[ 1], S21); /* 21 */ + GG (d, a, b, c, x[ 5], S22); /* 22 */ + GG (c, d, a, b, x[ 9], S23); /* 23 */ + GG (b, c, d, a, x[13], S24); /* 24 */ + GG (a, b, c, d, x[ 2], S21); /* 25 */ + GG (d, a, b, c, x[ 6], S22); /* 26 */ + GG (c, d, a, b, x[10], S23); /* 27 */ + GG (b, c, d, a, x[14], S24); /* 28 */ + GG (a, b, c, d, x[ 3], S21); /* 29 */ + GG (d, a, b, c, x[ 7], S22); /* 30 */ + GG (c, d, a, b, x[11], S23); /* 31 */ + GG (b, c, d, a, x[15], S24); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 0], S31); /* 33 */ + HH (d, a, b, c, x[ 8], S32); /* 34 */ + HH (c, d, a, b, x[ 4], S33); /* 35 */ + HH (b, c, d, a, x[12], S34); /* 36 */ + HH (a, b, c, d, x[ 2], S31); /* 37 */ + HH (d, a, b, c, x[10], S32); /* 38 */ + HH (c, d, a, b, x[ 6], S33); /* 39 */ + HH (b, c, d, a, x[14], S34); /* 40 */ + HH (a, b, c, d, x[ 1], S31); /* 41 */ + HH (d, a, b, c, x[ 9], S32); /* 42 */ + HH (c, d, a, b, x[ 5], S33); /* 43 */ + HH (b, c, d, a, x[13], S34); /* 44 */ + HH (a, b, c, d, x[ 3], S31); /* 45 */ + HH (d, a, b, c, x[11], S32); /* 46 */ + HH (c, d, a, b, x[ 7], S33); /* 47 */ + HH (b, c, d, a, x[15], S34); /* 48 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + memset(x, 0, sizeof(x)); + } + }//namespace + + class MD4:public Hash + { + enum + { + BLOCK_SIZE = 64, + DIGEST_SIZE = 16 + }; + + uint32 state[4]; // state (ABCD) + uint32 count[2]; // number of bits, modulo 2^64 (lsb first) + uchar buffer[64]; // input buffer + + public: + + void GetName(UTF8String &str)const override{str="MD4";} + void GetName(UTF16String &str)const override{str=U16_TEXT("MD4");} + + const int GetHashBytes()const override{return DIGEST_SIZE;} + + void Init()override + { + count[0] = count[1] = 0; + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; + } + + void Update(const void *input,uint inputLen)override + { + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((count[0] += ((uint32) inputLen << 3)) < ((uint32) inputLen << 3)) + count[1]++; + count[1] += ((uint32) inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) + { + memcpy(&buffer[index], input, partLen); + md4_transform(state, buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + md4_transform(state, ((uchar *)input)+i); + + index = 0; + } + else i = 0; + + /* Buffer remaining input */ + memcpy(&buffer[index], ((uchar *)input)+i, inputLen-i); + } + + void Final(void *digest)override + { + static const unsigned char PADDING[64] = + { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + md4_encode(bits, count, 8); + + /* Pad out to 56 mod 64. */ + index = (unsigned int)((count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + Update(PADDING, padLen); + + /* Append length (before padding) */ + Update(bits, 8); + + /* Store state in digest */ + md4_encode((uchar *)digest, state, 16); + } + };//class MD4 + + Hash *CreateMD4Hash(){return(new MD4);} + }//namespace util +}//namespace hgl diff --git a/src/hash/md5.cpp b/src/hash/md5.cpp new file mode 100644 index 0000000..7b240fa --- /dev/null +++ b/src/hash/md5.cpp @@ -0,0 +1,258 @@ +#include + +namespace hgl +{ + namespace util + { + namespace + { + /* Constants for MD5Transform routine. */ + #define S11 7 + #define S12 12 + #define S13 17 + #define S14 22 + #define S21 5 + #define S22 9 + #define S23 14 + #define S24 20 + #define S31 4 + #define S32 11 + #define S33 16 + #define S34 23 + #define S41 6 + #define S42 10 + #define S43 15 + #define S44 21 + + /* F, G, H and I are basic MD5 functions. */ + #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) + #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) + #define H(x, y, z) ((x) ^ (y) ^ (z)) + #define I(x, y, z) ((y) ^ ((x) | (~z))) + + /* ROTATE_LEFT rotates x left n bits. */ + #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + + + /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + Rotation is separate from addition to prevent recomputation. */ + #define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + #define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + #define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + #define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (uint32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + + void md5_encode(unsigned char* output, const uint32* input, unsigned int len) + { + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } + } + + void md5_decode(uint32* output, const unsigned char* input, unsigned int len) + { + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint32)input[j]) | (((uint32)input[j+1]) << 8) | + (((uint32)input[j+2]) << 16) | (((uint32)input[j+3]) << 24); + } + + void md5_transform (uint32 state[4], const unsigned char block[64]) + { + uint32 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + md5_decode(x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + memset(x, 0, sizeof(x)); + } + }//namespace + + class MD5:public Hash + { + enum + { + BLOCK_SIZE = 64, + DIGEST_SIZE = 16 + }; + + uint32 state[4]; + uint32 count[2]; + uchar buffer[64]; + + public: + + void GetName(UTF8String &str)const override{str="MD5";} + void GetName(UTF16String &str)const override{str=U16_TEXT("MD5");} + + const int GetHashBytes()const override{return DIGEST_SIZE;} + + void Init()override + { + count[0] = count[1] = 0; + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; + } + + void Update(const void *input,uint inputLen)override + { + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((count[0] += ((uint32) inputLen << 3)) < ((uint32) inputLen << 3)) + count[1]++; + count[1] += ((uint32) inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) + { + memcpy(&buffer[index], input, partLen); + md5_transform(state, buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + md5_transform(state, ((uchar *)input)+i); + + index = 0; + } + else i = 0; + + /* Buffer remaining input */ + memcpy(&buffer[index], ((uchar *)input)+i,inputLen-i); + } + + void Final(void *digest)override + { + static const unsigned char PADDING[64] = + { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + md5_encode(bits, count, 8); + + /* Pad out to 56 mod 64. */ + index = (unsigned int)((count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + Update(PADDING, padLen); + + /* Append length (before padding) */ + Update(bits, 8); + + /* Store state in digest */ + md5_encode((uchar *)digest, state, 16); + } + };//class MD5 + + Hash *CreateMD5Hash(){return(new MD5);} + }//namespace util +}//namespace hgl diff --git a/src/hash/sha1.cpp b/src/hash/sha1.cpp new file mode 100644 index 0000000..949a60e --- /dev/null +++ b/src/hash/sha1.cpp @@ -0,0 +1,250 @@ +#include +#include + +namespace hgl +{ + namespace util + { + namespace + { + /* The SHA f()-functions */ + #define f1(x,y,z) ( ( x & y ) | ( ~x & z ) ) /* Rounds 0-19 */ + #define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */ + #define f3(x,y,z) ( ( x & y ) | ( x & z ) | ( y & z ) ) /* Rounds 40-59 */ + #define f4(x,y,z) ( x ^ y ^ z ) /* Rounds 60-79 */ + + /* The SHA Mysterious Constants */ + #define K1 0x5A827999L /* Rounds 0-19 */ + #define K2 0x6ED9EBA1L /* Rounds 20-39 */ + #define K3 0x8F1BBCDCL /* Rounds 40-59 */ + #define K4 0xCA62C1D6L /* Rounds 60-79 */ + + #define S(n,X) ( ( ((uint32)X) << n ) | ( ((uint32)X) >> ( 32 - n ) ) ) + + /* The initial expanding function */ + #define expand(count) W[ count ] = S(1,(W[ count - 3 ] ^ W[ count - 8 ] ^ W[ count - 14 ] ^ W[ count - 16 ])) /* to make this SHA-1 */ + + /* The four SHA sub-rounds */ + #define subRound1(count) \ + { \ + temp = S( 5, A ) + f1( B, C, D ) + E + W[ count ] + K1; \ + E = D; \ + D = C; \ + C = S( 30, B ); \ + B = A; \ + A = temp; \ + } + + #define subRound2(count) \ + { \ + temp = S( 5, A ) + f2( B, C, D ) + E + W[ count ] + K2; \ + E = D; \ + D = C; \ + C = S( 30, B ); \ + B = A; \ + A = temp; \ + } + + #define subRound3(count) \ + { \ + temp = S( 5, A ) + f3( B, C, D ) + E + W[ count ] + K3; \ + E = D; \ + D = C; \ + C = S( 30, B ); \ + B = A; \ + A = temp; \ + } + + #define subRound4(count) \ + { \ + temp = S( 5, A ) + f4( B, C, D ) + E + W[ count ] + K4; \ + E = D; \ + D = C; \ + C = S( 30, B ); \ + B = A; \ + A = temp; \ + } + }//namespace + + class SHA1:public Hash + { + enum + { + BLOCK_SIZE = 64, + DIGEST_SIZE = 20 + }; + + uint32 digest[5]; // Message digest + uint32 countLo; // 64-bit bit count + uint32 countHi; + uint32 data[16]; // SHA data buffer + uint32 slop; // # of bytes saved in data[] + + uint32 W[80]; + + private: + + void sha1_transform() + { + uint32 temp; + uint32 A, B, C, D, E; + + /* Step A. Copy the data buffer into the local work buffer */ + hgl_cpy(W,data,16); + + /* Step B. Expand the 16 words into 64 temporary data words */ + expand( 16 ); expand( 17 ); expand( 18 ); expand( 19 ); expand( 20 ); + expand( 21 ); expand( 22 ); expand( 23 ); expand( 24 ); expand( 25 ); + expand( 26 ); expand( 27 ); expand( 28 ); expand( 29 ); expand( 30 ); + expand( 31 ); expand( 32 ); expand( 33 ); expand( 34 ); expand( 35 ); + expand( 36 ); expand( 37 ); expand( 38 ); expand( 39 ); expand( 40 ); + expand( 41 ); expand( 42 ); expand( 43 ); expand( 44 ); expand( 45 ); + expand( 46 ); expand( 47 ); expand( 48 ); expand( 49 ); expand( 50 ); + expand( 51 ); expand( 52 ); expand( 53 ); expand( 54 ); expand( 55 ); + expand( 56 ); expand( 57 ); expand( 58 ); expand( 59 ); expand( 60 ); + expand( 61 ); expand( 62 ); expand( 63 ); expand( 64 ); expand( 65 ); + expand( 66 ); expand( 67 ); expand( 68 ); expand( 69 ); expand( 70 ); + expand( 71 ); expand( 72 ); expand( 73 ); expand( 74 ); expand( 75 ); + expand( 76 ); expand( 77 ); expand( 78 ); expand( 79 ); + + /* Step C. Set up first buffer */ + A = digest[ 0 ]; + B = digest[ 1 ]; + C = digest[ 2 ]; + D = digest[ 3 ]; + E = digest[ 4 ]; + + /* Step D. Serious mangling, divided into four sub-rounds */ + subRound1( 0 ); subRound1( 1 ); subRound1( 2 ); subRound1( 3 ); + subRound1( 4 ); subRound1( 5 ); subRound1( 6 ); subRound1( 7 ); + subRound1( 8 ); subRound1( 9 ); subRound1( 10 ); subRound1( 11 ); + subRound1( 12 ); subRound1( 13 ); subRound1( 14 ); subRound1( 15 ); + subRound1( 16 ); subRound1( 17 ); subRound1( 18 ); subRound1( 19 ); + + subRound2( 20 ); subRound2( 21 ); subRound2( 22 ); subRound2( 23 ); + subRound2( 24 ); subRound2( 25 ); subRound2( 26 ); subRound2( 27 ); + subRound2( 28 ); subRound2( 29 ); subRound2( 30 ); subRound2( 31 ); + subRound2( 32 ); subRound2( 33 ); subRound2( 34 ); subRound2( 35 ); + subRound2( 36 ); subRound2( 37 ); subRound2( 38 ); subRound2( 39 ); + + subRound3( 40 ); subRound3( 41 ); subRound3( 42 ); subRound3( 43 ); + subRound3( 44 ); subRound3( 45 ); subRound3( 46 ); subRound3( 47 ); + subRound3( 48 ); subRound3( 49 ); subRound3( 50 ); subRound3( 51 ); + subRound3( 52 ); subRound3( 53 ); subRound3( 54 ); subRound3( 55 ); + subRound3( 56 ); subRound3( 57 ); subRound3( 58 ); subRound3( 59 ); + + subRound4( 60 ); subRound4( 61 ); subRound4( 62 ); subRound4( 63 ); + subRound4( 64 ); subRound4( 65 ); subRound4( 66 ); subRound4( 67 ); + subRound4( 68 ); subRound4( 69 ); subRound4( 70 ); subRound4( 71 ); + subRound4( 72 ); subRound4( 73 ); subRound4( 74 ); subRound4( 75 ); + subRound4( 76 ); subRound4( 77 ); subRound4( 78 ); subRound4( 79 ); + + /* Step E. Build message digest */ + digest[ 0 ] += A; + digest[ 1 ] += B; + digest[ 2 ] += C; + digest[ 3 ] += D; + digest[ 4 ] += E; + } + + public: + + void GetName(UTF8String &str)const override{str="SHA1";} + void GetName(UTF16String &str)const override{str=U16_TEXT("SHA1");} + + const int GetHashBytes()const override{return DIGEST_SIZE;} + + void Init()override + { + digest[0] = 0x67452301L; + digest[1] = 0xEFCDAB89L; + digest[2] = 0x98BADCFEL; + digest[3] = 0x10325476L; + digest[4] = 0xC3D2E1F0L; + countLo = 0; + countHi = 0; + slop = 0; + memset(data, 0, sizeof(data)); + } + + void Update(const void *input,uint count)override + { + const uint8 *buffer=(const uint8 *)input; + uint size; + + /* Update bitcount */ + if ((countLo + ((uint32) count << 3)) < countLo) + countHi++; /* Carry from low to high bitCount */ + countLo += ((uint32) count << 3); + countHi += ((uint32 ) count >> 29); + + /* Process data in BLOCK_SIZE chunks */ + while (count > 0) + { + size=BLOCK_SIZE-slop; + if(size>count) + size=count; + + memcpy(data,buffer,size); + + slop+=size; + buffer+=size; + count-=size; + + if (slop == BLOCK_SIZE) + { + /* transform this one block */ + ToBigEndian(data, BLOCK_SIZE>>2); + sha1_transform(); + slop = 0 ; /* no slop left */ + } + } + } + + void Final(void *result)override + { + int count; + uint32 lowBitcount = countLo; + uint32 highBitcount = countHi; + + /* Compute number of bytes mod 64 */ + count = (int) ((countLo >> 3) & 0x3F); + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + ((uint8*) data)[count++] = 0x80; + + /* Pad out to 56 mod 64 */ + if (count > 56) + { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset((uint8*) &data + count, 0, 64 - count); + ToBigEndian(data, BLOCK_SIZE>>2); + sha1_transform(); + + /* Now fill the next block with 56 bytes */ + memset(&data, 0, 56); + } + else + { + /* Pad block to 56 bytes */ + memset((uint8*) &data + count, 0, 56 - count); + } + ToBigEndian(data, BLOCK_SIZE>>2); + + /* Append length in bits and transform */ + data[14] = highBitcount; + data[15] = lowBitcount; + + sha1_transform(); + ToBigEndian(data, BLOCK_SIZE>>2); + + uint8 *hash=(uint8 *)result; + for (count = 0; count < DIGEST_SIZE; count++) + hash[count] = (uint8) ((digest[count>>2]) >> (8*(3-(count & 0x3)))) & 0xff; + } + };//class SHA1 + + Hash *CreateSHA1Hash(){return(new SHA1);} + }//namespace util +}//namespace hgl diff --git a/src/hash/sha1le.cpp b/src/hash/sha1le.cpp new file mode 100644 index 0000000..b91f98a --- /dev/null +++ b/src/hash/sha1le.cpp @@ -0,0 +1,227 @@ +#include + +namespace hgl +{ + namespace util + { + namespace + { + /* The SHA f()-functions */ + #define f1(x,y,z) ( ( x & y ) | ( ~x & z ) ) /* Rounds 0-19 */ + #define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */ + #define f3(x,y,z) ( ( x & y ) | ( x & z ) | ( y & z ) ) /* Rounds 40-59 */ + #define f4(x,y,z) ( x ^ y ^ z ) /* Rounds 60-79 */ + + #define S(n,X) ( ( ((uint32)X) << n ) | ( ((uint32)X) >> ( 32 - n ) ) ) + + /* The initial expanding function */ + #define expand(count) W[ count ] = S(1,(W[ count - 3 ] ^ W[ count - 8 ] ^ W[ count - 14 ] ^ W[ count - 16 ])) /* to make this SHA-1 */ + + /* The four SHA sub-rounds */ + #define subRound1(count) \ + { \ + temp = S( 5, A ) + f1( B, C, D ) + E + W[ count ] + K[0]; \ + E = D; \ + D = C; \ + C = S( 30, B ); \ + B = A; \ + A = temp; \ + } + + #define subRound2(count) \ + { \ + temp = S( 5, A ) + f2( B, C, D ) + E + W[ count ] + K[1]; \ + E = D; \ + D = C; \ + C = S( 30, B ); \ + B = A; \ + A = temp; \ + } + + #define subRound3(count) \ + { \ + temp = S( 5, A ) + f3( B, C, D ) + E + W[ count ] + K[2]; \ + E = D; \ + D = C; \ + C = S( 30, B ); \ + B = A; \ + A = temp; \ + } + + #define subRound4(count) \ + { \ + temp = S( 5, A ) + f4( B, C, D ) + E + W[ count ] + K[3]; \ + E = D; \ + D = C; \ + C = S( 30, B ); \ + B = A; \ + A = temp; \ + } + }//namespace + + void SHA1LE::sha1_transform() + { + uint32 temp; + uint32 A, B, C, D, E; + + /* Step A. Copy the data buffer into the local work buffer */ + hgl_cpy(W,data,16); + + /* Step B. Expand the 16 words into 64 temporary data words */ + expand( 16 ); expand( 17 ); expand( 18 ); expand( 19 ); expand( 20 ); + expand( 21 ); expand( 22 ); expand( 23 ); expand( 24 ); expand( 25 ); + expand( 26 ); expand( 27 ); expand( 28 ); expand( 29 ); expand( 30 ); + expand( 31 ); expand( 32 ); expand( 33 ); expand( 34 ); expand( 35 ); + expand( 36 ); expand( 37 ); expand( 38 ); expand( 39 ); expand( 40 ); + expand( 41 ); expand( 42 ); expand( 43 ); expand( 44 ); expand( 45 ); + expand( 46 ); expand( 47 ); expand( 48 ); expand( 49 ); expand( 50 ); + expand( 51 ); expand( 52 ); expand( 53 ); expand( 54 ); expand( 55 ); + expand( 56 ); expand( 57 ); expand( 58 ); expand( 59 ); expand( 60 ); + expand( 61 ); expand( 62 ); expand( 63 ); expand( 64 ); expand( 65 ); + expand( 66 ); expand( 67 ); expand( 68 ); expand( 69 ); expand( 70 ); + expand( 71 ); expand( 72 ); expand( 73 ); expand( 74 ); expand( 75 ); + expand( 76 ); expand( 77 ); expand( 78 ); expand( 79 ); + + /* Step C. Set up first buffer */ + A = digest[ 0 ]; + B = digest[ 1 ]; + C = digest[ 2 ]; + D = digest[ 3 ]; + E = digest[ 4 ]; + + /* Step D. Serious mangling, divided into four sub-rounds */ + subRound1( 0 ); subRound1( 1 ); subRound1( 2 ); subRound1( 3 ); + subRound1( 4 ); subRound1( 5 ); subRound1( 6 ); subRound1( 7 ); + subRound1( 8 ); subRound1( 9 ); subRound1( 10 ); subRound1( 11 ); + subRound1( 12 ); subRound1( 13 ); subRound1( 14 ); subRound1( 15 ); + subRound1( 16 ); subRound1( 17 ); subRound1( 18 ); subRound1( 19 ); + + subRound2( 20 ); subRound2( 21 ); subRound2( 22 ); subRound2( 23 ); + subRound2( 24 ); subRound2( 25 ); subRound2( 26 ); subRound2( 27 ); + subRound2( 28 ); subRound2( 29 ); subRound2( 30 ); subRound2( 31 ); + subRound2( 32 ); subRound2( 33 ); subRound2( 34 ); subRound2( 35 ); + subRound2( 36 ); subRound2( 37 ); subRound2( 38 ); subRound2( 39 ); + + subRound3( 40 ); subRound3( 41 ); subRound3( 42 ); subRound3( 43 ); + subRound3( 44 ); subRound3( 45 ); subRound3( 46 ); subRound3( 47 ); + subRound3( 48 ); subRound3( 49 ); subRound3( 50 ); subRound3( 51 ); + subRound3( 52 ); subRound3( 53 ); subRound3( 54 ); subRound3( 55 ); + subRound3( 56 ); subRound3( 57 ); subRound3( 58 ); subRound3( 59 ); + + subRound4( 60 ); subRound4( 61 ); subRound4( 62 ); subRound4( 63 ); + subRound4( 64 ); subRound4( 65 ); subRound4( 66 ); subRound4( 67 ); + subRound4( 68 ); subRound4( 69 ); subRound4( 70 ); subRound4( 71 ); + subRound4( 72 ); subRound4( 73 ); subRound4( 74 ); subRound4( 75 ); + subRound4( 76 ); subRound4( 77 ); subRound4( 78 ); subRound4( 79 ); + + /* Step E. Build message digest */ + digest[ 0 ] += A; + digest[ 1 ] += B; + digest[ 2 ] += C; + digest[ 3 ] += D; + digest[ 4 ] += E; + } + + void SHA1LE::SetMark(const uint32 *mysterious_constants) + { + hgl_cpy(K,mysterious_constants,4); + } + + void SHA1LE::Init(const uint32 *_start_digest,const uint32 *mysterious_constants) + { + hgl_cpy(digest,_start_digest,5); + + SetMark(mysterious_constants); + + countLo = 0; + countHi = 0; + slop = 0; + + memset(data, 0, sizeof(data)); + } + + void SHA1LE::Init() + { + constexpr uint32 d[5]={0x01234567L,0x89ABCDEFL,0xFEDCBA98L,0x76543210L,0x0F1E2D3CL}; + constexpr uint32 k[4]={0x5A827999L,0x6ED9EBA1L,0x8F1BBCDCL,0xCA62C1D6L}; + + Init(d,k); + } + + void SHA1LE::Update(const void *input,uint count) + { + const uint8 *buffer=(const uint8 *)input; + uint size; + + /* Update bitcount */ + if ((countLo + ((uint32) count << 3)) < countLo) + countHi++; /* Carry from low to high bitCount */ + + countLo += ((uint32) count << 3); + countHi += ((uint32 ) count >> 29); + + /* Process data in BLOCK_SIZE chunks */ + while (count > 0) + { + size=BLOCK_SIZE-slop; + if(size>count) + size=count; + + memcpy(data,buffer,size); + + slop+=size; + buffer+=size; + count-=size; + + if (slop == BLOCK_SIZE) + { + /* transform this one block */ + sha1_transform(); + slop = 0 ; /* no slop left */ + } + } + } + + void SHA1LE::Final(void *result) + { + int count; + uint32 lowBitcount = countLo; + uint32 highBitcount = countHi; + + /* Compute number of bytes mod 64 */ + count = (int) ((countLo >> 3) & 0x3F); + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + ((uint8*) data)[count++] = 0x80; + + /* Pad out to 56 mod 64 */ + if (count > 56) + { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset((uint8*) &data + count, 0, 64 - count); + sha1_transform(); + + /* Now fill the next block with 56 bytes */ + memset(&data, 0, 56); + } + else + { + /* Pad block to 56 bytes */ + memset((uint8*) &data + count, 0, 56 - count); + } + + /* Append length in bits and transform */ + data[14] = highBitcount; + data[15] = lowBitcount; + + sha1_transform(); + + uint8 *hash=(uint8 *)result; + for (count = 0; count < DIGEST_SIZE; count++) + hash[count] = (uint8) ((digest[count>>2]) >> (8*(3-(count & 0x3)))) & 0xff; + } + + Hash *CreateSHA1LEHash(){return(new SHA1LE);} + }//namespace util +}//namespace hgl diff --git a/src/hash/sha256.cpp b/src/hash/sha256.cpp new file mode 100644 index 0000000..69d06bd --- /dev/null +++ b/src/hash/sha256.cpp @@ -0,0 +1,198 @@ +#include + +namespace hgl +{ + namespace util + { + namespace + { + #define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) + #define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) + + #define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) + #define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + #define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) + #define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) + #define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) + #define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) + + /**************************** VARIABLES *****************************/ + constexpr uint32 k[64] = + { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 + }; + }//namespace + + class SHA256:public Hash + { + enum + { + BLOCK_SIZE = 64, + DIGEST_SIZE = 32 + }; + + uint32 state[8]; + uint8 data[64]; // SHA data buffer + uint64 bitlen; + uint32 datalen; + + uint32 m[64]; + + private: + + void sha256_transform() + { + uint32 a, b, c, d, e, f, g, h, i, j, t1, t2; + + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); + + for ( ; i < 64; ++i) + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; + + for (i = 0; i < 64; ++i) { + t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; + t2 = EP0(a) + MAJ(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + state[5] += f; + state[6] += g; + state[7] += h; + } + + public: + + void GetName(UTF8String &str)const override{str="SHA256";} + void GetName(UTF16String &str)const override{str=U16_TEXT("SHA256");} + + const int GetHashBytes()const override{return DIGEST_SIZE;} + + void Init()override + { + state[0] = 0x6a09e667; + state[1] = 0xbb67ae85; + state[2] = 0x3c6ef372; + state[3] = 0xa54ff53a; + state[4] = 0x510e527f; + state[5] = 0x9b05688c; + state[6] = 0x1f83d9ab; + state[7] = 0x5be0cd19; + + bitlen=0; + datalen=0; + memset(data, 0, sizeof(data)); + } + + void Update(const void *input,uint count)override + { + const uint8 *u8input=(const uint8 *)input; + uint32 size; + + while(count>0) + { + size=BLOCK_SIZE-datalen; + + if(size>count) + size=count; + + memcpy(data+datalen,u8input,size); + datalen+=size; + count-=size; + u8input+=size; + + if (datalen == BLOCK_SIZE) + { + sha256_transform(); + bitlen += 512; + datalen = 0; + } + } + } + + void Final(void *result)override + { + uint32 i; + + i = datalen; + + // Pad whatever data is left in the buffer. + if (datalen < 56) + { + data[i++] = 0x80; + + memset(data+i,0,56-i); + } + else + { + data[i++] = 0x80; + + memset(data+i,0,64-i); + + sha256_transform(); + memset(data, 0, 56); + } + + // Append to the padding the total message's length in bits and transform. + bitlen += datalen * 8; + data[63] = bitlen; + data[62] = bitlen >> 8; + data[61] = bitlen >> 16; + data[60] = bitlen >> 24; + data[59] = bitlen >> 32; + data[58] = bitlen >> 40; + data[57] = bitlen >> 48; + data[56] = bitlen >> 56; + sha256_transform(); + + // Since this implementation uses little endian byte ordering and SHA uses big endian, + // reverse all the bytes when copying the final state to the output hash. + + uint8 *hash=(uint8 *)result; + + for (i = 0; i < 4; ++i) + { + hash[i] = (state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i + 4] = (state[1] >> (24 - i * 8)) & 0x000000ff; + hash[i + 8] = (state[2] >> (24 - i * 8)) & 0x000000ff; + hash[i + 12] = (state[3] >> (24 - i * 8)) & 0x000000ff; + hash[i + 16] = (state[4] >> (24 - i * 8)) & 0x000000ff; + hash[i + 20] = (state[5] >> (24 - i * 8)) & 0x000000ff; + hash[i + 24] = (state[6] >> (24 - i * 8)) & 0x000000ff; + hash[i + 28] = (state[7] >> (24 - i * 8)) & 0x000000ff; + } + } + };//class SHA256 + + Hash *CreateSHA256Hash(){return(new SHA256);} + }//namespace util +}//namespace hgl + diff --git a/src/hash/sha512.cpp b/src/hash/sha512.cpp new file mode 100644 index 0000000..b0b5ee0 --- /dev/null +++ b/src/hash/sha512.cpp @@ -0,0 +1,244 @@ +#include + +namespace hgl +{ + namespace util + { + namespace + { + #define SHA2_SHFR(x, n) (x >> n) + #define SHA2_ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) + #define SHA2_ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) + #define SHA2_CH(x, y, z) ((x & y) ^ (~x & z)) + #define SHA2_MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) + #define SHA512_F1(x) (SHA2_ROTR(x, 28) ^ SHA2_ROTR(x, 34) ^ SHA2_ROTR(x, 39)) + #define SHA512_F2(x) (SHA2_ROTR(x, 14) ^ SHA2_ROTR(x, 18) ^ SHA2_ROTR(x, 41)) + #define SHA512_F3(x) (SHA2_ROTR(x, 1) ^ SHA2_ROTR(x, 8) ^ SHA2_SHFR(x, 7)) + #define SHA512_F4(x) (SHA2_ROTR(x, 19) ^ SHA2_ROTR(x, 61) ^ SHA2_SHFR(x, 6)) + + #define SHA2_UNPACK32(x, str) \ + { \ + *((str) + 3) = (uint8) ((x) ); \ + *((str) + 2) = (uint8) ((x) >> 8); \ + *((str) + 1) = (uint8) ((x) >> 16); \ + *((str) + 0) = (uint8) ((x) >> 24); \ + } + + #define SHA2_UNPACK64(x, str) \ + { \ + *((str) + 7) = (uint8) ((x) ); \ + *((str) + 6) = (uint8) ((x) >> 8); \ + *((str) + 5) = (uint8) ((x) >> 16); \ + *((str) + 4) = (uint8) ((x) >> 24); \ + *((str) + 3) = (uint8) ((x) >> 32); \ + *((str) + 2) = (uint8) ((x) >> 40); \ + *((str) + 1) = (uint8) ((x) >> 48); \ + *((str) + 0) = (uint8) ((x) >> 56); \ + } + + #define SHA2_PACK64(str, x) \ + { \ + *(x) = ((uint64) *((str) + 7) ) \ + | ((uint64) *((str) + 6) << 8) \ + | ((uint64) *((str) + 5) << 16) \ + | ((uint64) *((str) + 4) << 24) \ + | ((uint64) *((str) + 3) << 32) \ + | ((uint64) *((str) + 2) << 40) \ + | ((uint64) *((str) + 1) << 48) \ + | ((uint64) *((str) + 0) << 56); \ + } + + constexpr uint SHA384_512_BLOCK_SIZE = (1024/8); + + constexpr uint64 K[80] = + { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL + }; + }//namespace + + class SHA512:public Hash + { + enum + { + BLOCK_SIZE = 64, + DIGEST_SIZE = 64 + }; + + uint m_tot_len; + uint m_len; + uint8 m_block[2 * SHA384_512_BLOCK_SIZE]; + uint64 m_h[8]; + + uint64 w[80]; + uint64 wv[8]; + + private: + + void transform(const unsigned char *message, unsigned int block_nb) + { + uint64 t1, t2; + const unsigned char *sub_block; + int i, j; + + for (i = 0; i < (int) block_nb; i++) + { + sub_block = message + (i << 7); + + for (j = 0; j < 16; j++) + { + SHA2_PACK64(&sub_block[j << 3], &w[j]); + } + + for (j = 16; j < 80; j++) + { + w[j] = SHA512_F4(w[j - 2]) + w[j - 7] + SHA512_F3(w[j - 15]) + w[j - 16]; + } + + for (j = 0; j < 8; j++) + { + wv[j] = m_h[j]; + } + + for (j = 0; j < 80; j++) + { + t1 = wv[7] + SHA512_F2(wv[4]) + SHA2_CH(wv[4], wv[5], wv[6]) + K[j] + w[j]; + t2 = SHA512_F1(wv[0]) + SHA2_MAJ(wv[0], wv[1], wv[2]); + + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + + for (j = 0; j < 8; j++) + { + m_h[j] += wv[j]; + } + } + } + + + public: + + void GetName(UTF8String &str)const override{str="SHA512";} + void GetName(UTF16String &str)const override{str=U16_TEXT("SHA512");} + + const int GetHashBytes()const override{return DIGEST_SIZE;} + + void Init()override + { + m_h[0] = 0x6a09e667f3bcc908ULL; + m_h[1] = 0xbb67ae8584caa73bULL; + m_h[2] = 0x3c6ef372fe94f82bULL; + m_h[3] = 0xa54ff53a5f1d36f1ULL; + m_h[4] = 0x510e527fade682d1ULL; + m_h[5] = 0x9b05688c2b3e6c1fULL; + m_h[6] = 0x1f83d9abfb41bd6bULL; + m_h[7] = 0x5be0cd19137e2179ULL; + m_len = 0; + m_tot_len = 0; + } + + void Update(const void *input,uint len)override + { + uint8 *message=(uint8 *)input; + + uint block_nb; + uint new_len, rem_len, tmp_len; + const uint8 *shifted_message; + + tmp_len = SHA384_512_BLOCK_SIZE - m_len; + rem_len = len < tmp_len ? len : tmp_len; + + memcpy(&m_block[m_len], message, rem_len); + + if (m_len + len < SHA384_512_BLOCK_SIZE) + { + m_len += len; + return; + } + + new_len = len - rem_len; + block_nb = new_len / SHA384_512_BLOCK_SIZE; + shifted_message = message + rem_len; + transform(m_block, 1); + transform(shifted_message, block_nb); + rem_len = new_len % SHA384_512_BLOCK_SIZE; + + memcpy(m_block, &shifted_message[block_nb << 7], rem_len); + + m_len = rem_len; + m_tot_len += (block_nb + 1) << 7; + } + + void Final(void *result)override + { + uint block_nb; + uint pm_len; + uint len_b; + int i; + + block_nb = 1 + ((SHA384_512_BLOCK_SIZE - 17) + < (m_len % SHA384_512_BLOCK_SIZE)); + + len_b = (m_tot_len + m_len) << 3; + pm_len = block_nb << 7; + memset(m_block + m_len, 0, pm_len - m_len); + m_block[m_len] = 0x80; + SHA2_UNPACK32(len_b, m_block + pm_len - 4); + transform(m_block, block_nb); + + uint8 *digest=(uint8 *)result; + + for (i = 0 ; i < 8; i++) { + SHA2_UNPACK64(m_h[i], &digest[i << 3]); + } + } + };//class SHA512 + + Hash *CreateSHA512Hash(){return(new SHA512);} + }//namespace util +}//namespace hgl