add HMAC support

This commit is contained in:
2025-05-12 18:18:32 +08:00
parent 09c40a4203
commit 5f4061aec3
2 changed files with 73 additions and 0 deletions

View File

@@ -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);

View File

@@ -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");
}