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