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