Ejemplo n.º 1
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);
}
Ejemplo n.º 2
0
u32 CryptBuffer(CryptBufferInfo *info)
{
    u8 ctr[16] __attribute__((aligned(32)));
    memcpy(ctr, info->ctr, 16);

    u8* buffer = info->buffer;
    u32 size = info->size;
    u32 mode = info->mode;

    if (info->setKeyY) {
        u8 keyY[16] __attribute__((aligned(32)));
        memcpy(keyY, info->keyY, 16);
        setup_aeskeyY(info->keyslot, keyY);
        info->setKeyY = 0;
    }
    use_aeskey(info->keyslot);

    for (u32 i = 0; i < size; i += 0x10, buffer += 0x10) {
        if (((mode & (0x7 << 27)) != AES_ECB_DECRYPT_MODE) && ((mode & (0x7 << 27)) != AES_ECB_ENCRYPT_MODE))
            set_ctr(ctr);
        if ((mode & (0x7 << 27)) == AES_CBC_DECRYPT_MODE)
            memcpy(ctr, buffer, 0x10);
        aes_decrypt((void*) buffer, (void*) buffer, 1, mode);
        if ((mode & (0x7 << 27)) == AES_CBC_ENCRYPT_MODE)
            memcpy(ctr, buffer, 0x10);
        else if ((mode & (0x7 << 27)) == AES_CTR_MODE)
            add_ctr(ctr, 0x1);
    }

    memcpy(info->ctr, ctr, 16);
    
    return 0;
}
Ejemplo n.º 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;
}
Ejemplo n.º 4
0
u32 DecryptTitlekeys(void)
{
    EncKeysInfo *info = (EncKeysInfo*)0x20316000;

    if (!DebugFileOpen("/encTitleKeys.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 specified: %i", info->n_entries);
        FileClose();
        return 1;
    }

    Debug("Number of entries: %i", info->n_entries);
    if (!DebugFileRead(info->entries, info->n_entries * sizeof(TitleKeyEntry), 16)) {
        FileClose();
        return 1;
    }
    
    FileClose();

    Debug("Decrypting Title Keys...");

    u8 ctr[16] __attribute__((aligned(32)));
    u8 keyY[16] __attribute__((aligned(32)));
    u32 i;
    for (i = 0; i < info->n_entries; i++) {
        memset(ctr, 0, 16);
        memcpy(ctr, info->entries[i].titleId, 8);
        set_ctr(AES_BIG_INPUT|AES_NORMAL_INPUT, ctr);
        memcpy(keyY, (void *)common_keyy[info->entries[i].commonKeyIndex], 16);
        setup_aeskey(0x3D, AES_BIG_INPUT|AES_NORMAL_INPUT, keyY);
        use_aeskey(0x3D);
        aes_decrypt(info->entries[i].encryptedTitleKey, info->entries[i].encryptedTitleKey, ctr, 1, AES_CBC_DECRYPT_MODE);
    }

    if (!DebugFileCreate("/decTitleKeys.bin", true))
        return 1;
    if (!DebugFileWrite(info, info->n_entries * sizeof(TitleKeyEntry) + 16, 0)) {
        FileClose();
        return 1;
    }
    FileClose();

    Debug("Done!");

    return 0;
}
Ejemplo n.º 5
0
static inline void input(void *io, void *buffer, uint64_t block, size_t block_count)
{
	ctr_crypto_interface *crypto_io = io;
	if (block_count)
	{
		uint32_t mode = crypto_io->input_mode;
		alignas(4) uint8_t ctr[16];

		memcpy(ctr, crypto_io->ctr, 16);
		crypto_io->advance_ctr_input(crypto_io, buffer, block_count * crypto_io->block_size, block, ctr);

		use_aeskey(crypto_io->keySlot);

		crypto_io->crypto_input(buffer, buffer, block_count, mode, ctr);
	}
}
Ejemplo n.º 6
0
u32 DecryptPartition(PartitionInfo* info){
	size_t bytesWritten;
	if (info->keyY != NULL)
		setup_aeskey(info->keyslot, AES_BIG_INPUT | AES_NORMAL_INPUT, info->keyY);
	use_aeskey(info->keyslot);

	u8 ctr[16] __attribute__((aligned(32)));
	memcpy(ctr, info->ctr, 16);

	u32 size_bytes = info->size;
	for (u32 i = 0; i < size_bytes; i += BLOCK_SIZE) {
		u32 j;
		for (j = 0; (j < BLOCK_SIZE) && (i + j < size_bytes); j += 16) {
			set_ctr(AES_BIG_INPUT | AES_NORMAL_INPUT, ctr);
			aes_decrypt((void*)info->buffer + j, (void*)info->buffer + j, ctr, 1, AES_CTR_MODE);
			add_ctr(ctr, 1);
		}
	}
	return 0;
}
Ejemplo n.º 7
0
u32 DecryptPartition(PartitionInfo* info){
    size_t bytesWritten;
	if(info->keyY != NULL)
		setup_aeskey(info->keyslot, AES_BIG_INPUT|AES_NORMAL_INPUT, info->keyY);
    use_aeskey(info->keyslot);

    u8 ctr[16] __attribute__((aligned(32)));
    memcpy(ctr, info->ctr, 16);

    u32 size_bytes = info->size;
    for (u32 i = 0; i < size_bytes; i += BLOCK_SIZE) {
        u32 j;
        for (j = 0; (j < BLOCK_SIZE) && (i+j < size_bytes); j+= 16) {
            set_ctr(AES_BIG_INPUT|AES_NORMAL_INPUT, ctr);
            aes_decrypt((void*)info->buffer+j, (void*)info->buffer+j, ctr, 1, AES_CTR_MODE);
            add_ctr(ctr, 1);
			TryScreenShot(); //Putting it here allows us to take screenshots at any decryption point, since everyting loops in this
        }
    }
    return 0;
}
Ejemplo n.º 8
0
u32 DecryptBuffer(DecryptBufferInfo *info)
{
    u8 ctr[16] __attribute__((aligned(32)));
    memcpy(ctr, info->CTR, 16);

    u8* buffer = info->buffer;
    u32 size = info->size;

    if (info->setKeyY) {
        setup_aeskey(info->keyslot, AES_BIG_INPUT | AES_NORMAL_INPUT, info->keyY);
        info->setKeyY = 0;
    }
    use_aeskey(info->keyslot);

    for (u32 i = 0; i < size; i += 0x10, buffer += 0x10) {
        set_ctr(AES_BIG_INPUT | AES_NORMAL_INPUT, ctr);
        aes_decrypt((void*) buffer, (void*) buffer, ctr, 1, AES_CTR_MODE);
        add_ctr(ctr, 0x1);
    }

    memcpy(info->CTR, ctr, 16);

    return 0;
}
Ejemplo n.º 9
0
u32 NandPadgen()
{
    u8* ctrStart = FindNandCtr();
    if (ctrStart == NULL)
        return 1;

    u8 ctr[16] = {0x0};
    u32 i = 0;
    for(i = 0; i < 16; i++)
        ctr[i] = *(ctrStart + (15 - i)); //The CTR is stored backwards in memory.

    add_ctr(ctr, 0xB93000); //The CTR stored in memory would theoretically be for NAND block 0, so we need to increment it some.

    u32 keyslot = 0x0;
    u32 nand_size = 0;
    switch (GetUnitPlatform()) {
        case PLATFORM_3DS:
            keyslot = 0x4;
            nand_size = 758;
            break;
        case PLATFORM_N3DS:
            keyslot = 0x5;
            nand_size = 1055;
            break;
    }

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

    PadInfo padInfo = {.keyslot = keyslot, .setKeyY = 0, .size_mb = nand_size , .filename = "/nand.fat16.xorpad"};
    memcpy(padInfo.CTR, ctr, 16);

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

u32 CreatePad(PadInfo *info)
{
    static const uint8_t zero_buf[16] __attribute__((aligned(16))) = {0};
    u8* buffer = BUFFER_ADDRESS;
    u32 result = 0;
    
    if (!FileCreate(info->filename, true)) // No DebugFileCreate() here - messages are already given
        return 1;

    if(info->setKeyY)
        setup_aeskey(info->keyslot, AES_BIG_INPUT | AES_NORMAL_INPUT, info->keyY);
    use_aeskey(info->keyslot);

    u8 ctr[16] __attribute__((aligned(32)));
    memcpy(ctr, info->CTR, 16);

    u32 size_bytes = info->size_mb * 1024*1024;
    for (u32 i = 0; i < size_bytes; i += BUFFER_MAX_SIZE) {
        u32 curr_block_size = min(BUFFER_MAX_SIZE, size_bytes - i);

        for (u32 j = 0; j < curr_block_size; j+= 16) {
            set_ctr(AES_BIG_INPUT | AES_NORMAL_INPUT, ctr);
            aes_decrypt((void*)zero_buf, (void*)buffer + j, ctr, 1, AES_CTR_MODE);
            add_ctr(ctr, 1);
        }

        ShowProgress(i, size_bytes);

        if (!DebugFileWrite((void*)buffer, curr_block_size, i)) {
            result = 1;
            break;
        }
    }

    ShowProgress(0, 0);
    FileClose();

    return result;
}

u32 NandDumper() {
    u8* buffer = BUFFER_ADDRESS;
    u32 nand_size = (GetUnitPlatform() == PLATFORM_3DS) ? 0x3AF00000 : 0x4D800000;
    u32 result = 0;

    Debug("Dumping System NAND. Size (MB): %u", nand_size / (1024 * 1024));

    if (!DebugFileCreate("/NAND.bin", true))
        return 1;

    u32 n_sectors = nand_size / NAND_SECTOR_SIZE;
    for (u32 i = 0; i < n_sectors; i += SECTORS_PER_READ) {
        ShowProgress(i, n_sectors);
        sdmmc_nand_readsectors(i, SECTORS_PER_READ, buffer);
        if(!DebugFileWrite(buffer, NAND_SECTOR_SIZE * SECTORS_PER_READ, i * NAND_SECTOR_SIZE)) {
            result = 1;
            break;
        }
    }

    ShowProgress(0, 0);
    FileClose();

    return result;
}

u32 NandPartitionsDumper() {
    u32 ctrnand_offset;
    u32 ctrnand_size;
    u32 keyslot;

    switch (GetUnitPlatform()) {
    case PLATFORM_3DS:
        ctrnand_offset = 0x0B95CA00;
        ctrnand_size = 0x2F3E3600;
        keyslot = 0x4;
        break;
    case PLATFORM_N3DS:
        ctrnand_offset = 0x0B95AE00;
        ctrnand_size = 0x41D2D200;
        keyslot = 0x5;
        break;
    }

    // see: http://3dbrew.org/wiki/Flash_Filesystem
    Debug("Dumping firm0.bin: %s!", DumpPartition("firm0.bin", 0x0B130000, 0x00400000, 0x6) == 0 ? "succeeded" : "failed");
    Debug("Dumping firm1.bin: %s!", DumpPartition("firm1.bin", 0x0B530000, 0x00400000, 0x6) == 0 ? "succeeded" : "failed");
    Debug("Dumping ctrnand.bin: %s!", DumpPartition("ctrnand.bin", ctrnand_offset, ctrnand_size, keyslot) == 0 ? "succeeded" : "failed");

    return 0;
}
Ejemplo n.º 10
0
u32 SdPadgen()
{
    u32 result;

    SdInfo *info = (SdInfo*)0x20316000;

    u8 movable_seed[0x120] = {0};

    // Load console 0x34 keyY from movable.sed if present on SD card
    if (DebugFileOpen("/movable.sed")) {
        if (!DebugFileRead(&movable_seed, 0x120, 0)) {
            FileClose();
            return 1;
        }
        FileClose();
        if (memcmp(movable_seed, "SEED", 4) != 0) {
            Debug("movable.sed is too corrupt!");
            return 1;
        }
        setup_aeskey(0x34, AES_BIG_INPUT|AES_NORMAL_INPUT, &movable_seed[0x110]);
        use_aeskey(0x34);
    }

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

    if (!info->n_entries || info->n_entries > MAX_ENTRIES) {
        Debug("Too many/few entries!");
        return 1;
    }

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

    if (!DebugFileRead(info->entries, info->n_entries * sizeof(SdInfoEntry), 4)) {
        FileClose();
        return 1;
    }
    FileClose();

    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 = {.keyslot = 0x34, .setKeyY = 0, .size_mb = info->entries[i].size_mb};
        memcpy(padInfo.CTR, info->entries[i].CTR, 16);
        memcpy(padInfo.filename, info->entries[i].filename, 180);

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

    return 0;
}

static u8* FindNandCtr()
{
    static const char* versions[] = {"4.x", "5.x", "6.x", "7.x", "8.x", "9.x"};
    static const u8* version_ctrs[] = {
        (u8*)0x080D7CAC,
        (u8*)0x080D858C,
        (u8*)0x080D748C,
        (u8*)0x080D740C,
        (u8*)0x080D74CC,
        (u8*)0x080D794C
    };
    static const u32 version_ctrs_len = sizeof(version_ctrs) / sizeof(u32);

    for (u32 i = 0; i < version_ctrs_len; i++) {
        if (*(u32*)version_ctrs[i] == 0x5C980) {
            Debug("System version %s", versions[i]);
            return (u8*)(version_ctrs[i] + 0x30);
        }
    }

    // If value not in previous list start memory scanning (test range)
    for (u8* c = (u8*)0x080D8FFF; c > (u8*)0x08000000; c--) {
        if (*(u32*)c == 0x5C980 && *(u32*)(c + 1) == 0x800005C9) {
            Debug("CTR Start 0x%08X", c + 0x30);
            return c + 0x30;
        }
    }

    return NULL;
}

u32 DumpPartition(char* filename, u32 offset, u32 size, u32 keyslot) {
    DecryptBufferInfo info;
    u8* buffer = BUFFER_ADDRESS;
    u8* ctrStart = FindNandCtr();
    u32 result = 0;

    Debug("Dumping System NAND Partition. Size (MB): %u", size / (1024 * 1024));
    Debug("Filename: %s", filename);

    if (ctrStart == NULL)
        return 1;

    info.keyslot = keyslot;
    info.setKeyY = 0;
    info.size = SECTORS_PER_READ * NAND_SECTOR_SIZE;
    info.buffer = buffer;
    for (u32 i = 0; i < 16; i++) {
        info.CTR[i] = *(ctrStart + (0xF - i)); // The CTR is stored backwards in memory.
    }

    add_ctr(info.CTR, offset / 0x10);

    if (!DebugFileCreate(filename, true))
        return 1;

    u32 n_sectors = size / NAND_SECTOR_SIZE;
    u32 start_sector = offset / NAND_SECTOR_SIZE;
    for (u32 i = 0; i < n_sectors; i += SECTORS_PER_READ) {
        ShowProgress(i, n_sectors);
        sdmmc_nand_readsectors(start_sector + i, SECTORS_PER_READ, buffer);
        DecryptBuffer(&info);
        if (!DebugFileWrite(buffer, NAND_SECTOR_SIZE * SECTORS_PER_READ, i * NAND_SECTOR_SIZE)) {
            result = 1;
            break;
        }
    }

    ShowProgress(0, 0);
    FileClose();

    return result;
}
Ejemplo n.º 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);
}
Ejemplo n.º 12
0
uint32_t NcchPadgen()
{
	uint32_t result;
	File pf;
	NcchInfo *info = (NcchInfo*)0x20316000;

	const char *filename = "/ncchinfo.bin";
	wchar_t wfilename[14];
	mbstowcs(wfilename, filename, 14);
	if (!FileOpen(&pf, filename, 0)) {
		print(strings[STR_ERROR_OPENING], filename+1);
		return 1;
	}
	FileRead(&pf, info, 16, 0);

	if (info->ncch_info_version != 0xF0000003) {
        	print(strings[STR_WRONG], filename+1, strings[STR_VERSION]);
		return 0;
	}
	if (!info->n_entries || info->n_entries > MAXENTRIES) {
        	print(strings[STR_WRONG], filename+1, strings[STR_ENTRIES_COUNT]);
		return 0;
	}
	FileRead(&pf, info->entries, info->n_entries * sizeof(NcchInfoEntry), 16);
	FileClose(&pf);

	print(strings[STR_PROCESSING], wfilename+1);
	ConsoleShow();
	for(uint32_t i = 0; i < info->n_entries; i++) {
		PadInfo padInfo = {.setKeyY = 1, .size_mb = info->entries[i].size_mb};
		memcpy(padInfo.CTR, info->entries[i].CTR, 16);
		memcpy(padInfo.keyY, info->entries[i].keyY, 16);
		memcpy(padInfo.filename, info->entries[i].filename, 112);

		if(info->entries[i].uses7xCrypto)
			padInfo.keyslot = 0x25;
		else
			padInfo.keyslot = 0x2C;

		result = CreatePad(&padInfo, i);
		if (result) return 1;
	}

	return 0;
}

uint32_t SdPadgen()
{
	size_t bytesRead;
	uint32_t result;
	File fp;
	SdInfo *info = (SdInfo*)0x20316000;

	uint8_t movable_seed[0x120] = {0};
	const char *filename = "/movable.sed";
	wchar_t wfilename[13];
	mbstowcs(wfilename, filename, 13);
	// Load console 0x34 keyY from movable.sed if present on SD card
	if (FileOpen(&fp, filename, 0)) {
		bytesRead = FileRead(&fp, &movable_seed, 0x120, 0);
		FileClose(&fp);
		if (bytesRead != 0x120) {
			print(strings[STR_WRONG], filename+1, strings[STR_SIZE]);
			return 1;
		}
		if (memcmp(movable_seed, "SEED", 4) != 0) {
			print(strings[STR_WRONG], filename+1, strings[STR_CONTENT]);
			return 1;
		}
		setup_aeskey(0x34, AES_BIG_INPUT|AES_NORMAL_INPUT, &movable_seed[0x110]);
		use_aeskey(0x34);
	}

	filename = "/SDinfo.bin";
	if (!FileOpen(&fp, filename, 0)) {
		print(strings[STR_ERROR_OPENING], filename+1);
		return 1;
	}
	bytesRead = FileRead(&fp, info, 4, 0);

	if (!info->n_entries || info->n_entries > MAXENTRIES) {
        	print(strings[STR_WRONG], filename+1, strings[STR_ENTRIES_COUNT]);
		return 1;
	}

       	print(strings[STR_PROCESSING], wfilename+1);
	ConsoleShow();

	bytesRead = FileRead(&fp, info->entries, info->n_entries * sizeof(SdInfoEntry), 4);
	FileClose(&fp);

	for(uint32_t i = 0; i < info->n_entries; i++) {
		PadInfo padInfo = {.keyslot = 0x34, .setKeyY = 0, .size_mb = info->entries[i].size_mb};
		memcpy(padInfo.CTR, info->entries[i].CTR, 16);
		memcpy(padInfo.filename, info->entries[i].filename, 180);

		result = CreatePad(&padInfo, i);
		if (result)
			return 1;
	}

	return 0;
}

static const uint8_t zero_buf[16] __attribute__((aligned(16))) = {0};

uint32_t CreatePad(PadInfo *info, int index)
{
	File pf;
	#define BUFFER_ADDR ((volatile uint8_t*)0x21000000)
	#define BLOCK_SIZE  (4*1024*1024)

	if (!FileOpen(&pf, info->filename, 1))
		return 1;

	if(info->setKeyY != 0)
		setup_aeskey(info->keyslot, AES_BIG_INPUT|AES_NORMAL_INPUT, info->keyY);
	use_aeskey(info->keyslot);

	uint8_t ctr[16] __attribute__((aligned(32)));
	memcpy(ctr, info->CTR, 16);

	uint32_t size_bytes = info->size_mb*1024*1024;
	uint32_t size_100 = size_bytes/100;
	uint32_t seekpos = 0;
	for (uint32_t i = 0; i < size_bytes; i += BLOCK_SIZE) {
		uint32_t j;
		for (j = 0; (j < BLOCK_SIZE) && (i+j < size_bytes); j+= 16) {
			set_ctr(AES_BIG_INPUT|AES_NORMAL_INPUT, ctr);
			aes_decrypt((void*)zero_buf, (void*)BUFFER_ADDR+j, ctr, 1, AES_CTR_MODE);
			add_ctr(ctr, 1);
		}

		print(strings[STR_GENERATING], strings[STR_PAD]);
		print(L"%i : %i%%", index, (i+j)/size_100);
		ConsolePrevLine();
		ConsolePrevLine();
		ConsoleShow();
		FileWrite(&pf, (void*)BUFFER_ADDR, j, seekpos);
		seekpos += j;
	}

	FileClose(&pf);
	return 0;
}