/*---------------------------------------------------------------------------* Project: NET demo File: crypto.c Copyright (C) 2006 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: crypto.c,v $ Revision 1.1 2006/10/27 08:03:46 yosizaki initial upload. $NoKeywords: $ *---------------------------------------------------------------------------*/ #include #include #include #define LINES 24 #define STACK_SIZE 4000 static void DoReport(void); static void* DoTest(void* arg); GXColor Black = { 0, 0, 0, 0 }; GXColor Blue = { 0, 0, 192, 0 }; GXColor Red = { 255, 0, 0, 0 }; GXColor Green = { 0, 224, 0, 0 }; GXColor White = { 255, 255, 255, 0 }; GXColor SucceededGreen = { 0, 128, 0, 0 }; GXColor FailedRed = { 128, 0, 0, 0 }; static char ReportBuffer[4096]; static char PrintBuffer[4096]; static OSThread testThread; static u8 testThreadStack[STACK_SIZE] ATTRIBUTE_ALIGN(32); /*---------------------------------------------------------------------------* Application main loop *---------------------------------------------------------------------------*/ void main(void) { DEMOInit(NULL); if ( ! DEMOInitROMFont() ) { OSHalt("DEMOInitROMFont()"); } // Clear EFB GXSetCopyClear(Blue, GX_MAX_Z24); GXCopyDisp(DEMOGetCurrentBuffer(), GX_TRUE); (void)OSReport("NET Demo: Test crypto functions\n"); // Launch the test thread if( ! OSCreateThread( &testThread, DoTest, NULL, (void*)((u32)testThreadStack + STACK_SIZE), STACK_SIZE, 20, 0 ) ) { OSHalt( "OSCrateThread()" ); } if ( OSResumeThread( &testThread ) < 0 ) { OSHalt( "OSResumeThread()" ); } while ( ! OSIsThreadTerminated(&testThread) ) { DEMOBeforeRender(); DoReport(); DEMODoneRender(); } { BOOL result; if( ! OSJoinThread( &testThread, (void**)&result ) ) { OSHalt( "OSJoinThread()" ); } if ( result ) { // succeeded OSReport("------ Test Succeeded ------\n"); GXSetCopyClear(SucceededGreen, GX_MAX_Z24); GXCopyDisp(DEMOGetCurrentBuffer(), GX_TRUE); } else { // failed OSReport("****** Test Failed ******\n"); GXSetCopyClear(FailedRed, GX_MAX_Z24); GXCopyDisp(DEMOGetCurrentBuffer(), GX_TRUE); } } while ( TRUE ) { DEMOBeforeRender(); DoReport(); DEMODoneRender(); } } /*---------------------------------------------------------------------------* Display Settings *---------------------------------------------------------------------------*/ static void DoReport(void) { GXRenderModeObj* rmp; rmp = DEMOGetRenderModeObj(); DEMOInitCaption(DM_FT_XLU, (s16) rmp->fbWidth, (s16) rmp->efbHeight); DEMOSetROMFontSize(16, -1); (void)DEMORFPuts(25, 25, 0, ReportBuffer); } // Define program-specific OSReport() function. void OSReport(const char* msg, ...) { BOOL enabled; va_list marker; u32 len; int c; char* p; char* q; va_start(marker, msg); (void)vsnprintf(PrintBuffer, sizeof(PrintBuffer)-1, msg, marker); va_end(marker); PrintBuffer[sizeof(PrintBuffer)-1] = 0; (void)printf("%s", PrintBuffer); enabled = OSDisableInterrupts(); (void)strncat(ReportBuffer, PrintBuffer, sizeof(ReportBuffer)-1); ReportBuffer[sizeof(ReportBuffer)-1] = 0; len = strlen(ReportBuffer); c = 0; q = ReportBuffer; for (p = ReportBuffer; p < ReportBuffer + len; ++p) { if (*p == '\n') { ++c; if (LINES <= c) { q = strchr(q, '\n'); } } } if (LINES <= c) { (void)memmove(ReportBuffer, q + 1, len - (q - ReportBuffer)); } (void)OSRestoreInterrupts(enabled); } inline static void PrintBinary(const void *buffer, u32 length) { u32 i; for (i = 0; i < length; ++i) { OSReport("%02X ", ((const u8 *)buffer)[i]); } } /*---------------------------------------------------------------------------* Tests *---------------------------------------------------------------------------*/ #define PrintResultEq( a, b, f ) \ do { OSReport( ((a) == (b)) ? "[--OK--] " : "[**NG**] " ); (f) = (f) && ((a) == (b)); } while( FALSE ) #define PrintResultBinaryEq( a, b, l, f ) \ do { OSReport( (memcmp((a), (b), (l)) == 0) ? "[--OK--] " : "[**NG**] " ); (f) = (f) && (memcmp((a), (b), (l)) == 0); } while( FALSE ) static void* DoTest(void* arg) { BOOL flag = TRUE; int i; (void)arg; if (!NETLockCrypto()) { OSHalt("failed to lock crypto"); } // Test AES-128 // see: FIPS-197 Appendix B and C { static const struct { u32 keylen; /* in bytes */ const char *key; const char *plain; const char *cipher; } samples[] = { { 128 / 8, "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", "\x32\x43\xf6\xa8\x88\x5a\x30\x8d\x31\x31\x98\xa2\xe0\x37\x07\x34", "\x39\x25\x84\x1d\x02\xdc\x09\xfb\xdc\x11\x85\x97\x19\x6a\x0b\x32", }, { 128 / 8, "\x00\x01\x02\x03\x04\x05\x06\x07" "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff", "\x69\xc4\xe0\xd8\x6a\x7b\x04\x30\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a", }, { 192 / 8, "\x00\x01\x02\x03\x04\x05\x06\x07" "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" "\x10\x11\x12\x13\x14\x15\x16\x17", "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff", "\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0\x6e\xaf\x70\xa0\xec\x0d\x71\x91", }, { 256 / 8, "\x00\x01\x02\x03\x04\x05\x06\x07" "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" "\x10\x11\x12\x13\x14\x15\x16\x17" "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff", "\x8e\xa2\xb7\xca\x51\x67\x45\xbf\xea\xfc\x49\x90\x4b\x49\x60\x89", }, }; for (i = 0; i < sizeof(samples) / sizeof(*samples); ++i) { NETAESContext ctx[1]; u8 iv[16]; u8 enc[NET_AES_BLOCK_LENGTH]; u8 dec[NET_AES_BLOCK_LENGTH]; BOOL result; OSReport("\ntest[%d] : AES-%d\n", i + 1, samples[i].keylen * 8); (void)memset(iv, 0x00, sizeof(iv)); (void)memset(enc, 0x00, sizeof(iv)); (void)memset(dec, 0x00, sizeof(iv)); (void)NETAESCreate(ctx, samples[i].key, samples[i].keylen, iv); (void)NETAESEncrypt(ctx, enc, samples[i].plain, sizeof(enc)); (void)NETAESDelete(ctx); result = TRUE; PrintResultBinaryEq(enc, samples[i].cipher, NET_AES_BLOCK_LENGTH, result); flag &= result; if (!result) { OSReport("\nenc-answer:"); PrintBinary(samples[i].cipher, NET_AES_BLOCK_LENGTH); OSReport("\nenc-result:"); PrintBinary(enc, NET_AES_BLOCK_LENGTH); OSReport("\n"); } (void)memset(iv, 0x00, sizeof(iv)); (void)NETAESCreate(ctx, samples[i].key, samples[i].keylen, iv); (void)NETAESDecrypt(ctx, dec, enc, sizeof(dec)); (void)NETAESDelete(ctx); result = TRUE; PrintResultBinaryEq(dec, samples[i].plain, NET_AES_BLOCK_LENGTH, result); flag &= result; if (!result) { OSReport("\ndec-answer:"); PrintBinary(samples[i].plain, NET_AES_BLOCK_LENGTH); OSReport("\ndec-result:"); PrintBinary(dec, NET_AES_BLOCK_LENGTH); OSReport("\n"); } OSReport("\n"); } } NETUnlockCrypto(); return (void*)flag; }