#ifndef _UTIL_HASH_LIB_H #define _UTIL_HASH_LIB_H #include #include #ifdef __cplusplus #include #include #include #include "fileop.h" namespace hash_lib { class Hash { public: /** * The byte length of the hash */ virtual int digestLength() = 0; /** * The byte length of the block */ virtual int blockSize() = 0; /** * Update the hash with data * @param data Data to be hashed * @param len Length of the data * @return this */ virtual Hash* update(const uint8_t* data, size_t len) = 0; /** * Update the hash with data * @param data Data to be hashed * @return this */ template Hash* update(const uint8_t(&data)[T]) { return this->update(data, T); } Hash* update(const std::string& data); Hash* update(const std::vector& data); /** * Update the hash with data from a file * @param f File pointer * @return this */ Hash* update(FILE* f); /** * Reset the hash * @return this */ virtual Hash* reset() = 0; /** * Finish the hash and return the result * @param data Buffer to store the result * @param len Length of the buffer * @return this */ virtual Hash* finish(uint8_t* data, size_t len) = 0; /** * Finish the hash and return the result * @param data Buffer to store the result * @return this */ template Hash* finish(uint8_t(&data)[T]) { return this->finish(data, T); } Hash* finish(std::string& data); Hash* finish(std::vector& data); /** * Finish the hash and return the result * @return The hash result */ std::vector digest(); /** * Reset the hash and clean the buffer * @return this */ virtual void clean() = 0; /** * Finish the hash and return the result in hex format * @return The hash result in hex format */ std::string hexDigest(); }; class SHA512: public Hash { public: SHA512(); virtual int digestLength() override; int blockSize() override; Hash* update(const uint8_t* data, size_t len) override; using Hash::update; Hash* reset() override; Hash* finish(uint8_t* data, size_t len) override; using Hash::finish; void clean() override; protected: uint32_t stateHi[8]; uint32_t stateLo[8]; virtual void _initState(); private: uint32_t _tempHi[16]; uint32_t _tempLo[16]; uint8_t _buffer[256]; size_t _bufferLength = 0; size_t _bytesHashed = 0; bool _finished = false; size_t hashBlocks(const uint8_t* m, size_t pos, size_t len); }; class SHA512_256: public SHA512 { public: SHA512_256(); int digestLength() override; protected: void _initState() override; }; class SHA384: public SHA512 { public: SHA384(); int digestLength() override; protected: void _initState() override; }; class SHA256: public Hash { public: SHA256(); virtual int digestLength() override; int blockSize() override; Hash* update(const uint8_t* data, size_t len) override; using Hash::update; Hash* reset() override; Hash* finish(uint8_t* data, size_t len) override; using Hash::finish; void clean() override; protected: uint32_t state[8]; virtual void _initState(); private: uint32_t _temp[64]; uint8_t _buffer[128]; size_t _bufferLength = 0; size_t _bytesHashed = 0; bool _finished = false; size_t hashBlocks(const uint8_t* m, size_t pos, size_t len); }; class SHA224: public SHA256 { public: SHA224(); int digestLength() override; protected: void _initState() override; }; class SHA1: public Hash { public: SHA1(); virtual int digestLength() override; int blockSize() override; Hash* update(const uint8_t* data, size_t len) override; using Hash::update; Hash* reset() override; Hash* finish(uint8_t* data, size_t len) override; using Hash::finish; void clean() override; protected: uint32_t state[5]; virtual void _initState(); private: uint32_t _temp[80]; uint8_t _buffer[128]; size_t _bufferLength = 0; size_t _bytesHashed = 0; bool _finished = false; size_t hashBlocks(const uint8_t* m, size_t pos, size_t len); }; class MD5: public Hash { public: MD5(); virtual int digestLength() override; int blockSize() override; Hash* update(const uint8_t* data, size_t len) override; using Hash::update; Hash* reset() override; Hash* finish(uint8_t* data, size_t len) override; using Hash::finish; void clean() override; protected: uint32_t state[4]; virtual void _initState(); private: uint32_t _temp[64]; uint8_t _buffer[128]; size_t _bufferLength = 0; size_t _bytesHashed = 0; bool _finished = false; size_t hashBlocks(const uint8_t* m, size_t pos, size_t len); }; template class HMAC: public Hash { public: HMAC(const uint8_t* key, size_t len) { int blockSize = _outer.blockSize(); std::vector pad(blockSize); if (len > blockSize) { _inner.update(key, len)->finish(pad)->clean(); } else { memcpy(pad.data(), key, len); } _pad = std::move(pad); reset(); } HMAC(const std::string& key) : HMAC((const uint8_t*)key.c_str(), key.size()) {} HMAC(const std::vector& key) : HMAC(key.data(), key.size()) {} template HMAC(const uint8_t (&key)[T]) : HMAC(key, T) {} Hash* reset() override { _inner.clean(); _outer.clean(); int blockSize = _outer.blockSize(); auto pad(_pad); for (int i = 0; i < blockSize; i++) { pad[i] ^= 0x36; } _inner.update(pad); for (int i = 0; i < blockSize; i++) { pad[i] ^= 0x36 ^ 0x5c; } _outer.update(pad); _finished = false; return this; } int digestLength() override { return _outer.digestLength(); } int blockSize() override { return _outer.blockSize(); } Hash* update(const uint8_t* data, size_t len) override { _inner.update(data, len); return this; } using Hash::update; Hash* finish(uint8_t* data, size_t len) override { if (_finished) { _outer.finish(data, len); return this; } _outer.update(_inner.digest())->finish(data, len); _finished = true; return this; } using Hash::finish; void clean() override { reset(); } private: H _inner; H _outer; std::vector _pad; bool _finished = false; }; template std::vector hash(const uint8_t* data, size_t len, Args... args) { H h(args...); h.update(data, len); return h.digest(); } template std::vector hash(const std::string& data, Args... args) { H h(args...); h.update(data); return h.digest(); } template std::vector hash(const std::vector& data, Args... args) { H h(args...); h.update(data); return h.digest(); } template std::vector hash(const uint8_t(&data)[T], Args... args) { H h(args...); h.update(data); return h.digest(); } template std::string hashHex(const uint8_t* data, size_t len, Args... args) { H h(args...); h.update(data, len); return h.hexDigest(); } template std::string hashHex(const std::string& data, Args... args) { H h(args...); h.update(data); return h.hexDigest(); } template std::string hashHex(const std::vector& data, Args... args) { H h(args...); h.update(data); return h.hexDigest(); } template std::string hashHex(const uint8_t(&data)[T], Args... args) { H h(args...); h.update(data); return h.hexDigest(); } template std::vector hashFile(const std::string& filePath, Args... args) { FILE* f = fileop::fopen(filePath.c_str(), "rb"); if (!f) { return {}; } H h(args...); h.update(f); if (ferror(f)) { fileop::fclose(f); return {}; } fileop::fclose(f); return h.digest(); } template std::string hashHexFile(const std::string& filePath, Args... args) { FILE* f = fileop::fopen(filePath.c_str(), "rb"); if (!f) { return ""; } H h(args...); h.update(f); if (ferror(f)) { fileop::fclose(f); return ""; } fileop::fclose(f); return h.hexDigest(); } } #endif #endif