• sha1算法实现原理深剖


    一、基本介绍

    SHA (Security Hash Algorithm) 是美国的 NIST 和 NSA 设计的一种标准的 Hash 算法,SHA 用于数字签名的标准算法的 DSS 中,也是安全性很高的一种 Hash 算法。

    SHA-1 是第一代 SHA 算法标准,后来的 SHA-224、SHA-256、SHA-384 和 SHA-512 被统称为 SHA-2。

    二、实现原理

    有关 SHA1 算法详情请参见 RFC 3174 http://www.ietf.org/rfc/rfc3174.txt

    RFC 3174 是SHA1算法的官方文档,(建议了解SHA1算法前,先了解下MD4 md4算法实现原理深剖 )其实现原理共分为5步:

    第1步:字节填充(Append Padding Bytes)

    数据先补上1个1比特,再补上k个0比特,使得补位后的数据比特数(n+1+k)满足(n+1+k) mod 512 = 448,k取最小正整数。

    第2步:追加长度信息(Append Length)

    数据比特位的数据长度追加到最后8字节中。【注意字节顺序与MD4不同 大小端之分】

    第3步:初始化MD Buffer(Initialize MD Buffer)

    这一步最简单了,定义ABCD四个4字节数组,分别赋初值即可。【注意相对于MD4 添加了H4】

        uint32_t H0 = 0x67452301;	// 0x01, 0x23, 0x45, 0x67
        uint32_t H1 = 0xEFCDAB89;	// 0x89, 0xAB, 0xCD, 0xEF
        uint32_t H2 = 0x98BADCFE;	// 0xFE, 0xDC, 0xBA, 0x98
        uint32_t H3 = 0x10325476;	// 0x76, 0x54, 0x32, 0x10
        uint32_t H4 = 0xC3D2E1F0;	// 0xF0, 0xE1, 0xD2, 0xC3

    第4步:处理消息块(Process Message in 16-Byte Blocks)

    这个是SHA1算法最核心的部分了,对第2步组装数据进行分块依次处理。

    	/* Process each 16-word block. */
    	For i = 0 to N/16-1 do
    
    		/* Copy block i into X. */
    		For j = 0 to 15 do
    			Set X[j] to M[i*16+j].
    		end /* of loop on j */
    
    	a. Divide M(i) into 16 words W(0), W(1), ... , W(15), where W(0) is the left-most word.
    
    	b. For t = 16 to 79 let
    		W(t) = S^1(W(t-3) XOR W(t-8) XOR W(t-14) XOR W(t-16)).
    
    	c. Let A = H0, B = H1, C = H2, D = H3, E = H4.
    
    	d. For t = 0 to 79 do
    		
    		TEMP = S^5(A) + f(t;B,C,D) + E + W(t) + K(t);
    
    		E = D;  D = C;  C = S^30(B);  B = A; A = TEMP;
    
    	e. Let H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E.
    
       end /* of loop on i */

    第5步:输出(Output)

    这一步也非常简单,只需要将计算后的H0、H1、H2、H3、H4进行拼接输出即可。

    三、示例讲解

     

     四、代码实现

    以下为C/C++代码实现:

    #include <string.h>
    #include <stdio.h>
    
    #define HASH_BLOCK_SIZE         64  /* 512 bits = 64 bytes */
    #define HASH_LEN_SIZE           8   /* 64 bits =  8 bytes */
    #define HASH_LEN_OFFSET         56  /* 64 bytes - 8 bytes */
    #define HASH_DIGEST_SIZE        16  /* 128 bits = 16 bytes */
    #define HASH_ROUND_NUM          80	
    
    typedef unsigned char		uint8_t;
    typedef unsigned short int	uint16_t;
    typedef unsigned int		uint32_t;
    typedef unsigned long long	uint64_t;
    
    /* Swap bytes in 32 bit value. 0x01234567 -> 0x67452301 */
    #define __bswap_32(x)    \
         ((((x) & 0xff000000) >> 24)  \
         | (((x) & 0x00ff0000) >>  8) \
         | (((x) & 0x0000ff00) <<  8) \
         | (((x) & 0x000000ff) << 24))
    
    /* SHA1 Constants */
    static uint32_t K[4] =
    {
    	0x5A827999,		/* [0,  19] */
    	0x6ED9EBA1,		/* [20, 39] */
    	0x8F1BBCDC,		/* [40, 59] */
    	0xCA62C1D6		/* [60, 79] */
    };
    
    /*					f(X, Y, Z)						*/
    /* [0,  19] */
    static uint32_t Ch(uint32_t X, uint32_t Y, uint32_t Z)
    {
    	return (X & Y) ^ ((~X) & Z);
    }
    /* [20, 39] */	/* [60, 79] */
    static uint32_t Parity(uint32_t X, uint32_t Y, uint32_t Z)
    {
    	return X ^ Y ^ Z;
    }
    /* [40, 59] */
    static uint32_t Maj(uint32_t X, uint32_t Y, uint32_t Z)
    {
    	return (X & Y) ^ (X & Z) ^ (Y & Z);
    }
    
    /* 循环向左移动offset个比特位 */
    static uint32_t MoveLeft(uint32_t X, uint8_t offset)
    {
    	uint32_t res = (X << offset) | (X >> (32 - offset));
    	return res;
    }
    
    #define ASSERT_RETURN_INT(x, d) if(!(x)) { return d; }
    
    int sha1(unsigned char *out, const unsigned char* in, const int inlen)
    {
    	ASSERT_RETURN_INT(out && in && (inlen >= 0), 1);
    	int i = 0, j = 0, t = 0;
    
    	// step 1: 字节填充(Append Padding Bytes)
    	// 数据先补上1个1比特,再补上k个0比特,使得补位后的数据比特数(n+1+k)满足(n+1+k) mod 512 = 448,k取最小正整数
    	int iX = inlen / HASH_BLOCK_SIZE;
    	int iY = inlen % HASH_BLOCK_SIZE;
    	iX = (iY < HASH_LEN_OFFSET) ? iX : (iX + 1);
    
    	int iLen = (iX + 1) * HASH_BLOCK_SIZE;
    	unsigned char* X = malloc(iLen);
    	memcpy(X, in, inlen);
    	// 先补上1个1比特+7个0比特
    	X[inlen] = 0x80;
    	// 再补上(k-7)个0比特
    	for (i = inlen + 1; i < (iX * HASH_BLOCK_SIZE + HASH_LEN_OFFSET); i++)
    	{
    		X[i] = 0;
    	}
    
    	// step 2: 追加长度信息(Append Length)
    	uint8_t *pLen = (uint64_t*)(X + (iX * HASH_BLOCK_SIZE + HASH_LEN_OFFSET));
    	uint64_t iTempLen = inlen << 3;
    	uint8_t *pTempLen = &iTempLen;
    	pLen[0] = pTempLen[7]; pLen[1] = pTempLen[6]; pLen[2] = pTempLen[5];  pLen[3] = pTempLen[4];
    	pLen[4] = pTempLen[3]; pLen[5] = pTempLen[2]; pLen[6] = pTempLen[1];  pLen[7] = pTempLen[0];
    
    	// Step 3. 初始化MD Buffer(Initialize MD Buffer)
    	uint32_t H0 = 0x67452301;	// 0x01, 0x23, 0x45, 0x67
    	uint32_t H1 = 0xEFCDAB89;	// 0x89, 0xAB, 0xCD, 0xEF
    	uint32_t H2 = 0x98BADCFE;	// 0xFE, 0xDC, 0xBA, 0x98
    	uint32_t H3 = 0x10325476;	// 0x76, 0x54, 0x32, 0x10
    	uint32_t H4 = 0xC3D2E1F0;	// 0xF0, 0xE1, 0xD2, 0xC3
    
    	uint32_t M[HASH_BLOCK_SIZE / 4] = { 0 };
    	uint32_t W[HASH_ROUND_NUM] = { 0 };
    
    	// step 4: 处理消息块(Process Message in 64-Byte Blocks)
    	for (i = 0; i < iLen / HASH_BLOCK_SIZE; i++)
    	{
    		/* Copy block i into X. */
    		for (j = 0; j < HASH_BLOCK_SIZE; j = j + 4)
    		{
    			uint64_t k = i * HASH_BLOCK_SIZE + j;
    			M[j / 4] = (X[k] << 24) | (X[k + 1] << 16) | (X[k + 2] << 8) | X[k + 3];
    		}
    
    		/*	a. Divide M(i) into 16 words W(0), W(1), ..., W(15), where W(0) is the left - most word. */
    		for (t = 0; t <= 15; t++)
    		{
    			W[t] = M[t];
    		}
    
    		/*  b. For t = 16 to 79 let
    		W(t) = S^1(W(t-3) XOR W(t-8) XOR W(t-14) XOR W(t-16)). */
    		for (t = 16; t <= 79; t++)
    		{
    			W[t] = MoveLeft(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);
    		}
    
    		/*	c. Let A = H0, B = H1, C = H2, D = H3, E = H4. */
    		uint32_t A = H0;
    		uint32_t B = H1;
    		uint32_t C = H2;
    		uint32_t D = H3;
    		uint32_t E = H4;
    
    		/*	d. For t = 0 to 79 do
    		TEMP = S^5(A) + f(t;B,C,D) + E + W(t) + K(t);
    		E = D;  D = C;  C = S^30(B);  B = A; A = TEMP; */
    		for (t = 0; t <= 19; t++)
    		{
    			uint32_t temp = MoveLeft(A, 5) + Ch(B, C, D) + E + W[t] + K[0];
    			E = D;
    			D = C;
    			C = MoveLeft(B, 30);
    			B = A;
    			A = temp;
    		}
    		for (t = 20; t <= 39; t++)
    		{
    			uint32_t temp = MoveLeft(A, 5) + Parity(B, C, D) + E + W[t] + K[1];
    			E = D;
    			D = C;
    			C = MoveLeft(B, 30);
    			B = A;
    			A = temp;
    		}
    		for (t = 40; t <= 59; t++)
    		{
    			uint32_t temp = MoveLeft(A, 5) + Maj(B, C, D) + E + W[t] + K[2];
    			E = D;
    			D = C;
    			C = MoveLeft(B, 30);
    			B = A;
    			A = temp;
    		}
    		for (t = 60; t <= 79; t++)
    		{
    			uint32_t temp = MoveLeft(A, 5) + Parity(B, C, D) + E + W[t] + K[3];
    			E = D;
    			D = C;
    			C = MoveLeft(B, 30);
    			B = A;
    			A = temp;
    		}
    
    		/*	e. Let H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E. */
    		H0 = H0 + A;
    		H1 = H1 + B;
    		H2 = H2 + C;
    		H3 = H3 + D;
    		H4 = H4 + E;
    	}
    
    	// step 5: 输出ABCD
    	uint32_t* pOut = (uint8_t*)out;
    	pOut[0] = __bswap_32(H0);
    	pOut[1] = __bswap_32(H1);
    	pOut[2] = __bswap_32(H2);
    	pOut[3] = __bswap_32(H3);
    	pOut[4] = __bswap_32(H4);
    	free(X);
    
    	return 0;
    }
    
    int main()
    {
    	unsigned char digest[20] = { 0 };
    
    	sha1(digest, "Hello World!", strlen("Hello World!"));
    
    	return 0;
    }
  • 相关阅读:
    主效应|处理误差 |组间误差|处理效应|随机误差|组内误差|误差|效应分析|方差齐性检验|SSE|SSA|SST|MSE|MSA|F检验|关系系数|完全随机化设计|区组设计|析因分析
    第二类错误|检验统计量|左偏|右偏|P值
    估计量|估计值|置信度|置信水平|非正态的小样本|t分布|大样本抽样分布|总体方差|
    参数|统计量|抽样分布|估计标准误差|标准误差|标准误|标准差|二项分布|泊松分布|中心极限定理|样本方差|
    ruby 分析日志,提取特定记录
    find 找出大文件
    momentjs 求小时差异
    linux下对date和timestamp的互转
    golang protobuf SetExtension
    对文本中的某两列求和,请统计重复出现次数
  • 原文地址:https://www.cnblogs.com/Kingfans/p/16561821.html
Copyright © 2020-2023  润新知