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