mirror of
https://github.com/lifegpc/c-utils.git
synced 2026-07-08 01:30:39 +08:00
Add SHA1
This commit is contained in:
127
hash_lib.cpp
127
hash_lib.cpp
@@ -9,6 +9,8 @@
|
|||||||
#define SHA256_DIGEST_LENGTH 32
|
#define SHA256_DIGEST_LENGTH 32
|
||||||
#define SHA256_BLOCK_SIZE 64
|
#define SHA256_BLOCK_SIZE 64
|
||||||
#define SHA224_DIGEST_LENGTH 28
|
#define SHA224_DIGEST_LENGTH 28
|
||||||
|
#define SHA1_DIGEST_LENGTH 20
|
||||||
|
#define SHA1_BLOCK_SIZE 64
|
||||||
|
|
||||||
using namespace hash_lib;
|
using namespace hash_lib;
|
||||||
|
|
||||||
@@ -84,7 +86,7 @@ void SHA512::clean() {
|
|||||||
cleanBuffer(_buffer);
|
cleanBuffer(_buffer);
|
||||||
cleanBuffer(_tempHi);
|
cleanBuffer(_tempHi);
|
||||||
cleanBuffer(_tempLo);
|
cleanBuffer(_tempLo);
|
||||||
_initState();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHA512::_initState() {
|
void SHA512::_initState() {
|
||||||
@@ -477,7 +479,7 @@ Hash* SHA256::reset() {
|
|||||||
void SHA256::clean() {
|
void SHA256::clean() {
|
||||||
cleanBuffer(_buffer);
|
cleanBuffer(_buffer);
|
||||||
cleanBuffer(_temp);
|
cleanBuffer(_temp);
|
||||||
_initState();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
Hash* SHA256::update(const uint8_t* data, size_t len) {
|
Hash* SHA256::update(const uint8_t* data, size_t len) {
|
||||||
@@ -598,3 +600,124 @@ void SHA224::_initState() {
|
|||||||
state[6] = 0x64f98fa7;
|
state[6] = 0x64f98fa7;
|
||||||
state[7] = 0xbefa4fa4;
|
state[7] = 0xbefa4fa4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SHA1::SHA1() {
|
||||||
|
this->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SHA1::digestLength() {
|
||||||
|
return SHA1_DIGEST_LENGTH; // SHA-1 produces a 160-bit hash value (20 bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
int SHA1::blockSize() {
|
||||||
|
return SHA1_BLOCK_SIZE; // SHA-1 processes data in 512-bit blocks (64 bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHA1::_initState() {
|
||||||
|
state[0] = 0x67452301;
|
||||||
|
state[1] = 0xEFCDAB89;
|
||||||
|
state[2] = 0x98BADCFE;
|
||||||
|
state[3] = 0x10325476;
|
||||||
|
state[4] = 0xC3D2E1F0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hash* SHA1::reset() {
|
||||||
|
_initState();
|
||||||
|
_bufferLength = 0;
|
||||||
|
_bytesHashed = 0;
|
||||||
|
_finished = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHA1::clean() {
|
||||||
|
cleanBuffer(_buffer);
|
||||||
|
cleanBuffer(_temp);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Hash* SHA1::update(const uint8_t* data, size_t len) {
|
||||||
|
if (_finished) return this;
|
||||||
|
size_t dataPos = 0;
|
||||||
|
_bytesHashed += len;
|
||||||
|
if (_bufferLength > 0) {
|
||||||
|
while (_bufferLength < SHA1_BLOCK_SIZE && len > 0) {
|
||||||
|
_buffer[_bufferLength++] = data[dataPos++];
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
if (_bufferLength == SHA1_BLOCK_SIZE) {
|
||||||
|
hashBlocks(_buffer, 0, SHA1_BLOCK_SIZE);
|
||||||
|
_bufferLength = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (len >= SHA1_BLOCK_SIZE) {
|
||||||
|
dataPos = hashBlocks(data, dataPos, len);
|
||||||
|
len %= SHA1_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
while (len > 0) {
|
||||||
|
_buffer[_bufferLength++] = data[dataPos++];
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hash* SHA1::finish(uint8_t* data, size_t len) {
|
||||||
|
if (!_finished) {
|
||||||
|
size_t bytesHashed = _bytesHashed;
|
||||||
|
size_t left = _bufferLength;
|
||||||
|
uint64_t bitLen = bytesHashed << 3;
|
||||||
|
size_t padLength = (bytesHashed % SHA1_BLOCK_SIZE) < 56 ? 64 : 128;
|
||||||
|
_buffer[left] = 0x80;
|
||||||
|
memset(_buffer + left + 1, 0, padLength - left - 9);
|
||||||
|
cstr_write_uint64(_buffer + padLength - 8, bitLen, 1);
|
||||||
|
hashBlocks(_buffer, 0, padLength);
|
||||||
|
_finished = true;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < this->digestLength() / 4 && i < len / 4; i++) {
|
||||||
|
cstr_write_uint32(data + i * 4, state[i], 1);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SHA1::hashBlocks(const uint8_t* m, size_t pos, size_t len) {
|
||||||
|
while (len >= 64) {
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
size_t j = i * 4 + pos;
|
||||||
|
_temp[i] = cstr_read_uint32(m + j, 1);
|
||||||
|
}
|
||||||
|
for (int i = 16; i < 80; i++) {
|
||||||
|
uint32_t u = _temp[i - 3] ^ _temp[i - 8] ^ _temp[i - 14] ^ _temp[i - 16];
|
||||||
|
_temp[i] = (u << 1) | (u >> (32 - 1));
|
||||||
|
}
|
||||||
|
uint32_t a = state[0], b = state[1], c = state[2], d = state[3], e = state[4];
|
||||||
|
for (int i = 0; i < 80; i++) {
|
||||||
|
uint32_t f, k;
|
||||||
|
if (i < 20) {
|
||||||
|
f = (b & c) | (~b & d);
|
||||||
|
k = 0x5A827999;
|
||||||
|
} else if (i < 40) {
|
||||||
|
f = b ^ c ^ d;
|
||||||
|
k = 0x6ED9EBA1;
|
||||||
|
} else if (i < 60) {
|
||||||
|
f = (b & c) | (b & d) | (c & d);
|
||||||
|
k = 0x8F1BBCDC;
|
||||||
|
} else {
|
||||||
|
f = b ^ c ^ d;
|
||||||
|
k = 0xCA62C1D6;
|
||||||
|
}
|
||||||
|
uint32_t temp = ((a << 5) | (a >> (32 - 5))) + f + e + k + _temp[i];
|
||||||
|
e = d;
|
||||||
|
d = c;
|
||||||
|
c = ((b << 30) | (b >> (32 - 30)));
|
||||||
|
b = a;
|
||||||
|
a = temp;
|
||||||
|
}
|
||||||
|
state[0] += a;
|
||||||
|
state[1] += b;
|
||||||
|
state[2] += c;
|
||||||
|
state[3] += d;
|
||||||
|
state[4] += e;
|
||||||
|
pos += 64;
|
||||||
|
len -= 64;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|||||||
22
hash_lib.h
22
hash_lib.h
@@ -104,6 +104,28 @@ namespace hash_lib {
|
|||||||
protected:
|
protected:
|
||||||
void _initState() override;
|
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);
|
||||||
|
};
|
||||||
template<class H>
|
template<class H>
|
||||||
std::vector<uint8_t> hash(const uint8_t* data, size_t len) {
|
std::vector<uint8_t> hash(const uint8_t* data, size_t len) {
|
||||||
H h;
|
H h;
|
||||||
|
|||||||
@@ -42,3 +42,9 @@ TEST(HashLibTest, SHA224Test) {
|
|||||||
GTEST_ASSERT_EQ(hashHex<SHA224>("Hello, World!"), "72a23dfa411ba6fde01dbfabf3b00a709c93ebf273dc29e2d8b261ff");
|
GTEST_ASSERT_EQ(hashHex<SHA224>("Hello, World!"), "72a23dfa411ba6fde01dbfabf3b00a709c93ebf273dc29e2d8b261ff");
|
||||||
GTEST_ASSERT_EQ(hashHex<SHA224>("随便来一些中文。测试超过一百二十八字节时的状况。用于测试是否存在问题。还是不够长呢。啊啊啊。"), "6dc50e486071b01bf45d5d228207e9c0a8254e1cc48c88b989f8527d");
|
GTEST_ASSERT_EQ(hashHex<SHA224>("随便来一些中文。测试超过一百二十八字节时的状况。用于测试是否存在问题。还是不够长呢。啊啊啊。"), "6dc50e486071b01bf45d5d228207e9c0a8254e1cc48c88b989f8527d");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(HashLibTest, SHA1Test) {
|
||||||
|
GTEST_ASSERT_EQ(hashHex<SHA1>(""), "da39a3ee5e6b4b0d3255bfef95601890afd80709");
|
||||||
|
GTEST_ASSERT_EQ(hashHex<SHA1>("Hello, World!"), "0a0a9f2a6772942557ab5355d76af442f8f65e01");
|
||||||
|
GTEST_ASSERT_EQ(hashHex<SHA1>("随便来一些中文。测试超过一百二十八字节时的状况。用于测试是否存在问题。还是不够长呢。啊啊啊。"), "21c05e3532d593ec382b8e361d43a17e8fb8774a");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user