SHA1消息摘要算法

前言:SHA消息摘要算法的学习笔记

什么是SHA-1消息摘要算法

Sha系列算法,又叫做安全散列算法,其包括 sha-1,sha-256,sha-384,sha-512总共这四种,分别产生160/256/384/512位的散列值,该算法与MD4算法设计原理相同,但安全性更高一些。

以sha-1为例,其会产生160位消息摘要,在对消息处理之前,初始散列值H用5个32位双子进行初始化,可以通过识别这些双字压缩常数来确定是否是该算法。

h0=> 67452301h h1=>efcdab89h h2=>98badcfeh h3=>10325476h h4=>c3d2e1f0h

SHA-1消息摘要算法的实现过程

SHA-1消息摘要算法代码实现

/*-------------------------------------------------------
/* 《加密与解密》第三版 第7章 加密算法   
/*  MD5计算器源码
/*  (c) www.PEDIY.com  
/*  code by cnbragon 2007.9
-------------------------------------------------------*/

////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <windows.h>

typedef struct {
unsigned int length[2];
unsigned int h[8];
unsigned int w[80];
} sha;

#define H0 0x67452301L
#define H1 0xefcdab89L
#define H2 0x98badcfeL
#define H3 0x10325476L
#define H4 0xc3d2e1f0L

#define K0 0x5a827999L
#define K1 0x6ed9eba1L
#define K2 0x8f1bbcdcL
#define K3 0xca62c1d6L

#define PAD  0x80
#define ZERO 0

/* functions */

#define S(n,x) (((x)<<n) | ((x)>>(32-n)))

#define F0(x,y,z) ((x&y)|((~x)&z))
#define F1(x,y,z) (x^y^z)
#define F2(x,y,z) ((x&y) | (x&z)|(y&z)) 
#define F3(x,y,z) (x^y^z)

static void sha1_transform(sha *sh)
{ /* basic transformation step */
    unsigned int a,b,c,d,e,temp;
    int t;

    for (t=16;t<80;t++) sh->w[t]=S(1,sh->w[t-3]^sh->w[t-8]^sh->w[t-14]^sh->w[t-16]);
    a=sh->h[0]; b=sh->h[1]; c=sh->h[2]; d=sh->h[3]; e=sh->h[4];
    for (t=0;t<20;t++)
    { /* 20 times - mush it up */
        temp=K0+F0(b,c,d)+S(5,a)+e+sh->w[t];
        e=d; d=c;
        c=S(30,b);
        b=a; a=temp;
    }
    for (t=20;t<40;t++)
    { /* 20 more times - mush it up */
        temp=K1+F1(b,c,d)+S(5,a)+e+sh->w[t];
        e=d; d=c;
        c=S(30,b);
        b=a; a=temp;
    }
    for (t=40;t<60;t++)
    { /* 20 more times - mush it up */
        temp=K2+F2(b,c,d)+S(5,a)+e+sh->w[t];
        e=d; d=c;
        c=S(30,b);
        b=a; a=temp;
    }
    for (t=60;t<80;t++)
    { /* 20 more times - mush it up */
        temp=K3+F3(b,c,d)+S(5,a)+e+sh->w[t];
        e=d; d=c;
        c=S(30,b);
        b=a; a=temp;
    }
    sh->h[0]+=a; sh->h[1]+=b; sh->h[2]+=c;
    sh->h[3]+=d; sh->h[4]+=e;
} 

void sha1_init(sha *sh)
{ /* re-initialise */
    int i;
	
    for (i=0;i<80;i++) sh->w[i]=0L;
    sh->length[0]=sh->length[1]=0L;
	
    sh->h[0]=H0;
    sh->h[1]=H1;
    sh->h[2]=H2;
    sh->h[3]=H3;
    sh->h[4]=H4;
}

void sha1_process(sha * sh,int byte)
{ /* process the next message byte */
    int cnt;
    
    cnt=(int)((sh->length[0]/32)%16);
    
    sh->w[cnt]<<=8;
    sh->w[cnt]|=(unsigned int)(byte&0xFF);

    sh->length[0]+=8;
    if (sh->length[0]==0L) { sh->length[1]++; sh->length[0]=0L; }
    if ((sh->length[0]%512)==0) sha1_transform(sh);
}

void sha1_hash(sha *sh, char hash[20])
{ /* pad message and finish - supply digest */
    int i;
    unsigned int len0,len1;
    len0=sh->length[0];
    len1=sh->length[1];
    sha1_process(sh,PAD);
    while ((sh->length[0]%512)!=448) sha1_process(sh,ZERO);
    sh->w[14]=len1;
    sh->w[15]=len0;    
    sha1_transform(sh);
    for (i=0;i<20;i++)
    { /* convert to bytes */
        hash[i]=((sh->h[i/4]>>(8*(3-i%4))) & 0xffL);
    }
    sha1_init(sh);
}


int main()
{
	return 0;
}

在逆向中识别SHA1系列算法的特征

第一个特征就是SHA1的初始化的五个常数,跟MD5_INIT一样,SHA1_INIT也是对要变换的常数进行初始化操作

IDA中的识别特征如下图所示

动态调试的特征如下图所示

同样的跟MD5_INIT一样,在transform的过程中也会对初始化的五个常数进行变换操作

IDA中的特征如下图所示

动态调试的特征如下图所示

其他SHA1系列算法的特征

SHA1题目

注册机代码如下

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#define MAXINPUTLEN 200
typedef struct {
unsigned int length[2];
unsigned int h[8];
unsigned int w[80];
} sha;

#define H0 0x67452301L
#define H1 0xefcdab89L
#define H2 0x98badcfeL
#define H3 0x10325476L
#define H4 0xc3d2e1f0L

#define K0 0x5a827999L
#define K1 0x6ed9eba1L
#define K2 0x8f1bbcdcL
#define K3 0xca62c1d6L

#define PAD  0x80
#define ZERO 0

/* functions */

#define S(n,x) (((x)<<n) | ((x)>>(32-n)))

#define F0(x,y,z) ((x&y)|((~x)&z))
#define F1(x,y,z) (x^y^z)
#define F2(x,y,z) ((x&y) | (x&z)|(y&z)) 
#define F3(x,y,z) (x^y^z)

static void sha1_transform(sha* sh)
{ /* basic transformation step */
	// 在sha1加密中迭代的次数为80次
    unsigned int a,b,c,d,e,temp;
    int t;

	for (t = 16; t < 80; t++)
		sh->w[t] = S(1, sh->w[t - 3] ^ sh->w[t - 8] ^ sh->w[t - 14] ^ sh->w[t - 16]);
	
	// 重新覆盖 sha1中默认初始化的常数
	a = sh->h[0]; b = sh->h[1]; c = sh->h[2]; d = sh->h[3]; e = sh->h[4];
	
    for (t=0;t<20;t++)
    { /* 20 times - mush it up */
        temp=K0+F0(b,c,d)+S(5,a)+e+sh->w[t];
        e=d; d=c;
        c=S(30,b);
        b=a; a=temp;
    }
	
    for (t=20;t<40;t++)
    { /* 20 more times - mush it up */
        temp=K1+F1(b,c,d)+S(5,a)+e+sh->w[t];
        e=d; d=c;
        c=S(30,b);
        b=a; a=temp;
    }
	
    for (t=40;t<60;t++)
    { /* 20 more times - mush it up */
        temp=K2+F2(b,c,d)+S(5,a)+e+sh->w[t];
        e=d; d=c;
        c=S(30,b);
        b=a; a=temp;
    }
	
    for (t=60;t<80;t++)
    { /* 20 more times - mush it up */
        temp=K3+F3(b,c,d)+S(5,a)+e+sh->w[t];
        e=d; d=c;
        c=S(30,b);
        b=a; a=temp;
    }
    
	// 重新覆盖 sha1中默认初始化的常数
	sh->h[0]+=a; 
	sh->h[1]+=b; 
	sh->h[2]+=c;
    sh->h[3]+=d; 
	sh->h[4]+=e;
} 

void sha1_init(sha *sh)
{ /* re-initialise */
	// 初始化5个常数
    int i;
	
    for (i=0;i<80;i++) 
		sh->w[i]=0L;
    
	sh->length[0] = sh->length[1] = 0L; // the same as md5
	sh->h[0] = 0x67452301L;
	sh->h[1] = 0xefcdab89L;
	sh->h[2] = 0x98badcfeL;
	sh->h[3] = 0x10325476L;
	sh->h[4] = 0xc3d2e1f0L;
}

void sha1_process(sha* sh, int byte)
{ 
	// 对每个字节都进行对应的操作如下的操作
	int cnt;
	
	cnt = (int)((sh->length[0] / 32) % 16);
    
	sh->w[cnt] <<= 8;
	sh->w[cnt] |= (unsigned int)(byte & 0xFF);

	sh->length[0] += 8;
	if (sh->length[0] == 0L) 
	{
		sh->length[1]++;
		sh->length[0] = 0L;
	}
    
	if ((sh->length[0] % 512) == 0)
		sha1_transform(sh);
}

void sha1_hash(sha* sh, char hash[20])
{ /* pad message and finish - supply digest */
    int i;
	unsigned int len0, len1;
	len0 = sh->length[0];
	len1 = sh->length[1];

	// 填充一次PAD,默认的PAD -> 0x80
	sha1_process(sh, PAD);
	
	// 然后再把剩下的全部填充,填充数为0
	while ((sh->length[0] % 512) != 448)
		sha1_process(sh, ZERO);
	
	sh->w[14] = len1; 
	sh->w[15] = len0; // len0为 当前加密的长度*8

	// 对默认初始化的五个常数进行变换
    sha1_transform(sh);

	// 生成20个字节的SHA1
    for (i=0;i<20;i++)
    { /* convert to bytes */
		hash[i] = ((sh->h[i / 4] >> (8 * (3 - i % 4))) & 0xffL);
    }

	// 结束玩重新初始化常数
    sha1_init(sh);
}

int main()
{
	sha sh;
	DWORD i, k, q;
	TCHAR szName[MAXINPUTLEN] = "test";
	TCHAR szHash[MAXINPUTLEN] = { 0 };
	TCHAR szSNtemp[MAXINPUTLEN] = { 0 };
	TCHAR szFinaEncodeData[41] = { 0 };
	TCHAR szPediyForumBuffer[41] = { 0 };
	TCHAR szPediyComForumBuffer[41] = { 0 };

	sha1_init(&sh); // d033e22ae348aeb5660fc2140aec35850c4da997
	for (i = 0; i<strlen(szName); i++)
		sha1_process(&sh, szName[i]);
	sha1_hash(&sh, szHash);
	strcpy(szPediyForumBuffer, "PEDIY Forum");
	strcpy(szPediyComForumBuffer, "pediy.com");
	// 前面填充17个字节
	q = 12;
	for (i = 0;i<17;i++)
	{
		k = szPediyForumBuffer[i] ^ szHash[i];
		szPediyForumBuffer[q++] = k;
	}
	
	// 最后填充三个字节
	szPediyForumBuffer[q++] = szHash[17] ^ 0x70;
	szPediyForumBuffer[q++] = szHash[18] ^ 0x65;
	szPediyForumBuffer[q++] = szHash[19] ^ 0x64;
	
	k = strlen(szPediyForumBuffer) + 1;
	for (i = 0; i < 10;i++)
		szPediyForumBuffer[k + i] = szPediyForumBuffer[k + i] ^ szPediyForumBuffer[k + i + 10];
	for (i = 0; i < 10; i++)
	{
		wsprintf((szSNtemp + i * 2), "%02X", (unsigned char)szPediyForumBuffer[k]);
		k++;
	}
	printf("final encode data -> %s\n", szSNtemp);
	return 0;
}

posted @ 2022-09-19 22:45  zpchcbd  阅读(443)  评论(0编辑  收藏  举报