Пример #1
0
static FRESULT initN3DSKeys()
{
    uint8_t buff[AES_BLOCK_SIZE];
	UINT br;
	FRESULT r;
	FIL f;

	r = f_open(&f, _T("key_0x16.bin"), FA_READ);
	if (r != FR_OK)
		return r;

	r = f_read(&f, buff, sizeof(buff), &br);
	if (br < sizeof(buff))
		return r == FR_OK ? EOF : r;

	f_close(&f);
	setup_aeskeyX(0x16, buff);

	r = f_open(&f, _T("key_0x1B.bin"), FA_READ);
	if (r != FR_OK)
		return r;

	r = f_read(&f, buff, sizeof(buff), &br);
	if (br < sizeof(buff))
		return r == FR_OK ? EOF : r;

	f_close(&f);
	setup_aeskeyX(0x1B, buff);
	return 0;
}
Пример #2
0
static int decryptFirmKtrArm9(void *p)
{
	uint8_t key[AES_BLOCK_SIZE];
	PartitionInfo info;
	Arm9Hdr *hdr;
	FirmSeg *seg, *btm;

	seg = ((FirmHdr *)p)->segs;
	for (btm = seg + FIRM_SEG_NUM; seg->isArm11; seg++)
		 if (seg == btm)
			 return -1;

	hdr = (void *)(p + seg->offset);

	info.ctr = hdr->ctr;
	info.buffer = (uint8_t *)hdr + 0x800;
	info.keyY = hdr->keyY;
	info.size = atoi(hdr->size);

	use_aeskey(0x11);
	if (hdr->ext.pad[0] == 0xFFFFFFFF) {
		info.keyslot = 0x15;
		aes_decrypt(hdr->keyX, key, NULL, 1, AES_ECB_DECRYPT_MODE);
	} else {
		info.keyslot = 0x16;
		aes_decrypt(hdr->ext.s.keyX_0x16, key, NULL, 1, AES_ECB_DECRYPT_MODE);
	}

	setup_aeskeyX(info.keyslot, key);
	return DecryptPartition(&info);
}
Пример #3
0
void ctr_twl_keyslot_setup(void)
{
	//Only a9lh really needs to bother with this, and it really only needs to happen once, before ITCM gets messed up.
	static bool setup = false;
	if (!setup && ctr_detect_a9lh_entry())
	{
		uint32_t* TwlCustId = (uint32_t*) (0x01FFB808);
		uint32_t TwlKeyX[4];
		alignas(32) uint8_t TwlKeyY[16];

		// thanks b1l1s & Normmatt
		// see source from https://gbatemp.net/threads/release-twltool-dsi-downgrading-save-injection-etc-multitool.393488/
		const char* nintendo = "NINTENDO";
		TwlKeyX[0] = (TwlCustId[0] ^ 0xB358A6AF) | 0x80000000;
		TwlKeyX[3] = TwlCustId[1] ^ 0x08C267B7;
		memcpy(TwlKeyX + 1, nintendo, 8);

		// see: https://www.3dbrew.org/wiki/Memory_layout#ARM9_ITCM
		uint32_t TwlKeyYW3 = 0xE1A00005;
		memcpy(TwlKeyY, (uint8_t*) 0x01FFD3C8, 12);
		memcpy(TwlKeyY + 12, &TwlKeyYW3, 4);

		setup_aeskeyX(0x03, (uint8_t*)TwlKeyX);
		setup_aeskeyY(0x03, TwlKeyY);
		use_aeskey(0x03);
	}
	setup = true;
}
Пример #4
0
void Key7X(void)
{
	size_t bytesRead;
	if (FSFileOpen("/slot0x25KeyX.bin")) {
		u8 slot0x25KeyX[16] = { 0 };

		bytesRead = FSFileRead(&slot0x25KeyX, 16, 0);
		FSFileClose();
		if (bytesRead != 16) {
			DrawDebug(0, 1, "slot0x25KeyX.bin is too small!");
		}
		DrawDebug(0, 1, "slot0x25KeyX.bin Found!");
		DrawDebug(0, 1, "");
		u8 zero[16] = { 0x00 };
		memcpy((u32*)0x01FFCD00, zero, 16);
		setup_aeskeyX(0x25, slot0x25KeyX);
	}
	else {
		DrawDebug(0, 1, "You can't perform firmlaunch without slot0x25KeyX.bin");
		int a;
		while (1)
		{
			a += 1;
			a -= 1;
		}
	}
}
Пример #5
0
// @breif Initialize N3DS keys
void KeyInit(void* source)
{
	int i;
	u8 firm_key[16] = { 0 };
	u8 * _source = (u8*)source;
	u8 firm_key_xored[16] = { 0xDE, 0x0E, 0x42, 0x0F, 0xE5, 0x75, 0x2C, 0xF0, 0x77, 0x4D, 0xA1, 0x87, 0x42, 0x33, 0xB9, 0xAA };
	for (i = 0; i<16; i++)
	{
		firm_key[i] = _source[i] ^ firm_key_xored[i];
	}
	setup_aeskeyX(0x16, firm_key);
	DrawDebug(0, 1, "N3DS Key Initialized!");
}
Пример #6
0
int main(){
	if (Initialize())
		while (1);

	//7.X Keys stuff
	File KeyFile;
	const char *keyfile = "/slot0x25KeyX.bin";
	if(FileOpen(&KeyFile, keyfile, 0)){
		uint8_t keyX[16];
		FileRead(&KeyFile, keyX, 16, 0);
		FileClose(&KeyFile);
		setup_aeskeyX(0x25, keyX);
	}else{
		if (sysver < 7) {
			ConsoleInit();
			ConsoleSetTitle(strings[STR_WARNING]);
			print(strings[STR_ERROR_OPENING], keyfile);
			print(strings[STR_WARNING_KEYFILE]);
			print(strings[STR_PRESS_BUTTON_ACTION], strings[STR_BUTTON_A], strings[STR_CONTINUE]);
			ConsoleShow();
			WaitForButton(BUTTON_A);
		}
	}

	//That's the Main Menu initialization, easy and cool
	OpenAnimation();
	MenuInit(&MainMenu);
	MenuShow();
	while (true) {
		uint32_t pad_state = InputWait();
		if (pad_state & (BUTTON_DOWN | BUTTON_RIGHT | BUTTON_R1)) MenuNextSelection(); //I try to support every theme style
		if (pad_state & (BUTTON_UP   | BUTTON_LEFT  | BUTTON_L1)) MenuPrevSelection();
		if (pad_state & BUTTON_A)    	{ OpenAnimation(); MenuSelect(); }
		if (pad_state & BUTTON_SELECT)	{ fadeOut(); ShutDown(); }
		if (pad_state & BUTTON_START)	{ fadeOut(); returnHomeMenu(); }
		TryScreenShot();
		MenuShow();
	}

	FSDeInit();
	return 0;
}
Пример #7
0
int main(){
	Initialize();
	DrawString(TOP_SCREEN, "SUPPORT THE ORIGINAL, NOT THE IMITATION!", 75, 240-10, GREY, BLACK);
	//7.X Keys stuff
	File KeyFile;
	if(FileOpen(&KeyFile, "/slot0x25KeyX.bin", 0)){
		u8 keyX[16];
		FileRead(&KeyFile, keyX, 16, 0);
		FileClose(&KeyFile);
		setup_aeskeyX(0x25, keyX);
		DrawString(TOP_SCREEN, " NewKeyX ", 0, 240-8, GREEN, BLACK);
	}else{
		if(GetSystemVersion() < 3){
			ConsoleInit();
			print("WARNING:\n\nCannot find slot0x25KeyX.bin.\nSome titles decryption will fail,\nand some some EmuNANDs will not boot.\n\nPress A to continue...\n");
			ConsoleShow();
			WaitForButton(BUTTON_A);
		}
		DrawString(TOP_SCREEN, " NewKeyX ", 0, 240-8, RED, BLACK);
	}
	DrawString(TOP_SCREEN, " EmuNAND ", 0, 240-16, checkEmuNAND() ? GREEN : RED, BLACK);

	//That's the Main Menu initialization, easy and cool
	MenuInit(&MainMenu);
	MenuShow();

    while (true) {
		DrawString(TOP_SCREEN,  "[SELECT] Reboot", 349-18*8, 181-24-8, RED, BLACK);
		DrawString(TOP_SCREEN,  "[START]  Shutdown", 349-18*8, 181-24, RED, BLACK);
        u32 pad_state = InputWait();
		if(pad_state & BUTTON_DOWN) 	MenuNextSelection();
		if(pad_state & BUTTON_UP)   	MenuPrevSelection();
		if(pad_state & BUTTON_A)    	MenuSelect();
		if(pad_state & BUTTON_SELECT)	returnHomeMenu();
		if(pad_state & BUTTON_START)	ShutDown();
		TryScreenShot();
		MenuShow();
    }

    FSDeInit();
    return 0;
}
Пример #8
0
u32 LoadKeyXFromFile(u32 keyslot)
{
    char filename[32];
    u8 keyX[16] = {0};
    
    snprintf(filename, 31, "%s/%02X" SUFFIX, dir, (unsigned int) keyslot);
    if (!FileOpen(filename)) {
        Debug("Loading %s: not found", filename);
        return 1;
    }
    if (FileRead(keyX, 16, 0) != 16) {
        Debug("Loading %s: bad file", filename);
        FileClose();
        return 1;
    }
    FileClose();
    setup_aeskeyX(keyslot, keyX);
    Debug("Loading %s: ok", filename);
    
    return 0;
}
Пример #9
0
int main(){
	Initialize();
	//7.X Keys stuff
	File KeyFile;
	if(FileOpen(&KeyFile, "/slot0x25KeyX.bin", 0)){
		u8 keyX[16];
		FileRead(&KeyFile, keyX, 16, 0);
		FileClose(&KeyFile);
		setup_aeskeyX(0x25, keyX);
	}else{
		if(GetSystemVersion() < 3){
			ConsoleInit();
			ConsoleSetTitle("          WARNING");
			print("WARNING:\n\nCannot find slot0x25KeyX.bin. If\nyour firmware version is less than\n7.X, some titles decryption will\nfail, and some EmuNANDs will not\nboot.\n\nPress A to continue...\n");
			ConsoleShow();
			WaitForButton(BUTTON_A);
		}
	}

	//That's the Main Menu initialization, easy and cool
	MenuInit(&MainMenu);
	MenuShow();

	while (true) {
		u32 pad_state = InputWait();
		if (pad_state & (BUTTON_DOWN | BUTTON_RIGHT | BUTTON_R1)) MenuNextSelection(); //I try to support every theme style
		if (pad_state & (BUTTON_UP   | BUTTON_LEFT  | BUTTON_L1)) MenuPrevSelection();
		if(pad_state & BUTTON_A)    	MenuSelect();
		if(pad_state & BUTTON_SELECT)	ShutDown();
		if(pad_state & BUTTON_START)	returnHomeMenu();
		TryScreenShot();
		MenuShow();
	}

	FSDeInit();
	return 0;
}
Пример #10
0
u32 NcchPadgen()
{
    u32 result;

    NcchInfo *info = (NcchInfo*)0x20316000;
    SeedInfo *seedinfo = (SeedInfo*)0x20400000;

    if (DebugFileOpen("/slot0x25KeyX.bin")) {
        u8 slot0x25KeyX[16] = {0};
        if (!DebugFileRead(&slot0x25KeyX, 16, 0)) {
            FileClose();
            return 1;
        }
        FileClose();
        setup_aeskeyX(0x25, slot0x25KeyX);
    } else {
        Debug("7.x game decryption will fail on less than 7.x!");
    }

    if (DebugFileOpen("/seeddb.bin")) {
        if (!DebugFileRead(seedinfo, 16, 0)) {
            FileClose();
            return 1;
        }
        if (!seedinfo->n_entries || seedinfo->n_entries > MAX_ENTRIES) {
            Debug("Too many/few seeddb entries.");
            return 1;
        }
        if (!DebugFileRead(seedinfo->entries, seedinfo->n_entries * sizeof(SeedInfoEntry), 16)) {
            FileClose();
            return 1;
        }
        FileClose();
    } else {
        // Debug("Warning, didn't open seeddb.bin");
        Debug("9.x seed crypto game decryption will fail!");
    }

    if (!DebugFileOpen("/ncchinfo.bin"))
        return 1;
    if (!DebugFileRead(info, 16, 0)) {
        FileClose();
        return 1;
    }

    if (!info->n_entries || info->n_entries > MAX_ENTRIES) {
        Debug("Too many/few entries in ncchinfo.bin");
        return 1;
    }
    if (info->ncch_info_version != 0xF0000004) {
        Debug("Wrong version ncchinfo.bin");
        return 1;
    }
    if (!DebugFileRead(info->entries, info->n_entries * sizeof(NcchInfoEntry), 16)) {
        FileClose();
        return 1;
    }
    FileClose();

    Debug("Number of entries: %i", info->n_entries);

    for(u32 i = 0; i < info->n_entries; i++) {
        Debug("Creating pad number: %i. Size (MB): %i", i+1, info->entries[i].size_mb);

        PadInfo padInfo = {.setKeyY = 1, .size_mb = info->entries[i].size_mb};
        memcpy(padInfo.CTR, info->entries[i].CTR, 16);
        memcpy(padInfo.filename, info->entries[i].filename, 112);
        if (info->entries[i].uses7xCrypto && info->entries[i].usesSeedCrypto) {
            u8 keydata[32];
            memcpy(keydata, info->entries[i].keyY, 16);
            u32 found_seed = 0;
            for (u32 j = 0; j < seedinfo->n_entries; j++) {
                if (seedinfo->entries[j].titleId == info->entries[i].titleId) {
                    found_seed = 1;
                    memcpy(&keydata[16], seedinfo->entries[j].external_seed, 16);
                    break;
                }
            }
            if (!found_seed)
            {
                Debug("Failed to find seed in seeddb.bin");
                return 0;
            }
            u8 sha256sum[32];
            sha256_context shactx;
            sha256_starts(&shactx);
            sha256_update(&shactx, keydata, 32);
            sha256_finish(&shactx, sha256sum);
            memcpy(padInfo.keyY, sha256sum, 16);
        }
        else
            memcpy(padInfo.keyY, info->entries[i].keyY, 16);

        if(info->entries[i].uses7xCrypto == 0xA) // won't work on an Old 3DS
            padInfo.keyslot = 0x18;
        else if(info->entries[i].uses7xCrypto >> 8 == 0xDEC0DE) // magic value to manually specify keyslot
            padInfo.keyslot = info->entries[i].uses7xCrypto & 0x3F;
        else if(info->entries[i].uses7xCrypto)
            padInfo.keyslot = 0x25;
        else
            padInfo.keyslot = 0x2C;
        Debug("Using keyslot: %02X", padInfo.keyslot);

        result = CreatePad(&padInfo);
        if (!result)
            Debug("Done!");
        else
            return 1;
    }

    return 0;
}
Пример #11
0
u32 SdPadgen(u32 param)
{
    (void) (param); // param is unused here
    SdInfo *info = (SdInfo*) 0x20316000;

    // setup AES key from SD
    SetupSdKeyY0x34(false, NULL);
    
    if (!DebugFileOpen("SDinfo.bin"))
        return 1;
    if (!DebugFileRead(info, 4, 0)) {
        FileClose();
        return 1;
    }
    if (!info->n_entries || info->n_entries > MAX_ENTRIES) {
        FileClose();
        Debug("Bad number of entries!");
        return 1;
    }
    if (!DebugFileRead(info->entries, info->n_entries * sizeof(SdInfoEntry), 4)) {
        FileClose();
        return 1;
    }
    FileClose();
    
    Debug("Number of entries: %i", info->n_entries);
    for(u32 i = 0; i < info->n_entries; i++) {
        PadInfo padInfo = {.keyslot = 0x34, .setKeyY = 0, .size_mb = info->entries[i].size_mb, .mode = AES_CNT_CTRNAND_MODE};
        memcpy(padInfo.ctr, info->entries[i].ctr, 16);
        memcpy(padInfo.filename, info->entries[i].filename, 180);
        Debug ("%2i: %s (%iMB)", i, info->entries[i].filename, info->entries[i].size_mb);
        if (CreatePad(&padInfo) != 0)
            return 1; // this can't fail anyways
    }

    return 0;
}

u32 SdPadgenDirect(u32 param)
{
    (void) (param); // param is unused here
    SdInfo *info = (SdInfo*) 0x20316000;
    char basepath[256];
    u8 movable_keyY[16];
    
    if (SetupSdKeyY0x34(true, movable_keyY) != 0)
        return 1; // movable.sed has to be present in NAND
    
    Debug("");
    if (SdFolderSelector(basepath, movable_keyY) != 0)
        return 1;
    Debug("");
    if (SdInfoGen(info, basepath) != 0)
        return 1;
    if (!info->n_entries) {
        Debug("Nothing found in folder");
        return 1;
    }
    
    Debug("Number of entries: %i", info->n_entries);
    for(u32 i = 0; i < info->n_entries; i++) {
        PadInfo padInfo = {.keyslot = 0x34, .setKeyY = 0, .size_mb = info->entries[i].size_mb, .mode = AES_CNT_CTRNAND_MODE};
        memcpy(padInfo.ctr, info->entries[i].ctr, 16);
        memcpy(padInfo.filename, info->entries[i].filename, 180);
        Debug ("%2i: %s (%iMB)", i, info->entries[i].filename, info->entries[i].size_mb);
        if (CreatePad(&padInfo) != 0)
            return 1; // this can't fail anyways
    }

    return 0;
}

u32 AnyPadgen(u32 param)
{
    (void) (param); // param is unused here
    AnyPadInfo *info = (AnyPadInfo*) 0x20316000;
    
    // get header
    if ((FileGetData("anypad.bin", info, 16, 0) != 16) || !info->n_entries || info->n_entries > MAX_ENTRIES) {
        Debug("Corrupt or not existing: anypad.bin");
        return 1;
    }
    
    // get data
    u32 data_size = info->n_entries * sizeof(AnyPadInfoEntry);
    if (FileGetData("anypad.bin", (u8*) info + 16, data_size, 16) != data_size) {
        Debug("File is missing data: anypad.bin");
        return 1;
    }
    
    Debug("Processing anypad.bin...");
    Debug("Number of entries: %i", info->n_entries);
    for (u32 i = 0; i < info->n_entries; i++) { // this translates all entries to a standard padInfo struct
        AnyPadInfoEntry* entry = &(info->entries[i]);
        PadInfo padInfo = {.keyslot = entry->keyslot, .setKeyY = 0, .size_mb = 0, .size_b = entry->size_b, .mode = entry->mode};
        memcpy(padInfo.filename, entry->filename, 80);
        memcpy(padInfo.ctr, entry->ctr, 16);
        // process keys
        if (entry->setNormalKey)
            setup_aeskey(entry->keyslot, entry->normalKey);
        if (entry->setKeyX)
            setup_aeskeyX(entry->keyslot, entry->keyX);
        if (entry->setKeyY)
            setup_aeskeyY(entry->keyslot, entry->keyY);
        use_aeskey(entry->keyslot);
        // process flags
        if (entry->flags & (AP_USE_NAND_CTR|AP_USE_SD_CTR)) {
            u32 ctr_add = getbe32(padInfo.ctr + 12);
            u8 shasum[32];
            u8 cid[16];
            sdmmc_get_cid((entry->flags & AP_USE_NAND_CTR) ? 1 : 0, (uint32_t*) cid);
            if (entry->mode == AES_CNT_TWLNAND_MODE) {
                sha_quick(shasum, cid, 16, SHA1_MODE);
                for (u32 i = 0; i < 16; i++)
                    padInfo.ctr[i] = shasum[15-i];
            } else {
                sha_quick(shasum, cid, 16, SHA256_MODE);
                memcpy(padInfo.ctr, shasum, 16);
            }
            add_ctr(padInfo.ctr, ctr_add);
        }
        // create the pad
        Debug ("%2i: %s (%ikB)", i, entry->filename, entry->size_b / 1024);
        if (CreatePad(&padInfo) != 0)
            return 1; // this can't fail anyways
    }

    return 0;
}

u32 CtrNandPadgen(u32 param)
{
    char* filename = (param & PG_FORCESLOT4) ? "nand.fat16.slot0x04.xorpad" : "nand.fat16.xorpad";
    u32 keyslot;
    u32 nand_size;

    // legacy sizes & offset, to work with Python 3DSFAT16Tool
    if (GetUnitPlatform() == PLATFORM_3DS) {
        if (param & PG_FORCESLOT4) {
            Debug("This is a N3DS only feature");
            return 1;
        }
        keyslot = 0x4;
        nand_size = 758;
    } else {
        keyslot = (param & PG_FORCESLOT4) ? 0x4 : 0x5;
        nand_size = 1055;
    }

    Debug("Creating NAND FAT16 xorpad. Size (MB): %u", nand_size);
    Debug("Filename: %s", filename);

    PadInfo padInfo = {
        .keyslot = keyslot,
        .setKeyY = 0,
        .size_mb = nand_size,
        .mode = AES_CNT_CTRNAND_MODE
    };
    strncpy(padInfo.filename, filename, 64);
    if(GetNandCtr(padInfo.ctr, 0xB930000) != 0)
        return 1;

    return CreatePad(&padInfo);
}

u32 TwlNandPadgen(u32 param)
{
    (void) (param); // param is unused here
    PartitionInfo* twln_info = GetPartitionInfo(P_TWLN);
    u32 size_mb = (twln_info->size + (1024 * 1024) - 1) / (1024 * 1024);
    Debug("Creating TWLN FAT16 xorpad. Size (MB): %u", size_mb);
    Debug("Filename: twlnand.fat16.xorpad");

    PadInfo padInfo = {
        .keyslot = twln_info->keyslot,
        .setKeyY = 0,
        .size_mb = size_mb,
        .filename = "twlnand.fat16.xorpad",
        .mode = AES_CNT_TWLNAND_MODE
    };
    if(GetNandCtr(padInfo.ctr, twln_info->offset) != 0)
        return 1;

    return CreatePad(&padInfo);
}

u32 Firm0Firm1Padgen(u32 param)
{
    (void) (param); // param is unused here
    PartitionInfo* firm0_info = GetPartitionInfo(P_FIRM0);
    PartitionInfo* firm1_info = GetPartitionInfo(P_FIRM1);
    u32 size_mb = (firm0_info->size + firm1_info->size + (1024 * 1024) - 1) / (1024 * 1024);
    Debug("Creating FIRM0FIRM1 xorpad. Size (MB): %u", size_mb);
    Debug("Filename: firm0firm1.xorpad");

    PadInfo padInfo = {
        .keyslot = firm0_info->keyslot,
        .setKeyY = 0,
        .size_mb = size_mb,
        .filename = "firm0firm1.xorpad",
        .mode = AES_CNT_CTRNAND_MODE
    };
    if(GetNandCtr(padInfo.ctr, firm0_info->offset) != 0)
        return 1;

    return CreatePad(&padInfo);
}
Пример #12
0
FRESULT LoadAllKeyXFromFile()
{
    char fpath[_MAX_LFN + 1];
    char *p;
    long keyslot;
    u8 key[AES_BLOCK_SIZE];
    FILINFO fno;
    FRESULT r;
    FIL f;
    DIR d;
    UINT br;

    r = f_opendir(&d, dir);
    if (r == FR_NO_PATH)
        return FR_OK;
    else if (r != FR_OK)
        return r;

    fno.lfname = NULL;

    while (1) {
        r = f_readdir(&d, &fno);
        if (r != FR_OK) {
            Debug("Failed to read directory %s: %d", dir, r);
            f_closedir(&d);

            return r;
        }

	if (fno.fname[0] == 0)
		break;

        keyslot = strtol(fno.fname, &p, 16);
        if (strcmp(p, SUFFIX))
            continue;

        snprintf(fpath, _MAX_LFN, "%s/%s", dir, fno.fname);
        r = f_open(&f, fpath, FA_READ);
        if (r) {
            Debug("Failed to open %s: %d", fpath, r);
            f_closedir(&d);

            return r;
        }

        r = f_read(&f, key, sizeof(key), &br);
        if (r) {
            Debug("Failed to read %s: %d", fpath, r);
            f_close(&f);
            f_closedir(&d);
            return r;
        }

        if (br < sizeof(key)) {
            Debug("%s is too small. expected: %d, result: %d",
                  fpath, br, sizeof(key));
            f_close(&f);
            f_closedir(&d);

            return -1;
        }

        f_close(&f);
        setup_aeskeyX(keyslot, key);
    }

    f_closedir(&d);
    return FR_OK;
}