1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - aes - demos - ccm-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 Declare internal variables
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 #define DEMO_CCM_COMPATIBLE_2_MAX_ADATA_SIZE 0xFEFF
40 #define DEMO_CCM_COMPATIBLE_6_MAX_ADATA_SIZE AES_ADATA_SIZE_MAX // Originally and normally 0xFFFFFFFF
41 #define DEMO_CCM_COMPATIBLE_2_HEADER_SIZE 2
42 #define DEMO_CCM_COMPATIBLE_6_HEADER_SIZE 6
43 #define DEMO_CCM_COMPATIBLE_6_MAGIC_NUMBER 0xFFFE
44
45 static u32 DEMO_CalcAdataHeaderSize(u32 adataSize);
46 static void DEMO_MakeAdataHeader(void* pv, u32 adataSize);
47 static AESResult DEMO_CcmEncryptCompatible(
48 const AESKey* pKey,
49 const AESNonce* pNonce,
50 void* pWorkBuffer,
51 const void* pAdata,
52 u32 adataSize,
53 const void* pPdata,
54 u32 pdataSize,
55 AESMacLength macLength,
56 void* dst );
57 static AESResult DEMO_CcmDecryptCompatible(
58 const AESKey* pKey,
59 const AESNonce* pNonce,
60 void* pWorkBuffer,
61 const void* pAdata,
62 u32 adataSize,
63 const void* pCdata,
64 u32 cdataSize,
65 AESMacLength macLength,
66 void* dst );
67
68
69
70 /*---------------------------------------------------------------------------*
71 Function definitions
72 *---------------------------------------------------------------------------*/
73
74 /*---------------------------------------------------------------------------*
75 Name: SampleMain
76
77 Description: The main body of the sample.
78
79 Arguments: None.
80
81 Returns: Whether sample processing succeeded.
82 *---------------------------------------------------------------------------*/
SampleMain(void)83 static BOOL SampleMain(void)
84 {
85 BOOL bSuccess = FALSE;
86 AESResult aesResult;
87
88 // The first AES function to call must be AES_Init
89 AES_Init();
90
91 // CCM mode encryption
92 {
93 const AESMacLength macLength = AES_MAC_LENGTH_16;
94
95 const u32 macSize = AES_GetMacLengthValue(macLength);
96 void* pAdata;
97 void* pPdata;
98 void* pEncrypted;
99 void* pKey;
100 void* pNonce;
101 u32 adataSize;
102 u32 pdataSize;
103
104 // Load the data needed for encryption.
105 // In this sample, the nonce 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 nonce.
106 //
107 //
108 pKey = DEMO_LoadFile(NULL, "key.bin");
109 pNonce = DEMO_LoadFile(NULL, "nonce.bin");
110 pAdata = DEMO_LoadFile(&adataSize, "sample_adata.txt");
111 pPdata = DEMO_LoadFile(&pdataSize, "sample_pdata.txt");
112
113 if( (pdataSize % AES_BLOCK_SIZE) != 0 )
114 {
115 OS_TPrintf("pdataSize(=%d) must be multiple of 16.\n", pdataSize);
116 return FALSE;
117 }
118
119
120 // Allocate the buffer to store encrypted data.
121 // Only the MAC portion requires a large buffer.
122 pEncrypted = OS_Alloc(pdataSize + macSize);
123
124 if( ! SDK_IS_VALID_POINTER(pEncrypted) )
125 {
126 OS_TPrintf("fail to OS_Alloc\n");
127 return FALSE;
128 }
129
130
131 // Display parameters
132 OS_TPrintf("== CCM encrypt ==========================\n");
133 OS_TPrintf("---- parameter -----------\n");
134 OS_TPrintf("-- key\n");
135 DEMO_PrintBytes(pKey, sizeof(AESKey));
136 OS_TPrintf("-- nonce\n");
137 DEMO_PrintBytes(pNonce, sizeof(AESNonce));
138
139 OS_TPrintf("---- encrypt -------------\n");
140 OS_TPrintf("-- Adata (ascii)\n");
141 DEMO_PrintText(pAdata, adataSize);
142 OS_TPrintf("-- Pdata (ascii)\n");
143 DEMO_PrintText(pPdata, pdataSize);
144 OS_TPrintf("\n");
145 OS_TPrintf("-- Adata (hex)\n");
146 DEMO_PrintBytes(pAdata, adataSize);
147 OS_TPrintf("-- Pdata (hex)\n");
148 DEMO_PrintBytes(pPdata, pdataSize);
149
150
151 // Perform encryption that is compatible with the general-purpose AES libraries
152 if( adataSize <= DEMO_CCM_COMPATIBLE_6_MAX_ADATA_SIZE )
153 {
154 const u32 headerSize = DEMO_CalcAdataHeaderSize(adataSize);
155 const u32 workSize = headerSize + adataSize + pdataSize;
156 void* pWorkBuffer = OS_Alloc(workSize);
157
158 aesResult = DEMO_CcmEncryptCompatible(
159 pKey, // Key
160 pNonce, // Nonce
161 pWorkBuffer, // Working buffer
162 pAdata, // Pointer to buffer where Adata is stored
163 adataSize, // Adata's size
164 pPdata, // Pointer to buffer where Pdata is stored
165 pdataSize, // Pdata's size
166 macLength, // MAC size
167 pEncrypted ); // Buffer that stores encrypted data
168
169 OS_Free(pWorkBuffer);
170 }
171 else
172 {
173 OS_TPrintf("Too huge Adata size(=%d)\n", adataSize);
174 OS_Free(pEncrypted);
175 OS_Free(pPdata);
176 OS_Free(pAdata);
177 OS_Free(pNonce);
178 OS_Free(pKey);
179 return FALSE;
180 }
181 if( aesResult != AES_RESULT_SUCCESS )
182 {
183 OS_TPrintf("DEMO_CcmEncryptCompatible failed(%d)\n", aesResult);
184 OS_Free(pEncrypted);
185 OS_Free(pPdata);
186 OS_Free(pAdata);
187 OS_Free(pNonce);
188 OS_Free(pKey);
189 return FALSE;
190 }
191
192
193 // Display results
194 OS_TPrintf("-- encrypted (hex)\n");
195 DEMO_PrintBytes(pEncrypted, pdataSize);
196
197 OS_TPrintf("-- mac (hex)\n");
198 DEMO_PrintBytes((u8*)pEncrypted + pdataSize, macSize);
199
200 // Confirm that the data matches data encrypted on the PC
201 {
202 void* pEncryptedOnPC;
203 u32 size;
204
205 pEncryptedOnPC = DEMO_LoadFile(&size, "encrypted.bin");
206
207 if( (pdataSize + macSize == size) && MI_CpuComp8(pEncrypted, pEncryptedOnPC, size) == 0 )
208 {
209 OS_TPrintf("** pEncrypted == pEncryptedOnPC\n");
210 }
211 else
212 {
213 OS_TPrintf("** pEncrypted != pEncryptedOnPC\n");
214 }
215
216 OS_Free(pEncryptedOnPC);
217 }
218
219 OS_Free(pEncrypted);
220 OS_Free(pPdata);
221 OS_Free(pAdata);
222 OS_Free(pNonce);
223 OS_Free(pKey);
224 }
225
226 // CCM Mode Decryption
227 {
228 const AESMacLength macLength = AES_MAC_LENGTH_16;
229
230 const u32 macSize = AES_GetMacLengthValue(macLength);
231 void* pAdata;
232 void* pEncrypted;
233 void* pDecrypted;
234 void* pKey;
235 void* pNonce;
236 u32 adataSize;
237 u32 cdataSize;
238 u32 srcFileSize;
239
240 // Load data encrypted on a PC.
241 // In the sample, both the key and the ciphertext are in ROM, but they should normally not both be obtainable via the same method.
242 //
243 pKey = DEMO_LoadFile(NULL, "key.bin");
244 pNonce = DEMO_LoadFile(NULL, "nonce.bin");
245 pAdata = DEMO_LoadFile(&adataSize, "sample_adata.txt");
246 pEncrypted = DEMO_LoadFile(&srcFileSize, "encrypted.bin");
247 cdataSize = srcFileSize - macSize;
248
249 // Allocate the buffer to store decrypted data
250 pDecrypted = OS_Alloc(cdataSize);
251
252 if( ! SDK_IS_VALID_POINTER(pDecrypted) )
253 {
254 OS_TPrintf("fail to OS_Alloc\n");
255 return FALSE;
256 }
257
258 // Display parameters
259 OS_TPrintf("== CCM decrypt ==========================\n");
260 OS_TPrintf("---- parameter -----------\n");
261 OS_TPrintf("-- key\n");
262 DEMO_PrintBytes(pKey, sizeof(AESKey));
263 OS_TPrintf("-- nonce\n");
264 DEMO_PrintBytes(pNonce, sizeof(AESNonce));
265
266 OS_TPrintf("---- decrypt -------------\n");
267 OS_TPrintf("-- Adata (ascii)\n");
268 DEMO_PrintText(pAdata, adataSize);
269 OS_TPrintf("\n");
270 OS_TPrintf("-- Adata (hex)\n");
271 DEMO_PrintBytes(pAdata, adataSize);
272 OS_TPrintf("-- encrypted (hex)\n");
273 DEMO_PrintBytes(pEncrypted, cdataSize + macSize);
274
275 // Performs decryption that is compatible with general-purpose AES libraries
276 if( adataSize <= DEMO_CCM_COMPATIBLE_6_MAX_ADATA_SIZE )
277 {
278 const u32 headerSize = DEMO_CalcAdataHeaderSize(adataSize);
279 const u32 workSize = headerSize + adataSize + cdataSize + macSize;
280 void* pWorkBuffer = OS_Alloc(workSize);
281
282 aesResult = DEMO_CcmDecryptCompatible(
283 pKey, // Key
284 pNonce, // Nonce
285 pWorkBuffer, // Working buffer
286 pAdata, // Pointer to buffer where Adata is stored
287 adataSize, // Adata's size
288 pEncrypted, // Pointer to buffer where ciphertext and MAC are stored
289 cdataSize, // Ciphertext size
290 macLength, // MAC size
291 pDecrypted ); // Buffer that stores decrypted data
292
293 OS_Free(pWorkBuffer);
294 }
295 else
296 {
297 OS_TPrintf("Too huge Adata size(=%d)\n", adataSize);
298 OS_Free(pEncrypted);
299 OS_Free(pAdata);
300 OS_Free(pNonce);
301 OS_Free(pKey);
302 return FALSE;
303 }
304 // If the encrypted data has been falsified, the aesResult obtained here is AES_RESULT_VERIFICATION_FAILED
305 //
306 if( aesResult != AES_RESULT_SUCCESS )
307 {
308 OS_TPrintf("DEMO_CcmDecryptCompatible failed(%d)\n", aesResult);
309 OS_Free(pDecrypted);
310 OS_Free(pEncrypted);
311 OS_Free(pAdata);
312 OS_Free(pNonce);
313 OS_Free(pKey);
314 return FALSE;
315 }
316
317
318 // Display results
319 OS_TPrintf("-- decrypted (hex)\n");
320 DEMO_PrintBytes(pDecrypted, cdataSize);
321
322 OS_TPrintf("-- decrypted (ascii)\n");
323 DEMO_PrintText(pDecrypted, cdataSize);
324 OS_TPrintf("\n");
325
326 // Confirm that it matches the original
327 {
328 void* pOriginal;
329 u32 size;
330
331 pOriginal = DEMO_LoadFile(&size, "sample_pdata.txt");
332
333 if( (cdataSize == size) && MI_CpuComp8(pDecrypted, pOriginal, size) == 0 )
334 {
335 OS_TPrintf("** pDecrypted == pOriginal\n");
336 bSuccess = TRUE;
337 }
338 else
339 {
340 OS_TPrintf("** pDecrypted != pOriginal\n");
341 }
342
343 OS_Free(pOriginal);
344 }
345
346
347 OS_Free(pDecrypted);
348 OS_Free(pEncrypted);
349 OS_Free(pAdata);
350 OS_Free(pNonce);
351 OS_Free(pKey);
352 }
353
354 return bSuccess;
355 }
356
357 /*---------------------------------------------------------------------------*
358 Name: TwlMain
359
360 Description: Main function.
361
362 Arguments: None.
363
364 Returns: None.
365 *---------------------------------------------------------------------------*/
TwlMain(void)366 void TwlMain(void)
367 {
368 BOOL bSampleSucceeded = FALSE;
369
370 // Initialization
371 OS_Init();
372 DEMO_InitInteruptSystem();
373 DEMO_InitAllocSystem();
374 DEMO_InitFileSystem();
375 OS_TPrintf("*** start aes demo\n");
376
377 // When in NITRO mode, stopped by Panic
378 DEMOCheckRunOnTWL();
379 // Run demo
380 bSampleSucceeded = SampleMain();
381
382 // Display demo run results
383 OS_TPrintf("*** End of demo\n");
384 OS_TPrintf("demo %s\n", (bSampleSucceeded ? "succeeded": "failed"));
385 GX_Init();
386 *(GXRgb*)HW_BG_PLTT = (GXRgb)(bSampleSucceeded ? GX_RGB(0, 31, 0): GX_RGB(31, 0, 0));
387 GX_DispOn();
388 OS_Terminate();
389 }
390
391
392
393 /*---------------------------------------------------------------------------*
394 Name: DEMO_CalcAdataHeaderSize
395
396 Description: There is no compatibility for output results between those of the TWL-SDK AES library and those of general AES libraries.
397 As one example of incompatibility, sometimes the size of the Adata immediately following the CCM header is NOT automatically added.
398 This function calculates the size of the region needed to store the Adata size.
399
400
401
402
403
404 Arguments: adataSize: Adata's size
405
406 Returns: Returns the region size needed to store a size equivalent to the Adata size.
407 *---------------------------------------------------------------------------*/
DEMO_CalcAdataHeaderSize(u32 adataSize)408 static u32 DEMO_CalcAdataHeaderSize(u32 adataSize)
409 {
410 return (u32)( (adataSize <= DEMO_CCM_COMPATIBLE_2_MAX_ADATA_SIZE)
411 ? DEMO_CCM_COMPATIBLE_2_HEADER_SIZE:
412 DEMO_CCM_COMPATIBLE_6_HEADER_SIZE );
413 }
414
415
416
417 /*---------------------------------------------------------------------------*
418 Name: DEMO_MakeAdataHeader
419
420 Description: There is no compatibility for output results between those of the TWL-SDK AES library and those of general AES libraries.
421 As one example of incompatibility, sometimes the size of the Adata immediately following the CCM header is NOT automatically added.
422 This function writes out the Adata size in the prescribed format to a buffer.
423
424
425
426
427
428 Arguments: pv: Pointer to the buffer where the Adata size is written
429 adataSize: Adata's size
430
431 Returns: None.
432 *---------------------------------------------------------------------------*/
DEMO_MakeAdataHeader(void * pv,u32 adataSize)433 static void DEMO_MakeAdataHeader(void* pv, u32 adataSize)
434 {
435 u8* p = (u8*)pv;
436
437 if( adataSize <= DEMO_CCM_COMPATIBLE_2_MAX_ADATA_SIZE )
438 {
439 MI_StoreBE16(p, (u16)adataSize);
440 }
441 else
442 {
443 MI_StoreBE16(p + 0, DEMO_CCM_COMPATIBLE_6_MAGIC_NUMBER);
444 MI_StoreBE32(p + 2, adataSize);
445 }
446 }
447
448
449
450 /*---------------------------------------------------------------------------*
451 Name: DEMO_CcmEncryptCompatible
452
453 Description: There is no compatibility for output results between those of the TWL-SDK AES library and those of general AES libraries.
454 This function uses appropriate processing before and after AES processes to perform encryption compatible with general AES libraries.
455 However, there is a limitation compared to AES_CcmEncryptAndSign: pdataSize must be a multiple of AES_BLOCK_SIZE (=16).
456 Also, the limit on adataSize is not a multiple of 16. In some cases it will be a multiple of 16 minus 2 or a multiple of 16 minus 4.
457
458
459
460
461
462 Arguments: pKey: Key to use
463 pNonce: Nonce to use
464 pWorkBuffer: Passes a pointer to the working buffer used by the function internally.
465
466 A size equivalent to [adataSize + pdataSize + DEMO_CalcAdataHeaderSize(adataSize)] is needed.
467
468 The pointer must be 4-byte aligned.
469
470 pAdata: Pointer to Adata
471 adataSize: Adata size.
472 Must be a multiple of 16 minus DEMO_CalcAdataHeaderSize(adataSize).
473
474 pPdata: Pointer to Pdata
475 pdataSize: Pdata size.
476 Must be a multiple of 16.
477 macLength: MAC size
478 dst: Pointer to the buffer where the ciphertext is written out.
479 A size equivalent to [pdataSize + DEMO_CalcAdataHeaderSize(adataSize)] is needed.
480 The pointer must be 4-byte aligned.
481
482
483 Returns: Returns the processing result.
484 *---------------------------------------------------------------------------*/
DEMO_CcmEncryptCompatible(const AESKey * pKey,const AESNonce * pNonce,void * pWorkBuffer,const void * pAdata,u32 adataSize,const void * pPdata,u32 pdataSize,AESMacLength macLength,void * dst)485 AESResult DEMO_CcmEncryptCompatible(
486 const AESKey* pKey,
487 const AESNonce* pNonce,
488 void* pWorkBuffer,
489 const void* pAdata,
490 u32 adataSize,
491 const void* pPdata,
492 u32 pdataSize,
493 AESMacLength macLength,
494 void* dst )
495 {
496 const u32 headerSize = DEMO_CalcAdataHeaderSize(adataSize);
497 AESKey key;
498 AESNonce nonce;
499
500 SDK_POINTER_ASSERT(pKey);
501 SDK_POINTER_ASSERT(pNonce);
502 SDK_POINTER_ASSERT(pWorkBuffer);
503 SDK_POINTER_ASSERT(pAdata);
504 SDK_POINTER_ASSERT(pPdata);
505 SDK_POINTER_ASSERT(dst);
506 SDK_MAX_ASSERT( adataSize, AES_ADATA_SIZE_MAX );
507 SDK_MAX_ASSERT( pdataSize, AES_PDATA_SIZE_MAX );
508 SDK_ASSERT( (adataSize > DEMO_CCM_COMPATIBLE_2_MAX_ADATA_SIZE) || ((adataSize % 16) == 14) );
509 SDK_ASSERT( (adataSize <= DEMO_CCM_COMPATIBLE_2_MAX_ADATA_SIZE) || ((adataSize % 16) == 10) );
510 SDK_ASSERT( (pdataSize % 16) == 0 );
511
512 // Create the input data
513 {
514 const u32 offsetHeader = 0;
515 const u32 offsetAdata = offsetHeader + headerSize;
516 const u32 offsetPdata = offsetAdata + adataSize;
517
518 u8* pWork = (u8*)pWorkBuffer;
519 DEMO_MakeAdataHeader(pWork + offsetHeader, adataSize); // Adata size
520 MI_CpuCopy(pAdata, pWork + offsetAdata, adataSize); // Adata
521 MI_CpuCopy(pPdata, pWork + offsetPdata, pdataSize); // Pdata
522 }
523
524 // Switch the byte order of all input
525 {
526 const u32 workSize = headerSize + adataSize + pdataSize;
527
528 AES_ReverseBytes(pKey, &key, sizeof(key)); // Key
529 AES_ReverseBytes(pNonce, &nonce, sizeof(nonce)); // Nonce
530 AES_SwapEndianEach128(pWorkBuffer, pWorkBuffer, workSize); // Adata size, Adata, Pdata
531 }
532
533 // AES processing
534 {
535 OSMessageQueue msgQ;
536 OSMessage msgQBuffer[1];
537 AESResult aesResult;
538
539 OS_InitMessageQueue(&msgQ, msgQBuffer, sizeof(msgQBuffer)/sizeof(*msgQBuffer));
540
541 aesResult = AES_SetKey(&key);
542 if( aesResult != AES_RESULT_SUCCESS )
543 {
544 return aesResult;
545 }
546
547 aesResult = AES_CcmEncryptAndSign(
548 &nonce,
549 pWorkBuffer,
550 adataSize + headerSize,
551 pdataSize,
552 macLength,
553 dst,
554 DEMO_AESCallback,
555 &msgQ );
556 if( aesResult != AES_RESULT_SUCCESS )
557 {
558 return aesResult;
559 }
560
561 aesResult = DEMO_WaitAes(&msgQ);
562 if( aesResult != AES_RESULT_SUCCESS )
563 {
564 return aesResult;
565 }
566 }
567
568 // Switch the output byte order, too
569 {
570 void* mac = (u8*)dst + pdataSize;
571 u32 macSize = AES_GetMacLengthValue(macLength);
572
573 AES_SwapEndianEach128(dst, dst, pdataSize); // Cdata
574 AES_ReverseBytes(mac, mac, macSize); // MAC
575 }
576
577 return AES_RESULT_SUCCESS;
578 }
579
580
581
582 /*---------------------------------------------------------------------------*
583 Name: DEMO_CcmDecryptCompatible
584
585 Description: There is no compatibility for output results between those of the TWL-SDK AES library and those of general AES libraries.
586 This function uses appropriate processing before and after AES processes to perform decryption compatible with general AES libraries.
587 However, there is a limitation compared to AES_CcmDecryptAndVerify: cdataSize must be a multiple of AES_BLOCK_SIZE (=16).
588 Also, the limit on adataSize is not a multiple of 16. In some cases it will be a multiple of 16 minus 2 or a multiple of 16 minus 4.
589
590
591
592
593
594 Arguments: pKey: Key to use
595 pNonce: Nonce to use
596 pWorkBuffer: Passes a pointer to the working buffer used by the function internally.
597
598 A size equivalent to [adataSize + pdataSize + DEMO_CalcAdataHeaderSize(adataSize) + AES_GetMacLengthValue(macLength)] is needed.
599
600 The pointer must be 4-byte aligned.
601
602
603 pAdata: Pointer to Adata
604 adataSize: Adata size.
605 Must be a multiple of 16 minus DEMO_CalcAdataHeaderSize(adataSize).
606
607 pPdata: Pointer to buffer where ciphertext and MAC are stored
608 pdataSize: Size of the ciphertext.
609 Must be a multiple of 16.
610 macLength: MAC size
611 dst: Pointer to the buffer where the ciphertext is written out.
612 The pointer must be 4-byte aligned.
613
614 Returns: Returns the processing result.
615 *---------------------------------------------------------------------------*/
DEMO_CcmDecryptCompatible(const AESKey * pKey,const AESNonce * pNonce,void * pWorkBuffer,const void * pAdata,u32 adataSize,const void * pCdata,u32 cdataSize,AESMacLength macLength,void * dst)616 AESResult DEMO_CcmDecryptCompatible(
617 const AESKey* pKey,
618 const AESNonce* pNonce,
619 void* pWorkBuffer,
620 const void* pAdata,
621 u32 adataSize,
622 const void* pCdata,
623 u32 cdataSize,
624 AESMacLength macLength,
625 void* dst )
626 {
627 const u32 headerSize = DEMO_CalcAdataHeaderSize(adataSize);
628 const u32 macSize = AES_GetMacLengthValue(macLength);
629 AESKey key;
630 AESNonce nonce;
631
632 SDK_POINTER_ASSERT(pKey);
633 SDK_POINTER_ASSERT(pNonce);
634 SDK_POINTER_ASSERT(pWorkBuffer);
635 SDK_POINTER_ASSERT(pAdata);
636 SDK_POINTER_ASSERT(pCdata);
637 SDK_POINTER_ASSERT(dst);
638 SDK_MAX_ASSERT( adataSize, AES_ADATA_SIZE_MAX );
639 SDK_MAX_ASSERT( cdataSize, AES_PDATA_SIZE_MAX );
640 SDK_ASSERT( (adataSize > DEMO_CCM_COMPATIBLE_2_MAX_ADATA_SIZE) || ((adataSize % 16) == 14) );
641 SDK_ASSERT( (adataSize <= DEMO_CCM_COMPATIBLE_2_MAX_ADATA_SIZE) || ((adataSize % 16) == 10) );
642 SDK_ASSERT( (cdataSize % 16) == 0 );
643
644 // Create the input data
645 {
646 const u32 offsetHeader = 0;
647 const u32 offsetAdata = offsetHeader + headerSize;
648 const u32 offsetCdata = offsetAdata + adataSize;
649
650 u8* pWork = (u8*)pWorkBuffer;
651 DEMO_MakeAdataHeader(pWork + offsetHeader, adataSize); // Adata size
652 MI_CpuCopy(pAdata, pWork + offsetAdata, adataSize); // Adata
653 MI_CpuCopy(pCdata, pWork + offsetCdata, cdataSize + macSize); // Cdata, MAC
654 }
655
656 // Switch the byte order of all input
657 {
658 const u32 workSize = headerSize + adataSize + cdataSize + macSize;
659
660 AES_ReverseBytes(pKey, &key, sizeof(key)); // Key
661 AES_ReverseBytes(pNonce, &nonce, sizeof(nonce)); // Nonce
662 AES_SwapEndianEach128(pWorkBuffer, pWorkBuffer, workSize); // Adata size, Adata, Cdata, MAC
663 }
664
665 // AES processing
666 {
667 OSMessageQueue msgQ;
668 OSMessage msgQBuffer[1];
669 AESResult aesResult;
670
671 OS_InitMessageQueue(&msgQ, msgQBuffer, sizeof(msgQBuffer)/sizeof(*msgQBuffer));
672
673 aesResult = AES_SetKey(&key);
674 if( aesResult != AES_RESULT_SUCCESS )
675 {
676 return aesResult;
677 }
678
679 aesResult = AES_CcmDecryptAndVerify(
680 &nonce,
681 pWorkBuffer,
682 adataSize + headerSize,
683 cdataSize,
684 macLength,
685 dst,
686 DEMO_AESCallback,
687 &msgQ );
688 if( aesResult != AES_RESULT_SUCCESS )
689 {
690 return aesResult;
691 }
692
693 aesResult = DEMO_WaitAes(&msgQ);
694 if( aesResult != AES_RESULT_SUCCESS )
695 {
696 return aesResult;
697 }
698 }
699
700 // Switch the output byte order, too
701 {
702 AES_SwapEndianEach128(dst, dst, cdataSize); // Pdata
703 }
704
705 return AES_RESULT_SUCCESS;
706 }
707
708
709
710 /*---------------------------------------------------------------------------*
711 Name: DEMO_LoadFile
712
713 Description: Allocates memory and loads a file.
714
715 Arguments: pSize: Pointer to the buffer that stores the size of the file that was loaded.
716 Specify NULL when size is unnecessary.
717 path: Path of the file to load
718
719 Returns: Returns a pointer to the buffer where the file content is stored.
720 This buffer must be deallocated with the OS_Free function when it is no longer needed.
721 Returns NULL if it failed to load.
722 *---------------------------------------------------------------------------*/
DEMO_LoadFile(u32 * pSize,const char * path)723 static void* DEMO_LoadFile(u32* pSize, const char* path)
724 {
725 BOOL bSuccess;
726 FSFile f;
727 u32 fileSize;
728 s32 readSize;
729 void* pBuffer;
730
731 FS_InitFile(&f);
732
733 bSuccess = FS_OpenFileEx(&f, path, FS_FILEMODE_R);
734 if( ! bSuccess )
735 {
736 OS_Warning("fail to FS_OpenFileEx(%s)\n", path);
737 return NULL;
738 }
739
740 fileSize = FS_GetFileLength(&f);
741 pBuffer = OS_Alloc(fileSize + 1);
742 if( pBuffer == NULL )
743 {
744 (void)FS_CloseFile(&f);
745 OS_Warning("fail to OS_Alloc(%d)\n", fileSize + 1);
746 return NULL;
747 }
748
749 readSize = FS_ReadFile(&f, pBuffer, (s32)fileSize);
750 if( readSize != fileSize )
751 {
752 OS_Free(pBuffer);
753 (void)FS_CloseFile(&f);
754 OS_Warning("fail to FS_ReadFile(%d)\n", fileSize + 1);
755 return NULL;
756 }
757
758 bSuccess = FS_CloseFile(&f);
759 SDK_ASSERT( bSuccess );
760
761 ((char*)pBuffer)[fileSize] = '\0';
762
763 if( pSize != NULL )
764 {
765 *pSize = fileSize;
766 }
767
768 return pBuffer;
769 }
770
771 /*---------------------------------------------------------------------------*
772 Name: DEMO_AESCallback
773
774 Description: This is the callback called at AES processing completion.
775 It is of type AESCallback.
776
777 Arguments: result: AES processing result.
778 arg: Last argument passed in AES_Ctr
779
780 Returns: None.
781 *---------------------------------------------------------------------------*/
DEMO_AESCallback(AESResult result,void * arg)782 static void DEMO_AESCallback(AESResult result, void* arg)
783 {
784 OSMessageQueue* pQ = (OSMessageQueue*)arg;
785 (void)OS_SendMessage(pQ, (OSMessage)result, OS_MESSAGE_BLOCK);
786 }
787
788 /*---------------------------------------------------------------------------*
789 Name: DEMO_WaitAes
790
791 Description: Returns the result of awaiting AES processing completion.
792 DEMO_AESCallback must have been specified in AES_Ctr.
793
794 Arguments: pQ: Message queue passed as the last AES_Ctr argument
795
796 Returns: AES processing result.
797 *---------------------------------------------------------------------------*/
DEMO_WaitAes(OSMessageQueue * pQ)798 static AESResult DEMO_WaitAes(OSMessageQueue* pQ)
799 {
800 OSMessage msg;
801 (void)OS_ReceiveMessage(pQ, &msg, OS_MESSAGE_BLOCK);
802 return (AESResult)msg;
803 }
804
805 /*---------------------------------------------------------------------------*
806 Name: DEMO_PrintText
807
808 Description: Prints a string of specified length to debug output.
809
810 Arguments: pvoid: Target string
811 size: Target string byte count
812
813 Returns: None.
814 *---------------------------------------------------------------------------*/
DEMO_PrintText(const void * pvoid,u32 size)815 static void DEMO_PrintText(const void* pvoid, u32 size)
816 {
817 static const u32 TMP_BUFFER_LEN = 128 - 1;
818 char tmp_buffer[TMP_BUFFER_LEN + 1];
819 const u8* p = (const u8*)pvoid;
820
821 while( size >= TMP_BUFFER_LEN )
822 {
823 MI_CpuCopy8(p, tmp_buffer, TMP_BUFFER_LEN);
824 tmp_buffer[TMP_BUFFER_LEN] = '\0';
825 OS_PutString(tmp_buffer);
826
827 size -= TMP_BUFFER_LEN;
828 p += TMP_BUFFER_LEN;
829 }
830
831 if( size > 0 )
832 {
833 MI_CpuCopy8(p, tmp_buffer, size);
834 tmp_buffer[size] = '\0';
835 OS_PutString(tmp_buffer);
836 }
837 }
838
839 /*---------------------------------------------------------------------------*
840 Name: DEMO_PrintBytes
841
842 Description: Outputs the specified binary array in hexadecimal to debug output.
843
844 Arguments: pvoid: Pointer to the target binary array
845 size: Number of bytes in the target binary array
846
847 Returns: None.
848 *---------------------------------------------------------------------------*/
DEMO_PrintBytes(const void * pvoid,u32 size)849 static void DEMO_PrintBytes(const void* pvoid, u32 size)
850 {
851 const u8* p = (const u8*)pvoid;
852 u32 i;
853
854 for( i = 0; i < size; ++i )
855 {
856 OS_TPrintf("%02X ", p[i]);
857 if( i % 16 == 15 )
858 {
859 OS_TPrintf("\n");
860 }
861 }
862
863 if( i % 16 != 0 )
864 {
865 OS_TPrintf("\n");
866 }
867 }
868
869 /*---------------------------------------------------------------------------*
870 Name: DEMO_InitInteruptSystem
871
872 Description: Initializes interrupts.
873
874 Arguments: None.
875
876 Returns: None.
877 *---------------------------------------------------------------------------*/
DEMO_InitInteruptSystem(void)878 static void DEMO_InitInteruptSystem(void)
879 {
880 // Enable master interrupt flag
881 (void)OS_EnableIrq();
882 }
883
884 /*---------------------------------------------------------------------------*
885 Name: DEMO_InitAllocSystem
886
887 Description: Creates a heap and makes OS_Alloc usable.
888
889 Arguments: None.
890
891 Returns: None.
892 *---------------------------------------------------------------------------*/
DEMO_InitAllocSystem(void)893 static void DEMO_InitAllocSystem(void)
894 {
895 void* newArenaLo;
896 OSHeapHandle hHeap;
897
898 // Initialize the main arena's allocation system
899 newArenaLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
900 OS_SetMainArenaLo(newArenaLo);
901
902 // Create a heap in the main arena
903 hHeap = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
904 (void)OS_SetCurrentHeap(OS_ARENA_MAIN, hHeap);
905 }
906
907 /*---------------------------------------------------------------------------*
908 Name: DEMO_InitFileSystem
909
910 Description: Initializes the file system and makes the ROM accessible.
911 The DEMO_InitInteruptSystem and DEMO_InitAllocSystem functions must have been called before calling this function.
912
913
914 Arguments: None.
915
916 Returns: None.
917 *---------------------------------------------------------------------------*/
DEMO_InitFileSystem(void)918 static void DEMO_InitFileSystem(void)
919 {
920 void* p_table;
921 u32 need_size;
922
923 // Enables interrupts for the communications FIFO with the ARM7
924 (void)OS_EnableIrqMask(OS_IE_SPFIFO_RECV);
925
926 // Initialize file system
927 FS_Init( FS_DMA_NOT_USE );
928
929 // File table cache
930 need_size = FS_GetTableSize();
931 p_table = OS_Alloc(need_size);
932 SDK_POINTER_ASSERT(p_table);
933 (void)FS_LoadTable(p_table, need_size);
934 }
935