From 8bb0e356a875e79d607830653cd96385d4de33b0 Mon Sep 17 00:00:00 2001 From: koolkdev Date: Sat, 11 Feb 2017 04:29:57 +0200 Subject: [PATCH] disc2app first commit --- Makefile | 2 +- src/fst.h | 34 +++ src/main.c | 556 ++++++++++++++++++++++++++++++++----------------- src/rijndael.c | 394 +++++++++++++++++++++++++++++++++++ src/rijndael.h | 9 + src/structs.h | 20 ++ src/tmd.h | 52 +++++ 7 files changed, 871 insertions(+), 196 deletions(-) create mode 100644 src/fst.h create mode 100644 src/rijndael.c create mode 100644 src/rijndael.h create mode 100644 src/structs.h create mode 100644 src/tmd.h diff --git a/Makefile b/Makefile index 0b9d6b5..7ba2b42 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ export OBJCOPY := $(PREFIX)objcopy # SOURCES is a list of directories containing source code # INCLUDES is a list of directories containing extra header files #--------------------------------------------------------------------------------- -TARGET := wudump +TARGET := disc2app BUILD := build BUILD_DBG := $(TARGET)_dbg SOURCES := src \ diff --git a/src/fst.h b/src/fst.h new file mode 100644 index 0000000..6985dc4 --- /dev/null +++ b/src/fst.h @@ -0,0 +1,34 @@ + +#ifndef _FST_H_ +#define _FST_H_ + +typedef struct _FEntry +{ + union + { + struct + { + uint32_t Type :8; + uint32_t NameOffset :24; + }; + uint32_t TypeName; + }; + union + { + struct // File Entry + { + uint32_t FileOffset; + uint32_t FileLength; + }; + struct // Dir Entry + { + uint32_t ParentOffset; + uint32_t NextOffset; + }; + uint32_t entry[2]; + }; + uint16_t Flags; + uint16_t ContentID; +} __attribute__ ((gcc_struct, __packed__)) FEntry; + +#endif diff --git a/src/main.c b/src/main.c index 1f5a74a..750560b 100644 --- a/src/main.c +++ b/src/main.c @@ -21,6 +21,12 @@ #include "main.h" #include "exploit.h" #include "../payload/wupserver_bin.h" +#include "rijndael.h" +#include "fst.h" +#include "tmd.h" +#include "structs.h" + +#define ALIGN_FORWARD(x, alignment) (((x) + ((alignment)-1)) & (~((alignment)-1))) //just to be able to call async void someFunc(void *arg) @@ -74,10 +80,62 @@ void println(int line, const char *msg) #define SECTOR_SIZE 2048 #define NUM_SECTORS 1024 +#define MAX_SECTORS 0xBA7400 + +static uint64_t odd_offset = 0; + +int fsa_odd_read_sectors(int fsa_fd, int fd, void *buf, unsigned int sector, unsigned int count, int retry) { + int res; + if (sector + count > MAX_SECTORS) return -1; + do { + res = IOSUHAX_FSA_RawRead(fsa_fd, buf, SECTOR_SIZE, count, sector, fd); + } while(retry && res < 0); + // Failed to read + return res; +} -int fsa_odd_read(int fsa_fd, int fd, void *buf, int offset) +int fsa_odd_read(int fsa_fd, int fd, char *buf, size_t len, int retry) { - return IOSUHAX_FSA_RawRead(fsa_fd, buf, SECTOR_SIZE, NUM_SECTORS, offset, fd); + if (!len) return 0; + + unsigned int sector = odd_offset / SECTOR_SIZE; + // Read unaligned first sector + size_t unaligned_length = (-odd_offset)%SECTOR_SIZE; + if (unaligned_length > len) unaligned_length = len; + if (unaligned_length) + { + char sector_buf[SECTOR_SIZE]; + if (fsa_odd_read_sectors(fsa_fd, fd, sector_buf, sector, 1, retry) < 0) return -1; + memcpy(buf, sector_buf + (odd_offset%SECTOR_SIZE), unaligned_length); + odd_offset += unaligned_length; + buf += unaligned_length; + len -= unaligned_length; + sector += 1; + } + if (!len) return 0; + unsigned int full_sectors = len / SECTOR_SIZE; + if (full_sectors) { + + if (fsa_odd_read_sectors(fsa_fd, fd, buf, sector, full_sectors, retry) < 0) return -1; + sector += full_sectors; + odd_offset += full_sectors * SECTOR_SIZE; + buf += full_sectors * SECTOR_SIZE; + len -= full_sectors * SECTOR_SIZE; + } + // Read unaligned last sector + if (len) + { + char sector_buf[SECTOR_SIZE]; + if (fsa_odd_read_sectors(fsa_fd, fd, sector_buf, sector, 1, retry) < 0) return -1; + memcpy(buf, sector_buf, len); + odd_offset += len; + } + return 0; +} + +static void fsa_odd_seek(uint64_t offset) +{ + odd_offset = offset; } int fsa_write(int fsa_fd, int fd, void *buf, int len) @@ -96,78 +154,17 @@ int fsa_write(int fsa_fd, int fd, void *buf, int len) return done; } -static const char *hdrStr = "wudump v1.5 by FIX94"; +static const char *hdrStr = "disc2app v1.0 (based on wudump and wud2app by FIX94)"; void printhdr_noflip() { println_noflip(0,hdrStr); } -void write_hash_file(char *fName, char *dir, unsigned int crc32, - md5_context *md5ctx, sha1_context *sha1ctx) -{ - unsigned int md5[4]; - md5_finish(md5ctx, (unsigned char*)md5); - unsigned int sha1[5]; - sha1_finish(sha1ctx, (unsigned char*)sha1); - - char wudPath[64]; - sprintf(wudPath, "%s/%s.txt", dir, fName); - FILE *f = fopen(wudPath, "w"); - if(f) - { - fprintf(f, "%s\n\n", hdrStr); - fprintf(f, "Hashes for %s.wud:\n", fName); - fprintf(f, "CRC32: %08X\n" - "MD5: %08X%08X%08X%08X\n" - "SHA1: %08X%08X%08X%08X%08X\n", - crc32, md5[0],md5[1],md5[2],md5[3], - sha1[0],sha1[1],sha1[2],sha1[3],sha1[4]); - fclose(f); - f = NULL; - } -} - -//imported OS zlib crc32 function pointer -static unsigned int (*zlib_crc32)(unsigned int crc32, const void *buf, int bufsize) = (void*)0; - -static const int bufSize = SECTOR_SIZE*NUM_SECTORS; -static void *sectorBuf = NULL; -static bool threadRunning = true; -static unsigned int crc32Val = 0; -static md5_context md5ctx; -static sha1_context sha1ctx; -static unsigned int crc32PartVal = 0; -static md5_context md5PartCtx; -static sha1_context sha1PartCtx; - -static int hashThread(s32 argc, void *args) -{ - (void)argc; - (void)args; - while(threadRunning) - { - //update global hashes - crc32Val = zlib_crc32(crc32Val, sectorBuf, bufSize); - md5_update(&md5ctx, sectorBuf, bufSize); - sha1_update(&sha1ctx, sectorBuf, bufSize); - //update hashes for part file - crc32PartVal = zlib_crc32(crc32PartVal, sectorBuf, bufSize); - md5_update(&md5PartCtx, sectorBuf, bufSize); - sha1_update(&sha1PartCtx, sectorBuf, bufSize); - //go back to sleep - OSSuspendThread(OSGetCurrentThread()); - } - return 0; -} - int Menu_Main(void) { InitOSFunctionPointers(); InitSysFunctionPointers(); InitVPadFunctionPointers(); - unsigned int zlib_handle = 0; - OSDynLoad_Acquire("zlib125.rpl", &zlib_handle); - OSDynLoad_FindExport(zlib_handle, 0, "crc32", &zlib_crc32); VPADInit(); memoryInitialize(); @@ -236,10 +233,9 @@ int Menu_Main(void) int fsaFd = -1; int oddFd = -1; int ret; - char wudumpPath[64]; - char wudPath[64]; - char keyPath[64]; + char outDir[64]; FILE *f = NULL; + sha1_context sha1ctx; //done with iosu exploit, take over mcp if(MCPHookOpen() < 0) @@ -293,59 +289,34 @@ int Menu_Main(void) goto prgEnd; } - //get our 2MB I/O Buffer and read out first sector - sectorBuf = MEMBucket_alloc(bufSize, 0x100); - if(sectorBuf == NULL || fsa_odd_read(fsaFd, oddFd, sectorBuf, 0) < 0) - { - println(line++,"Failed to read first disc sector!"); - goto prgEnd; - } - //get disc name for folder char discId[11]; discId[10] = '\0'; - memcpy(discId, sectorBuf, 10); + fsa_odd_seek(0); + if(fsa_odd_read(fsaFd, oddFd, discId, 10, 0)) + { + println(line++,"Failed to read first disc sector!"); + goto prgEnd; + } char discStr[64]; sprintf(discStr, "Inserted %s", discId); println(line++, discStr); - // make wudump dir we will write to + // make install dir we will write to char *device = (action == 0) ? "sd:" : "usb:"; - sprintf(wudumpPath, "%s/wudump", device); - mkdir(wudumpPath, 0x600); - sprintf(wudumpPath, "%s/wudump/%s", device, discId); - mkdir(wudumpPath, 0x600); + sprintf(outDir, "%s/install", device); + mkdir(outDir, 0x600); + sprintf(outDir, "%s/install/%s", device, discId); + mkdir(outDir, 0x600); + // Read common key u8 cKey[0x10]; memcpy(cKey, (void*)0xF5E104E0, 0x10); - sprintf(keyPath, "%s/common.key", wudumpPath); - f = fopen(keyPath, "wb"); - if(f == NULL) - { - println(line++,"Failed to write Common Key!"); - goto prgEnd; - } - fwrite(cKey, 1, 0x10, f); - fclose(f); - f = NULL; - println(line++,"Common Key dumped!"); - + // Read disc key u8 discKey[0x10]; memcpy(discKey, (void*)0xF5E10C00, 0x10); - sprintf(keyPath, "%s/game.key", wudumpPath); - f = fopen(keyPath, "wb"); - if(f == NULL) - { - println(line++,"Failed to write Disc Key!"); - goto prgEnd; - } - fwrite(discKey, 1, 0x10, f); - fclose(f); - f = NULL; - println(line++, "Disc Key dumped!"); - int apd_enabled = 0; IMIsAPDEnabled(&apd_enabled); if(apd_enabled) @@ -354,118 +325,315 @@ int Menu_Main(void) println(line++, "Disabled Auto Power-Down."); } - sprintf(discStr, "Dumping %s...", discId); - char progress[64]; - bool newF = true; - int part = 0; - unsigned int readSectors = 0; + sprintf(discStr, "Converting %s to app...", discId); + + println(line++, "Reading Disc FST from WUD"); + //read out and decrypt partition table + uint8_t *partTblEnc = MEMBucket_alloc(0x8000, 0x100); + fsa_odd_seek(0x18000); + fsa_odd_read(fsaFd, oddFd, partTblEnc, 0x8000, 1); + uint8_t iv[16]; + memset(iv,0,16); + aes_set_key(discKey); + uint8_t *partTbl = MEMBucket_alloc(0x8000, 0x100); + aes_decrypt(iv,partTblEnc,partTbl,0x8000); + MEMBucket_free(partTblEnc); + + if(*(uint32_t*)partTbl != 0xCCA6E67B) + { + println(line++, "Invalid FST!"); + goto prgEnd; + } + + //make sure TOC is actually valid + unsigned int expectedHash[5]; + expectedHash[0] = *(uint32_t*)(partTbl+8); + expectedHash[1] = *(uint32_t*)(partTbl+12); + expectedHash[2] = *(uint32_t*)(partTbl+16); + expectedHash[3] = *(uint32_t*)(partTbl+20); + expectedHash[4] = *(uint32_t*)(partTbl+24); - //full hashes - crc32Val = 0; - md5_starts(&md5ctx); sha1_starts(&sha1ctx); + sha1_update(&sha1ctx, partTbl+0x800, 0x7800); + unsigned int sha1[5]; + sha1_finish(&sha1ctx, (unsigned char*)sha1); + + if(memcmp(sha1, expectedHash, 0x14) != 0) + { + println(line++,"Invalid TOC SHA1!"); + goto prgEnd; + } - //part hashes - crc32PartVal = 0; - md5_starts(&md5PartCtx); - sha1_starts(&sha1PartCtx); + int numPartitions = *(uint32_t*)(partTbl+0x1C); + int siPart; + toc_t *tbl = (toc_t*)(partTbl+0x800); + void *tmdBuf = NULL; + bool certFound = false, tikFound = false, tmdFound = false; + uint8_t tikKey[16]; - //create hashing thread - void *stack = MEMBucket_alloc(0x4000, 0x20); - void *thread = memalign(8, 0x1000); //thread cant be in MEMBucket - OSCreateThread(thread, hashThread, 0, NULL, (unsigned int)stack+0x4000, 0x4000, 20, (1<> 16; + void *titleF = MEMBucket_alloc(ALIGN_FORWARD(CNTSize,16), 0x100); + fsa_odd_seek(offset + CNTOff); + fsa_odd_read(fsaFd, oddFd, titleF, ALIGN_FORWARD(CNTSize,16), 1); + uint8_t *titleDec = MEMBucket_alloc(ALIGN_FORWARD(CNTSize,16), 0x100); + memset(iv,0,16); + memcpy(iv + 8, &CNT_IV, 8); + aes_set_key(discKey); + aes_decrypt(iv,titleF,titleDec,ALIGN_FORWARD(CNTSize,16)); + MEMBucket_free(titleF); + char outF[64]; + sprintf(outF,"%s/%s",outDir,name); + //just write the first found cert, they're all the same anyways + if(strncasecmp(name, "title.cert", 11) == 0 && !certFound) + { + println(line++,"Writing title.cert"); + FILE *t = fopen(outF, "wb"); + if (t == NULL) { + println(line++,"Failed to create file"); + goto prgEnd; + } + fwrite(titleDec, 1, CNTSize, t); + fclose(t); + certFound = true; + } + else if(strncasecmp(name, "title.tik", 10) == 0 && !tikFound) { - if(f != NULL) + uint32_t tidHigh = *(uint32_t*)(titleDec+0x1DC); + if(tidHigh == 0x00050000) { - //close file - fclose(f); - f = NULL; - //write in file hashes - char tmpChar[64]; - sprintf(tmpChar, "game_part%i", part); - write_hash_file(tmpChar, wudumpPath, crc32PartVal, - &md5PartCtx, &sha1PartCtx); - //open new hashes - crc32PartVal = 0; - md5_starts(&md5PartCtx); - sha1_starts(&sha1PartCtx); + println(line++,"Writing title.tik"); + FILE *t = fopen(outF, "wb"); + if (t == NULL) { + println(line++,"Failed to create file"); + goto prgEnd; + } + fwrite(titleDec, 1, CNTSize, t); + fclose(t); + tikFound = true; + uint8_t *title_id = titleDec+0x1DC; + int k; + for(k = 0; k < 8; k++) + { + iv[k] = title_id[k]; + iv[k + 8] = 0x00; + } + uint8_t *tikKeyEnc = titleDec+0x1BF; + aes_set_key(cKey); + aes_decrypt(iv,tikKeyEnc,tikKey,16); } - //set part int for next file - part++; - sprintf(wudPath, "%s/game_part%i.wud", wudumpPath, part); - f = fopen(wudPath, "wb"); - if(f == NULL) - break; - newF = false; } - //read offsets until no error returns - do { - ret = fsa_odd_read(fsaFd, oddFd, sectorBuf, readSectors); - } while(ret < 0); - //update hashes in thread - OSResumeThread(thread); - //write in new offsets - fwrite(sectorBuf, 1, bufSize, f); - readSectors += NUM_SECTORS; - if((readSectors % 0x100000) == 0) - newF = true; //new file every 2gb - if((readSectors % 0x2000) == 0) + else if(strncasecmp(name, "title.tmd", 10) == 0 && !tmdFound) + { + uint32_t tidHigh = *(uint32_t*)(titleDec+0x18C); + if(tidHigh == 0x00050000) + { + println(line++,"Writing title.tmd"); + FILE *t = fopen(outF, "wb"); + if (t == NULL) { + println(line++,"Failed to create file"); + goto prgEnd; + } + fwrite(titleDec, 1, CNTSize, t); + fclose(t); + tmdFound = true; + tmdBuf = MEMBucket_alloc(CNTSize, 0x100); + memcpy(tmdBuf, titleDec, CNTSize); + } + } + MEMBucket_free(titleDec); + } + OSScreenClearBufferEx(0, 0); + OSScreenClearBufferEx(1, 0); + MEMBucket_free(fstDec); + + if(!tikFound || !tmdFound) + { + println(line++,"tik or tmd not found!"); + goto prgEnd; + } + TitleMetaData *tmd = (TitleMetaData*)tmdBuf; + char gmChar[19]; + char gmmsg[64]; + uint64_t fullTid = tmd->TitleID; + sprintf(gmChar,"GM%016" PRIx64, fullTid); + sprintf(gmmsg,"Searching for %s Partition", gmChar); + println(line++,gmmsg); + uint32_t appBufLen = SECTOR_SIZE*NUM_SECTORS; + void *appBuf = MEMBucket_alloc(appBufLen, 0x100); + //write game .app data next + int gmPart; + for(gmPart = 0; gmPart < numPartitions; gmPart++) + { + if(strncasecmp(tbl[gmPart].name,gmChar,18) == 0) + break; + } + if(strncasecmp(tbl[gmPart].name,gmChar,18) != 0) + { + println(line++,"No GM Partition found!"); + goto prgEnd; + } + println(line++,"Reading GM Header from WUD"); + offset = ((uint64_t)tbl[gmPart].offsetBE)*0x8000; + uint8_t *fHdr = MEMBucket_alloc(0x8000, 0x100); + fsa_odd_seek(offset); + fsa_odd_read(fsaFd, oddFd, fHdr, 0x8000, 1); + uint32_t fHdrCnt = *(uint32_t*)(fHdr+0x10); + uint8_t *hashPos = fHdr + 0x40 + (fHdrCnt*4); + + //grab FST first + println(line++,"Reading GM FST from WUD"); + uint64_t fstSize = tmd->Contents[0].Size; + fstEnc = MEMBucket_alloc(ALIGN_FORWARD(fstSize,16), 0x100); + fsa_odd_seek(offset + 0x8000); + fsa_odd_read(fsaFd, oddFd, fstEnc, ALIGN_FORWARD(fstSize,16), 1); + //write FST to file + uint32_t fstContentCid = tmd->Contents[0].ID; + char outF[64]; + char outbuf[64]; + sprintf(outF,"%s/%08x.app",outDir,fstContentCid); + sprintf(outbuf, "Writing %08x.app",fstContentCid); + println(line, outbuf); + FILE *t = fopen(outF, "wb"); + if (t == NULL) { + println(line++,"Failed to create file"); + goto prgEnd; + } + fwrite(fstEnc, 1, ALIGN_FORWARD(fstSize,16), t); + fclose(t); + //decrypt FST to use now + memset(iv, 0, 16); + uint16_t content_index = tmd->Contents[0].Index; + memcpy(iv, &content_index, 2); + aes_set_key(tikKey); + fstDec = MEMBucket_alloc(ALIGN_FORWARD(fstSize,16), 0x100); + aes_decrypt(iv, fstEnc, fstDec, ALIGN_FORWARD(fstSize,16)); + MEMBucket_free(fstEnc); + app_tbl_t *appTbl = (app_tbl_t*)(fstDec+0x20); + + //write in files + uint16_t titleCnt = tmd->ContentCount; + uint16_t curCont; + char progress[64]; + for(curCont = 1; curCont < titleCnt; curCont++) + { + uint64_t appOffset = ((uint64_t)appTbl[curCont].offsetBE)*0x8000; + uint64_t totalAppOffset = offset + appOffset; + fsa_odd_seek(totalAppOffset); + uint64_t tSize = tmd->Contents[curCont].Size; + uint32_t curContentCid = tmd->Contents[curCont].ID; + char outF[64]; + char outbuf[64]; + char titlesmsg[64]; + sprintf(titlesmsg,"Dumping title %d/%d",curCont,titleCnt-1); + sprintf(outF,"%s/%08x.app",outDir,curContentCid); + sprintf(outbuf,"Writing %08x.app",curContentCid); + OSScreenClearBufferEx(0, 0); + OSScreenClearBufferEx(1, 0); + printhdr_noflip(); + println_noflip(2,discStr); + println_noflip(3,titlesmsg); + println_noflip(4,outbuf); + OSScreenFlipBuffersEx(0); + OSScreenFlipBuffersEx(1); + line=5; + FILE *t = fopen(outF, "wb"); + if (t == NULL) { + println(line++,"Failed to create file"); + goto prgEnd; + } + uint64_t total = tSize; + while(total > 0) { + uint32_t toWrite = ((total > (uint64_t)appBufLen) ? (appBufLen) : (uint32_t)(total)); + sprintf(progress,"0x%08X/0x%08X (%i%%)",(uint32_t)(tSize-total),(uint32_t)tSize,(uint32_t)((tSize-total)*100/tSize)); + fsa_odd_read(fsaFd, oddFd, appBuf, toWrite, 1); + fwrite(appBuf, 1, toWrite, t); + total -= toWrite; OSScreenClearBufferEx(0, 0); OSScreenClearBufferEx(1, 0); - sprintf(progress,"0x%06X/0xBA7400 (%i%%)",readSectors,(readSectors*100)/0xBA7400); printhdr_noflip(); println_noflip(2,discStr); - println_noflip(3,progress); + println_noflip(3,titlesmsg); + println_noflip(4,outbuf); + println_noflip(5,progress); OSScreenFlipBuffersEx(0); OSScreenFlipBuffersEx(1); } - //wait for hashes to get done - while(!OSIsThreadSuspended(thread)) ; - } - - //write last part hash - if(f != NULL) - { - //close file - fclose(f); - f = NULL; - //write in file hashes - char tmpChar[64]; - sprintf(tmpChar, "game_part%i", part); - write_hash_file(tmpChar, wudumpPath, crc32PartVal, &md5PartCtx, &sha1PartCtx); + line=6; + fclose(t); + uint16_t type = tmd->Contents[curCont].Type; + if(type & 2) //h3 hashes used + { + char outF[64]; + char outbuf[64]; + sprintf(outF,"%s/%08x.h3",outDir,curContentCid); + sprintf(outbuf,"Writing %08x.h3",curContentCid); + println(line++,outbuf); + t = fopen(outF, "wb"); + if (t == NULL) { + println(line++,"Failed to create file"); + goto prgEnd; + } + uint32_t hashNum = (uint32_t)((tSize / 0x10000000ULL) + 1); + fwrite(hashPos, 1, (0x14*hashNum), t); + fclose(t); + hashPos += (0x14*hashNum); + } } + MEMBucket_free(fstDec); + MEMBucket_free(appBuf); + MEMBucket_free(tmdBuf); - //write global hashes into file - write_hash_file("game", wudumpPath, crc32Val, &md5ctx, &sha1ctx); - - //close down hash thread - threadRunning = false; - OSResumeThread(thread); - OSJoinThread(thread, &ret); - free(thread); //thread cant be in MEMBucket - MEMBucket_free(stack); + println(line++,"Done!"); - //all finished! - OSScreenClearBufferEx(0, 0); - OSScreenClearBufferEx(1, 0); - sprintf(progress,"0x%06X/0xBA7400 (%i%%)",readSectors,(readSectors*100)/0xBA7400); - printhdr_noflip(); - println_noflip(2,discStr); - println_noflip(3,progress); - if(readSectors == 0xBA7400) - println_noflip(4,"Disc dumped!"); - else //only error we handle while dumping - println_noflip(4,"Failed to write Disc WUD!"); if(apd_enabled) { if(IMEnableAPD() == 0) - println_noflip(5, "Re-Enabled Auto Power-Down."); + println_noflip(line++, "Re-Enabled Auto Power-Down."); } OSScreenFlipBuffersEx(0); OSScreenFlipBuffersEx(1); @@ -481,8 +649,6 @@ int Menu_Main(void) if(oddFd >= 0) IOSUHAX_FSA_RawClose(fsaFd, oddFd); IOSUHAX_FSA_Close(fsaFd); - if(sectorBuf != NULL) - MEMBucket_free(sectorBuf); } //close out old mcp instance MCPHookClose(); diff --git a/src/rijndael.c b/src/rijndael.c new file mode 100644 index 0000000..db48c10 --- /dev/null +++ b/src/rijndael.c @@ -0,0 +1,394 @@ +/* Rijndael Block Cipher - rijndael.c + + Written by Mike Scott 21st April 1999 + mike@compapp.dcu.ie + + Permission for free direct or derivative use is granted subject + to compliance with any conditions that the originators of the + algorithm place on its exploitation. + +*/ + +#include +#include + +/* rotates x one bit to the left */ + +#define ROTL(x) (((x)>>7)|((x)<<1)) + +/* Rotates 32-bit word left by 1, 2 or 3 byte */ + +#define ROTL8(x) (((x)<<8)|((x)>>24)) +#define ROTL16(x) (((x)<<16)|((x)>>16)) +#define ROTL24(x) (((x)<<24)|((x)>>8)) + +/* Fixed Data */ + +static unsigned char InCo[4]={0xB,0xD,0x9,0xE}; /* Inverse Coefficients */ + +static unsigned char fbsub[256]; +static unsigned char rbsub[256]; +static unsigned char ptab[256],ltab[256]; +static unsigned int ftable[256]; +static unsigned int rtable[256]; +static unsigned int rco[30]; + +/* Parameter-dependent data */ + +int Nk,Nb,Nr; +unsigned char fi[24],ri[24]; +unsigned int fkey[120]; +unsigned int rkey[120]; + +static unsigned int pack(unsigned char *b) +{ /* pack bytes into a 32-bit Word */ + return ((unsigned int)b[3]<<24)|((unsigned int)b[2]<<16)|((unsigned int)b[1]<<8)|(unsigned int)b[0]; +} + +static void unpack(unsigned int a,unsigned char *b) +{ /* unpack bytes from a word */ + b[0]=(unsigned char)a; + b[1]=(unsigned char)(a>>8); + b[2]=(unsigned char)(a>>16); + b[3]=(unsigned char)(a>>24); +} + +static unsigned char xtime(unsigned char a) +{ + unsigned char b; + if (a&0x80) b=0x1B; + else b=0; + a<<=1; + a^=b; + return a; +} + +static unsigned char bmul(unsigned char x,unsigned char y) +{ /* x.y= AntiLog(Log(x) + Log(y)) */ + if (x && y) return ptab[(ltab[x]+ltab[y])%255]; + else return 0; +} + +static unsigned int SubByte(unsigned int a) +{ + unsigned char b[4]; + unpack(a,b); + b[0]=fbsub[b[0]]; + b[1]=fbsub[b[1]]; + b[2]=fbsub[b[2]]; + b[3]=fbsub[b[3]]; + return pack(b); +} + +static unsigned char product(unsigned int x,unsigned int y) +{ /* dot product of two 4-byte arrays */ + unsigned char xb[4],yb[4]; + unpack(x,xb); + unpack(y,yb); + return bmul(xb[0],yb[0])^bmul(xb[1],yb[1])^bmul(xb[2],yb[2])^bmul(xb[3],yb[3]); +} + +static unsigned int InvMixCol(unsigned int x) +{ /* matrix Multiplication */ + unsigned int y,m; + unsigned char b[4]; + + m=pack(InCo); + b[3]=product(m,x); + m=ROTL24(m); + b[2]=product(m,x); + m=ROTL24(m); + b[1]=product(m,x); + m=ROTL24(m); + b[0]=product(m,x); + y=pack(b); + return y; +} + +unsigned char ByteSub(unsigned char x) +{ + unsigned char y=ptab[255-ltab[x]]; /* multiplicative inverse */ + x=y; x=ROTL(x); + y^=x; x=ROTL(x); + y^=x; x=ROTL(x); + y^=x; x=ROTL(x); + y^=x; y^=0x63; + return y; +} + +void gentables(void) +{ /* generate tables */ + int i; + unsigned char y,b[4]; + + /* use 3 as primitive root to generate power and log tables */ + + ltab[0]=0; + ptab[0]=1; ltab[1]=0; + ptab[1]=3; ltab[3]=1; + for (i=2;i<256;i++) + { + ptab[i]=ptab[i-1]^xtime(ptab[i-1]); + ltab[ptab[i]]=i; + } + + /* affine transformation:- each bit is xored with itself shifted one bit */ + + fbsub[0]=0x63; + rbsub[0x63]=0; + for (i=1;i<256;i++) + { + y=ByteSub((unsigned char)i); + fbsub[i]=y; rbsub[y]=i; + } + + for (i=0,y=1;i<30;i++) + { + rco[i]=y; + y=xtime(y); + } + + /* calculate forward and reverse tables */ + for (i=0;i<256;i++) + { + y=fbsub[i]; + b[3]=y^xtime(y); b[2]=y; + b[1]=y; b[0]=xtime(y); + ftable[i]=pack(b); + + y=rbsub[i]; + b[3]=bmul(InCo[0],y); b[2]=bmul(InCo[1],y); + b[1]=bmul(InCo[2],y); b[0]=bmul(InCo[3],y); + rtable[i]=pack(b); + } +} + +void gkey(int nb,int nk,unsigned char *key) +{ /* blocksize=32*nb bits. Key=32*nk bits */ + /* currently nb,bk = 4, 6 or 8 */ + /* key comes as 4*Nk bytes */ + /* Key Scheduler. Create expanded encryption key */ + int i,j,k,m,N; + int C1,C2,C3; + unsigned int CipherKey[8]; + + Nb=nb; Nk=nk; + + /* Nr is number of rounds */ + if (Nb>=Nk) Nr=6+Nb; + else Nr=6+Nk; + + C1=1; + if (Nb<8) { C2=2; C3=3; } + else { C2=3; C3=4; } + + /* pre-calculate forward and reverse increments */ + for (m=j=0;j>8)])^ + ROTL16(ftable[(unsigned char)(x[fi[m+1]]>>16)])^ + ROTL24(ftable[x[fi[m+2]]>>24]); + } + t=x; x=y; y=t; /* swap pointers */ + } + +/* Last Round - unroll if possible */ + for (m=j=0;j>8)])^ + ROTL16((unsigned int)fbsub[(unsigned char)(x[fi[m+1]]>>16)])^ + ROTL24((unsigned int)fbsub[x[fi[m+2]]>>24]); + } + for (i=j=0;i>8)])^ + ROTL16(rtable[(unsigned char)(x[ri[m+1]]>>16)])^ + ROTL24(rtable[x[ri[m+2]]>>24]); + } + t=x; x=y; y=t; /* swap pointers */ + } + +/* Last Round - unroll if possible */ + for (m=j=0;j>8)])^ + ROTL16((unsigned int)rbsub[(unsigned char)(x[ri[m+1]]>>16)])^ + ROTL24((unsigned int)rbsub[x[ri[m+2]]>>24]); + } + for (i=j=0;i