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