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