1 /*---------------------------------------------------------------------------*
2   Project:  NitroSDK - CRYPTO - demos
3   File:     main.c
4 
5   Copyright 2005-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   Demo of attack-proof encryption using the CRYPTO library RC4 algorithm
19 
20   This uses a PRNG to get a random initial vector (IV), different every time, and safely encrypt with the RC4 algorithm.
21 
22  *---------------------------------------------------------------------------*/
23 
24 #include <nitro.h>
25 #include <nitro/crypto.h>
26 
27 #include "prng.h"
28 #include "rc4enc.h"
29 
30 #define TEST_BUFFER_SIZE 256
31 
32 static void InitializeAllocateSystem(void);
33 static void VBlankIntr(void);
34 static void DisplayInit(void);
35 static void PRNGInit(void);
36 static void FillScreen(u16 col);
37 static BOOL RC4EncText(void);
38 static BOOL CompareBinary(void* ptr1, void* ptr2, u32 n);
39 static u32 GetStringLength(char* str);
40 static void PrintBinary(u8* ptr, u32 len);
41 
42 /*---------------------------------------------------------------------------*
43     Variable Definitions
44  *---------------------------------------------------------------------------*/
45 
46 /*---------------------------------------------------------------------------*
47     Function Definitions
48  *---------------------------------------------------------------------------*/
49 
50 /*---------------------------------------------------------------------------*
51   Name:         NitroMain
52 
53   Description:  Initialization and main loop.
54 
55   Arguments:    None.
56 
57   Returns:      None.
58  *---------------------------------------------------------------------------*/
NitroMain(void)59 void NitroMain(void)
60 {
61     // Various types of initialization
62     OS_Init();
63     OS_InitTick();
64     InitializeAllocateSystem();
65 
66     DisplayInit();
67 
68     PRNGInit();
69 
70     if (RC4EncText())
71     {
72         // Success
73         OS_TPrintf("------ Test Succeeded ------\n");
74         FillScreen(GX_RGB(0, 31, 0));
75     }
76     else
77     {
78         // Failed
79         OS_TPrintf("****** Test Failed ******\n");
80         FillScreen(GX_RGB(31, 0, 0));
81     }
82 
83     // Main loop
84     while (TRUE)
85     {
86         // Waiting for the V-Blank
87         OS_WaitVBlankIntr();
88     }
89 }
90 
91 /*---------------------------------------------------------------------------*
92   Name:         VBlankIntr
93 
94   Description:  V-Blank interrupt vector.
95 
96   Arguments:    None.
97 
98   Returns:      None.
99  *---------------------------------------------------------------------------*/
VBlankIntr(void)100 static void VBlankIntr(void)
101 {
102     // The internal state of the PRNG is churned by the current system status.
103     // It is periodically churned to improve security because initialization with PRNGInit() only is insufficient.
104     //
105     // Be sure to call this function periodically as calling it just once does not provide sufficient churning.
106     ChurnRandomPool();
107 
108     // Sets the IRQ check flag
109     OS_SetIrqCheckFlag(OS_IE_V_BLANK);
110 }
111 
112 /*---------------------------------------------------------------------------*
113   Name:         InitializeAllocateSystem
114 
115   Description:  Initializes the memory allocation system within the main memory arena.
116 
117   Arguments:    None.
118 
119   Returns:      None.
120  *---------------------------------------------------------------------------*/
InitializeAllocateSystem(void)121 static void InitializeAllocateSystem(void)
122 {
123     void *tempLo;
124     OSHeapHandle hh;
125 
126     tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
127     OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
128     hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
129     if (hh < 0)
130     {
131         OS_Panic("ARM9: Fail to create heap...\n");
132     }
133     hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
134 }
135 
136 /*---------------------------------------------------------------------------*
137   Name:         DisplayInit
138 
139   Description:  Graphics initialization.
140 
141   Arguments:    None.
142 
143   Returns:      None.
144  *---------------------------------------------------------------------------*/
DisplayInit(void)145 static void DisplayInit(void)
146 {
147 
148     GX_Init();
149     FX_Init();
150 
151     GX_DispOff();
152     GXS_DispOff();
153 
154     GX_SetDispSelect(GX_DISP_SELECT_SUB_MAIN);
155 
156     OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
157     (void)OS_EnableIrqMask(OS_IE_V_BLANK);
158     (void)GX_VBlankIntr(TRUE);         // To generate V-Blank interrupt request
159     (void)OS_EnableIrq();
160 
161 
162     GX_SetBankForLCDC(GX_VRAM_LCDC_ALL);
163     MI_CpuClearFast((void *)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE);
164 
165     MI_CpuFillFast((void *)HW_OAM, 192, HW_OAM_SIZE);   // Clear OAM
166     MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE);     // Clear the standard palette
167 
168     MI_CpuFillFast((void *)HW_DB_OAM, 192, HW_DB_OAM_SIZE);     // Clear OAM
169     MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE);       // Clear the standard palette
170     MI_DmaFill32(3, (void *)HW_LCDC_VRAM_C, 0x7FFF7FFF, 256 * 192 * sizeof(u16));
171 
172 
173     GX_SetBankForOBJ(GX_VRAM_OBJ_256_AB);       // Set VRAM-A,B for OBJ
174 
175     GX_SetGraphicsMode(GX_DISPMODE_VRAM_C,      // VRAM mode
176                        (GXBGMode)0,    // Dummy
177                        (GXBG0As)0);    // Dummy
178 
179     GX_SetVisiblePlane(GX_PLANEMASK_OBJ);       // Make OBJs visible
180     GX_SetOBJVRamModeBmp(GX_OBJVRAMMODE_BMP_1D_128K);   // 2D mapping OBJ
181 
182     OS_WaitVBlankIntr();              // Waiting for the end of the V-Blank interrupt
183     GX_DispOn();
184 
185 }
186 
187 /*---------------------------------------------------------------------------*
188   Name:         PRNGInit
189 
190   Description:  Initializes the pseudorandom number generator.
191 
192   Arguments:    None.
193 
194   Returns:      None.
195  *---------------------------------------------------------------------------*/
PRNGInit(void)196 static void PRNGInit(void)
197 {
198     int i;
199     for ( i = 0; i < 10; i++ )
200     {
201         ChurnRandomPool();
202         OS_WaitVBlankIntr();
203     }
204     // You must continue to call ChurnRandomPool() periodically because calling it several times will not collect enough entropy.
205     //
206 
207     // If greater security is required, you could call the AddRandomSeed function with several kilobytes of microphone input data as an argument to initialize the PRNG.
208     //
209     //
210 }
211 
212 /*---------------------------------------------------------------------------*
213   Name:         FillScreen
214 
215   Description:  Fills the screen.
216 
217   Arguments:    col: FillColor
218 
219   Returns:      None.
220  *---------------------------------------------------------------------------*/
FillScreen(u16 col)221 static void FillScreen(u16 col)
222 {
223     MI_CpuFill16((void *)HW_LCDC_VRAM_C, col, 256 * 192 * 2);
224 }
225 
226 /*---------------------------------------------------------------------------*
227   Name:         RC4EncText
228 
229   Description:  RC4 algorithm test routine.
230 
231   Arguments:    None.
232 
233   Returns:      TRUE if test succeeds.
234  *---------------------------------------------------------------------------*/
235 #define PrintResultEq( a, b, f ) \
236     { OS_TPrintf( ((a) == (b)) ? "[--OK--] " : "[**NG**] " ); (f) = (f) && ((a) == (b)); }
237 #define PrintResultBinaryEq( a, b, l, f ) \
238     { OS_TPrintf( (CompareBinary((a), (b), (l))) ? "[--OK--] " : "[**NG**] " ); (f) = (f) && (CompareBinary((a), (b), (l))); }
239 
RC4EncText(void)240 static BOOL RC4EncText(void)
241 {
242     int i;
243     int testcase = 1;
244     BOOL flag = TRUE;
245 
246     // Encode and decode using RC4Enc and check that the results match
247     {
248         char* d[] = {
249             "\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67\x89\xab\xcd\xef",
250             "Copyright 2006 Nintendo.  All rights reserved.",
251         };
252         char* key[] = {
253             "\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67",
254             "Nintendo DS.",
255         };
256 
257         for (i = 0; i < sizeof(d) / sizeof(char*); i++)
258         {
259             RC4EncoderContext enc_context;
260             RC4DecoderContext dec_context;
261             u8 result[TEST_BUFFER_SIZE];
262             u8 result2[TEST_BUFFER_SIZE];
263             u32 len;
264             u32 encoded_len;
265             u32 decoded_len;
266 
267             InitRC4Encoder(&enc_context, key[i]);
268             len = GetStringLength(d[i]);
269             encoded_len = EncodeRC4(&enc_context, d[i], len, result, sizeof(result));
270 
271             PrintResultEq(encoded_len, len + RC4ENC_ADDITIONAL_SIZE, flag);
272             OS_TPrintf("RC4Enc: Test Case %d: encryption phase: length check\n", testcase);
273 
274             PrintBinary(result, encoded_len);
275             OS_TPrintf("\n");
276 
277             InitRC4Decoder(&dec_context, key[i]);
278             decoded_len = DecodeRC4(&dec_context, result, encoded_len, result2, sizeof(result2));
279 
280             PrintResultEq(decoded_len, len, flag);
281             OS_TPrintf("RC4Enc: Test Case %d: decryption phase: length check\n", testcase);
282 
283             PrintResultBinaryEq(d[i], result2, len, flag);
284             OS_TPrintf("RC4Enc: Test Case %d: decryption phase: binary comparing\n", testcase);
285 
286             testcase++;
287         }
288     }
289 
290     {
291         char* d = "abcdefghijklmnopqrstuvwxyz";
292         char* key = "123456789012";
293         u8 result[TEST_BUFFER_SIZE];
294         u8 result2[TEST_BUFFER_SIZE];
295         u8 result_backup[TEST_BUFFER_SIZE];
296         u32 len;
297         u32 encoded_len;
298         u32 decoded_len;
299         RC4EncoderContext enc_context;
300         RC4DecoderContext dec_context;
301 
302         // Check the buffer size used during encoding
303 
304         InitRC4Encoder(&enc_context, key);
305         len = GetStringLength(d);
306 
307         encoded_len = EncodeRC4(&enc_context, d, len, result, 0);
308         PrintResultEq(encoded_len, 0, flag);
309         OS_TPrintf("RC4Enc: Test Case %d\n", testcase++);
310 
311         encoded_len = EncodeRC4(&enc_context, d, len, result, 1);
312         PrintResultEq(encoded_len, 0, flag);
313         OS_TPrintf("RC4Enc: Test Case %d\n", testcase++);
314 
315         encoded_len = EncodeRC4(&enc_context, d, len, result, len + RC4ENC_ADDITIONAL_SIZE - 1);
316         PrintResultEq(encoded_len, 0, flag);
317         OS_TPrintf("RC4Enc: Test Case %d\n", testcase++);
318 
319         encoded_len = EncodeRC4(&enc_context, d, len, result, len + RC4ENC_ADDITIONAL_SIZE);
320         PrintResultEq(encoded_len, len + RC4ENC_ADDITIONAL_SIZE, flag);
321         OS_TPrintf("RC4Enc: Test Case %d\n", testcase++);
322 
323         // Check the buffer size used during decoding
324 
325         InitRC4Decoder(&dec_context, key);
326 
327         decoded_len = DecodeRC4(&dec_context, result, encoded_len, result2, 0);
328         PrintResultEq(decoded_len, 0, flag);
329         OS_TPrintf("RC4Enc: Test Case %d\n", testcase++);
330 
331         decoded_len = DecodeRC4(&dec_context, result, encoded_len, result2, 1);
332         PrintResultEq(decoded_len, 0, flag);
333         OS_TPrintf("RC4Enc: Test Case %d\n", testcase++);
334 
335         decoded_len = DecodeRC4(&dec_context, result, encoded_len, result2, len - 1);
336         PrintResultEq(decoded_len, 0, flag);
337         OS_TPrintf("RC4Enc: Test Case %d\n", testcase++);
338 
339         decoded_len = DecodeRC4(&dec_context, result, encoded_len, result2, len);
340         PrintResultEq(decoded_len, len, flag);
341         OS_TPrintf("RC4Enc: Test Case %d\n", testcase++);
342 
343         // If part of the following encoded data is changed, check whether an error occurs when decoding
344         //
345 
346         // Create a backup of encoded data
347         MI_CpuCopy8(result, result_backup, encoded_len);
348 
349         result[0] ^= 1;
350         decoded_len = DecodeRC4(&dec_context, result, encoded_len, result2, len);
351         PrintResultEq(decoded_len, 0, flag);
352         OS_TPrintf("RC4Enc: Test Case %d\n", testcase++);
353 
354         MI_CpuCopy8(result_backup, result, encoded_len); // Restore from backup
355 
356         result[3] ^= 0xff;
357         decoded_len = DecodeRC4(&dec_context, result, encoded_len, result2, len);
358         PrintResultEq(decoded_len, 0, flag);
359         OS_TPrintf("RC4Enc: Test Case %d\n", testcase++);
360 
361         MI_CpuCopy8(result_backup, result, encoded_len); // Restore from backup
362 
363         result[4] ^= 1;
364         decoded_len = DecodeRC4(&dec_context, result, encoded_len, result2, len);
365         PrintResultEq(decoded_len, 0, flag);
366         OS_TPrintf("RC4Enc: Test Case %d\n", testcase++);
367 
368         MI_CpuCopy8(result_backup, result, encoded_len); // Restore from backup
369 
370         result[4+len] ^= 0x55;
371         decoded_len = DecodeRC4(&dec_context, result, encoded_len, result2, len);
372         PrintResultEq(decoded_len, 0, flag);
373         OS_TPrintf("RC4Enc: Test Case %d\n", testcase++);
374 
375         MI_CpuCopy8(result_backup, result, encoded_len); // Restore from backup
376 
377         result[encoded_len-1] ^= 0x80;
378         decoded_len = DecodeRC4(&dec_context, result, encoded_len, result2, len);
379         PrintResultEq(decoded_len, 0, flag);
380         OS_TPrintf("RC4Enc: Test Case %d\n", testcase++);
381     }
382 
383 
384 
385 
386 
387     return flag;
388 }
389 
390 
391 /*---------------------------------------------------------------------------*
392   Name:         CompareBinary
393 
394   Description:  Compares memory contents.
395 
396   Arguments:    ptr1, ptr2: Memory locations to compare
397                 n: Length to compar
398 
399   Returns:      If they match, TRUE.
400  *---------------------------------------------------------------------------*/
CompareBinary(void * ptr1,void * ptr2,u32 n)401 static BOOL CompareBinary(void* ptr1, void* ptr2, u32 n)
402 {
403     u32 i;
404     u8* p1 = (u8*)ptr1;
405     u8* p2 = (u8*)ptr2;
406 
407     for (i = 0; i < n; i++)
408     {
409         if (*(p1++) != *(p2++))
410         {
411             return FALSE;
412         }
413     }
414     return TRUE;
415 }
416 
417 /*---------------------------------------------------------------------------*
418   Name:         GetStringLength
419 
420   Description:  Gets the length of a string.
421 
422   Arguments:    str: Pointer to a string
423 
424   Returns:      Length of string
425  *---------------------------------------------------------------------------*/
GetStringLength(char * str)426 static u32 GetStringLength(char* str)
427 {
428     u32 i;
429     for (i = 0; ; i++)
430     {
431         if (*(str++) == '\0')
432         {
433             return i;
434         }
435     }
436 }
437 
438 /*---------------------------------------------------------------------------*
439   Name:         PrintBinary
440 
441   Description:  Binary array output.
442 
443   Arguments:    ptr: Memory location to be output
444                 len: Output length
445 
446   Returns:      None.
447  *---------------------------------------------------------------------------*/
PrintBinary(u8 * ptr,u32 len)448 static void PrintBinary(u8* ptr, u32 len)
449 {
450 #ifndef SDK_FINALROM
451     u32 i;
452     for (i = 0; i < len; i++)
453     {
454         if (i != 0)
455         {
456             OS_PutString(", ");
457         }
458         OS_TPrintf("0x%02x", ptr[i]);
459     }
460 #else
461 #pragma unused(ptr,len)
462 #endif
463     return;
464 }
465 
466 /*---------------------------------------------------------------------------*
467   End of file
468  *---------------------------------------------------------------------------*/
469