1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - MATH - libraries
3   File:     dgt.h
4 
5   Copyright 2003-2008 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2008-09-17#$
14   $Rev: 8556 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 
18 #include <nitro/mi/memory.h>
19 #include <nitro/math/dgt.h>
20 #include "hmac.h"
21 
22 #ifdef  SDK_WIN32
23 #include <string.h>
24 #define MI_CpuCopy8(_x_, _y_, _z_)  memcpy(_y_, _x_, _z_)
25 #define MI_CpuFill8                 memset
26 #endif
27 
28 //
29 // Calculate SHA1 digest
30 //
31 
32 
33 /*
34  * If giving priority to stack conservation rather than execution speed, make this option valid.
35  * Specifically, this affects the following locations.
36  *   - Increase/decrease the local variable's 256 bytes used by the MATHi_SHA1ProcessBlock function
37  */
38 #define MATH_SHA1_SMALL_STACK
39 
40 /*
41  * To try using BSAFE SHA1, make this option valid.
42  */
43 //#define MATH_SHA1_BSAFE_TEST
44 
45 // Internal Function Declarations
46 #if !defined(MATH_SHA1_ASM)
47 static void MATHi_SHA1ProcessBlock(MATHSHA1Context *context);
48 #else
49 extern void MATHi_SHA1ProcessBlock(MATHSHA1Context *context);
50 #endif
51 static void MATHi_SHA1ProcessBlockForOverlay(MATHSHA1Context *context);
52 static void MATHi_SHA1Fill(MATHSHA1Context* context, u8 input, u32 length);
53 
54 
55 // Static Variables
56 static int MATHi_OverlayTableMode = 0;
57 static void (*MATHi_SHA1ProcessMessageBlockFunc)(MATHSHA1Context*) = MATHi_SHA1ProcessBlock;
58 
59 
60 
61 // Internal Function Definitions
62 
63 #if defined(PLATFORM_ENDIAN_LITTLE)
64 #define NETConvert32HToBE        NETSwapBytes32
65 #else
66 #define NETConvert32HToBE(val)   (val)
67 #endif
68 
NETSwapBytes32(u32 val)69 inline static u32 NETSwapBytes32( u32 val )
70 {
71     return (u32)( (((val) >> 24UL) & 0x000000FFUL) |
72                   (((val) >>  8UL) & 0x0000FF00UL) |
73                   (((val) <<  8UL) & 0x00FF0000UL) |
74                   (((val) << 24UL) & 0xFF000000UL) );
75 }
76 
NETRotateLeft32(int shift,u32 value)77 inline static u32 NETRotateLeft32(int shift, u32 value)
78 {
79     return (u32)((value << shift) | (value >> (u32)(32 - shift)));
80 }
81 
82 #if !defined(MATH_SHA1_ASM)
83 /*---------------------------------------------------------------------------*
84   Name:         MATHi_SHA1ProcessBlock
85 
86   Description:  Calculate hash using 1 block that expired in the SHA-1 context.
87 
88   Arguments:    context:   MATHSHA1Context structure
89 
90   Returns:      None.
91  *---------------------------------------------------------------------------*/
MATHi_SHA1ProcessBlock(MATHSHA1Context * context)92 static void MATHi_SHA1ProcessBlock(MATHSHA1Context *context)
93 {
94     u32     a = context->h[0];
95     u32     b = context->h[1];
96     u32     c = context->h[2];
97     u32     d = context->h[3];
98     u32     e = context->h[4];
99 #if defined(MATH_SHA1_SMALL_STACK)
100     u32     w[16];
101 #define w_alias(t)  w[(t) & 15]
102 #define w_update(t)                         \
103         if (t >= 16)                        \
104         {                                   \
105             w_alias(t) = NETRotateLeft32(1, \
106                 w_alias(t - 16 +  0) ^      \
107                 w_alias(t - 16 +  2) ^      \
108                 w_alias(t - 16 +  8) ^      \
109                 w_alias(t - 16 + 13));      \
110         }(void)0
111 
112 #else
113     u32     w[80];
114 #define w_alias(t)  w[t]
115 #define w_update(t) (void)0
116 #endif /* defined(MATH_SHA1_SMALL_STACK) */
117 
118     int     t;
119 	u32     tmp;
120     for (t = 0; t < 16; ++t)
121     {
122         w[t] = NETConvert32HToBE(((u32*)context->block)[t]);
123     }
124 #if !defined(MATH_SHA1_SMALL_STACK)
125     for (; t < 80; ++t)
126     {
127         u32    *prev = &w[t - 16];
128         w[t] = NETRotateLeft32(1, prev[ 0] ^ prev[ 2] ^ prev[ 8] ^ prev[13]);
129     }
130 #endif /* !defined(MATH_SHA1_SMALL_STACK) */
131     for (t = 0; t < 20; ++t)
132     {
133         tmp = 0x5A827999UL + ((b & c) | (~b & d));
134         w_update(t);
135         tmp += w_alias(t) + NETRotateLeft32(5, a) + e;
136         e = d;
137         d = c;
138         c = NETRotateLeft32(30, b);
139         b = a;
140         a = tmp;
141     }
142     for (; t < 40; ++t)
143     {
144         tmp = 0x6ED9EBA1UL + (b ^ c ^ d);
145         w_update(t);
146         tmp += w_alias(t) + NETRotateLeft32(5, a) + e;
147         e = d;
148         d = c;
149         c = NETRotateLeft32(30, b);
150         b = a;
151         a = tmp;
152     }
153     for (; t < 60; ++t)
154     {
155         tmp = 0x8F1BBCDCUL + ((b & c) | (b & d) | (c & d));
156         w_update(t);
157         tmp += w_alias(t) + NETRotateLeft32(5, a) + e;
158         e = d;
159         d = c;
160         c = NETRotateLeft32(30, b);
161         b = a;
162         a = tmp;
163     }
164     for (; t < 80; ++t)
165     {
166         tmp = 0xCA62C1D6UL + (b ^ c ^ d);
167         w_update(t);
168         tmp += w_alias(t) + NETRotateLeft32(5, a) + e;
169         e = d;
170         d = c;
171         c = NETRotateLeft32(30, b);
172         b = a;
173         a = tmp;
174     }
175     context->h[0] += a;
176     context->h[1] += b;
177     context->h[2] += c;
178     context->h[3] += d;
179     context->h[4] += e;
180 }
181 #endif /* !defined(MATH_SHA1_ASM) */
182 
183 
184 // Set the portion calculated from the end to 0 when finding the hash value with the overlay table
185 // Each entry size of the overlay table is a multiple of 64 so processing here is OK
MATHi_SHA1ProcessBlockForOverlay(MATHSHA1Context * context)186 static void MATHi_SHA1ProcessBlockForOverlay(MATHSHA1Context *context)
187 {
188     u32 s0, s1;
189     u32 *block = (u32*)context->block;
190 
191     // Save and clear file_id in OverlayTable
192     s0 = block[6];      // 6   = location of file_id
193     s1 = block[6+8];    // 6+8 = location of next file_id
194     block[6]   = 0;
195     block[6+8] = 0;
196 
197     MATHi_SHA1ProcessBlock(context);
198 
199     // Restore file_id
200     block[6]   = s0;
201     block[6+8] = s1;
202 }
203 
MATHi_SHA1Fill(MATHSHA1Context * context,u8 input,u32 length)204 static void MATHi_SHA1Fill(MATHSHA1Context* context, u8 input, u32 length)
205 {
206     while (length > 0)
207     {
208         /* Fill data to the block margins */
209         u32     rest = MATH_SHA1_BLOCK_SIZE - context->pool;
210         if (rest > length)
211         {
212             rest = length;
213         }
214         MI_CpuFill8(&context->block[context->pool], input, rest);
215         length -= rest;
216         context->pool += rest;
217         /* Execute the hash calculation if the block has expired. */
218         if (context->pool >= MATH_SHA1_BLOCK_SIZE)
219         {
220             MATHi_SHA1ProcessMessageBlockFunc(context);
221             context->pool = 0;
222             ++context->blocks_low;
223             if (!context->blocks_low)
224             {
225                 ++context->blocks_high;
226             }
227         }
228     }
229 }
230 
MATHi_SetOverlayTableMode(int flag)231 int MATHi_SetOverlayTableMode( int flag )
232 {
233     int prev = MATHi_OverlayTableMode;
234 
235     MATHi_OverlayTableMode = flag;
236 
237     if (MATHi_OverlayTableMode)
238     {
239         MATHi_SHA1ProcessMessageBlockFunc = MATHi_SHA1ProcessBlockForOverlay;
240     }
241     else
242     {
243         MATHi_SHA1ProcessMessageBlockFunc = MATHi_SHA1ProcessBlock;
244     }
245 
246     return prev;
247 }
248 
249 /*---------------------------------------------------------------------------*
250   Name:         MATH_SHA1Init
251 
252   Description:  Initializes the MATHSHA1Context structure used for requesting the SHA1 value.
253 
254   Arguments:    context:   MATHSHA1Context structure
255 
256   Returns:      None.
257  *---------------------------------------------------------------------------*/
MATH_SHA1Init(MATHSHA1Context * context)258 void MATH_SHA1Init(MATHSHA1Context* context)
259 {
260     context->blocks_low = 0;
261     context->blocks_high = 0;
262     context->pool = 0;
263     context->h[0] = 0x67452301;
264     context->h[1] = 0xEFCDAB89;
265     context->h[2] = 0x98BADCFE;
266     context->h[3] = 0x10325476;
267     context->h[4] = 0xC3D2E1F0;
268 }
269 
270 /*---------------------------------------------------------------------------*
271   Name:         MATH_SHA1Update
272 
273   Description:  Updates the SHA1 value with given data.
274 
275   Arguments:    context:   MATHSHA1Context structure
276                 input:   Pointer to input data.
277                 length:  Length of input data.
278 
279   Returns:      None.
280  *---------------------------------------------------------------------------*/
MATH_SHA1Update(MATHSHA1Context * context,const void * input,u32 length)281 void MATH_SHA1Update(MATHSHA1Context* context, const void* input, u32 length)
282 {
283     while (length > 0)
284     {
285         /* Fill data to the block margins */
286         u32     rest = MATH_SHA1_BLOCK_SIZE - context->pool;
287         if (rest > length)
288         {
289             rest = length;
290         }
291         MI_CpuCopy8(input, &context->block[context->pool], rest);
292         input = (const u8 *)input + rest;
293         length -= rest;
294         context->pool += rest;
295         /* Execute the hash calculation if the block has expired. */
296         if (context->pool >= MATH_SHA1_BLOCK_SIZE)
297         {
298             MATHi_SHA1ProcessMessageBlockFunc(context);
299             context->pool = 0;
300             ++context->blocks_low;
301             if (!context->blocks_low)
302             {
303                 ++context->blocks_high;
304             }
305         }
306     }
307 }
308 
309 /*---------------------------------------------------------------------------*
310   Name:         MATH_SHA1GetHash
311 
312   Description:  Gets the final SHA1 value.
313 
314   Arguments:    context:   MATHSHA1Context structure
315                 digest:   Pointer to the location where the SHA1 value is stored.
316 
317   Returns:      None.
318  *---------------------------------------------------------------------------*/
MATH_SHA1GetHash(MATHSHA1Context * context,void * digest)319 void MATH_SHA1GetHash(MATHSHA1Context *context, void *digest)
320 {
321     u32    footer[2];
322     static const u8 padlead[1] = { 0x80 };
323     static const u8 padalign[sizeof(footer)] = { 0x00, };
324     /* Set up footer field (in bits, big endian)*/
325     footer[1] = NETConvert32HToBE((u32)
326         (context->blocks_low << (6 + 3)) + (context->pool << (0 + 3)));
327     footer[0] = NETConvert32HToBE((u32)
328         (context->blocks_high << (6 + 3)) + (context->blocks_low >> (u32)(32 - (6 + 3))));
329     /* Add leading padbyte '0x80'*/
330     MATH_SHA1Update(context, padlead, sizeof(padlead));
331     /* If necessary, add 2 padblocks*/
332     if (MATH_SHA1_BLOCK_SIZE - context->pool < sizeof(footer))
333     {
334         MATH_SHA1Update(context, padalign, MATH_SHA1_BLOCK_SIZE - context->pool);
335     }
336     /* Add trailing padbytes '0x00'*/
337     MATHi_SHA1Fill(context, 0x00, MATH_SHA1_BLOCK_SIZE - context->pool - sizeof(footer));
338     /* Add footer length*/
339     MATH_SHA1Update(context, footer, sizeof(footer));
340     /* Copy registers to the dst*/
341     context->h[0] = NETConvert32HToBE((u32)context->h[0]);
342     context->h[1] = NETConvert32HToBE((u32)context->h[1]);
343     context->h[2] = NETConvert32HToBE((u32)context->h[2]);
344     context->h[3] = NETConvert32HToBE((u32)context->h[3]);
345     context->h[4] = NETConvert32HToBE((u32)context->h[4]);
346     MI_CpuCopy8(context->h, digest, sizeof(context->h));
347 }
348 
349 #if defined(MATH_SHA1_BSAFE_TEST)
350 extern unsigned char *SHA1(const unsigned char *d, unsigned long n, unsigned char *md);
351 #endif
352 /*---------------------------------------------------------------------------*
353   Name:         MATH_CalcSHA1
354 
355   Description:  Calculates SHA-1.
356 
357   Arguments:    digest:   Pointer to the location where SHA-1 is stored.
358                 data:    Pointer to input data.
359                 dataLength:   Length of input data.
360 
361   Returns:      None.
362  *---------------------------------------------------------------------------*/
MATH_CalcSHA1(void * digest,const void * data,u32 dataLength)363 void MATH_CalcSHA1(void *digest, const void *data, u32 dataLength)
364 {
365 #if !defined(MATH_SHA1_BSAFE_TEST)
366     MATHSHA1Context context;
367     MATH_SHA1Init(&context);
368     MATH_SHA1Update(&context, data, dataLength);
369     MATH_SHA1GetHash(&context, digest);
370 #else
371 	SHA1((unsigned char*)data, dataLength, (unsigned char*)digest);
372 #endif
373 }
374 
375 
376 
377 // HMAC
378 
379 /*---------------------------------------------------------------------------*
380   Name:         MATH_CalcHMACSHA1
381 
382   Description:  Calculates HMAC-SHA-1.
383 
384   Arguments:    digest:   Pointer to the location where the HMAC-SHA-1 value is stored.
385                 data:    Pointer to input data.
386                 dataLength:   Length of input data.
387                 key:    Pointer to the key
388                 keyLength:   Length of the key
389 
390   Returns:      None.
391  *---------------------------------------------------------------------------*/
MATH_CalcHMACSHA1(void * digest,const void * bin_ptr,u32 bin_len,const void * key_ptr,u32 key_len)392 void MATH_CalcHMACSHA1(void *digest, const void *bin_ptr, u32 bin_len, const void *key_ptr, u32 key_len)
393 {
394     MATHSHA1Context context;
395     unsigned char   hash_buf[ MATH_SHA1_DIGEST_SIZE ]; /* Hash value gotten from the hash function */
396 
397     MATHiHMACFuncs hash2funcs = {
398         MATH_SHA1_DIGEST_SIZE,
399         (512/8),
400     };
401 
402     hash2funcs.context       = &context;
403     hash2funcs.hash_buf      = hash_buf;
404     hash2funcs.HashReset     = (void (*)(void*))                   MATH_SHA1Init;
405     hash2funcs.HashSetSource = (void (*)(void*, const void*, u32)) MATH_SHA1Update;
406     hash2funcs.HashGetDigest = (void (*)(void*, void*))            MATH_SHA1GetHash;
407 
408     MATHi_CalcHMAC(digest, bin_ptr, bin_len, key_ptr, key_len, &hash2funcs);
409 }
410