1. Terminology interpretation: The SHA1 algorithm requires a series of bitwise operations, the following describes the symbolic representation of the bit operations:
Xor different or A xor B
Or or A or B
And with A and B
Not is not A
<< left Shift A>>n (n is constant, same as below)
>> Right Shift A<<n
In addition, a more complex bit operation is needed here, which we call the cyclic left shift:
Sn (X) = (x<<n) OR (x>>32-n) loop left
For example, 1001 Loop left shift 1 bits: S1 (1001) =0011
Move the data to the left 1-bit, and then fill the left-hand side with a bit to add to the right.
2. Data pre-processing: When we get a message, we need to do a series of processing, mainly to complement, complement the length and chunking.
1) Complement: The message we get is the string "Bob", which we first convert to hexadecimal ASCII arrangement in characters. b--62,o--6f,b--62. Now the message information is 626f62. It is then converted to a binary arrangement, which can be: 01100010 01101111 01100010. Visible, this is a 24-bit length of data. Now for the complement operation, first add a 1 to our data. Get: 01100010 01101111 01100010 1. The current length l=25, calculate the length L to 512 of the take-up operation, and x=l%512, if x is not equal to 448, at the end of the data add a 0, has been circulating until x=448. At this point the length of the data should be 512 N times plus 448, i.e. L ' =512*n+448. The end of the complement.
2) complement the length and the BLOCK: Now we get a binary string with a length of 512*n+448 bit, we add a binary string with a length of 64 bits at the end of the binary string to represent the length of the original message data, as in the previous "Bob" length is 24 bits, the second binary means:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00011000
So, we finally get a binary string of length L ' =512*n (that is, a multiple of length 512). Finally, we determine whether the length of the binary string is greater than 512 bits (that is, whether n is 1). If it is greater than 512 bits, we need to split it into multiple strings of 512 bits in length, here with M[i] (m[0],m[1] ...) Said. If not greater than, it is saved directly with M0. To this, the complement length and the end of the block.
3. The values and function expressions of each constant required by the algorithm:
1) Constants:
Kt = 0x5a827999 (0 <= T <= 19)
Kt = 0X6ED9EBA1 (<= t <= 39)
Kt = 0X8F1BBCDC (<= t <= 59)
Kt = 0xca62c1d6 (<= t <= 79)
2) function expression:
FT (b,c,d) = (b and C) OR ((not B) and D) (0 <= T <= 19)
FT (b,c,d) = B xor C xor D (<= T <= 39)
FT (b,c,d) = (b and C) or (b and D) or (C and D) (<= T <= 59)
FT (b,c,d) = B xor C xor D (<= T <= 79).
4. Algorithm:
1) Buffer:
Some buffers are required to handle the binary strings mentioned above, and we will detail the specifications of each buffer below:
Buffer of a.32 bit 5: a,b,c,d,e
Buffer of b.32 bit 80: w[0]~w[79]
Buffer of c.32 bit 5: h[0]~h[4]
Buffer of d.32 bit 1: TEMP
First we assign the buffer h[] to the initialization value:
h[0]=0x67452301
H[1]=0xefcdab89
H[2]=0x98badcfe
h[3]=0x10325476
H[4]=0xc3d2e1f0
2) cycle for each m[i]:
A. Divide m[i] from left to right into 16 32-bit strings, and the values converted to UINT are stored in buffer w[0]~w[15].
B. For w[16]~w[79], we perform the following loops:
W[i] = S1 (w[i-3] xor w[i-8] XOR w[i-14] XOR w[i-16])
At this point, our w[] buffer has been fully assigned.
C. Assign values to buffer a,b,c,d,e, respectively:
A=H[0]
B=H[1]
C=H[2]
D=H[3]
E=H[4]
D. For w[0]~w[79], let's go through the following loops:
TEMP = S5 (A) + ft (b,c,d) + E + w[i] + k[i]
E=d
D=c
C=S30 (B)
B=a
A=temp
E. We will then operate on buffer h[]:
H[0]=h[0]+a
H[1]=h[1]+b
H[2]=h[2]+c
H[3]=h[3]+d
H[4]=h[4]+e
3) After completing each m[i] cycle, the resulting message digest is:
H[0] h[1] h[2] h[3] h[4]
The values in buffer h[] are all converted to 16 digits in string form, and are arranged in the above format as our final computed message digest.
Finally paste the SHA-1 algorithm to implement the source code:
SHA1.h
#ifndef sha1_h_a545e61d43e9404e8d736869ab3cbfe7 #define SHA1_H_A545E61D43E9404E8D736869AB3CBFE7 #if!defined (SHA1_ utility_functions) &&!defined (sha1_no_utility_functions) #define Sha1_utility_functions #endif #if!defined ( sha1_stl_functions) &&!defined (sha1_no_stl_functions) #define Sha1_stl_functions #if!defined (sha1_utility_
FUNCTIONS) #error STL FUNCTIONS require sha1_utility_functions. #endif #endif #include <memory.h> #include <limits.h> #ifdef sha1_utility_functions #include <stdio.h>
; #include <string.h> #endif #ifdef sha1_stl_functions #include <string> #endif #ifdef _msc_ver #include <s Tdlib.h> #endif//can define the endian mode in your files without modifying the SHA-1//source files. Just #define Sha1_little_endian or #define Sha1_big_endian//in your files, before including the SHA1.h header file.
If you don ' t//define anything, the class defaults to little endian. #if!defined (Sha1_little_endian) &&!defined (Sha1_big_endian) #define Sha1_little_endian #endif//If you want variable wiping, #define Sha1_wipe_variable S, if not,//#define Sha1_no_wipe_variables.
If you don ' t define anything, it//defaults to wiping. #if!defined (sha1_wipe_variables) &&!defined (sha1_no_wipe_variables) #define Sha1_wipe_variables #endif #if Defined (Sha1_has_tchar) #include <tchar.h> #else #ifdef _msc_ver #include <tchar.h> #else #ifndef TCHAR #defi Ne TCHAR char #endif #ifndef _t #define _t (__x) (__x) #define _tmain main #define _TPRINTF printf #define _getts gets #def
INE _tcslen strlen #define _tfopen fopen #define _TCSCPY strcpy #define _TCSCAT strcat #define _SNTPRINTF snprintf #endif #endif #endif/////////////////////////////////////////////////////////////////////////////Define variable types # ifndef uint_8 #ifdef _msc_ver//compiling with Microsoft compiler #define UINT_8 unsigned __int8 #else//!_msc_ver #defi Ne uint_8 unsigned char #endif//_msc_ver #endif #iFndef uint_32 #ifdef _msc_ver//compiling with Microsoft compiler #define UINT_32 unsigned __int32 #else//!_msc_ver #if (Ulong_max = = 0xFFFFFFFFUL) #define UINT_32 unsigned long #else #define UINT_32 unsigned int #endif #endif//_msc_ver #e NDIF//uint_32 #ifndef int_64 #ifdef _msc_ver//compiling with Microsoft compiler #define INT_64 __int64 #else//!_msc _ver #define INT_64 Long #endif//_msc_ver #endif//int_64 #ifndef uint_64 #ifdef _msc_ver//compiling with Micro Soft compiler #define UINT_64 unsigned __int64 #else//!_msc_ver #define UINT_64 unsigned long long #endif//_msc_ver #e NDIF//uint_64/////////////////////////////////////////////////////////////////////////////Declare SHA-1
Workspace typedef Union {uint_8 C[64];
Uint_32 l[16];
} Sha1_workspace_block; Class CSHA1 {public: #ifdef sha1_utility_functions//Different formats for Reporthash (STL) enum Report_type {Repor
T_hex = 0, Report_digit = 1, report_hex_short = 2}; #endif//ConstRuctor and destructor CSHA1 ();
#ifdef sha1_wipe_variables ~csha1 ();
#endif void Reset ();
Hash in binary data and strings void Update (const uint_8* pbdata, uint_32 Ulen);
#ifdef sha1_utility_functions//Hash in file contents bool Hashfile (const tchar* tszfilename); #endif//Finalize hash;
Call it before using Reporthash (Stl) void Final ();
#ifdef sha1_utility_functions bool Reporthash (tchar* tszreport, report_type rtreporttype = report_hex) const; #endif #ifdef sha1_stl_functions bool Reporthashstl (std::basic_string<tchar>& Strout, Report_type
Rtreporttype = report_hex) const;
#endif//Get The Raw Message Digest (bytes) bool Gethash (uint_8* pbDest20) const;
Private://private SHA-1 transformation void Transform (uint_32* pState, const uint_8* pbuffer);
Member variables uint_32 m_state[5];
Uint_32 m_count[2]; Uint_32 M_reserved0[1];
Memory alignment padding uint_8 m_buffer[64];
Uint_8 M_DIGEST[20]; Uint_32 M_reserved1[3]; MemorY alignment padding uint_8 m_workspace[64]; Sha1_workspace_block* M_block;
SHA1 pointer to the byte array above}; #endif//Sha1_h_a545e61d43e9404e8d736869ab3cbfe7
SHA1.cpp
#define _crt_secure_no_warnings #include "SHA1.h" #define SHA1_MAX_FILE_BUFFER (* * * 820)//Rotate p_val32 by P_NB Its bits to the left #ifndef ROL32 #ifdef _msc_ver #define ROL32 (p_val32,p_nbits) _rotl (p_val32,p_nbits) #else #define ROL (P_val32,p_nbits) ((P_val32 << (p_nbits)) | ( (P_VAL32) >> (32-(p_nbits))) #endif #endif #ifdef Sha1_little_endian #define SHABLK0 (i) (m_block->l[i] = \ (ROL3 2 (m_block->l[i],24) & 0xff00ff00) |
(ROL32 (m_block->l[i],8) & 0x00ff00ff)) #else #define SHABLK0 (i) (M_block->l[i]) #endif #define SHABLK (i) (m_block->l[i&15] = ROL32 (m_block->l[(i+
&15] ^ \ m_block->l[(i+8) &15] ^ m_block->l[(i+2) &15] ^ m_block->l[i&15],1)//SHA-1 rounds #define S_R0 (v,w,x,y,z,i) {z+= ((w& (x^y)) ^y) +shablk0 (i) +0x5a827999+rol32 (v,5); W=rol32 (w,30);} #define S_R1 (V,w, X,y,z,i) {z+= ((w& (x^y)) ^y) +shablk (i) +0x5a827999+rol32 (v,5); W=rol32 (w,30);} #define S_R2 (v,w,x,y,z,i) {z+= (w^x^ Y) +shablk (i) +0x6ed9eba1+ROL32 (v,5); W=rol32 (w,30);} #define S_R3 (v,w,x,y,z,i) {z+= ((w|x) &y) | (
W&X) +shablk (i) +0x8f1bbcdc+rol32 (v,5); W=rol32 (w,30);}
#define S_R4 (v,w,x,y,z,i) {z+= (w^x^y) +shablk (i) +0xca62c1d6+rol32 (v,5); W=rol32 (w,30);} #pragma warning (push)//Disable compiler warning ' Conditional expression is constant ' #pragma warning (disable:4127) CSH
A1::CSHA1 () {M_block = (sha1_workspace_block*) m_workspace;
Reset (); } #ifdef sha1_wipe_variables Csha1::~csha1 () {Reset (),} #endif void Csha1::reset () {//SHA1 initialization constant
s m_state[0] = 0x67452301;
M_STATE[1] = 0xefcdab89;
M_STATE[2] = 0x98badcfe;
M_STATE[3] = 0x10325476;
M_STATE[4] = 0xc3d2e1f0;
M_count[0] = 0;
M_COUNT[1] = 0; } void Csha1::transform (uint_32* pState, const uint_8* pbuffer) {uint_32 a = pstate[0], B = pstate[1], c = pstate[2], d
= Pstate[3], E = pstate[4];
memcpy (M_block, pbuffer, 64); 4 rounds of operations each, loop unrolled s_r0 (a,b,c,d,e, 0); S_r0 (e,a,b,c,d, 1); S_r0 (D,e,a,b,c, 2); S_r0(C,d,e,a,b, 3); S_r0 (B,c,d,e,a, 4); S_r0 (A,b,c,d,e, 5); S_r0 (E,a,b,c,d, 6);
S_r0 (D,e,a,b,c, 7); S_r0 (C,d,e,a,b, 8); S_r0 (B,c,d,e,a, 9); S_r0 (a,b,c,d,e,10);
S_r0 (e,a,b,c,d,11); S_r0 (d,e,a,b,c,12); S_r0 (c,d,e,a,b,13); S_r0 (b,c,d,e,a,14);
S_r0 (a,b,c,d,e,15); S_R1 (e,a,b,c,d,16); S_R1 (d,e,a,b,c,17); S_R1 (c,d,e,a,b,18);
S_R1 (b,c,d,e,a,19); S_R2 (a,b,c,d,e,20); S_R2 (e,a,b,c,d,21); S_R2 (d,e,a,b,c,22);
S_R2 (c,d,e,a,b,23); S_R2 (b,c,d,e,a,24); S_R2 (a,b,c,d,e,25); S_R2 (e,a,b,c,d,26);
S_R2 (d,e,a,b,c,27); S_R2 (c,d,e,a,b,28); S_R2 (b,c,d,e,a,29); S_R2 (a,b,c,d,e,30);
S_R2 (e,a,b,c,d,31); S_R2 (d,e,a,b,c,32); S_R2 (c,d,e,a,b,33); S_R2 (b,c,d,e,a,34);
S_R2 (a,b,c,d,e,35); S_R2 (e,a,b,c,d,36); S_R2 (d,e,a,b,c,37); S_R2 (c,d,e,a,b,38);
S_R2 (b,c,d,e,a,39); S_R3 (a,b,c,d,e,40); S_R3 (e,a,b,c,d,41); S_R3 (d,e,a,b,c,42);
S_R3 (c,d,e,a,b,43); S_R3 (b,c,d,e,a,44); S_R3 (a,b,c,d,e,45); S_R3 (e,a,b,c,d,46);
S_R3 (d,e,a,b,c,47); S_R3 (c,d,e,a,b,48); S_R3 (b,c,d,e,a,49); S_R3 (a,b,c,d,e,50);
S_R3 (e,a,b,c,d,51); S_R3 (D,e,a,B,C,52); S_R3 (c,d,e,a,b,53); S_R3 (b,c,d,e,a,54);
S_R3 (a,b,c,d,e,55); S_R3 (e,a,b,c,d,56); S_R3 (d,e,a,b,c,57); S_R3 (c,d,e,a,b,58);
S_R3 (b,c,d,e,a,59); S_R4 (a,b,c,d,e,60); S_R4 (e,a,b,c,d,61); S_R4 (d,e,a,b,c,62);
S_R4 (c,d,e,a,b,63); S_R4 (b,c,d,e,a,64); S_R4 (a,b,c,d,e,65); S_R4 (e,a,b,c,d,66);
S_R4 (d,e,a,b,c,67); S_R4 (c,d,e,a,b,68); S_R4 (b,c,d,e,a,69); S_R4 (a,b,c,d,e,70);
S_R4 (e,a,b,c,d,71); S_R4 (d,e,a,b,c,72); S_R4 (c,d,e,a,b,73); S_R4 (b,c,d,e,a,74);
S_R4 (a,b,c,d,e,75); S_R4 (e,a,b,c,d,76); S_R4 (d,e,a,b,c,77); S_R4 (c,d,e,a,b,78);
S_R4 (b,c,d,e,a,79);
ADD the working VARs back to State pstate[0] + = A;
PSTATE[1] + = b;
PSTATE[2] + = C;
PSTATE[3] + = D;
PSTATE[4] + = e;
Wipe variables #ifdef sha1_wipe_variables a = b = c = d = e = 0;
#endif} void Csha1::update (const uint_8* pbdata, uint_32 Ulen) {uint_32 j = ((M_count[0] >> 3) & 0x3F); if ((m_count[0] + = (Ulen << 3)) < (Ulen << 3)) ++m_count[1];
Overflow M_count[1] + = (ulen >> 29);Uint_32 i;
if ((j + Ulen) >) {i = 64-j;
memcpy (&m_buffer[j], pbdata, i);
Transform (M_state, M_buffer); for (; (i + +) < Ulen;
i + = +) Transform (M_state, &pbdata[i]);
j = 0;
} else i = 0;
if ((ulen-i)! = 0) memcpy (&m_buffer[j], &pbdata[i], ulen-i);
} #ifdef sha1_utility_functions bool Csha1::hashfile (const tchar* tszfilename) {if (Tszfilename = = NULL) return false;
file* Fpin = _tfopen (Tszfilename, _t ("RB"));
if (Fpin = = NULL) return false;
uint_8* pbdata = new Uint_8[sha1_max_file_buffer];
if (pbdata = = NULL) {fclose (Fpin); return false;}
BOOL bsuccess = true;
while (true) {const size_t uread = Fread (pbdata, 1, Sha1_max_file_buffer, Fpin);
if (Uread > 0) Update (pbdata, static_cast<uint_32> (Uread));
if (Uread < Sha1_max_file_buffer) {if (feof (fpin) = = 0) bsuccess = false;
Break }} Fclo