sha-1

一、整体简介

SHA-1(安全哈希算法1) 是一种常见的加密哈希函数,可以把任意长度的输入数据转换成固定长度的输出(160 位 = 20 字节),这个输出叫做哈希值摘要(digest)

它常用于:

  • 文件完整性校验(看数据有没有被篡改)
  • 数字签名
  • 认证协议等

但由于它存在安全漏洞(已被证明可被攻击),现代加密系统已经推荐使用 SHA-256 或 SHA-3 替代。

本程序模拟 SHA-1 哈希算法的主要计算过程,对长度不超过 55 字节的输入字符串进行加密计算,并输出结果到屏幕和文件。

SHA-1 的核心目标

将一个任意长度的输入消息,处理成一个 160 位的唯一表示(哈希值),且满足:

  • 相同输入 → 相同输出
  • 不同输入 → 尽量不同输出
  • 无法从输出反推出原文
  • 碰撞难以发生(两个不同输入哈希值相同)

SHA-1 的运算流程(5个阶段)

  1. 填充(padding)
  2. 分块(每块512位 = 64字节)
  3. 初始化(五个哈希变量 H0~H4)
  4. 主循环(80轮迭代处理每个块)
  5. 合并输出(最终哈希值)

二、核心模块说明

① 消息填充(Padding)

目的:让消息长度变成 512 的倍数,并记录原始长度。

步骤:

  • 在原始消息末尾加上一个 0x80(即二进制 10000000
  • 然后补若干个 0x00,直到最后剩 64位(8字节)
  • 这最后的8字节,用来表示原始消息的比特长度(大端格式)

🌟 如果原始消息已经接近 512 位,就需要多加一块新分组

② 消息分块(Block Divide)

将填充后的消息按每 512 位(64 字节)划分成一组一组的“块”,每个块会单独处理。

③ 初始化哈希值(Initial State)

SHA-1 维护五个 32 位寄存器(总共 160 位),初始值固定为:

H1 = 0xEFCDAB89
H2 = 0x98BADCFE
H3 = 0x10325476
H4 = 0xC3D2E1F0

这些就是 SHA-1 的“初始种子值”。

④ 主循环(Main Compression Loop)

对每个消息块,进行 80 轮压缩处理。

每轮都做什么?

  1. 将消息块扩展成 80 个 32 位整数 w[0]~w[79]
  2. 使用 5 个变量 A, B, C, D, E,初始值为:
H0 = 0x67452301
H1 = 0xefcdab89
H2 = 0x98badcfe
H3 = 0x10325476
H4 = 0xc3d2e1f0
    
    

每一轮都执行类似这样的操作:

temp = (A <<< 5) + f(B,C,D) + E + w[i] + k
E = D
D = C
C = B <<< 30
B = A
A = temp

  • 每 20 轮使用不同的函数 f 和常数 k,增加非线性复杂度:
轮数函数 f(B,C,D)常数 k
0~19(B & C)(~B & D)
20~39B ^ C ^ D0x6ED9EBA1
40~59(B & C)(B & D)
60~79B ^ C ^ D0xCA62C1D6

每个块处理完后,把结果累加到初始值中:

H0 += A
H1 += B
H2 += C
H3 += D
H4 += E

最终输出的是 H0~H4 连在一起的一串 160 位值。

三、代码展示

这是一段简化后的sha-1算法代码,可用于长度不超过55字节的输入字符加密


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>


FILE    *w_log, *h_log;

//creat_w 函数的作用是:将输入的 512 位(64 字节)消息块,转换为 80 个 32 位整数 w[0] ~ w[79],供 SHA-1 主循环使用。
void creat_w(unsigned char input[64],unsigned int w[80])
{
    int i,j;
    unsigned int temp,temp1;

    for(i=0;i<16;i++){
        j=4*i;
        //change to big-endian
        w[i]=input[j]<<24 | input[1+j]<<16 | input[2+j]<<8 | input[3+j]<<0;
    }
//将每 4 个 unsigned char(8 位)拼接成一个 unsigned int(32 位)
// 每个 w[i] 都对应 4 个字节,顺序从高位到低位(即大端格式)

    for(i=16;i<80;i++) {
        w[i]=w[i-16]^w[i-14]^w[i-8]^w[i-3];
        temp=w[i]<<1;
        temp1=w[i]>>31;
        w[i]=temp|temp1;
    }

    for(i=0; i<80; i++) {
        fprintf(w_log, "%08x\n", w[i]);
    }
}

//--- put string length at byte 60~63
char ms_len(int a,char intput[64])
{
    unsigned int temp3,p1;  
    int i,j;

    temp3=0;
    p1=~(~temp3<<8);
    for(i=0;i<4;i++) {
        j=8*i;
        intput[63-i]=(char)((a&(p1<<j))>>j);  //a[7:0] in intput[63]; a[31:24] in intput[60]
    }
	return '0';
}
 
int sha_1(unsigned char *input, unsigned int *res) 
{
    unsigned int  H0=0x67452301,H1=0xefcdab89,H2=0x98badcfe,H3=0x10325476,H4=0xc3d2e1f0;
    unsigned int  A,B,C,D,E,temp,temp1,temp2,temp3,k,f;
    int x;
    int n,i,flag;
    unsigned int w[80];


    n=strlen((const char *) input);

    if(n<= 55) {
        //pad 0x80 to the end a message
        input[n]= 0x80;
    
        //pad 0x00 to byte 59
        for(i=n+1;i<60;i++)
            input[i]=0;
        
        //put message length to byte 60~63
        x=n*8;
        ms_len(x,(char*)input);
    } else {
        printf("input message is too long, not supported in this model.\n");
        exit(1);
    }
    
    creat_w(input,w);
    
    /*for(i=0;i<80;i++)
    printf("%lx,",w[i]);*/
    
    printf("\n");
    A=H0;B=H1;C=H2;D=H3;E=H4;
    for(i=0;i<80;i++) {
        flag=i/20;
        switch(flag)
           {
            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;
           }
        /*printf("%lx,%lx\n",k,f); */
        temp1=A<<5;
        temp2=A>>27;
        temp3=temp1|temp2;
        temp=temp3+f+E+w[i]+k;
        E=D;
        D=C;
        
        temp1=B<<30;
        temp2=B>>2;
        C=temp1|temp2;
        B=A;
        A=temp;
        
        //printf("%lx,%lx,%lx,%lx,%lx\n",A,B,C,D,E);    //internal result of each cal round
        fprintf(h_log, "%08x%08x%08x%08x%08x\n", A,B,C,D,E);
    }

    H0=H0+A;
    H1=H1+B;
    H2=H2+C;
    H3=H3+D;
    H4=H4+E;
    printf("output hash value:\n");
    printf("%lx%lx%lx%lx%lx\n",H0,H1,H2,H3,H4);

    res[0]=H0; res[1]=H1; res[2]=H2;
    res[3]=H3; res[4]=H4;
}

void info_log(FILE *din_fp, FILE *dout_fp, unsigned char *input, unsigned int *res)
{
    int i;

    fwrite(input, sizeof(char), 64, din_fp);
    fwrite(res,   sizeof(int),  5,  dout_fp);
}


int main(int argc, char* argv[])
{
    unsigned char test0[64] = "abc";    //first byte in test0[0]
    unsigned char test1[64] = "a";
    unsigned char test2[64] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnop";    //maximal byte lenght: 55 byte
    unsigned char test3[64] = "01234567012345670123456701234567";
    unsigned char test[64];             //first byte in test[0]    

    unsigned char *input;
    unsigned int  res[5];
    unsigned char tmp;
    
    int i, len, cnt;

    FILE *din_fp, *dout_fp;

    din_fp  = fopen("./sha_in.bin", "wb");
    dout_fp = fopen("./sha_out.bin", "wb");

    w_log   = fopen("./w.log", "w");
    h_log   = fopen("./h.log", "w");
    
    printf("begin SHA-1 calculation:\n");

    //1: fixed pattern test
    input = test0;
    sha_1(input, res);
    info_log(din_fp, dout_fp, input, res);
    
    input = test1;
    sha_1(input, res);
    info_log(din_fp, dout_fp, input, res);
    
    input = test2;
    sha_1(input, res);
    info_log(din_fp, dout_fp, input, res);
    
    input = test3;
    sha_1(input, res);
    info_log(din_fp, dout_fp, input, res);
    
    //2: random test
    for(cnt=0; cnt<100; cnt++) {
        len = rand() % 56;
        if(len == 0) len = 1;
        
        //initial test with random data
        for(i=0; i<len; i++) {
            tmp = rand() % 256;
            if(tmp == 0)  tmp = 1;

            test[i] = tmp;
        }

        for(i= len; i<64; i++)
            test[i] = 0x00;

        input = test;
        sha_1(input, res);
        info_log(din_fp, dout_fp, input, res);
    }
    

    fclose(din_fp);
    fclose(dout_fp);
    fclose(w_log);
    fclose(h_log);

    printf("SHA-1 calculation end:\n");
    getch();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值