Exemple #1
0
u32 NcchPadgen(u32 param)
{
    (void) (param); // param is unused here
    NcchInfo *info = (NcchInfo*)0x20316000;
    SeedInfo *seedinfo = (SeedInfo*)0x20400000;

    if (CheckKeySlot(0x25, 'X') != 0) {
        Debug("slot0x25KeyX not set up");
        Debug("7.x crypto will fail on O3DS < 7.x or A9LH");
    }
    if ((GetUnitPlatform() == PLATFORM_3DS) && (CheckKeySlot(0x18, 'X') != 0)) {
        Debug("slot0x18KeyX not set up");
        Debug("Secure3 crypto will fail");
    }
    if (CheckKeySlot(0x1B, 'X') != 0) {
        Debug("slot0x1BKeyX not set up");
        Debug("Secure4 crypto will fail");
    }
       
    if (DebugFileOpen("seeddb.bin")) {
        if (!DebugFileRead(seedinfo, 16, 0)) {
            FileClose();
            return 1;
        }
        if (!seedinfo->n_entries || seedinfo->n_entries > MAX_ENTRIES) {
            FileClose();
            Debug("Bad number of seeddb entries");
            return 1;
        }
        if (!DebugFileRead(seedinfo->entries, seedinfo->n_entries * sizeof(SeedInfoEntry), 16)) {
            FileClose();
            return 1;
        }
        FileClose();
    } else {
        Debug("9.x seed crypto 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) {
        FileClose();
        Debug("Bad number of entries in ncchinfo.bin");
        return 1;
    }
    if (info->ncch_info_version == 0xF0000004) { // ncchinfo v4
        if (!DebugFileRead(info->entries, info->n_entries * sizeof(NcchInfoEntry), 16)) {
            FileClose();
            return 1;
        }
    } else if (info->ncch_info_version == 0xF0000003) { // ncchinfo v3
        // read ncchinfo v3 entry & convert to ncchinfo v4
        for (u32 i = 0; i < info->n_entries; i++) {
            u8* entry_data = (u8*) (info->entries + i);
            if (!DebugFileRead(entry_data, 160, 16 + (160*i))) {
                FileClose();
                return 1;
            }
            memmove(entry_data + 56, entry_data + 48, 112);
            *(u64*) (entry_data + 48) = 0;
        }
    } else { // unknown file / ncchinfo version
        FileClose();
        Debug("Incompatible version ncchinfo.bin");
        return 1;
    }
    FileClose();

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

    for (u32 i = 0; i < info->n_entries; i++) { // check and fix filenames
        char* filename = info->entries[i].filename;
        if (filename[1] == 0x00) { // convert UTF-16 -> UTF-8
            for (u32 j = 1; j < (112 / 2); j++)
                filename[j] = filename[j*2];
        }
        if (memcmp(filename, "sdmc:", 5) == 0) // fix sdmc: prefix
            memmove(filename, filename + 5, 112 - 5);
    }
    
    for (u32 i = 0; i < info->n_entries; i++) {
        PadInfo padInfo = {.setKeyY = 1, .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, 112);
        Debug ("%2i: %s (%iMB)", i, info->entries[i].filename, info->entries[i].size_mb);
        
        // workaround to still be able to process old ncchinfo.bin
        if ((info->entries[i].ncchFlag7 == 0x01) && info->entries[i].ncchFlag3)
            info->entries[i].ncchFlag7 = 0x20; // this combination means seed crypto rather than FixedKey
        
        if (info->entries[i].ncchFlag7 & 0x20) { // seed crypto
            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 1;
            }
            u8 sha256sum[32];
            sha_quick(sha256sum, keydata, 32, SHA256_MODE);
            memcpy(padInfo.keyY, sha256sum, 16);
        } else {
            memcpy(padInfo.keyY, info->entries[i].keyY, 16);
        }
        
        if (info->entries[i].ncchFlag7 == 0x01) {
            u8 zeroKey[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
            u8 sysKey[16]  = {0x52, 0x7C, 0xE6, 0x30, 0xA9, 0xCA, 0x30, 0x5F, 0x36, 0x96, 0xF3, 0xCD, 0xE9, 0x54, 0x19, 0x4B};
            setup_aeskey(0x11, (info->entries[i].titleId & ((u64) 0x10 << 32)) ? sysKey : zeroKey);
            padInfo.setKeyY = 0;
            padInfo.keyslot = 0x11; // fixedKey crypto
        } else if (info->entries[i].ncchFlag3 == 0x0A) {
            padInfo.keyslot = 0x18; // Secure3 crypto, needs slot0x18KeyX.bin on O3DS
        } else if (info->entries[i].ncchFlag3 == 0x0B) {
            padInfo.keyslot = 0x1B; // Secure4 crypto, needs slot0x1BKeyX.bin
        } else if(info->entries[i].ncchFlag3 >> 8 == 0xDEC0DE) { // magic value to manually specify keyslot
            padInfo.keyslot = info->entries[i].ncchFlag3 & 0x3F;
        } else if (info->entries[i].ncchFlag3) {
            padInfo.keyslot = 0x25; // 7.x crypto
        } else {
            padInfo.keyslot = 0x2C; // standard crypto
        }
        Debug("Using keyslot: %02X", padInfo.keyslot);
        
        if (CreatePad(&padInfo) != 0)
            return 1; // this can't fail anyways
    }

    return 0;
}
Exemple #2
0
u32 SelfTest(u32 param)
{
    u8* test_data = (u8*) 0x20316000;
    const u8 teststr[16] = { 'D', '9', ' ', 'S', 'E', 'L', 'F', 'T', 'E', 'S', 'T', ' ', ' ', ' ', ' ' };
    const u8 zeroes[16] = { 0x00 };
    bool selftest = !(param & ST_REFERENCE);
    
    // check keyslots
    Debug("Checking keyslots...");
    Debug("0x05 KeyY: %s", (CheckKeySlot(0x05, 'Y') == 0) ? "set up" : "not set up");
    Debug("0x25 KeyX: %s", (CheckKeySlot(0x25, 'X') == 0) ? "set up" : "not set up");
    Debug("0x18 KeyX: %s", (CheckKeySlot(0x18, 'X') == 0) ? "set up" : "not set up");
    Debug("0x1B KeyX: %s", (CheckKeySlot(0x1B, 'X') == 0) ? "set up" : "not set up");
    Debug("");
    
    Debug((selftest) ? "Running selftest..." : "Creating selftest reference data...");
    
    // process all subtests
    u32 num_tests = sizeof(TestList) / sizeof(SubTestInfo);
    u8* test_ptr = test_data;
    u32 fsize_test = 0;
    for (u32 i = 0; i < num_tests; i++) {
        u32 size = TestList[i].size;
        u32 size_a = align(size, 16);
        u32 type = TestList[i].type;
        u32 tparam = TestList[i].param;
        
        memset(test_ptr, 0x00, 16 + size_a);
        strncpy((char*) test_ptr, TestList[i].name, 16);
        test_ptr += 16;
        
        if (type == ST_NAND_CID_HARD) {
            sdmmc_get_cid(1, (uint32_t*) test_ptr);
        } else if (type == ST_NAND_CID_MEM) {
            memcpy(test_ptr, (void*) 0x01FFCD84, 16);
        } else if (type == ST_SHA) {
            sha_quick(test_ptr, teststr, 16, tparam);
        } else if ((type == ST_AES_MODE) || (type == ST_AES_KEYSLOT) || (type == ST_AES_KEYSLOT_Y)) {
            CryptBufferInfo info = {.setKeyY = 0, .size = 16, .buffer = test_ptr};
            if (type == ST_AES_MODE) {
                info.mode = tparam;
                info.keyslot = 0x11;
                setup_aeskey(0x11, (void*) zeroes);
            } else {
                if (type == ST_AES_KEYSLOT_Y) {
                    info.setKeyY = 1;
                    memcpy(info.keyY, zeroes, 16);
                }
                info.mode = AES_CNT_CTRNAND_MODE;
                info.keyslot = tparam;
            }
            memset(info.ctr, 0x00, 16);
            memcpy(test_ptr, teststr, 16);
            CryptBuffer(&info);
        } else if (type == ST_TITLEKEYS) {
            TitleKeyEntry titlekey;
            memset(&titlekey, 0x00, sizeof(TitleKeyEntry));
            for (titlekey.commonKeyIndex = 0; titlekey.commonKeyIndex < 6; titlekey.commonKeyIndex++) {
                memset(titlekey.titleId, 0x00, 8);
                memset(titlekey.titleKey, 0x00, 16);
                CryptTitlekey(&titlekey, false);
                memcpy(test_ptr + (titlekey.commonKeyIndex * 16), titlekey.titleKey, 16);
            }     
        }
        
        test_ptr += size_a;
        fsize_test += 16 + size_a;
    }