SHA-1アルゴリズム解釈とC/C++実装


SHA-1
MD 5アルゴリズムと同様に、ハッシュアルゴリズムにも属し、暗号アルゴリズムではなく、その不可逆性のため、暗号界でよく応用され、MD 5との違いがある.
  • 出力定長20バイト
  • より強い安全強度
  • アルゴリズム計算パスはわずかに異なる
  • アルゴリズム実装プロセス
  • 他のハッシュアルゴリズムと同様に、まず必ず原文データを埋め込み、不定長の原文を入力し、その長さが「長さmod 512 bit=448 bit」
  • を満たすようにする.
  • は、その長さが満足するかどうかにかかわらず、その後に少なくとも1つの10進数128である0 x 80を追加しなければならない.その2進数は1000 0000であり、長さが満足しない場合は0 x 80を追加した後も0を充填し続け、「長さmod 512 bit=448 bit」を満たすまで
  • に一致して充填する.
  • 0 x 80を追加した後に原文のデータの長さを追加して、原文のデータの長さが8バイトを占めることを覚えて、最後に5組の32 bitの幻数を初期化することを覚えて、それぞれ:A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476,E=0xc3d2e1f0で、MD 5アルゴリズムより1つのE
  • が多いことを見ることができます
  • 上記の手順を行った後、エラーが発生しなければ、このときのパディング後のデータ長は、512 bitである64 byteの倍数となり、512 bitごとの
  • の計算を開始する.
  • 現在、私たちはグループごとに64バイトのデータを取得することができますが、SHA-1アルゴリズムはMD 5アルゴリズムとは異なり、MD 5アルゴリズムはこの64バイトを4グループに分けてグループごとに4バイトで16バイトで4ラウンド演算し、4*16は最後にこの64バイトを処理し、SHA-1も4グループごとに4バイトで4ラウンド計算しています.しかし、異なるのは、出力長が20バイトに固定されているため、充填後のデータ長を処理し、処理手順:
  • .
    for (int i = 0; i < 16; i++)
    	{
    		int j = 4 * i;
    		ulong_data[i] = ((unsigned int)char_data[j]) << 24 | 
    						((unsigned int)char_data[1 + j]) << 16 | 
    						((unsigned int)char_data[2 + j]) << 8 |
    						((unsigned int)char_data[3 + j]) << 0;
    	}
    	for (int i = 16; i < 80; i++)
    	{
    		ulong_data[i] = ulong_data[i - 16] ^ ulong_data[i - 14] ^ 
    						ulong_data[i - 8] ^ ulong_data[i - 3];
    		ulong_data[i] = (ulong_data[i] << 1) | (ulong_data[i] >> 31);
    	}
    

    まず、従来の64バイトの文字データを1組の4バイトの符号なし整数データに統一処理し、その後、80個の符号なし整形データを満たす位置6に充填する.これで処理が完了し、80/20でちょうど4組の4バイトを手に入れ始めました.次にABCDEの5組の幻数を移動する、D->E、C->E、そしてCに対して計算処理を行い、A->BはAに対して計算処理を行い、1回のループ計算を行う.最終的に各ラウンドで計算したABCDEを加算して最終結果を出す
    コード実装
    まず、5つの幻のグループなど、使用する定数を初期化します.
    	unsigned int k = 0, f = 0;
    	unsigned int temp_ul_text[80];
    	unsigned int temp_A = 0;
    	unsigned int h[] = { 0x67452301,0xefcdab89,0x98badcfe,0x10325476,0xc3d2e1f0 };
    

    その後、元のデータの入力を開始します.
    /*
    	*      
    	*/
    	size_t n_len = ((len + 8) / 64) * 64 + 56 + 8;
    	unsigned char*n_text = (unsigned char*)malloc(n_len);
    	memset(n_text, 0x00, n_len);
    	memcpy(n_text, text, len);
    	n_text[len] = 0x80;
    	unsigned char c_lens[8];
    	memset(c_lens, 0x00, 8);
    	unsigned int temp_len = (unsigned int)(len * 8);
    	memcpy(c_lens, &temp_len, sizeof(unsigned long));
    	/*
    	*           
    	*/
    	for (int i = 7; i >= 4; i--)
    	{
    		int y = c_lens[i];
    		c_lens[i] = c_lens[7-i];
    		c_lens[7-i] = y;
    	}
    	memcpy(n_text + (n_len - 8), c_lens, 8);
    

    ここでは長さ位置を逆さまにして、1バイト目を最後に、2バイト目を逆さまに…というように、SHA-1アルゴリズムはなぜこのように処理しなければならないのか分かりませんが、MD 5は必要ありませんが、私のテストを経て、SHA-1がそうしなければ最終結果は間違っています
    64バイトのグループで計算を開始します
    /*
    	*    ,512bits  
    	*/
    	for (int i = 0; i < n_len; i += 64)
    	{
    		//A=H[0],B=H[1],C=H[2],D=H[3],E=H[4]
    		unsigned int H[5] = { 0,0,0,0,0 };
    		unsigned char temp_text[64];
    
    		memset(temp_text, 0x00, 64);
    		memset(temp_ul_text, 0x00, 80*sizeof(unsigned int));
    		memcpy(H, h, 5 * (sizeof(unsigned int)));
    		memcpy(temp_text, (n_text + i), 64);
    
    		CharToUlong(temp_text, temp_ul_text);
    
    		for (int j = 0; j < 80; j++)
    		{
    			switch ((int)j/20)
    			{
    			case 0:
    				k = 0x5a827999;
    				f = (H[1] & H[2]) | ((~H[1]) & H[3]);
    				break;
    			case 1:
    				k = 0x6ed9eba1;
    				f = H[1] ^ H[2] ^ H[3];
    				break;
    			case 2:
    				k = 0x8f1bbcdc;
    				f = (H[1] & H[2]) | (H[1] & H[3]) | (H[2] & H[3]);
    				break;
    			case 3:
    				k = 0xca62c1d6;
    				f = H[1] ^ H[2] ^ H[3];
    				break;
    			default:
    				break;
    			}
    			//ABCDE    
    			temp_A = ((H[0] << 5) | (H[0] >> 27)) + f + H[4] + temp_ul_text[j] + k;
    			H[4] = H[3];
    			H[3] = H[2];
    			H[2] = (H[1] << 30) | (H[1] >> 2);
    			H[1] = H[0];
    			H[0] = temp_A;
    		}
    		//ABCDE  
    		for (int k = 0; k < 5; k++)
    			h[k] += H[k];
    	}
    

    ここにはもう一つのCharToUlong関数があります.彼の実現は:
    inline void SHA1::CharToUlong
    (
    	_In_ const unsigned char* char_data,
    	_Inout_ unsigned int* ulong_data
    ) 
    {
    	for (int i = 0; i < 16; i++)
    	{
    		int j = 4 * i;
    		ulong_data[i] = ((unsigned int)char_data[j]) << 24 | 
    						((unsigned int)char_data[1 + j]) << 16 | 
    						((unsigned int)char_data[2 + j]) << 8 |
    						((unsigned int)char_data[3 + j]) << 0;
    	}
    	for (int i = 16; i < 80; i++)
    	{
    		ulong_data[i] = ulong_data[i - 16] ^ ulong_data[i - 14] ^ 
    						ulong_data[i - 8] ^ ulong_data[i - 3];
    		ulong_data[i] = (ulong_data[i] << 1) | (ulong_data[i] >> 31);
    	}
    }
    

    最後に、以前に申請したメモリを解放し、結果を文字列に変換すればいいです.
    free(n_text);
    	//            
    	for (int o = 0; o < 5; o++)
    	{
    		sprintf_s(outData, 40, "%08x", h[o]);
    		outData += 8;
    	}
    	outData[40] = '\0';
    

    完全なコードアドレス:Linux GCC:github Windows MSVC:github