https://www.cnblogs.com/scu-cjx/p/6878853.html
https://www.icode9.com/content-1-978138.html
原来MD5和SHA1分组是不一样的。大小端区别。
#define _CRT_SECURE_NO_WARNINGS
#ifndef SHA1_H
#define SHA1_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned char uint8_t;
typedef unsigned uint32_t;
typedef unsigned long long uint64_t;
// 循环左移
#define LEFTROTATE(num, n) (((num) << n) | ((num >> (32 - n))))
#define SHA1_F(B,C,D,t) ((t<40)?((t<20)?((B&C)|((~B)&D)):(B^C^D)):((t<60)?((B&C)|(B&D)|(C&D)):(B^C^D)))
// k表,32位字,一共有80个元素,对应80次迭代,也成为加法常数
static uint32_t K[80];
uint32_t A, B, C, D, E;
static int Initialized = 0;
void SHA1Init()
{
A = 0x67452301;
B = 0xefcdab89;
C = 0x98badcfe;
D = 0x10325476;
E = 0xc3d2e1f0;
if (Initialized == 0) {
Initialized = 1;
uint32_t p = (uint32_t)1 << 30;
uint32_t x1 = sqrt(2) * p, x2 = sqrt(3) * p, x3 = sqrt(5) * p, x4 = sqrt(10) * p;
int i;
for ( i = 0; i < 20; K[i++] = x1 );
for ( i = 20; i < 40; K[i++] = x2 );
for ( i = 40; i < 60; K[i++] = x3 );
for ( i = 60; i < 80; K[i++] = x4 );
// 0x5A827999 0x6ED9EBA1 0x8F1BBCDC 0xCA62C1D6
}
}
// 两个工具函数 大端形式转换
void int2byte(uint32_t val, uint8_t *bytes)
{
bytes[0] = (uint8_t)(val >> 24);
bytes[1] = (uint8_t)(val >> 16);
bytes[2] = (uint8_t)(val >> 8);
bytes[3] = (uint8_t)val;
}
uint32_t byte2int(const uint8_t *bytes)
{
return ((uint32_t)bytes[0] << 24)
| ((uint32_t)bytes[1] << 16)
| ((uint32_t)bytes[2] << 8)
| (uint32_t)bytes[3];
}
extern int StrSHA1( const char* str, uint64_t length, char* sha1 )
{
uint8_t block[64];
uint32_t W[80];
SHA1Init();
uint64_t new_len = length + (((length & 0x3F) >= 56) ? (56 + 64 - (length & 0x3F)) : (56 - (length & 0x3F)));
// 还要增加64bit 8字节
uint8_t* tempstr = (uint8_t*)malloc(new_len + 8);
if (!tempstr) return -1;
memcpy(tempstr, str, length);
// // 填充1000...0
tempstr[length] = 0x80;
for (uint32_t offset = length + 1; offset < new_len; offset++)
tempstr[offset] = 0;
// 在末尾再附加总长度count的低64位,由于这里的count单位是byte,所以要乘以8
int2byte(length * 8, tempstr + new_len + 4);
int2byte(length >> 29, tempstr + new_len); //参考了其他代码,count>>29相当于count*8>>32,但可以避免值溢出
for (uint32_t offset = 0; offset < new_len; offset += 64) {
memcpy(block, tempstr + offset, 64);
// 保存512位的每32位分组,大端形式存放
for (int i = 0; i < 16; i++) {
W[i] = byte2int(block + i * 4);
}
for (int i = 16; i < 80; i++) {
W[i] = LEFTROTATE((W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]), 1);
}
uint32_t a, b, c, d, e, temp;
a = A, b = B, c = C, d = D, e = E;
for (int i = 0; i < 80; i++) {
temp = LEFTROTATE(a, 5) + SHA1_F(b, c, d, i) + e + W[i] + K[i];
e = d, d = c, c = LEFTROTATE(b, 30), b = a, a = temp;
}
A += a, B += b, C += c, D += d, E += e;
}
free(tempstr);
sprintf( sha1, "%08X%08X%08X%08X%08X", A, B, C, D, E );
return 0;
}
extern int FileSHA1(const char* filepath, char *sha1)
{
FILE *fp = NULL;
uint8_t buffer[1024], block[64];
uint8_t* tempstr = NULL;
uint64_t count = 0; // count用于记录总长度,补位的时候需要用到
uint32_t W[80];
int flag = 0;
if ((fp = fopen(filepath, "rb+")) == NULL) {
printf("[ERROR] File in %s not found.", filepath);
return -1;
}
SHA1Init();
while (!feof(fp)) {
memset(buffer, 0, sizeof(buffer));
uint32_t len = fread(buffer, sizeof(char), 1024, fp);
// 更新文件总长度
count += len;
if (feof(fp)) {
flag = 1;
// 因为恰好等于448bit不行,所以new_len直接等于len+1
uint32_t new_len = len + (((len & 0x3F) >= 56) ? (56 + 64 - (len & 0x3F)) : (56 - (len & 0x3F)));
// 还要增加64bit
tempstr = (uint8_t*)malloc(new_len + 8);
memcpy(tempstr, buffer, len);
// 填充1000...0
tempstr[len] = 0x80;
for (int offset = len + 1; offset < new_len; offset++)
tempstr[offset] = 0;
// 在末尾再附加总长度count的低64位,由于这里的count单位是byte,所以要乘以8 大端存放
int2byte(count * 8, tempstr + new_len + 4);
int2byte(count >> 29, tempstr + new_len); //参考了其他代码,count>>29相当于count*8>>32,但可以避免值溢出
len = new_len;
}
for (int offset = 0; offset < len; offset += 64) {
if (flag == 1) {
memcpy(block, tempstr + offset, 64);
} else {
memcpy(block, buffer + offset, 64);
}
for (int i = 0; i < 16; i++) { // 保存512位的每32位分组,大端形式存放
W[i] = byte2int(block + i * 4);
}
for (int i = 16; i < 80; i++) {
W[i] = LEFTROTATE((W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]), 1);
}
uint32_t a, b, c, d, e, temp;
a = A, b = B, c = C, d = D, e = E;
for (int i = 0; i < 80; i++) {
temp = LEFTROTATE(a, 5) + SHA1_F(b, c, d, i) + e + W[i] + K[i];
e = d, d = c, c = LEFTROTATE(b, 30), b = a, a = temp;
}
A += a, B += b, C += c, D += d, E += e;
}
}
fclose(fp);
free(tempstr);
sprintf( sha1, "%08X%08X%08X%08X%08X", A, B, C, D, E );
return 0;
}
#ifdef __cplusplus
}
#endif
#endif // !SHA1_H
//int main( int argc, char *argv[] )
//{
// char sha1[41] = {0};
// FileSHA1( "C:\\Users\\wzdyq\\Downloads\\RunningCheeseChrome.7z", sha1 );
// printf( "%s\n", sha1 );
//
// char sha2[41] = {0};
// char buf[] = "你要测试的字符串你要测试的字符串你要测试的字符串你要测试的字符串";
// StrSHA1(buf, strlen(buf), sha2);
// printf( "%s\n", sha2 );
//
// return 0;
//}