mirror of
https://github.com/lifegpc/c-utils.git
synced 2026-06-06 05:08:45 +08:00
add HMAC support
This commit is contained in:
64
hash_lib.h
64
hash_lib.h
@@ -127,6 +127,70 @@ namespace hash_lib {
|
||||
size_t hashBlocks(const uint8_t* m, size_t pos, size_t len);
|
||||
};
|
||||
template<class H>
|
||||
class HMAC: public Hash {
|
||||
public:
|
||||
HMAC(const uint8_t* key, size_t len) {
|
||||
int blockSize = _outer.blockSize();
|
||||
std::vector<uint8_t> 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<uint8_t>& key) : HMAC(key.data(), key.size()) {}
|
||||
template <size_t T>
|
||||
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<uint8_t> _pad;
|
||||
bool _finished = false;
|
||||
};
|
||||
template<class H>
|
||||
std::vector<uint8_t> hash(const uint8_t* data, size_t len) {
|
||||
H h;
|
||||
h.update(data, len);
|
||||
|
||||
@@ -48,3 +48,12 @@ TEST(HashLibTest, SHA1Test) {
|
||||
GTEST_ASSERT_EQ(hashHex<SHA1>("Hello, World!"), "0a0a9f2a6772942557ab5355d76af442f8f65e01");
|
||||
GTEST_ASSERT_EQ(hashHex<SHA1>("随便来一些中文。测试超过一百二十八字节时的状况。用于测试是否存在问题。还是不够长呢。啊啊啊。"), "21c05e3532d593ec382b8e361d43a17e8fb8774a");
|
||||
}
|
||||
|
||||
TEST(HashLibTest, HMACClassTest) {
|
||||
HMAC<SHA512> hmac("key");
|
||||
hmac.update("Hello, World!");
|
||||
GTEST_ASSERT_EQ(hmac.hexDigest(), "7b735ac190ebd1432d56f95ae2aea5a04a23128f4c228e299b7a49fb7561de8cc8f4fdf4486dc743dfd07827d617273aab42b3bf819d243ded322fac167419f1");
|
||||
hmac.clean();
|
||||
hmac.update("Hello, World!");
|
||||
GTEST_ASSERT_EQ(hmac.hexDigest(), "7b735ac190ebd1432d56f95ae2aea5a04a23128f4c228e299b7a49fb7561de8cc8f4fdf4486dc743dfd07827d617273aab42b3bf819d243ded322fac167419f1");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user