SHA-1算法解釋與C/C++實現

SHA-1

與MD5算法一樣,也屬於是一種哈希算法,並非是密碼算法,也是因爲其不可逆性,導致其在密碼界常有應用,他與MD5的區別:

  • 輸出定長爲20字節
  • 安全強度更強
  • 算法計算過程略有不同

算法實現過程

  1. 與其他哈希算法一樣,首先肯定是對原文數據進行填充,輸入不定長度的原文,要使其長度滿足: “長度 mod 512bit =448bit”
  2. 不管其長度是否滿足,都要在其後至少添加一個十進制數128即0x80,其二進制形式爲1000 0000,如果長度不滿足就在添加完0x80後繼續填充0,一致填充到滿足"長度 mod 512bit =448bit "爲止
  3. 在添加完0x80後添加原文數據長度,記住原文數據長度要佔八字節,最後記得初始化五組32bit的幻數,分別爲:A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476,E=0xc3d2e1f0,可以看出比MD5算法多出了一個E
  4. 在進行完上述步驟後,不出錯的話,此時填充後的數據長度剛好是512bit即64byte的倍數,然後開始每512bit一算
  5. 現在我們每組能獲取一個64字節的數據,但是要注意SHA-1算法與MD5算法不同就在於,MD5算法是再將這64字節分爲4組每組4個字節共16個字節共四輪運算,4*16最後將這64個字節處理完,而SHA-1則也是分爲四組每組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個字節的字符數據統一處理成一組四個字節的無符號整型數據,然後再在其後填充,一填充到滿足80個無符號整形數據位置
6. 現在處理就完成了,我們開始用80/20剛好得4組每組四個字節
7. 然後將ABCDE五組幻數進行移動,D->E,C->E,然後對C進行計算處理,A->B然後對A進行計算處理,一次循環計算
8. 最終將每輪計算的ABCDE相加得出最後結果

代碼實現

首先初始化一下我們要使用到的一些常量比如五組幻數:

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

這裏要注意要將長度位置顛倒一下,把第一個字節放到最後一個,第二個放到倒二…以此類推,我不知道爲什麼SHA-1算法必須要這樣處理,而MD5不需要,但經過我的測試,如果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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章