xref: /netbsd-src/external/bsd/elftosb/dist/common/SHA1.cpp (revision 993229b6fea628ff8b1fa09146c80b0cfb2768eb)
1*993229b6Sjkunz /*
2*993229b6Sjkunz 	100% free public domain implementation of the SHA-1 algorithm
3*993229b6Sjkunz 	by Dominik Reichl <dominik.reichl@t-online.de>
4*993229b6Sjkunz 	Web: http://www.dominik-reichl.de/
5*993229b6Sjkunz 
6*993229b6Sjkunz 	Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
7*993229b6Sjkunz 	- You can set the endianness in your files, no need to modify the
8*993229b6Sjkunz 	  header file of the CSHA1 class any more
9*993229b6Sjkunz 	- Aligned data support
10*993229b6Sjkunz 	- Made support/compilation of the utility functions (ReportHash
11*993229b6Sjkunz 	  and HashFile) optional (useful, if bytes count, for example in
12*993229b6Sjkunz 	  embedded environments)
13*993229b6Sjkunz 
14*993229b6Sjkunz 	Version 1.5 - 2005-01-01
15*993229b6Sjkunz 	- 64-bit compiler compatibility added
16*993229b6Sjkunz 	- Made variable wiping optional (define SHA1_WIPE_VARIABLES)
17*993229b6Sjkunz 	- Removed unnecessary variable initializations
18*993229b6Sjkunz 	- ROL32 improvement for the Microsoft compiler (using _rotl)
19*993229b6Sjkunz 
20*993229b6Sjkunz 	======== Test Vectors (from FIPS PUB 180-1) ========
21*993229b6Sjkunz 
22*993229b6Sjkunz 	SHA1("abc") =
23*993229b6Sjkunz 		A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
24*993229b6Sjkunz 
25*993229b6Sjkunz 	SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
26*993229b6Sjkunz 		84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
27*993229b6Sjkunz 
28*993229b6Sjkunz 	SHA1(A million repetitions of "a") =
29*993229b6Sjkunz 		34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
30*993229b6Sjkunz */
31*993229b6Sjkunz 
32*993229b6Sjkunz #include "SHA1.h"
33*993229b6Sjkunz 
34*993229b6Sjkunz #ifdef SHA1_UTILITY_FUNCTIONS
35*993229b6Sjkunz #define SHA1_MAX_FILE_BUFFER 8000
36*993229b6Sjkunz #endif
37*993229b6Sjkunz 
38*993229b6Sjkunz // Rotate x bits to the left
39*993229b6Sjkunz #ifndef ROL32
40*993229b6Sjkunz #ifdef _MSC_VER
41*993229b6Sjkunz #define ROL32(_val32, _nBits) _rotl(_val32, _nBits)
42*993229b6Sjkunz #else
43*993229b6Sjkunz #define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits))))
44*993229b6Sjkunz #endif
45*993229b6Sjkunz #endif
46*993229b6Sjkunz 
47*993229b6Sjkunz #ifdef SHA1_LITTLE_ENDIAN
48*993229b6Sjkunz #define SHABLK0(i) (m_block->l[i] = \
49*993229b6Sjkunz 	(ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))
50*993229b6Sjkunz #else
51*993229b6Sjkunz #define SHABLK0(i) (m_block->l[i])
52*993229b6Sjkunz #endif
53*993229b6Sjkunz 
54*993229b6Sjkunz #define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \
55*993229b6Sjkunz 	^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))
56*993229b6Sjkunz 
57*993229b6Sjkunz // SHA-1 rounds
58*993229b6Sjkunz #define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
59*993229b6Sjkunz #define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
60*993229b6Sjkunz #define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); }
61*993229b6Sjkunz #define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); }
62*993229b6Sjkunz #define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); }
63*993229b6Sjkunz 
CSHA1()64*993229b6Sjkunz CSHA1::CSHA1()
65*993229b6Sjkunz {
66*993229b6Sjkunz 	m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;
67*993229b6Sjkunz 
68*993229b6Sjkunz 	Reset();
69*993229b6Sjkunz }
70*993229b6Sjkunz 
~CSHA1()71*993229b6Sjkunz CSHA1::~CSHA1()
72*993229b6Sjkunz {
73*993229b6Sjkunz 	Reset();
74*993229b6Sjkunz }
75*993229b6Sjkunz 
Reset()76*993229b6Sjkunz void CSHA1::Reset()
77*993229b6Sjkunz {
78*993229b6Sjkunz 	// SHA1 initialization constants
79*993229b6Sjkunz 	m_state[0] = 0x67452301;
80*993229b6Sjkunz 	m_state[1] = 0xEFCDAB89;
81*993229b6Sjkunz 	m_state[2] = 0x98BADCFE;
82*993229b6Sjkunz 	m_state[3] = 0x10325476;
83*993229b6Sjkunz 	m_state[4] = 0xC3D2E1F0;
84*993229b6Sjkunz 
85*993229b6Sjkunz 	m_count[0] = 0;
86*993229b6Sjkunz 	m_count[1] = 0;
87*993229b6Sjkunz }
88*993229b6Sjkunz 
Transform(uint32_t * state,const uint8_t * buffer)89*993229b6Sjkunz void CSHA1::Transform(uint32_t *state, const uint8_t *buffer)
90*993229b6Sjkunz {
91*993229b6Sjkunz 	// Copy state[] to working vars
92*993229b6Sjkunz 	uint32_t a = state[0], b = state[1], c = state[2], d = state[3], e = state[4];
93*993229b6Sjkunz 
94*993229b6Sjkunz 	memcpy(m_block, buffer, 64);
95*993229b6Sjkunz 
96*993229b6Sjkunz 	// 4 rounds of 20 operations each. Loop unrolled.
97*993229b6Sjkunz 	_R0(a,b,c,d,e, 0); _R0(e,a,b,c,d, 1); _R0(d,e,a,b,c, 2); _R0(c,d,e,a,b, 3);
98*993229b6Sjkunz 	_R0(b,c,d,e,a, 4); _R0(a,b,c,d,e, 5); _R0(e,a,b,c,d, 6); _R0(d,e,a,b,c, 7);
99*993229b6Sjkunz 	_R0(c,d,e,a,b, 8); _R0(b,c,d,e,a, 9); _R0(a,b,c,d,e,10); _R0(e,a,b,c,d,11);
100*993229b6Sjkunz 	_R0(d,e,a,b,c,12); _R0(c,d,e,a,b,13); _R0(b,c,d,e,a,14); _R0(a,b,c,d,e,15);
101*993229b6Sjkunz 	_R1(e,a,b,c,d,16); _R1(d,e,a,b,c,17); _R1(c,d,e,a,b,18); _R1(b,c,d,e,a,19);
102*993229b6Sjkunz 	_R2(a,b,c,d,e,20); _R2(e,a,b,c,d,21); _R2(d,e,a,b,c,22); _R2(c,d,e,a,b,23);
103*993229b6Sjkunz 	_R2(b,c,d,e,a,24); _R2(a,b,c,d,e,25); _R2(e,a,b,c,d,26); _R2(d,e,a,b,c,27);
104*993229b6Sjkunz 	_R2(c,d,e,a,b,28); _R2(b,c,d,e,a,29); _R2(a,b,c,d,e,30); _R2(e,a,b,c,d,31);
105*993229b6Sjkunz 	_R2(d,e,a,b,c,32); _R2(c,d,e,a,b,33); _R2(b,c,d,e,a,34); _R2(a,b,c,d,e,35);
106*993229b6Sjkunz 	_R2(e,a,b,c,d,36); _R2(d,e,a,b,c,37); _R2(c,d,e,a,b,38); _R2(b,c,d,e,a,39);
107*993229b6Sjkunz 	_R3(a,b,c,d,e,40); _R3(e,a,b,c,d,41); _R3(d,e,a,b,c,42); _R3(c,d,e,a,b,43);
108*993229b6Sjkunz 	_R3(b,c,d,e,a,44); _R3(a,b,c,d,e,45); _R3(e,a,b,c,d,46); _R3(d,e,a,b,c,47);
109*993229b6Sjkunz 	_R3(c,d,e,a,b,48); _R3(b,c,d,e,a,49); _R3(a,b,c,d,e,50); _R3(e,a,b,c,d,51);
110*993229b6Sjkunz 	_R3(d,e,a,b,c,52); _R3(c,d,e,a,b,53); _R3(b,c,d,e,a,54); _R3(a,b,c,d,e,55);
111*993229b6Sjkunz 	_R3(e,a,b,c,d,56); _R3(d,e,a,b,c,57); _R3(c,d,e,a,b,58); _R3(b,c,d,e,a,59);
112*993229b6Sjkunz 	_R4(a,b,c,d,e,60); _R4(e,a,b,c,d,61); _R4(d,e,a,b,c,62); _R4(c,d,e,a,b,63);
113*993229b6Sjkunz 	_R4(b,c,d,e,a,64); _R4(a,b,c,d,e,65); _R4(e,a,b,c,d,66); _R4(d,e,a,b,c,67);
114*993229b6Sjkunz 	_R4(c,d,e,a,b,68); _R4(b,c,d,e,a,69); _R4(a,b,c,d,e,70); _R4(e,a,b,c,d,71);
115*993229b6Sjkunz 	_R4(d,e,a,b,c,72); _R4(c,d,e,a,b,73); _R4(b,c,d,e,a,74); _R4(a,b,c,d,e,75);
116*993229b6Sjkunz 	_R4(e,a,b,c,d,76); _R4(d,e,a,b,c,77); _R4(c,d,e,a,b,78); _R4(b,c,d,e,a,79);
117*993229b6Sjkunz 
118*993229b6Sjkunz 	// Add the working vars back into state
119*993229b6Sjkunz 	state[0] += a;
120*993229b6Sjkunz 	state[1] += b;
121*993229b6Sjkunz 	state[2] += c;
122*993229b6Sjkunz 	state[3] += d;
123*993229b6Sjkunz 	state[4] += e;
124*993229b6Sjkunz 
125*993229b6Sjkunz 	// Wipe variables
126*993229b6Sjkunz #ifdef SHA1_WIPE_VARIABLES
127*993229b6Sjkunz 	a = b = c = d = e = 0;
128*993229b6Sjkunz #endif
129*993229b6Sjkunz }
130*993229b6Sjkunz 
131*993229b6Sjkunz // Use this function to hash in binary data and strings
Update(const uint8_t * data,uint32_t len)132*993229b6Sjkunz void CSHA1::Update(const uint8_t *data, uint32_t len)
133*993229b6Sjkunz {
134*993229b6Sjkunz 	uint32_t i, j;
135*993229b6Sjkunz 
136*993229b6Sjkunz 	j = (m_count[0] >> 3) & 63;
137*993229b6Sjkunz 
138*993229b6Sjkunz 	if((m_count[0] += len << 3) < (len << 3)) m_count[1]++;
139*993229b6Sjkunz 
140*993229b6Sjkunz 	m_count[1] += (len >> 29);
141*993229b6Sjkunz 
142*993229b6Sjkunz 	if((j + len) > 63)
143*993229b6Sjkunz 	{
144*993229b6Sjkunz 		i = 64 - j;
145*993229b6Sjkunz 		memcpy(&m_buffer[j], data, i);
146*993229b6Sjkunz 		Transform(m_state, m_buffer);
147*993229b6Sjkunz 
148*993229b6Sjkunz 		for( ; i + 63 < len; i += 64) Transform(m_state, &data[i]);
149*993229b6Sjkunz 
150*993229b6Sjkunz 		j = 0;
151*993229b6Sjkunz 	}
152*993229b6Sjkunz 	else i = 0;
153*993229b6Sjkunz 
154*993229b6Sjkunz 	memcpy(&m_buffer[j], &data[i], len - i);
155*993229b6Sjkunz }
156*993229b6Sjkunz 
157*993229b6Sjkunz #ifdef SHA1_UTILITY_FUNCTIONS
158*993229b6Sjkunz // Hash in file contents
HashFile(char * szFileName)159*993229b6Sjkunz bool CSHA1::HashFile(char *szFileName)
160*993229b6Sjkunz {
161*993229b6Sjkunz 	unsigned long ulFileSize, ulRest, ulBlocks;
162*993229b6Sjkunz 	unsigned long i;
163*993229b6Sjkunz 	uint8_t uData[SHA1_MAX_FILE_BUFFER];
164*993229b6Sjkunz 	FILE *fIn;
165*993229b6Sjkunz 
166*993229b6Sjkunz 	if(szFileName == NULL) return false;
167*993229b6Sjkunz 
168*993229b6Sjkunz 	fIn = fopen(szFileName, "rb");
169*993229b6Sjkunz 	if(fIn == NULL) return false;
170*993229b6Sjkunz 
171*993229b6Sjkunz 	fseek(fIn, 0, SEEK_END);
172*993229b6Sjkunz 	ulFileSize = (unsigned long)ftell(fIn);
173*993229b6Sjkunz 	fseek(fIn, 0, SEEK_SET);
174*993229b6Sjkunz 
175*993229b6Sjkunz 	if(ulFileSize != 0)
176*993229b6Sjkunz 	{
177*993229b6Sjkunz 		ulBlocks = ulFileSize / SHA1_MAX_FILE_BUFFER;
178*993229b6Sjkunz 		ulRest = ulFileSize % SHA1_MAX_FILE_BUFFER;
179*993229b6Sjkunz 	}
180*993229b6Sjkunz 	else
181*993229b6Sjkunz 	{
182*993229b6Sjkunz 		ulBlocks = 0;
183*993229b6Sjkunz 		ulRest = 0;
184*993229b6Sjkunz 	}
185*993229b6Sjkunz 
186*993229b6Sjkunz 	for(i = 0; i < ulBlocks; i++)
187*993229b6Sjkunz 	{
188*993229b6Sjkunz 		fread(uData, 1, SHA1_MAX_FILE_BUFFER, fIn);
189*993229b6Sjkunz 		Update((uint8_t *)uData, SHA1_MAX_FILE_BUFFER);
190*993229b6Sjkunz 	}
191*993229b6Sjkunz 
192*993229b6Sjkunz 	if(ulRest != 0)
193*993229b6Sjkunz 	{
194*993229b6Sjkunz 		fread(uData, 1, ulRest, fIn);
195*993229b6Sjkunz 		Update((uint8_t *)uData, ulRest);
196*993229b6Sjkunz 	}
197*993229b6Sjkunz 
198*993229b6Sjkunz 	fclose(fIn); fIn = NULL;
199*993229b6Sjkunz 	return true;
200*993229b6Sjkunz }
201*993229b6Sjkunz #endif
202*993229b6Sjkunz 
Final()203*993229b6Sjkunz void CSHA1::Final()
204*993229b6Sjkunz {
205*993229b6Sjkunz 	uint32_t i;
206*993229b6Sjkunz 	uint8_t finalcount[8];
207*993229b6Sjkunz 
208*993229b6Sjkunz 	for(i = 0; i < 8; i++)
209*993229b6Sjkunz 		finalcount[i] = (uint8_t)((m_count[((i >= 4) ? 0 : 1)]
210*993229b6Sjkunz 			>> ((3 - (i & 3)) * 8) ) & 255); // Endian independent
211*993229b6Sjkunz 
212*993229b6Sjkunz 	Update((uint8_t *)"\200", 1);
213*993229b6Sjkunz 
214*993229b6Sjkunz 	while ((m_count[0] & 504) != 448)
215*993229b6Sjkunz 		Update((uint8_t *)"\0", 1);
216*993229b6Sjkunz 
217*993229b6Sjkunz 	Update(finalcount, 8); // Cause a SHA1Transform()
218*993229b6Sjkunz 
219*993229b6Sjkunz 	for(i = 0; i < 20; i++)
220*993229b6Sjkunz 	{
221*993229b6Sjkunz 		m_digest[i] = (uint8_t)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255);
222*993229b6Sjkunz 	}
223*993229b6Sjkunz 
224*993229b6Sjkunz 	// Wipe variables for security reasons
225*993229b6Sjkunz #ifdef SHA1_WIPE_VARIABLES
226*993229b6Sjkunz 	i = 0;
227*993229b6Sjkunz 	memset(m_buffer, 0, 64);
228*993229b6Sjkunz 	memset(m_state, 0, 20);
229*993229b6Sjkunz 	memset(m_count, 0, 8);
230*993229b6Sjkunz 	memset(finalcount, 0, 8);
231*993229b6Sjkunz 	Transform(m_state, m_buffer);
232*993229b6Sjkunz #endif
233*993229b6Sjkunz }
234*993229b6Sjkunz 
235*993229b6Sjkunz #ifdef SHA1_UTILITY_FUNCTIONS
236*993229b6Sjkunz // Get the final hash as a pre-formatted string
ReportHash(char * szReport,unsigned char uReportType)237*993229b6Sjkunz void CSHA1::ReportHash(char *szReport, unsigned char uReportType)
238*993229b6Sjkunz {
239*993229b6Sjkunz 	unsigned char i;
240*993229b6Sjkunz 	char szTemp[16];
241*993229b6Sjkunz 
242*993229b6Sjkunz 	if(szReport == NULL) return;
243*993229b6Sjkunz 
244*993229b6Sjkunz 	if(uReportType == REPORT_HEX)
245*993229b6Sjkunz 	{
246*993229b6Sjkunz 		sprintf(szTemp, "%02X", m_digest[0]);
247*993229b6Sjkunz 		strcat(szReport, szTemp);
248*993229b6Sjkunz 
249*993229b6Sjkunz 		for(i = 1; i < 20; i++)
250*993229b6Sjkunz 		{
251*993229b6Sjkunz 			sprintf(szTemp, " %02X", m_digest[i]);
252*993229b6Sjkunz 			strcat(szReport, szTemp);
253*993229b6Sjkunz 		}
254*993229b6Sjkunz 	}
255*993229b6Sjkunz 	else if(uReportType == REPORT_DIGIT)
256*993229b6Sjkunz 	{
257*993229b6Sjkunz 		sprintf(szTemp, "%u", m_digest[0]);
258*993229b6Sjkunz 		strcat(szReport, szTemp);
259*993229b6Sjkunz 
260*993229b6Sjkunz 		for(i = 1; i < 20; i++)
261*993229b6Sjkunz 		{
262*993229b6Sjkunz 			sprintf(szTemp, " %u", m_digest[i]);
263*993229b6Sjkunz 			strcat(szReport, szTemp);
264*993229b6Sjkunz 		}
265*993229b6Sjkunz 	}
266*993229b6Sjkunz 	else strcpy(szReport, "Error: Unknown report type!");
267*993229b6Sjkunz }
268*993229b6Sjkunz #endif
269*993229b6Sjkunz 
270*993229b6Sjkunz // Get the raw message digest
GetHash(uint8_t * puDest)271*993229b6Sjkunz void CSHA1::GetHash(uint8_t *puDest)
272*993229b6Sjkunz {
273*993229b6Sjkunz 	memcpy(puDest, m_digest, 20);
274*993229b6Sjkunz }
275