Merge branch '138-toggle-free-look-with-hotkey' into 'main/atys-live'
[ryzomcore.git] / nel / src / misc / sha1.cpp
blobd7085283a8aa07a0f6b447bb732efeb1c223a803
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 // Includes
24 #include "stdmisc.h"
26 #include "nel/misc/sha1.h"
27 #include "nel/misc/file.h"
28 #include "nel/misc/path.h"
31 // Namespaces
34 using namespace std;
35 using namespace NLMISC;
37 #ifdef DEBUG_NEW
38 #define new DEBUG_NEW
39 #endif
41 namespace NLMISC {
44 // Constantes
47 static const int bufferSize = 100000;
48 static uint8 buffer[bufferSize];
50 #define SHA1HashSize 20
53 // Types
57 * This structure will hold context information for the SHA-1
58 * hashing operation
60 typedef struct SHA1Context
62 uint32 Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
64 uint32 Length_Low; /* Message length in bits */
65 uint32 Length_High; /* Message length in bits */
67 /* Index into message block array */
68 sint16 Message_Block_Index;
69 uint8 Message_Block[64]; /* 512-bit message blocks */
71 int Computed; /* Is the digest computed? */
72 int Corrupted; /* Is the message digest corrupted? */
73 } SHA1Context;
75 enum
77 shaSuccess = 0,
78 shaNull, /* Null pointer parameter */
79 shaInputTooLong, /* input data too long */
80 shaStateError /* called Input after Result */
84 // Function Prototypes
87 int SHA1Reset (SHA1Context *);
88 int SHA1Input (SHA1Context *, const uint8 *, unsigned int);
89 int SHA1Result (SHA1Context *, uint8 Message_Digest[SHA1HashSize]);
92 // Functions
95 CHashKey getSHA1(const uint8 *buffer, uint32 size)
97 SHA1Context sha;
98 int err;
99 uint8 Message_Digest[20];
101 err = SHA1Reset(&sha);
102 if (err)
104 nlwarning("SHA: SHA1Reset Error %d.\n", err );
105 return CHashKey();
108 err = SHA1Input(&sha, (const uint8*)buffer, size);
109 if (err)
111 nlwarning ("SHA: SHA1Input Error %d.\n", err);
112 return CHashKey();
115 err = SHA1Result(&sha, Message_Digest);
116 if (err)
118 nlwarning("SHA: SHA1Result Error %d, could not compute message digest.\n", err );
119 return CHashKey();
122 CHashKey hk (Message_Digest);
123 return hk;
126 CHashKey getSHA1(const string &filename, bool forcePath)
128 SHA1Context sha;
129 int err;
130 uint8 Message_Digest[20];
132 //printf("reading '%s'\n", findData.cFileName);
133 CIFile ifile;
134 ifile.setCacheFileOnOpen(true);
135 if (!ifile.open(forcePath ? filename:CPath::lookup(filename)))
137 nlwarning ("SHA: Can't open the file '%s'", filename.c_str());
138 return CHashKey();
141 //FILE *fp = nlfopen (filename, "rb");
142 //if (fp == NULL) return CHashKey();
144 err = SHA1Reset(&sha);
145 if (err)
147 nlwarning("SHA: SHA1Reset Error %d.\n", err );
148 ifile.close ();
149 return CHashKey();
152 sint fs = ifile.getFileSize();
153 sint n, read = 0;
156 //bs = (int)fread (buffer, 1, bufferSize, fp);
157 n = std::min (bufferSize, fs-read);
158 //nlinfo ("read %d bytes", n);
159 ifile.serialBuffer((uint8 *)buffer, n);
161 err = SHA1Input(&sha, buffer, n);
162 if (err)
164 nlwarning ("SHA: SHA1Input Error %d.\n", err);
165 ifile.close();
166 return CHashKey();
168 read += n;
170 while (!ifile.eof());
172 ifile.close ();
174 err = SHA1Result(&sha, Message_Digest);
175 if (err)
177 nlwarning("SHA: SHA1Result Error %d, could not compute message digest.\n", err );
178 return CHashKey();
181 CHashKey hk (Message_Digest);
182 return hk;
187 * HMAC = hash( (Key ^ 0x5c) .. hash( (Key ^0x36) .. Message ) )
191 CHashKey getHMacSHA1(const uint8 *text, uint32 text_len, const uint8 *key, uint32 key_len)
193 SHA1Context sha;
195 uint8 SHA1_Key[64];
196 uint8 SHA1_Key1[20];
197 uint8 SHA1_Key2[20];
199 string buffer1;
200 string buffer2;
202 // Init some vars
203 for (uint i = 0; i < 64; i++)
204 SHA1_Key[i] = 0;
206 // If lenght of key > 64 use sha1 hash
207 if (key_len > 64) {
208 uint8 SHA1_Key0[20];
209 SHA1Reset(&sha);
210 SHA1Input(&sha, (const uint8*)key, key_len);
211 SHA1Result(&sha, SHA1_Key0);
212 CHashKey hk0 (SHA1_Key0);
213 for (uint i = 0; i < 20; i++)
214 SHA1_Key[i] = hk0.HashKeyString[i];
215 } else {
216 for (uint i = 0; i < key_len; i++)
217 SHA1_Key[i] = key[i];
220 // Do 0x36 XOR Key
221 for (uint i = 0; i < 64; i++)
222 buffer1 += 0x36 ^ SHA1_Key[i];
224 // Append text
225 for (uint i = 0; i < text_len; i++)
226 buffer1 += text[i];
228 // Get hash
229 SHA1Reset(&sha);
230 SHA1Input(&sha, (const uint8*)buffer1.c_str(), (uint)buffer1.size());
231 SHA1Result(&sha, SHA1_Key1);
232 CHashKey hk1 (SHA1_Key1);
234 // Do 0x5c XOR Key
235 for (uint i = 0; i < 64; i++)
236 buffer2 += 0x5c ^ SHA1_Key[i];
238 // Append previous hash
239 for (uint i = 0; i < 20; i++)
240 buffer2 += hk1.HashKeyString[i];
242 // Get new hash
243 SHA1Reset(&sha);
244 SHA1Input(&sha, (const uint8*)buffer2.c_str(), (uint)buffer2.size());
245 SHA1Result(&sha, SHA1_Key2);
246 CHashKey hk (SHA1_Key2);
248 return hk;
252 #ifdef _MFC_VER
253 #pragma runtime_checks( "", off )
254 #endif
257 * Define the SHA1 circular left shift macro
259 #define SHA1CircularShift(bits,word) \
260 (((word) << (bits)) | ((word) >> (32-(bits))))
262 /* Local Function Prototypes */
263 void SHA1PadMessage(SHA1Context *);
264 void SHA1ProcessMessageBlock(SHA1Context *);
267 * SHA1Reset
269 * Description:
270 * This function will initialize the SHA1Context in preparation
271 * for computing a new SHA1 message digest.
273 * Parameters:
274 * context: [in/out]
275 * The context to reset.
277 * Returns:
278 * sha Error Code.
281 int SHA1Reset(SHA1Context *context)
283 if (!context)
285 return shaNull;
288 context->Length_Low = 0;
289 context->Length_High = 0;
290 context->Message_Block_Index = 0;
292 context->Intermediate_Hash[0] = 0x67452301;
293 context->Intermediate_Hash[1] = 0xEFCDAB89;
294 context->Intermediate_Hash[2] = 0x98BADCFE;
295 context->Intermediate_Hash[3] = 0x10325476;
296 context->Intermediate_Hash[4] = 0xC3D2E1F0;
298 context->Computed = 0;
299 context->Corrupted = 0;
301 return shaSuccess;
305 * SHA1Result
307 * Description:
308 * This function will return the 160-bit message digest into the
309 * Message_Digest array provided by the caller.
310 * NOTE: The first octet of hash is stored in the 0th element,
311 * the last octet of hash in the 19th element.
313 * Parameters:
314 * context: [in/out]
315 * The context to use to calculate the SHA-1 hash.
316 * Message_Digest: [out]
317 * Where the digest is returned.
319 * Returns:
320 * sha Error Code.
323 int SHA1Result( SHA1Context *context,
324 uint8 Message_Digest[SHA1HashSize])
326 int i;
328 if (!context || !Message_Digest)
330 return shaNull;
333 if (context->Corrupted)
335 return context->Corrupted;
338 if (!context->Computed)
340 SHA1PadMessage(context);
341 for(i=0; i<64; ++i)
343 /* message may be sensitive, clear it out */
344 context->Message_Block[i] = 0;
346 context->Length_Low = 0; /* and clear length */
347 context->Length_High = 0;
348 context->Computed = 1;
352 for(i = 0; i < SHA1HashSize; ++i)
354 Message_Digest[i] = uint8((context->Intermediate_Hash[i>>2]
355 >> 8 * ( 3 - ( i & 0x03 ) ) ) & 0xff );
358 return shaSuccess;
362 * SHA1Input
364 * Description:
365 * This function accepts an array of octets as the next portion
366 * of the message.
368 * Parameters:
369 * context: [in/out]
370 * The SHA context to update
371 * message_array: [in]
372 * An array of characters representing the next portion of
373 * the message.
374 * length: [in]
375 * The length of the message in message_array
377 * Returns:
378 * sha Error Code.
381 int SHA1Input( SHA1Context *context,
382 const uint8 *message_array,
383 unsigned length)
385 if (!length)
387 return shaSuccess;
390 if (!context || !message_array)
392 return shaNull;
395 if (context->Computed)
397 context->Corrupted = shaStateError;
399 return shaStateError;
402 if (context->Corrupted)
404 return context->Corrupted;
406 while(length-- && !context->Corrupted)
408 context->Message_Block[context->Message_Block_Index++] =
409 (*message_array & 0xFF);
411 context->Length_Low += 8;
412 if (context->Length_Low == 0)
414 context->Length_High++;
415 if (context->Length_High == 0)
417 /* Message is too long */
418 context->Corrupted = 1;
422 if (context->Message_Block_Index == 64)
424 SHA1ProcessMessageBlock(context);
427 message_array++;
430 return shaSuccess;
434 * SHA1ProcessMessageBlock
436 * Description:
437 * This function will process the next 512 bits of the message
438 * stored in the Message_Block array.
440 * Parameters:
441 * None.
443 * Returns:
444 * Nothing.
446 * Comments:
448 * Many of the variable names in this code, especially the
449 * single character names, were used because those were the
450 * names used in the publication.
454 void SHA1ProcessMessageBlock(SHA1Context *context)
456 const uint32 K[] = { /* Constants defined in SHA-1 */
457 0x5A827999,
458 0x6ED9EBA1,
459 0x8F1BBCDC,
460 0xCA62C1D6
462 int t; /* Loop counter */
463 uint32 temp; /* Temporary word value */
464 uint32 W[80]; /* Word sequence */
465 uint32 A, B, C, D, E; /* Word buffers */
468 * Initialize the first 16 words in the array W
470 for(t = 0; t < 16; t++)
472 W[t] = context->Message_Block[t * 4] << 24;
473 W[t] |= context->Message_Block[t * 4 + 1] << 16;
474 W[t] |= context->Message_Block[t * 4 + 2] << 8;
475 W[t] |= context->Message_Block[t * 4 + 3];
478 for(t = 16; t < 80; t++)
480 W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
483 A = context->Intermediate_Hash[0];
484 B = context->Intermediate_Hash[1];
485 C = context->Intermediate_Hash[2];
486 D = context->Intermediate_Hash[3];
487 E = context->Intermediate_Hash[4];
489 for(t = 0; t < 20; t++)
491 temp = SHA1CircularShift(5,A) +
492 ((B & C) | ((~B) & D)) + E + W[t] + K[0];
493 E = D;
494 D = C;
495 C = SHA1CircularShift(30,B);
497 B = A;
498 A = temp;
501 for(t = 20; t < 40; t++)
503 temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
504 E = D;
505 D = C;
506 C = SHA1CircularShift(30,B);
507 B = A;
508 A = temp;
511 for(t = 40; t < 60; t++)
513 temp = SHA1CircularShift(5,A) +
514 ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
515 E = D;
516 D = C;
517 C = SHA1CircularShift(30,B);
518 B = A;
519 A = temp;
522 for(t = 60; t < 80; t++)
524 temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
525 E = D;
526 D = C;
527 C = SHA1CircularShift(30,B);
528 B = A;
529 A = temp;
532 context->Intermediate_Hash[0] += A;
533 context->Intermediate_Hash[1] += B;
534 context->Intermediate_Hash[2] += C;
535 context->Intermediate_Hash[3] += D;
536 context->Intermediate_Hash[4] += E;
538 context->Message_Block_Index = 0;
542 * SHA1PadMessage
545 * Description:
546 * According to the standard, the message must be padded to an even
547 * 512 bits. The first padding bit must be a '1'. The last 64
548 * bits represent the length of the original message. All bits in
549 * between should be 0. This function will pad the message
550 * according to those rules by filling the Message_Block array
551 * accordingly. It will also call the ProcessMessageBlock function
552 * provided appropriately. When it returns, it can be assumed that
553 * the message digest has been computed.
555 * Parameters:
556 * context: [in/out]
557 * The context to pad
558 * ProcessMessageBlock: [in]
559 * The appropriate SHA*ProcessMessageBlock function
560 * Returns:
561 * Nothing.
565 void SHA1PadMessage(SHA1Context *context)
568 * Check to see if the current message block is too small to hold
569 * the initial padding bits and length. If so, we will pad the
570 * block, process it, and then continue padding into a second
571 * block.
573 if (context->Message_Block_Index > 55)
575 context->Message_Block[context->Message_Block_Index++] = 0x80;
576 while(context->Message_Block_Index < 64)
578 context->Message_Block[context->Message_Block_Index++] = 0;
581 SHA1ProcessMessageBlock(context);
583 while(context->Message_Block_Index < 56)
585 context->Message_Block[context->Message_Block_Index++] = 0;
588 else
590 context->Message_Block[context->Message_Block_Index++] = 0x80;
591 while(context->Message_Block_Index < 56)
594 context->Message_Block[context->Message_Block_Index++] = 0;
599 * Store the message length as the last 8 octets
601 context->Message_Block[56] = uint8((context->Length_High >> 24)&0xff);
602 context->Message_Block[57] = uint8((context->Length_High >> 16)&0xff);
603 context->Message_Block[58] = uint8((context->Length_High >> 8)&0xff);
604 context->Message_Block[59] = uint8((context->Length_High)&0xff);
605 context->Message_Block[60] = uint8((context->Length_Low >> 24)&0xff);
606 context->Message_Block[61] = uint8((context->Length_Low >> 16)&0xff);
607 context->Message_Block[62] = uint8((context->Length_Low >> 8)&0xff);
608 context->Message_Block[63] = uint8((context->Length_Low)&0xff);
610 SHA1ProcessMessageBlock(context);