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