参考了rfc3174上的代码和网上某些代码,重写了sha1算法实现,可以计算大文件的hash值,通过64位编译测试,接口简单,代码进行了注释,gcc编译测试通过。
#include <cstdio>
#include <string>
#ifdef _MSC_VER
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
#define SHA1_MAX 2305843009213693952L
class Sha1
{
uint64_t _size;
uint32_t _hashs[5];
uint8_t _block[64];
short _index;
public:
Sha1(){ init();}
~Sha1(){}
void init()
{
_hashs[0] = 0x67452301;
_hashs[1] = 0xefcdab89;
_hashs[2] = 0x98badcfe;
_hashs[3] = 0x10325476;
_hashs[4] = 0xc3d2e1f0;
_index = 0;
_size = 0;
}
// 数据更新
bool update(const char *data, size_t len)
{
while(len--)
{
_block[_index++] = *data++; //拷贝数据
if(_size > SHA1_MAX) return false; //超出2^64计数范围
_size++; //计数器+1;
if(_index == 64){//一个块填充完成则进行hash计算
_hash();
}
}
return true;
}
// 结束计算
void final()
{
_block[_index++] = 0x80;//添加结束府
if(_index > 55){//如果后8位不够填充bit总数,则填0
_fill_zero(64);
_hash();
}
_fill_zero(56); //最后8字节前填充0
_size <<= 3;//计算总bit数
for(int i = 56; i >=0; i-=8)//最后8字节填充big endian总bit数
_block[_index++] = (uint8_t)(_size >> i);
_hash();//结束计算
printf("%8x%8x%8x%8x%8x\n", _hashs[0],_hashs[1],_hashs[2],_hashs[3],_hashs[4]);
}
private:
void _fill_zero(int n)
{
while(_index < n) _block[_index++]=0;
}
// sha1核心算法
void _hash()
{
uint32_tF, K, T = 0;
uint32_tt, W[80] = {0};
uint32_tA=_hashs[0],B=_hashs[1],C=_hashs[2],D=_hashs[3],E=_hashs[4];
// 前16个字为原始数据
for (t = 0; t < 16; ++t)
{
W[t]=(_block[t<<2] ) << 24
|(_block[(t<<2)+1] ) << 16
|(_block[(t<<2)+2] ) << 8
| _block[(t<<2)+3] ;
}
// 填充
for (t = 16; t < 80; ++t){
W[t] = _lShift(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
}
// 重复80次hash计算
for (t = 0; t < 80; ++t)
{
switch (t/20)
{
case 0: K=0x5a827999; F = (B & C) | ((~B) & D); break;
case 1: K=0x6ed9eba1;F = B ^ C ^ D; break;
case 2: K=0x8f1bbcdc; F = (B & C) | (B & D) | (C & D); break;
case 3: K=0xca62c1d6; F = B ^ C ^ D; break;
}
T = _lShift(A, 5) + F + E + W[t] + K;
E=D;
D=C;
C = _lShift(B, 30);
B=A;
A=T;
}
_index = 0; //清零
// 累加计算结果
_hashs[0] += A;
_hashs[1] += B;
_hashs[2] += C;
_hashs[3] += D;
_hashs[4] += E;
}
// 循环左移
template<typename T>
T _lShift(T val, int bits)
{
return (val << bits) | (val >> ((sizeof(T)<<3) - bits));
}
};
int main()
{
Sha1 s;
s.update("grape", 5);
s.final();
return 0;
}
#include <cstdio>
#include <string>
#ifdef _MSC_VER
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
#define SHA1_MAX 2305843009213693952L
class Sha1
{
uint64_t _size;
uint32_t _hashs[5];
uint8_t _block[64];
short _index;
public:
Sha1(){ init();}
~Sha1(){}
void init()
{
_hashs[0] = 0x67452301;
_hashs[1] = 0xefcdab89;
_hashs[2] = 0x98badcfe;
_hashs[3] = 0x10325476;
_hashs[4] = 0xc3d2e1f0;
_index = 0;
_size = 0;
}
// 数据更新
bool update(const char *data, size_t len)
{
while(len--)
{
_block[_index++] = *data++; //拷贝数据
if(_size > SHA1_MAX) return false; //超出2^64计数范围
_size++; //计数器+1;
if(_index == 64){//一个块填充完成则进行hash计算
_hash();
}
}
return true;
}
// 结束计算
void final()
{
_block[_index++] = 0x80;//添加结束府
if(_index > 55){//如果后8位不够填充bit总数,则填0
_fill_zero(64);
_hash();
}
_fill_zero(56); //最后8字节前填充0
_size <<= 3;//计算总bit数
for(int i = 56; i >=0; i-=8)//最后8字节填充big endian总bit数
_block[_index++] = (uint8_t)(_size >> i);
_hash();//结束计算
printf("%8x%8x%8x%8x%8x\n", _hashs[0],_hashs[1],_hashs[2],_hashs[3],_hashs[4]);
}
private:
void _fill_zero(int n)
{
while(_index < n) _block[_index++]=0;
}
// sha1核心算法
void _hash()
{
uint32_tF, K, T = 0;
uint32_tt, W[80] = {0};
uint32_tA=_hashs[0],B=_hashs[1],C=_hashs[2],D=_hashs[3],E=_hashs[4];
// 前16个字为原始数据
for (t = 0; t < 16; ++t)
{
W[t]=(_block[t<<2] ) << 24
|(_block[(t<<2)+1] ) << 16
|(_block[(t<<2)+2] ) << 8
| _block[(t<<2)+3] ;
}
// 填充
for (t = 16; t < 80; ++t){
W[t] = _lShift(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
}
// 重复80次hash计算
for (t = 0; t < 80; ++t)
{
switch (t/20)
{
case 0: K=0x5a827999; F = (B & C) | ((~B) & D); break;
case 1: K=0x6ed9eba1;F = B ^ C ^ D; break;
case 2: K=0x8f1bbcdc; F = (B & C) | (B & D) | (C & D); break;
case 3: K=0xca62c1d6; F = B ^ C ^ D; break;
}
T = _lShift(A, 5) + F + E + W[t] + K;
E=D;
D=C;
C = _lShift(B, 30);
B=A;
A=T;
}
_index = 0; //清零
// 累加计算结果
_hashs[0] += A;
_hashs[1] += B;
_hashs[2] += C;
_hashs[3] += D;
_hashs[4] += E;
}
// 循环左移
template<typename T>
T _lShift(T val, int bits)
{
return (val << bits) | (val >> ((sizeof(T)<<3) - bits));
}
};
int main()
{
Sha1 s;
s.update("grape", 5);
s.final();
return 0;
}