1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - aes - demos - ctr-partial
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 // Message queue used for waiting for the end of AES processing
26 #define DEMO_MESSAGE_Q_SIZE     1
27 static OSMessageQueue   sMsgQ;
28 static OSMessage        sMsgQBuffer[DEMO_MESSAGE_Q_SIZE];
29 
30 // Sample data to be encrypted
31 static const char DEMO_TEXT[] =
32     "These coded instructions, statements, and computer programs contain "
33     "proprietary information of Nintendo of America Inc. and/or Nintendo "
34     "Company Ltd., and are protected by Federal copyright law.  They may "
35     "not be disclosed to third parties or copied or duplicated in any form, "
36     "in whole or in part, without the prior written consent of Nintendo.";
37 
38 // Appropriate key to be used for encryption
39 static const AESKey DEMO_KEY =
40     { 0xb3,0x2f,0x3a,0x91,0xe6,0x98,0xc2,0x76,
41       0x70,0x6d,0xfd,0x71,0xbc,0xdd,0xb3,0x93, };
42 
43 
44 
45 /*---------------------------------------------------------------------------*
46     Internal function declarations
47  *---------------------------------------------------------------------------*/
48 
49 static void         DEMO_InitInteruptSystem(void);
50 static void         DEMO_InitAllocSystem(void);
51 static void         DEMO_AESCallback(AESResult result, void* arg);
52 static AESResult    DEMO_WaitAes(OSMessageQueue* pQ);
53 static void         DEMO_PrintBytes(const void* pvoid, u32 size);
54 static AESResult    DEMO_CtrDecryptPartial(
55                         const AESCounter*   pCounter,
56                         const void*         pEncrypted,
57                         u32                 decryptOffset,
58                         u32                 decryptSize,
59                         void*               dst,
60                         AESCallback         callback,
61                         void*               arg );
62 
63 
64 
65 /*---------------------------------------------------------------------------*
66     Function definitions
67  *---------------------------------------------------------------------------*/
68 
69 /*---------------------------------------------------------------------------*
70   Name:         SampleMain
71 
72   Description:  The main body of the sample.
73 
74   Arguments:    None.
75 
76   Returns:      Whether sample processing succeeded.
77  *---------------------------------------------------------------------------*/
SampleMain(void)78 static BOOL SampleMain(void)
79 {
80     BOOL bSuccess = FALSE;
81 
82     AESResult aesResult;
83     AESCounter counter;
84     const char* pPlainText = DEMO_TEXT;
85     void* pEncrypted;
86     void* pDecrypted;
87     u32 srcSize;
88 
89     // Initialize the message queue for waiting on AES processing
90     OS_InitMessageQueue(&sMsgQ, sMsgQBuffer, DEMO_MESSAGE_Q_SIZE);
91 
92     // Allocate the buffer to store encrypted/decrypted data.
93     // Data size doesn't change with encryption/decryption.
94     srcSize = (u32)STD_GetStringLength(pPlainText) + 1;
95     pEncrypted = OS_Alloc(srcSize);
96     pDecrypted = OS_Alloc(srcSize);
97 
98     if( ! SDK_IS_VALID_POINTER(pEncrypted)
99      || ! SDK_IS_VALID_POINTER(pDecrypted) )
100     {
101         OS_TPrintf("fail to OS_Alloc\n");
102         return FALSE;
103     }
104 
105     // The first AES function to call must be AES_Init
106     AES_Init();
107 
108     // The AES_Rand function is used to generate the initial counter value.
109     // The initial counter value can be any number, but you must avoid ever reusing values if at all possible.
110     //
111     aesResult = AES_Rand(&counter, sizeof(counter));
112     if( aesResult != AES_RESULT_SUCCESS )
113     {
114         OS_TPrintf("AES_Rand failed(%d)\n", aesResult);
115         goto error_exit;
116     }
117 
118     // Configure the encryption key
119     aesResult = AES_SetKey(&DEMO_KEY);
120     if( aesResult != AES_RESULT_SUCCESS )
121     {
122         OS_TPrintf("AES_SetKey failed(%d)\n", aesResult);
123         goto error_exit;
124     }
125 
126 
127     // Display parameters
128     OS_TPrintf("---- parameter -----------\n");
129     OS_TPrintf("-- key\n");
130     DEMO_PrintBytes(&DEMO_KEY, sizeof(DEMO_KEY));
131     OS_TPrintf("-- counter initial value\n");
132     DEMO_PrintBytes(&counter, sizeof(counter));
133 
134 
135     // Encryption
136     {
137         // Performs encryption in AES CTR Mode
138         aesResult = AES_CtrEncrypt( &counter,           // Initial counter value
139                                     pPlainText,         // Data to be encrypted
140                                     srcSize,            // Size of the data to encrypt
141                                     pEncrypted,         // Buffer that stores encrypted data
142                                     DEMO_AESCallback,   // Callback called at completion
143                                     &sMsgQ );           // Callback parameters
144         if( aesResult != AES_RESULT_SUCCESS )
145         {
146             OS_TPrintf("AES_CtrEncrypt failed(%d)\n", aesResult);
147             goto error_exit;
148         }
149 
150         // Wait for encryption to end
151         aesResult = DEMO_WaitAes(&sMsgQ);
152         if( aesResult != AES_RESULT_SUCCESS )
153         {
154             OS_TPrintf("AES_CtrEncrypt failed(%d)\n", aesResult);
155             goto error_exit;
156         }
157 
158 
159         // Display results
160         OS_TPrintf("---- encrypt -------------\n");
161         OS_TPrintf("-- plain text (ascii)\n");
162         OS_PutString(pPlainText);   // Use OS_PutString because OS_*Printf has a limit of 256 characters
163         OS_TPrintf("\n");
164 
165         OS_TPrintf("-- plain text (hex)\n");
166         DEMO_PrintBytes(pPlainText, srcSize);
167 
168         OS_TPrintf("-- encrypted (hex)\n");
169         DEMO_PrintBytes(pEncrypted, srcSize);
170     }
171 
172     // Decryption
173     {
174         // Performs decryption partially in AES CTR Mode
175         const u32 decryptOffset = 80;       // Must be a multiple of AES_BLOCK_SIZE
176         const u32 decryptSize   = 68;
177 
178         aesResult = DEMO_CtrDecryptPartial(
179                         &counter,           // Initial counter value (must be the same as that used during encryption)
180                         pEncrypted,         // Data to be decrypted
181                         decryptOffset,      // Offset for the start of decryption (must be a multiple of AES_BLOCK_SIZE)
182                         decryptSize,        // Size to decrypt
183                         pDecrypted,         // Buffer that stores decrypted data
184                         DEMO_AESCallback,   // Callback called at completion
185                         &sMsgQ );           // Callback parameters
186         if( aesResult != AES_RESULT_SUCCESS )
187         {
188             OS_TPrintf("AES_CtrDecrypt failed(%d)\n", aesResult);
189             goto error_exit;
190         }
191 
192         // Wait for decryption to end
193         aesResult = DEMO_WaitAes(&sMsgQ);
194         if( aesResult != AES_RESULT_SUCCESS )
195         {
196             OS_TPrintf("AES_CtrDecrypt failed(%d)\n", aesResult);
197             goto error_exit;
198         }
199 
200         // Add a null terminator because we want to display as text
201         ((char*)pDecrypted)[decryptSize] = '\0';
202 
203         // Display results
204         OS_TPrintf("---- decrypt -------------\n");
205         OS_TPrintf("-- encrypted (hex)\n");
206         DEMO_PrintBytes(pEncrypted, srcSize);
207 
208         OS_TPrintf("-- decrypted (hex)\n");
209         DEMO_PrintBytes(pDecrypted, decryptSize);
210 
211         OS_TPrintf("-- decrypted (ascii)\n");
212         OS_PutString(pDecrypted);   // Use OS_PutString because OS_*Printf has a limit of 256 characters
213         OS_TPrintf("\n");
214 
215         // Confirm that data that was encrypted, then decrypted, matches original
216         if( MI_CpuComp8(pDecrypted, pPlainText + decryptOffset, decryptSize) == 0 )
217         {
218             OS_TPrintf("** pDecrypted == pPlainText\n");
219             bSuccess = TRUE;
220         }
221         else
222         {
223             OS_TPrintf("** pDecrypted != pPlainText\n");
224         }
225     }
226 
227 error_exit:
228     OS_Free(pDecrypted);
229     OS_Free(pEncrypted);
230 
231     return bSuccess;
232 }
233 
234 
235 /*---------------------------------------------------------------------------*
236   Name:         TwlMain
237 
238   Description:  The main function.
239 
240   Arguments:    None.
241 
242   Returns:      None.
243  *---------------------------------------------------------------------------*/
TwlMain(void)244 void TwlMain(void)
245 {
246     BOOL bSampleSucceeded = FALSE;
247 
248     // Initialization
249     OS_Init();
250     DEMO_InitInteruptSystem();
251     DEMO_InitAllocSystem();
252     OS_TPrintf("*** start aes demo\n");
253 
254 
255     // Run demo
256     if( OS_IsRunOnTwl() )
257     {
258         bSampleSucceeded = SampleMain();
259     }
260     else
261     {
262         OS_Warning("demo is not run on TWL");
263     }
264 
265 
266     // Display demo run results
267     OS_TPrintf("*** End of demo\n");
268     OS_TPrintf("demo %s\n", (bSampleSucceeded ? "succeeded": "failed"));
269     GX_Init();
270     *(GXRgb*)HW_BG_PLTT = (GXRgb)(bSampleSucceeded ? GX_RGB(0, 31, 0): GX_RGB(31, 0, 0));
271     GX_DispOn();
272     OS_Terminate();
273 }
274 
275 
276 /*---------------------------------------------------------------------------*
277   Name:         DEMO_CtrDecryptPartial
278 
279   Description:  Partially decrypts the CTR Mode ciphertext.
280                 Decrypts 'decryptSize' bytes starting from the 'decryptOffset'-numbered byte of 'pEncrypted'.
281 
282 
283   Arguments:    pCounter:       Initial counter value that was used at encryption
284                 pEncrypted:     Pointer to the ciphertext's starting address.
285                                 The pointer must be 4-byte aligned.
286                 decryptOffset:  Offset at which to start decryption.
287                                 Must be a multiple of AES_BLOCK_SIZE.
288                 decryptSize:    Size to decrypt
289                 dst:            Pointer to the buffer where the ciphertext is written out.
290                                 The pointer must be 4-byte aligned.
291                 callback:       Callback called when the process is complete.
292                                 NULL can be specified, in which case no callback is invoked.
293 
294                 arg:            Parameter passed to the above callback.
295                                 NULL can be specified.
296 
297   Returns:      Returns the processing result.
298  *---------------------------------------------------------------------------*/
DEMO_CtrDecryptPartial(const AESCounter * pCounter,const void * pEncrypted,u32 decryptOffset,u32 decryptSize,void * dst,AESCallback callback,void * arg)299 static AESResult DEMO_CtrDecryptPartial(
300     const AESCounter*   pCounter,
301     const void*         pEncrypted,
302     u32                 decryptOffset,
303     u32                 decryptSize,
304     void*               dst,
305     AESCallback         callback,
306     void*               arg )
307 {
308     AESCounter counter;
309 
310     SDK_POINTER_ASSERT( pCounter );
311     SDK_ASSERT( (decryptOffset % AES_BLOCK_SIZE) == 0 );
312 
313     // Partial decryption can be done by adding the amount of offset to the initial counter value, then decrypting.
314     // The counter value is incremented once for each AES_BLOCK_SIZE.
315     counter = *pCounter;
316     AES_AddToCounter(&counter, decryptOffset / AES_BLOCK_SIZE);
317 
318     return AES_CtrDecrypt(
319                 &counter,
320                 (const u8*)pEncrypted + decryptOffset,
321                 decryptSize,
322                 dst,
323                 callback,
324                 arg );
325 }
326 
327 
328 /*---------------------------------------------------------------------------*
329   Name:         DEMO_AESCallback
330 
331   Description:  This is the callback called at AES processing completion.
332                 It is of type AESCallback.
333 
334   Arguments:    result: AES processing result
335                 arg:    Last argument passed in AES_Ctr
336 
337   Returns:      None.
338  *---------------------------------------------------------------------------*/
DEMO_AESCallback(AESResult result,void * arg)339 static void DEMO_AESCallback(AESResult result, void* arg)
340 {
341     OSMessageQueue* pQ = (OSMessageQueue*)arg;
342     (void)OS_SendMessage(pQ, (OSMessage)result, OS_MESSAGE_BLOCK);
343 }
344 
345 /*---------------------------------------------------------------------------*
346   Name:         DEMO_WaitAes
347 
348   Description:  Returns the result of awaiting AES processing completion.
349                 DEMO_AESCallback must have been specified in AES_Ctr.
350 
351   Arguments:    pQ: Message queue passed as the last AES_Ctr argument
352 
353   Returns:      AES processing result.
354  *---------------------------------------------------------------------------*/
DEMO_WaitAes(OSMessageQueue * pQ)355 static AESResult DEMO_WaitAes(OSMessageQueue* pQ)
356 {
357     OSMessage msg;
358     (void)OS_ReceiveMessage(pQ, &msg, OS_MESSAGE_BLOCK);
359     return (AESResult)msg;
360 }
361 
362 /*---------------------------------------------------------------------------*
363   Name:         DEMO_PrintBytes
364 
365   Description:  Outputs the specified binary array in hexadecimal to debug output.
366 
367   Arguments:    pvoid:  Pointer to the target binary array
368                 size:   Number of bytes in the target binary array
369 
370   Returns:      None.
371  *---------------------------------------------------------------------------*/
DEMO_PrintBytes(const void * pvoid,u32 size)372 static void DEMO_PrintBytes(const void* pvoid, u32 size)
373 {
374     const u8* p = (const u8*)pvoid;
375     u32 i;
376 
377     for( i = 0; i < size; ++i )
378     {
379         OS_TPrintf("%02X ", p[i]);
380         if( i % 16 == 15 )
381         {
382             OS_TPrintf("\n");
383         }
384     }
385 
386     if( i % 16 != 0 )
387     {
388         OS_TPrintf("\n");
389     }
390 }
391 
392 /*---------------------------------------------------------------------------*
393   Name:         DEMO_InitInteruptSystem
394 
395   Description:  Initializes interrupts.
396 
397   Arguments:    None.
398 
399   Returns:      None.
400  *---------------------------------------------------------------------------*/
DEMO_InitInteruptSystem(void)401 static void DEMO_InitInteruptSystem(void)
402 {
403     // Enable master interrupt flag
404     (void)OS_EnableIrq();
405 }
406 
407 /*---------------------------------------------------------------------------*
408   Name:         DEMO_InitAllocSystem
409 
410   Description:  Creates a heap and makes OS_Alloc usable.
411 
412   Arguments:    None.
413 
414   Returns:      None.
415  *---------------------------------------------------------------------------*/
DEMO_InitAllocSystem(void)416 static void DEMO_InitAllocSystem(void)
417 {
418     void* newArenaLo;
419     OSHeapHandle hHeap;
420 
421     // Initialize the main arena's allocation system
422     newArenaLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
423     OS_SetMainArenaLo(newArenaLo);
424 
425     // Create a heap in the main arena
426     hHeap = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
427     (void)OS_SetCurrentHeap(OS_ARENA_MAIN, hHeap);
428 }
429