#include #include #include #include #include #include const std::string kTitleKeyPersonalisation[2] = { "Generic (AESCBC)", "Personalised (AESCBC/RSA2048)" }; const std::string kLicenseType[6] = { "PERMANENT", "DEMO", "TRIAL", "RENTAL", "SUBSCRIPTION", "SERVICE" }; const std::string kBooleanStr[2] = { "FALSE", "TRUE" }; const byte_t eticket_common_key[16] = { 0x55, 0xA3, 0xF8, 0x72, 0xBD, 0xC8, 0x0C, 0x55, 0x5A, 0x65, 0x43, 0x81, 0x13, 0x9E, 0x15, 0x3B }; // lol this 3ds dev common key int main(int argc, char** argv) { if (argc < 2) { printf("usage: tiktool \n"); return 1; } try { fnd::MemoryBlob file; fnd::io::readFile(argv[1], file); // import es::ETicketBody_V2 body; body.importBinary(file.getBytes() + 0x140, file.getSize() - 0x140); printf("[ETICKET]\n"); printf(" Issuer: %s\n", body.getIssuer().c_str()); printf(" Title Key:\n"); printf(" EncMode: %s\n", kTitleKeyPersonalisation[body.getTitleKeyEncType()].c_str()); printf(" CommonKeyId: %02X\n", body.getCommonKeyId()); printf(" EncData:"); size_t size = body.getTitleKeyEncType() == es::ETicketBody_V2::RSA2048 ? crypto::rsa::kRsa2048Size : crypto::aes::kAes128KeySize; for (uint32_t i = 0; i < size; i++) { if (i % 16 == 0) { printf("\n "); } printf("%02X%s", body.getEncTitleKey()[i], (i+1 != size) ? "" : "\n"); } if (body.getTitleKeyEncType() == es::ETicketBody_V2::AES128_CBC && body.getCommonKeyId() == 0) { byte_t iv[crypto::aes::kAesBlockSize]; byte_t key[crypto::aes::kAes128KeySize]; memcpy(iv, body.getRightsId(), crypto::aes::kAesBlockSize); crypto::aes::AesCbcDecrypt(body.getEncTitleKey(), crypto::aes::kAes128KeySize, eticket_common_key, iv, key); size = crypto::aes::kAes128KeySize; printf(" TitleKey:"); for (uint32_t i = 0; i < size; i++) { if (i % 16 == 0) { printf("\n "); } printf("%02X%s", key[i], (i + 1 != size) ? "" : "\n"); } } printf(" Version: v%d\n", body.getTicketVersion()); printf(" License Type: %s\n", kLicenseType[body.getLicenseType()].c_str()); printf(" Flags:\n"); printf(" PreInstall: %s\n", kBooleanStr[body.isPreInstall()].c_str()); printf(" SharedTitle: %s\n", kBooleanStr[body.isSharedTitle()].c_str()); printf(" AllContent: %s\n", kBooleanStr[body.allowAllContent()].c_str()); printf(" Reserved Region:"); for (uint32_t i = 0; i < 8; i++) { if (i % 16 == 0) { printf("\n "); } printf("%02X%s", body.getReservedRegion()[i], (i + 1 != 8) ? "" : "\n"); } printf(" TicketId: 0x%016" PRIx64 "\n", body.getTicketId()); printf(" DeviceId: 0x%016" PRIx64 "\n", body.getDeviceId()); } catch (const fnd::Exception& e) { printf("%s\n", e.what()); } return 0; }