1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
26 #include "nel/misc/sha1.h"
27 #include "nel/misc/file.h"
28 #include "nel/misc/path.h"
35 using namespace NLMISC
;
47 static const int bufferSize
= 100000;
48 static uint8 buffer
[bufferSize
];
50 #define SHA1HashSize 20
57 * This structure will hold context information for the SHA-1
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? */
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
]);
95 CHashKey
getSHA1(const uint8
*buffer
, uint32 size
)
99 uint8 Message_Digest
[20];
101 err
= SHA1Reset(&sha
);
104 nlwarning("SHA: SHA1Reset Error %d.\n", err
);
108 err
= SHA1Input(&sha
, (const uint8
*)buffer
, size
);
111 nlwarning ("SHA: SHA1Input Error %d.\n", err
);
115 err
= SHA1Result(&sha
, Message_Digest
);
118 nlwarning("SHA: SHA1Result Error %d, could not compute message digest.\n", err
);
122 CHashKey
hk (Message_Digest
);
126 CHashKey
getSHA1(const string
&filename
, bool forcePath
)
130 uint8 Message_Digest
[20];
132 //printf("reading '%s'\n", findData.cFileName);
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());
141 //FILE *fp = nlfopen (filename, "rb");
142 //if (fp == NULL) return CHashKey();
144 err
= SHA1Reset(&sha
);
147 nlwarning("SHA: SHA1Reset Error %d.\n", err
);
152 sint fs
= ifile
.getFileSize();
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
);
164 nlwarning ("SHA: SHA1Input Error %d.\n", err
);
170 while (!ifile
.eof());
174 err
= SHA1Result(&sha
, Message_Digest
);
177 nlwarning("SHA: SHA1Result Error %d, could not compute message digest.\n", err
);
181 CHashKey
hk (Message_Digest
);
187 * HMAC = hash( (Key ^ 0x5c) .. hash( (Key ^0x36) .. Message ) )
191 CHashKey
getHMacSHA1(const uint8
*text
, uint32 text_len
, const uint8
*key
, uint32 key_len
)
203 for (uint i
= 0; i
< 64; i
++)
206 // If lenght of key > 64 use sha1 hash
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
];
216 for (uint i
= 0; i
< key_len
; i
++)
217 SHA1_Key
[i
] = key
[i
];
221 for (uint i
= 0; i
< 64; i
++)
222 buffer1
+= 0x36 ^ SHA1_Key
[i
];
225 for (uint i
= 0; i
< text_len
; i
++)
230 SHA1Input(&sha
, (const uint8
*)buffer1
.c_str(), (uint
)buffer1
.size());
231 SHA1Result(&sha
, SHA1_Key1
);
232 CHashKey
hk1 (SHA1_Key1
);
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
];
244 SHA1Input(&sha
, (const uint8
*)buffer2
.c_str(), (uint
)buffer2
.size());
245 SHA1Result(&sha
, SHA1_Key2
);
246 CHashKey
hk (SHA1_Key2
);
253 #pragma runtime_checks( "", off )
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
*);
270 * This function will initialize the SHA1Context in preparation
271 * for computing a new SHA1 message digest.
275 * The context to reset.
281 int SHA1Reset(SHA1Context
*context
)
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;
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.
315 * The context to use to calculate the SHA-1 hash.
316 * Message_Digest: [out]
317 * Where the digest is returned.
323 int SHA1Result( SHA1Context
*context
,
324 uint8 Message_Digest
[SHA1HashSize
])
328 if (!context
|| !Message_Digest
)
333 if (context
->Corrupted
)
335 return context
->Corrupted
;
338 if (!context
->Computed
)
340 SHA1PadMessage(context
);
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 );
365 * This function accepts an array of octets as the next portion
370 * The SHA context to update
371 * message_array: [in]
372 * An array of characters representing the next portion of
375 * The length of the message in message_array
381 int SHA1Input( SHA1Context
*context
,
382 const uint8
*message_array
,
390 if (!context
|| !message_array
)
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
);
434 * SHA1ProcessMessageBlock
437 * This function will process the next 512 bits of the message
438 * stored in the Message_Block array.
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 */
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];
495 C
= SHA1CircularShift(30,B
);
501 for(t
= 20; t
< 40; t
++)
503 temp
= SHA1CircularShift(5,A
) + (B
^ C
^ D
) + E
+ W
[t
] + K
[1];
506 C
= SHA1CircularShift(30,B
);
511 for(t
= 40; t
< 60; t
++)
513 temp
= SHA1CircularShift(5,A
) +
514 ((B
& C
) | (B
& D
) | (C
& D
)) + E
+ W
[t
] + K
[2];
517 C
= SHA1CircularShift(30,B
);
522 for(t
= 60; t
< 80; t
++)
524 temp
= SHA1CircularShift(5,A
) + (B
^ C
^ D
) + E
+ W
[t
] + K
[3];
527 C
= SHA1CircularShift(30,B
);
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;
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.
558 * ProcessMessageBlock: [in]
559 * The appropriate SHA*ProcessMessageBlock function
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
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;
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
);