1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - aes - demos - ctr-compatible
3 File: main.c
4
5 Copyright 2007-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:: 2009-09-24#$
14 $Rev: 11063 $
15 $Author: okubata_ryoma $
16 *---------------------------------------------------------------------------*/
17 #include <twl.h>
18 #include "DEMO.h"
19 #include <twl/aes.h>
20
21
22 /*---------------------------------------------------------------------------*
23 Internal variable declarations
24 *---------------------------------------------------------------------------*/
25
26 /*---------------------------------------------------------------------------*
27 Internal function declarations
28 *---------------------------------------------------------------------------*/
29
30 static void DEMO_InitInteruptSystem(void);
31 static void DEMO_InitAllocSystem(void);
32 static void DEMO_InitFileSystem(void);
33 static void DEMO_AESCallback(AESResult result, void* arg);
34 static AESResult DEMO_WaitAes(OSMessageQueue* pQ);
35 static void DEMO_PrintText(const void* pvoid, u32 size);
36 static void DEMO_PrintBytes(const void* pvoid, u32 size);
37 static void* DEMO_LoadFile(u32* pSize, const char* path);
38
39 static AESResult DEMO_CtrCompatible(
40 const AESKey* pKey,
41 AESCounter* pCounter,
42 void* src,
43 u32 srcSize,
44 void* dst );
45
46
47
48 /*---------------------------------------------------------------------------*
49 Function definitions
50 *---------------------------------------------------------------------------*/
51
52 /*---------------------------------------------------------------------------*
53 Name: SampleMain
54
55 Description: The main body of the sample.
56
57 Arguments: None.
58
59 Returns: Whether sample processing succeeded.
60 *---------------------------------------------------------------------------*/
SampleMain(void)61 static BOOL SampleMain(void)
62 {
63 BOOL bSuccess = FALSE;
64 AESResult aesResult;
65
66 // The first AES function called must be AES_Init.
67 AES_Init();
68
69 // CTR Mode Encryption
70 {
71 void* pPlaintext;
72 void* pEncrypted;
73 void* pKey;
74 void* pCounter;
75 u32 srcSize;
76
77 // Load the data needed for encryption.
78 // In this sample, the initial counter value is loaded from a file so data can be compared with data encrypted on a PC, but ordinarily you must not use a fixed value for the initial counter value.
79 //
80 //
81 pKey = DEMO_LoadFile(NULL, "key.bin");
82 pCounter = DEMO_LoadFile(NULL, "counter.bin");
83 pPlaintext = DEMO_LoadFile(&srcSize, "sample16.txt");
84
85 // Allocate the buffer to store encrypted data.
86 // Data size doesn't change with encryption.
87 pEncrypted = OS_Alloc(srcSize);
88
89 if( ! SDK_IS_VALID_POINTER(pEncrypted) )
90 {
91 OS_TPrintf("fail to OS_Alloc\n");
92 return FALSE;
93 }
94
95
96 // Display parameters
97 OS_TPrintf("== CTR encrypt ==========================\n");
98 OS_TPrintf("---- parameter -----------\n");
99 OS_TPrintf("-- key\n");
100 DEMO_PrintBytes(pKey, sizeof(AESKey));
101 OS_TPrintf("-- counter initial value\n");
102 DEMO_PrintBytes(pCounter, sizeof(AESCounter));
103
104 OS_TPrintf("---- encrypt -------------\n");
105 OS_TPrintf("-- plaintext (ascii)\n");
106 DEMO_PrintText(pPlaintext, srcSize);
107 OS_TPrintf("-- plaintext (hex)\n");
108 DEMO_PrintBytes(pPlaintext, srcSize);
109
110
111 // Perform encryption that is compatible with the general-purpose AES libraries
112 aesResult = DEMO_CtrCompatible(
113 pKey, // Key
114 pCounter, // Initial counter value
115 pPlaintext, // Data to be encrypted
116 srcSize, // Size of the data to encrypt
117 pEncrypted ); // Buffer that stores encrypted data
118 if( aesResult != AES_RESULT_SUCCESS )
119 {
120 OS_TPrintf("DEMO_CtrCompatible failed(%d)\n", aesResult);
121 OS_Free(pEncrypted);
122 OS_Free(pPlaintext);
123 OS_Free(pCounter);
124 OS_Free(pKey);
125 return FALSE;
126 }
127
128
129 // Display results
130 OS_TPrintf("-- encrypted (hex)\n");
131 DEMO_PrintBytes(pEncrypted, srcSize);
132
133 // Confirm that the data matches data encrypted on the PC
134 {
135 void* pEncryptedOnPC;
136 u32 size;
137
138 pEncryptedOnPC = DEMO_LoadFile(&size, "encrypted.bin");
139
140 if( (srcSize == size) && MI_CpuComp8(pEncrypted, pEncryptedOnPC, size) == 0 )
141 {
142 OS_TPrintf("** pEncrypted == pEncryptedOnPC\n");
143 }
144 else
145 {
146 OS_TPrintf("** pEncrypted != pEncryptedOnPC\n");
147 }
148
149 OS_Free(pEncryptedOnPC);
150 }
151
152 OS_Free(pEncrypted);
153 OS_Free(pPlaintext);
154 OS_Free(pCounter);
155 OS_Free(pKey);
156 }
157
158 // CTR Mode Decryption
159 {
160 void* pEncrypted;
161 void* pDecrypted;
162 void* pKey;
163 void* pCounter;
164 u32 srcSize;
165
166 // Load data encrypted on a PC.
167 // In the sample, both the key and the ciphertext are in ROM, but they should normally not both be obtainable via the same method.
168 //
169 pKey = DEMO_LoadFile(NULL, "key.bin");
170 pCounter = DEMO_LoadFile(NULL, "counter.bin");
171 pEncrypted = DEMO_LoadFile(&srcSize, "encrypted.bin");
172
173 // Allocate the buffer to store decrypted data
174 // Data size doesn't change with decryption.
175 pDecrypted = OS_Alloc(srcSize);
176
177 if( ! SDK_IS_VALID_POINTER(pDecrypted) )
178 {
179 OS_TPrintf("fail to OS_Alloc\n");
180 return FALSE;
181 }
182
183
184 // Display parameters
185 OS_TPrintf("== CTR decrypt ==========================\n");
186 OS_TPrintf("---- parameter -----------\n");
187 OS_TPrintf("-- key\n");
188 DEMO_PrintBytes(pKey, sizeof(AESKey));
189 OS_TPrintf("-- counter initial value\n");
190 DEMO_PrintBytes(pCounter, sizeof(AESCounter));
191
192 OS_TPrintf("---- decrypt -------------\n");
193 OS_TPrintf("-- encrypted (hex)\n");
194 DEMO_PrintBytes(pEncrypted, srcSize);
195
196
197 // Performs decryption that is compatible with general-purpose AES libraries
198 aesResult = DEMO_CtrCompatible(
199 pKey, // Key (must be the same as that used during encryption)
200 pCounter, // Initial counter value (must be the same as that used during encryption)
201 pEncrypted, // Data to be decrypted
202 srcSize, // Size of the data to decrypt
203 pDecrypted ); // Buffer that stores decrypted data
204 if( aesResult != AES_RESULT_SUCCESS )
205 {
206 OS_TPrintf("DEMO_CtrCompatible failed(%d)\n", aesResult);
207 OS_Free(pDecrypted);
208 OS_Free(pEncrypted);
209 OS_Free(pCounter);
210 OS_Free(pKey);
211 return FALSE;
212 }
213
214
215 // Display results
216 OS_TPrintf("-- decrypted (hex)\n");
217 DEMO_PrintBytes(pDecrypted, srcSize);
218
219 OS_TPrintf("-- decrypted (ascii)\n");
220 DEMO_PrintText(pDecrypted, srcSize);
221 OS_TPrintf("\n");
222
223 // Confirm that it matches the original
224 {
225 void* pOriginal;
226 u32 size;
227
228 pOriginal = DEMO_LoadFile(&size, "sample16.txt");
229
230 if( (srcSize == size) && MI_CpuComp8(pDecrypted, pOriginal, size) == 0 )
231 {
232 OS_TPrintf("** pDecrypted == pOriginal\n");
233 bSuccess = TRUE;
234 }
235 else
236 {
237 OS_TPrintf("** pDecrypted != pOriginal\n");
238 }
239
240 OS_Free(pOriginal);
241 }
242
243
244 OS_Free(pDecrypted);
245 OS_Free(pEncrypted);
246 OS_Free(pCounter);
247 OS_Free(pKey);
248 }
249
250 return bSuccess;
251 }
252
253
254 /*---------------------------------------------------------------------------*
255 Name: TwlMain
256
257 Description: The main function.
258
259 Arguments: None.
260
261 Returns: None.
262 *---------------------------------------------------------------------------*/
TwlMain(void)263 void TwlMain(void)
264 {
265 BOOL bSampleSucceeded = FALSE;
266
267 // Initialization
268 OS_Init();
269 DEMO_InitInteruptSystem();
270 DEMO_InitAllocSystem();
271 DEMO_InitFileSystem();
272 OS_TPrintf("*** start aes demo\n");
273
274 // When in NITRO mode, stopped by Panic
275 DEMOCheckRunOnTWL();
276 // Run demo
277 bSampleSucceeded = SampleMain();
278
279 // Display demo run results
280 OS_TPrintf("*** End of demo\n");
281 OS_TPrintf("demo %s\n", (bSampleSucceeded ? "succeeded": "failed"));
282 GX_Init();
283 *(GXRgb*)HW_BG_PLTT = (GXRgb)(bSampleSucceeded ? GX_RGB(0, 31, 0): GX_RGB(31, 0, 0));
284 GX_DispOn();
285 OS_Terminate();
286 }
287
288
289
290 /*---------------------------------------------------------------------------*
291 Name: DEMO_CtrCompatible
292
293 Description: There is no compatibility for output results between those of the TWL-SDK AES library and those of general AES libraries.
294 This function uses appropriate processing before and after AES processes to perform encryption/decryption compatible with general AES libraries.
295 However, there is a limitation compared to AES_Ctr: srcSize must be a multiple of AES_BLOCK_SIZE (=16).
296
297
298
299
300
301 Arguments: pKey: Key to use
302 pCounter: Initial counter value to use
303 src: Pointer to either the plaintext or the ciphertext
304 The pointer must be 4-byte aligned.
305 srcSize: Size of the plaintext or ciphertext.
306 Must be a multiple of 16.
307 dst: Pointer to the buffer where the plaintext or ciphertext is written out.
308
309 The pointer must be 4-byte aligned.
310
311 Returns: Returns the processing result.
312 *---------------------------------------------------------------------------*/
DEMO_CtrCompatible(const AESKey * pKey,AESCounter * pCounter,void * src,u32 srcSize,void * dst)313 static AESResult DEMO_CtrCompatible(
314 const AESKey* pKey,
315 AESCounter* pCounter,
316 void* src,
317 u32 srcSize,
318 void* dst )
319 {
320 AESKey key;
321
322 // Switch the byte order of all input
323 {
324 AES_ReverseBytes(pKey, &key, sizeof(key));
325 AES_ReverseBytes(pCounter, pCounter, sizeof(*pCounter));
326 AES_SwapEndianEach128(src, src, srcSize);
327 }
328
329 // AES processing
330 {
331 OSMessageQueue msgQ;
332 OSMessage msgQBuffer[1];
333 AESResult aesResult;
334
335 OS_InitMessageQueue(&msgQ, msgQBuffer, sizeof(msgQBuffer)/sizeof(*msgQBuffer));
336
337 aesResult = AES_SetKey(&key);
338 if( aesResult != AES_RESULT_SUCCESS )
339 {
340 return aesResult;
341 }
342
343 aesResult = AES_Ctr( pCounter,
344 src,
345 srcSize,
346 dst,
347 DEMO_AESCallback,
348 &msgQ );
349 if( aesResult != AES_RESULT_SUCCESS )
350 {
351 return aesResult;
352 }
353
354 aesResult = DEMO_WaitAes(&msgQ);
355 if( aesResult != AES_RESULT_SUCCESS )
356 {
357 return aesResult;
358 }
359 }
360
361 // Switch the output byte order, too
362 {
363 AES_SwapEndianEach128(dst, dst, srcSize);
364 }
365
366 return AES_RESULT_SUCCESS;
367 }
368
369
370 /*---------------------------------------------------------------------------*
371 Name: DEMO_LoadFile
372
373 Description: Allocates memory and loads a file.
374
375 Arguments: pSize: Pointer to the buffer that stores the size of the file that was loaded.
376 Specify NULL when size is unnecessary.
377 path: Path of the file to load
378
379 Returns: Returns a pointer to the buffer where the file content is stored.
380 This buffer must be deallocated with the OS_Free function when it is no longer needed.
381 Returns NULL if it failed to load.
382 *---------------------------------------------------------------------------*/
DEMO_LoadFile(u32 * pSize,const char * path)383 static void* DEMO_LoadFile(u32* pSize, const char* path)
384 {
385 BOOL bSuccess;
386 FSFile f;
387 u32 fileSize;
388 s32 readSize;
389 void* pBuffer;
390
391 FS_InitFile(&f);
392
393 bSuccess = FS_OpenFileEx(&f, path, FS_FILEMODE_R);
394 if( ! bSuccess )
395 {
396 OS_Warning("fail to FS_OpenFileEx(%s)\n", path);
397 return NULL;
398 }
399
400 fileSize = FS_GetFileLength(&f);
401 pBuffer = OS_Alloc(fileSize + 1);
402 if( pBuffer == NULL )
403 {
404 (void)FS_CloseFile(&f);
405 OS_Warning("fail to OS_Alloc(%d)\n", fileSize + 1);
406 return NULL;
407 }
408
409 readSize = FS_ReadFile(&f, pBuffer, (s32)fileSize);
410 if( readSize != fileSize )
411 {
412 OS_Free(pBuffer);
413 (void)FS_CloseFile(&f);
414 OS_Warning("fail to FS_ReadFile(%d)\n", fileSize + 1);
415 return NULL;
416 }
417
418 bSuccess = FS_CloseFile(&f);
419 SDK_ASSERT( bSuccess );
420
421 ((char*)pBuffer)[fileSize] = '\0';
422
423 if( pSize != NULL )
424 {
425 *pSize = fileSize;
426 }
427
428 return pBuffer;
429 }
430
431 /*---------------------------------------------------------------------------*
432 Name: DEMO_AESCallback
433
434 Description: This is the callback called at AES processing completion.
435 It is of type AESCallback.
436
437 Arguments: result: AES processing result.
438 arg: Last argument passed in AES_Ctr
439
440 Returns: None.
441 *---------------------------------------------------------------------------*/
DEMO_AESCallback(AESResult result,void * arg)442 static void DEMO_AESCallback(AESResult result, void* arg)
443 {
444 OSMessageQueue* pQ = (OSMessageQueue*)arg;
445 (void)OS_SendMessage(pQ, (OSMessage)result, OS_MESSAGE_BLOCK);
446 }
447
448 /*---------------------------------------------------------------------------*
449 Name: DEMO_WaitAes
450
451 Description: Waits for AES processing completion and returns results.
452 DEMO_AESCallback must have been specified in AES_Ctr.
453
454 Arguments: pQ: Message queue passed as the last AES_Ctr argument
455
456 Returns: AES processing result.
457 *---------------------------------------------------------------------------*/
DEMO_WaitAes(OSMessageQueue * pQ)458 static AESResult DEMO_WaitAes(OSMessageQueue* pQ)
459 {
460 OSMessage msg;
461 (void)OS_ReceiveMessage(pQ, &msg, OS_MESSAGE_BLOCK);
462 return (AESResult)msg;
463 }
464
465 /*---------------------------------------------------------------------------*
466 Name: DEMO_PrintText
467
468 Description: Prints a string of specified length to debug output.
469
470 Arguments: pvoid: Target string
471 size: Target string byte count
472
473 Returns: None.
474 *---------------------------------------------------------------------------*/
DEMO_PrintText(const void * pvoid,u32 size)475 static void DEMO_PrintText(const void* pvoid, u32 size)
476 {
477 static const u32 TMP_BUFFER_LEN = 128 - 1;
478 char tmp_buffer[TMP_BUFFER_LEN + 1];
479 const u8* p = (const u8*)pvoid;
480
481 while( size >= TMP_BUFFER_LEN )
482 {
483 MI_CpuCopy8(p, tmp_buffer, TMP_BUFFER_LEN);
484 tmp_buffer[TMP_BUFFER_LEN] = '\0';
485 OS_PutString(tmp_buffer);
486
487 size -= TMP_BUFFER_LEN;
488 p += TMP_BUFFER_LEN;
489 }
490
491 if( size > 0 )
492 {
493 MI_CpuCopy8(p, tmp_buffer, size);
494 tmp_buffer[size] = '\0';
495 OS_PutString(tmp_buffer);
496 }
497 }
498
499 /*---------------------------------------------------------------------------*
500 Name: DEMO_PrintBytes
501
502 Description: Outputs the specified binary array in hexadecimal to debug output.
503
504 Arguments: pvoid: Pointer to the target binary array.
505 size: Number of bytes in the target binary array.
506
507 Returns: None.
508 *---------------------------------------------------------------------------*/
DEMO_PrintBytes(const void * pvoid,u32 size)509 static void DEMO_PrintBytes(const void* pvoid, u32 size)
510 {
511 const u8* p = (const u8*)pvoid;
512 u32 i;
513
514 for( i = 0; i < size; ++i )
515 {
516 OS_TPrintf("%02X ", p[i]);
517 if( i % 16 == 15 )
518 {
519 OS_TPrintf("\n");
520 }
521 }
522
523 if( i % 16 != 0 )
524 {
525 OS_TPrintf("\n");
526 }
527 }
528
529 /*---------------------------------------------------------------------------*
530 Name: DEMO_InitInteruptSystem
531
532 Description: Initializes interrupts.
533
534 Arguments: None.
535
536 Returns: None.
537 *---------------------------------------------------------------------------*/
DEMO_InitInteruptSystem(void)538 static void DEMO_InitInteruptSystem(void)
539 {
540 // Enable master interrupt flag
541 (void)OS_EnableIrq();
542 }
543
544 /*---------------------------------------------------------------------------*
545 Name: DEMO_InitAllocSystem
546
547 Description: Creates a heap and makes OS_Alloc usable.
548
549 Arguments: None.
550
551 Returns: None.
552 *---------------------------------------------------------------------------*/
DEMO_InitAllocSystem(void)553 static void DEMO_InitAllocSystem(void)
554 {
555 void* newArenaLo;
556 OSHeapHandle hHeap;
557
558 // Initialize the main arena's allocation system
559 newArenaLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
560 OS_SetMainArenaLo(newArenaLo);
561
562 // Create a heap in the main arena
563 hHeap = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
564 (void)OS_SetCurrentHeap(OS_ARENA_MAIN, hHeap);
565 }
566
567 /*---------------------------------------------------------------------------*
568 Name: DEMO_InitFileSystem
569
570 Description: Initializes the file system and makes the ROM accessible.
571 The DEMO_InitInteruptSystem and DEMO_InitAllocSystem functions must have been called before calling this function.
572
573
574 Arguments: None.
575
576 Returns: None.
577 *---------------------------------------------------------------------------*/
DEMO_InitFileSystem(void)578 static void DEMO_InitFileSystem(void)
579 {
580 void* p_table;
581 u32 need_size;
582
583 // Enables interrupts for the communications FIFO with the ARM7
584 (void)OS_EnableIrqMask(OS_IE_SPFIFO_RECV);
585
586 // Initialize file system
587 FS_Init( FS_DMA_NOT_USE );
588
589 // File table cache
590 need_size = FS_GetTableSize();
591 p_table = OS_Alloc(need_size);
592 SDK_POINTER_ASSERT(p_table);
593 (void)FS_LoadTable(p_table, need_size);
594 }
595