SHA1算法 c语言(参考其他修改)

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;
//}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值