mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
345 lines
11 KiB
C
345 lines
11 KiB
C
/*H*******************************************************************/
|
|
/*!
|
|
\File cryptsha1.c
|
|
|
|
\Description
|
|
This module implements SHA1 as defined in RFC 3174.
|
|
|
|
\Notes
|
|
The implementation is based on the algorithm description in sections
|
|
3 through 6 of RFC 3174 and not on the C code in section 7.
|
|
|
|
Currently the code is a straightforward implementation of the
|
|
algorithm, no attempt has been made to optimize it in any way.
|
|
See the notes for individual functions for descriptions of where
|
|
optimizations are possible, but note that what is good for an x86
|
|
with large caches may not be good for a MIPS based PS2 which has
|
|
a much smaller instruction cache.
|
|
|
|
The code deliberately uses some of the naming conventions from
|
|
the RFC to in order to aid comprehension.
|
|
|
|
This implementation is limited to hashing no more than 2^32-9 bytes.
|
|
It will silently produce the wrong result if an attempt is made to
|
|
hash more data.
|
|
|
|
\Copyright
|
|
Copyright (c) Electronic Arts 2004. ALL RIGHTS RESERVED.
|
|
|
|
\Version 1.0 06/06/2004 (sbevan) First Version
|
|
*/
|
|
/*******************************************************************H*/
|
|
|
|
/*** Include files ***************************************************/
|
|
|
|
#include <string.h> /* memcpy */
|
|
|
|
#include "DirtySDK/platform.h"
|
|
#include "DirtySDK/crypt/cryptsha1.h"
|
|
|
|
/*** Defines *********************************************************/
|
|
|
|
// A circular left shift, see RFC 3174 section 3.c
|
|
//
|
|
// gcc understands the two shift idiom and replaces this
|
|
// with single rotate instruction on platforms that have it.
|
|
//
|
|
#define CRYPTSHA1_rol(n, x) (((x)<<(n))|((x)>>(32-(n))))
|
|
|
|
/*** Type Definitions ************************************************/
|
|
|
|
/*** Variables *******************************************************/
|
|
|
|
/*** Private functions ***********************************************/
|
|
|
|
/*F*******************************************************************/
|
|
/*!
|
|
\Function _CryptSha1CopyHash
|
|
|
|
\Description
|
|
Extract the SHA1 hash and copy it to a byte buffer.
|
|
|
|
\Input *pSha1 - SHA1 state
|
|
\Input *pBuffer - where to store the hash
|
|
\Input uLength - how many bytes of the hash to extract
|
|
|
|
\Output None
|
|
|
|
\Version 1.0 06/06/2004 (sbevan) First Version
|
|
*/
|
|
/*******************************************************************F*/
|
|
static void _CryptSha1CopyHash(CryptSha1T *pSha1, void *pBuffer, uint32_t uLength)
|
|
{
|
|
unsigned char *pOutput = pBuffer;
|
|
uint32_t i;
|
|
|
|
if (uLength > CRYPTSHA1_HASHSIZE)
|
|
{
|
|
uLength = CRYPTSHA1_HASHSIZE;
|
|
}
|
|
for (i = 0; i != uLength; i += 1)
|
|
{
|
|
pOutput[i] = pSha1->H[(i/4)]>>((3-(i%4))*8);
|
|
}
|
|
}
|
|
|
|
/*F*******************************************************************/
|
|
/*!
|
|
\Function _CryptSha1ProcessBlock
|
|
|
|
\Description
|
|
SHA1 a 64-byte block of data.
|
|
|
|
\Input *pSha1 - SHA1 state
|
|
\Input *M - start of 64-bytes to be processed
|
|
|
|
\Output None
|
|
|
|
\Notes
|
|
This is a literal translation of Method 1 as described in
|
|
RFC 3174 section 6.1. The variable names deliberately match those
|
|
used in that section in order to aid manual verification of algorithm
|
|
correctness.
|
|
|
|
There is a lot of scope for performance improvements. For example :-
|
|
|
|
a) performing manual loop unrolling and loop fusion.
|
|
An the extreme this could result in a single straight line
|
|
chunk of code that on a register rich machine this could
|
|
result in everything except the input and hash living in
|
|
a register.
|
|
|
|
b) taking advantage of hardware that can perform big-endian (MIPS)
|
|
and/or mis-aligned (x86) loads.
|
|
|
|
OpenSSL does a) but it causes problems for some compilers since
|
|
they don't do a good job of optimizing functions containing 80+
|
|
local variables. GCC should be able to cope but the x86 and
|
|
MIPS assembly would need to be checked to make sure.
|
|
|
|
\Version 1.0 06/06/2004 (sbevan) First Version
|
|
*/
|
|
/*******************************************************************F*/
|
|
static void _CryptSha1ProcessBlock(CryptSha1T *pSha1, const unsigned char *M)
|
|
{
|
|
uint32_t i;
|
|
uint32_t t;
|
|
unsigned A, B, C, D, E;
|
|
uint32_t W[80];
|
|
|
|
// RFC 3174 section 6.1.a, divide input into 16 words (big-endian format)
|
|
for (i = 0; i != 16; i += 1)
|
|
{
|
|
W[i] = (M[i*4]<<24)|(M[i*4+1]<<16)|(M[i*4+2]<<8)|M[i*4+3];
|
|
}
|
|
// RFC 3174 section 6.1.b
|
|
for (t = 16; t != 80; t += 1)
|
|
{
|
|
W[t] = CRYPTSHA1_rol(1, W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
|
|
}
|
|
// RFC 3174 section 6.1.c
|
|
A = pSha1->H[0];
|
|
B = pSha1->H[1];
|
|
C = pSha1->H[2];
|
|
D = pSha1->H[3];
|
|
E = pSha1->H[4];
|
|
|
|
// RFC 3174 section 6.1.d split into 4 groups one for each variation of
|
|
// f as defined in RFC 3174 section 5.
|
|
for (t = 0; t != 20; t += 1)
|
|
{
|
|
uint32_t TEMP = CRYPTSHA1_rol(5, A) + ((B&C)|((~B)&D)) + E + W[t] + 0x5A827999;
|
|
E = D; D = C; C = CRYPTSHA1_rol(30, B); B = A; A = TEMP;
|
|
}
|
|
|
|
for (t = 20; t != 40; t += 1)
|
|
{
|
|
uint32_t TEMP = CRYPTSHA1_rol(5, A) + (B^C^D) + E + W[t] + 0x6ED9EBA1;
|
|
E = D; D = C; C = CRYPTSHA1_rol(30, B); B = A; A = TEMP;
|
|
}
|
|
|
|
for (t = 40; t != 60; t += 1)
|
|
{
|
|
uint32_t TEMP = CRYPTSHA1_rol(5, A) + ((B&C)|(B&D)|(C&D)) + E + W[t] + 0x8F1BBCDC;
|
|
E = D; D = C; C = CRYPTSHA1_rol(30, B); B = A; A = TEMP;
|
|
}
|
|
|
|
for (t = 60; t != 80; t += 1)
|
|
{
|
|
uint32_t TEMP = CRYPTSHA1_rol(5, A) + (B^C^D) + E + W[t] + 0xCA62C1D6;
|
|
E = D; D = C; C = CRYPTSHA1_rol(30, B); B = A; A = TEMP;
|
|
}
|
|
|
|
// Section 6.1.e
|
|
pSha1->H[0] += A;
|
|
pSha1->H[1] += B;
|
|
pSha1->H[2] += C;
|
|
pSha1->H[3] += D;
|
|
pSha1->H[4] += E;
|
|
}
|
|
|
|
|
|
/*** Public functions ************************************************/
|
|
|
|
|
|
/*F*******************************************************************/
|
|
/*!
|
|
\Function CryptSha1Init
|
|
|
|
\Description
|
|
Hash the input and add it to the state
|
|
|
|
\Input *pSha1 - SHA1 state
|
|
|
|
\Output None
|
|
|
|
\Version 1.0 06/06/2004 (sbevan) First Version
|
|
*/
|
|
/*******************************************************************F*/
|
|
void CryptSha1Init(CryptSha1T *pSha1)
|
|
{
|
|
pSha1->uCount = 0;
|
|
pSha1->uPartialCount = 0;
|
|
// All the constants come from RFC 3174 section 6.1
|
|
pSha1->H[0] = 0x67452301;
|
|
pSha1->H[1] = 0xEFCDAB89;
|
|
pSha1->H[2] = 0x98BADCFE;
|
|
pSha1->H[3] = 0x10325476;
|
|
pSha1->H[4] = 0xC3D2E1F0;
|
|
}
|
|
|
|
/*F*******************************************************************/
|
|
/*!
|
|
\Function CryptSha1Init2
|
|
|
|
\Description
|
|
Hash the input and add it to the state (alternate form)
|
|
|
|
\Input *pSha1 - SHA1 state
|
|
\Input iHashSize - hash size (unused)
|
|
|
|
\Version 11/05/2013 (jbrookes)
|
|
*/
|
|
/*******************************************************************F*/
|
|
void CryptSha1Init2(CryptSha1T *pSha1, int32_t iHashSize)
|
|
{
|
|
CryptSha1Init(pSha1);
|
|
}
|
|
|
|
/*F*******************************************************************/
|
|
/*!
|
|
\Function CryptSha1Update
|
|
|
|
\Description
|
|
Hash the input and add it to the state
|
|
|
|
\Input *pSha1 - SHA1 state
|
|
\Input *pInput - the input
|
|
\Input uInputLen - length of input in bytes
|
|
|
|
\Output None
|
|
|
|
\Version 1.0 06/06/2004 (sbevan) First Version
|
|
*/
|
|
/*******************************************************************F*/
|
|
void CryptSha1Update(CryptSha1T *pSha1, const unsigned char *pInput, uint32_t uInputLen)
|
|
{
|
|
if (pSha1->uPartialCount != 0)
|
|
{
|
|
uint32_t uWant = sizeof(pSha1->strData) - pSha1->uPartialCount;
|
|
uint32_t uHave = uWant > uInputLen ? uInputLen : uWant;
|
|
ds_memcpy(&pSha1->strData[pSha1->uPartialCount], pInput, uHave);
|
|
pInput += uHave;
|
|
uInputLen -= uHave;
|
|
if (uHave == uWant)
|
|
{
|
|
_CryptSha1ProcessBlock(pSha1, pSha1->strData);
|
|
pSha1->uCount += sizeof(pSha1->strData);
|
|
pSha1->uPartialCount = 0;
|
|
}
|
|
else
|
|
{
|
|
pSha1->uPartialCount += uHave;
|
|
}
|
|
}
|
|
while (uInputLen >= sizeof(pSha1->strData))
|
|
{
|
|
_CryptSha1ProcessBlock(pSha1, pInput);
|
|
pSha1->uCount += sizeof(pSha1->strData);
|
|
uInputLen -= sizeof(pSha1->strData);
|
|
pInput += sizeof(pSha1->strData);
|
|
}
|
|
if (uInputLen != 0)
|
|
{
|
|
ds_memcpy(&pSha1->strData[pSha1->uPartialCount], pInput, uInputLen);
|
|
pSha1->uPartialCount += uInputLen;
|
|
}
|
|
}
|
|
|
|
/*F*******************************************************************/
|
|
/*!
|
|
\Function CryptSha1Final
|
|
|
|
\Description
|
|
Generate the final hash from the SHA1 state
|
|
|
|
\Input *pSha1 - the SHA1 state
|
|
\Input *pBuffer - where the hash should be written
|
|
\Input uLength - the number of bytes to write, [0..CRYPTSHA1_HASHSIZE]
|
|
|
|
\Output none
|
|
|
|
\Notes
|
|
Usually callers want the whole hash and so uOutputLen would be
|
|
CRYPTSHA1_HASHSIZE. However, if only a partial hash is needed then
|
|
any value up to CRYPTSHA1_HASHSIZE can be used. Any value
|
|
greater than CRYPTSHA1_HASHSIZE is silently truncated to
|
|
CRYPTSHA1_HASHSIZE.
|
|
|
|
CryptSha1Final is not idempotent. It could easily be made so but
|
|
callers typically tend not to need it so it is not supported.
|
|
|
|
\Version 1.0 06/06/2004 (sbevan) First Version
|
|
*/
|
|
/*******************************************************************F*/
|
|
void CryptSha1Final(CryptSha1T *pSha1, void *pBuffer, uint32_t uLength)
|
|
{
|
|
uint32_t i;
|
|
uint8_t uPad = 0x80;
|
|
uint32_t uSpace = sizeof(pSha1->strData) - pSha1->uPartialCount;
|
|
|
|
pSha1->uCount += pSha1->uPartialCount;
|
|
if (uSpace < 9)
|
|
{
|
|
pSha1->strData[pSha1->uPartialCount] = uPad;
|
|
for (i = pSha1->uPartialCount+1; i < sizeof(pSha1->strData); i += 1)
|
|
{
|
|
pSha1->strData[i] = 0x0;
|
|
}
|
|
_CryptSha1ProcessBlock(pSha1, pSha1->strData);
|
|
uPad = 0x0;
|
|
pSha1->uPartialCount = 0;
|
|
}
|
|
pSha1->strData[pSha1->uPartialCount] = uPad;
|
|
for (i = pSha1->uPartialCount+1; i < sizeof(pSha1->strData)-8; i += 1)
|
|
{
|
|
pSha1->strData[i] = 0x0;
|
|
}
|
|
|
|
/* Append length in bits, as per RFC 3174 section 4.c except we only
|
|
support a 32-bit byte length / 35-bit bit length. Uses some
|
|
bit shifting to avoid having to explicitly calculate
|
|
pSha1->uCount*8 which could overflow 32-bits. */
|
|
pSha1->strData[56] = 0;
|
|
pSha1->strData[57] = 0;
|
|
pSha1->strData[58] = 0;
|
|
pSha1->strData[59] = (pSha1->uCount>>(32-3))&0xFF;
|
|
pSha1->strData[60] = (pSha1->uCount>>(24-3))&0xFF;
|
|
pSha1->strData[61] = (pSha1->uCount>>(16-3))&0xFF;
|
|
pSha1->strData[62] = (pSha1->uCount>>(8-3))&0xFF;
|
|
pSha1->strData[63] = (pSha1->uCount<<3)&0xFF;
|
|
_CryptSha1ProcessBlock(pSha1, pSha1->strData);
|
|
|
|
_CryptSha1CopyHash(pSha1, pBuffer, uLength);
|
|
}
|