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