单项散列算法:SHA

单项散列算法_SHA

SHA-1是一种能够根据上限为2^64位的消息计算出160比特的散列值的单向散列函数,它的分组及对数据的填充方式与MD5是一样的,512位为1组,填充数据时先填1,后面填0,一直填满448位,最后64位表示原始数据长度。

SHA-1算法原理与实现

1.填充1

以abcde这条长度为六的消息进行填充。

ABCDEF=41 42 43 44 45 46 ,在消息末尾加

0100 00010100 0010 0100 00110100 0100   0100 0101 0100 01101

2.填充0

在消息末尾继续添加0,直到消息的长度达到512比特的整数倍,但是最后一个最后64位用来保存原始数据的长度。如:ABCDEF减掉最后的保存长度64位,填充0,直到消息长度为填充满448位。

0100 00010100 0010 0100 00110100 0100   0100 0101 0100 011010000000



-----448位
00000000000000000000000000000000000000000000000000000000

3.最末位添加原始数据长度

0100 00010100 0010 0100 00110100 0100   0100 0101 0100 011010000000



-----448位
00000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000110000--标记原始长度64位。

此时数据长度为512位,符合512整数倍。

完成数据的填充后,我们将以输入分组为单位进行下面的处理,这一步要对每个输入分组计算80个32位的值(W0~W79),首先将输入分组的512位分为32位*16组,并将它们命名为W0~W15,然后剩下W16~W79的计算,方法如下:

 for (t = 0; t < 16; t++)
    {
        W[t] = ((unsigned)Message_Block[t * 4]) << 24;
        W[t] |= ((unsigned)Message_Block[t * 4 + 1]) << 16;
        W[t] |= ((unsigned)Message_Block[t * 4 + 2]) << 8;
        W[t] |= ((unsigned)Message_Block[t * 4 + 3]);
    }
    for (t = 16; t < 80; t++)
    {
        W[t] = CircularShift(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]);            //W16 = (W0 ^ W2 ^ W8 ^ W13) 循环左移1位,即:Wt = (Wt - 16 ^ Wt - 14 ^ Wt - 8 ^ Wt - 3) 循环左移1位完成后,W0~W79的数据就生成完成了。
    }

4. SHA-1: 分组处理

接下来,对输入分组进行80个步骤的处理,目的是根据输入分组的信息来改变内部状态。

在对分组处理时,SHA-1中常数Kt及Ht:

其他初始化数据:SHA-1,SHA-256,SHA-384,和SHA-512初始化数据

5.算法逻辑实现

SHA-1使用了f0, f1, .... f79这样的一个逻辑函数序列,每一个ft对3个32位双字B,C,D进行操作,产生一个32位双字的输出。

SHA-1算法从f0,f1。。。。f79,逻辑函数序列,每一个ft(0<t<79)对3个32位双字B C D进行操作,产生一个32位双字的输出,ft(B,C,D)定义如下:

w0~w79的处理


#define F0(x,y,z) (z^(x&(Y^z)))
#define F1(x,y,z) (z^Y^z)
#define F2(x,y,z) ((x&y)|(z&(x^y)))
#define F3(x,y,z) (x^Y^z)
for (t = 0; t < 20; t++)
{
    temp = CircularShift(5, A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
    temp &= 0xFFFFFFFF;
    E = D;
    D = C;
    C = CircularShift(30, B);
    B = A;
    A = temp;
}
for (t = 20; t < 40; t++)
{
    temp = CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[1];
    temp &= 0xFFFFFFFF;
    E = D;
    D = C;
    C = CircularShift(30, B);
    B = A;
    A = temp;
}
   for (t = 40; t < 60; t++)
{
    temp = CircularShift(5, A) +
        ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
    temp &= 0xFFFFFFFF;
    E = D;
    D = C;
    C = CircularShift(30, B);
    B = A;
    A = temp;
}
for (t = 60; t < 80; t++)
{
    temp = CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[3];
    temp &= 0xFFFFFFFF;
    E = D;
    D = C;
    C = CircularShift(30, B);
    B = A;
    A = temp;

}
获取摘要:

在一个步骤完成之后,缓冲区a,b,c,d的内容会被分别复制到b,c,d,e中(其中b要循环左移30位之后再复制),而缓冲区e的内容则会与其他缓冲区的内容以及Wt、Kt相加之后再复制到缓冲区a中。

最终将循环80个步骤的值与原始相加,即更新原始的5个H常量,得到最终160位的消息摘要。

    H[0] = (H[0] + A) & 0xFFFFFFFF;
    H[1] = (H[1] + B) & 0xFFFFFFFF;
    H[2] = (H[2] + C) & 0xFFFFFFFF;
    H[3] = (H[3] + D) & 0xFFFFFFFF;
    H[4] = (H[4] + E) & 0xFFFFFFFF

代码实现:

编译环境VS2017:

.h
#pragma once
class SHA1
{
public:
    SHA1();
    virtual ~SHA1();
    bool SHA_GO(const char *lpData_Input, char *lpSHACode_Output);
private:
    unsigned int H[5];              
    unsigned int Length_Low;                
    unsigned int Length_High;           
    unsigned char Message_Block[64];    
    int Message_Block_Index;                
private:
    void SHAInit();
    void AddDataLen(int nDealDataLen);
	 // 处理消息的下一个512位
	 void ProcessMessageBlock();
	// 将当前消息块填充为512位
	 void PadMessage();
	 // 执行循环左移位操作
	 inline unsigned CircularShift(int bits, unsigned word);
};
//******************************************
.cpp
#include "stdafx.h"
#include "SHA1.h"
#include <string.h>
#pragma warning(disable:4996)
SHA1::SHA1()
{
    SHAInit();
}
SHA1::~SHA1()
{
}
void SHA1::SHAInit()
{
	Length_Low = 0;
	Length_High = 0;
	Message_Block_Index = 0;
	H[0] = 0x67452301;
	H[1] = 0xEFCDAB89;
	H[2] = 0x98BADCFE;
	H[3] = 0x10325476;
	H[4] = 0xC3D2E1F0;
}
//SHA计算
bool SHA1::SHA_GO(const char *lpData_Input, char *lpSHACode_Output)
{
    if (lpData_Input == NULL || lpSHACode_Output == NULL)
        return false;
    SHAInit();
    // One times analyse 64Bytes, 512 bits.
    int nInputLen = strlen(lpData_Input);
    int nDealDataLen = 0;                           //  计算输入长度
    for (int pos = 0; pos <= nInputLen; pos += 64)
    {
        if (nInputLen - pos >= 64)
        {
            nDealDataLen = 64;                      
            memset(Message_Block, 0, sizeof(Message_Block));
            memcpy(Message_Block, lpData_Input + pos, nDealDataLen);
            AddDataLen(nDealDataLen);
            ProcessMessageBlock();
            AddDataLen(0);
        }
        else
        {
            nDealDataLen = nInputLen - pos;     
            memset(Message_Block, 0, sizeof(Message_Block));
            memcpy(Message_Block, lpData_Input + pos, nDealDataLen);
            AddDataLen(nDealDataLen);
            PadMessage();
        }
    }
    // copy result to output
    for (int i = 0; i < 5; i++)
    {
        sprintf(&(lpSHACode_Output[8 * i]), "%08x", H[i]);
    }
    return true;
}
void SHA1::AddDataLen(int nDealDataLen)
{
    Message_Block_Index = nDealDataLen;
    if ((Length_Low += ((unsigned int)nDealDataLen << 3)) < ((unsigned int)nDealDataLen << 3))
    {
        Length_High++;
    }
    Length_High += ((unsigned int)nDealDataLen >> 29);
}
//  此函数将处理消息的下一个512位 存储在 Message_Block 阵列中。
void SHA1::ProcessMessageBlock()
{
    const unsigned K[] = {              // Constants defined for SHA-1
        0x5A827999,
        0x6ED9EBA1,
        0x8F1BBCDC,
        0xCA62C1D6
    };
    int         t;                          // Loop counter
    unsigned    temp;                       // Temporary word value
    unsigned    W[80];                      // Word sequence
    unsigned    A, B, C, D, E;              // Word buffers
    for (t = 0; t < 16; t++)
    {
        W[t] = ((unsigned)Message_Block[t * 4]) << 24;
        W[t] |= ((unsigned)Message_Block[t * 4 + 1]) << 16;
        W[t] |= ((unsigned)Message_Block[t * 4 + 2]) << 8;
        W[t] |= ((unsigned)Message_Block[t * 4 + 3]);
    }
    for (t = 16; t < 80; t++)
    {
        W[t] = CircularShift(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]);
    }
    A = H[0];
    B = H[1];
    C = H[2];
    D = H[3];
    E = H[4];
    for (t = 0; t < 20; t++)
    {
        temp = CircularShift(5, A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
        temp &= 0xFFFFFFFF;
        E = D;
        D = C;
        C = CircularShift(30, B);
        B = A;
        A = temp;
    }
    for (t = 20; t < 40; t++)
    {
        temp = CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[1];
        temp &= 0xFFFFFFFF;
        E = D;
        D = C;
        C = CircularShift(30, B);
        B = A;
        A = temp;
    }
    for (t = 40; t < 60; t++)
    {
        temp = CircularShift(5, A) +
            ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
        temp &= 0xFFFFFFFF;
        E = D;
        D = C;
        C = CircularShift(30, B);
        B = A;
        A = temp;
    }
    for (t = 60; t < 80; t++)
    {
        temp = CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[3];
        temp &= 0xFFFFFFFF;
        E = D;
        D = C;
        C = CircularShift(30, B);
        B = A;
        A = temp;
    }
    H[0] = (H[0] + A) & 0xFFFFFFFF;
    H[1] = (H[1] + B) & 0xFFFFFFFF;
    H[2] = (H[2] + C) & 0xFFFFFFFF;
    H[3] = (H[3] + D) & 0xFFFFFFFF;
    H[4] = (H[4] + E) & 0xFFFFFFFF;
}
void SHA1::PadMessage()
{
    /*
    检查当前消息块太小,是否大于512
    如果大于初始填充位和长度。如果大于将增加填充快大小512位倍数,处理它,然后继续填充到第二块。 
    */
    if (Message_Block_Index > 55)
    {
        Message_Block[Message_Block_Index++] = 0x80;
        while (Message_Block_Index < 64)
        {
            Message_Block[Message_Block_Index++] = 0;
        }
        ProcessMessageBlock();
        while (Message_Block_Index < 56)
        {
            Message_Block[Message_Block_Index++] = 0;
        }
    }
    else
    {
        Message_Block[Message_Block_Index++] = 0x80;
        while (Message_Block_Index < 56)
        {
            Message_Block[Message_Block_Index++] = 0;
        }
    }
    Message_Block[56] = (Length_High >> 24) & 0xFF;
    Message_Block[57] = (Length_High >> 16) & 0xFF;
    Message_Block[58] = (Length_High >> 8) & 0xFF;
    Message_Block[59] = (Length_High) & 0xFF;
    Message_Block[60] = (Length_Low >> 24) & 0xFF;
    Message_Block[61] = (Length_Low >> 16) & 0xFF;
    Message_Block[62] = (Length_Low >> 8) & 0xFF;
    Message_Block[63] = (Length_Low) & 0xFF;
    ProcessMessageBlock();
}
unsigned SHA1::CircularShift(int bits, unsigned word)
{
    return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32 - bits));
}

调用实例:

// SHA算法实现.cpp: 定义控制台应用程序的入口点。
#include "stdafx.h"
#include "SHA1.h"
#include <string.h>
int main()
{
    char Strng[]="12343444dasfdfaeda3rfsda43fsdfaew4thhgsdt4";
    char Array[512];
    SHA1 sha1_algorithm;
    sha1_algorithm.SHA_GO(Strng,Array );
    printf_s("%s",Array);
    getchar();
    return 0;
}

ANALYZER通过对ProcessMessageBlock函数检测SHA算法特殊操作,以及初始K数组中常数判断算法。

 

 

 

 

     

 

 


 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值