#include "KeyBag.h" #include "util.h" #include #include #include #include #include #include #include #include nstool::KeyBagInitializer::KeyBagInitializer(bool isDev, const tc::Optional& keyfile_path, const tc::Optional& tik_path, const tc::Optional& cert_path) { if (keyfile_path.isSet()) { importBaseKeyFile(keyfile_path.get(), isDev); } if (cert_path.isSet()) { importCertificateChain(cert_path.get()); } if (tik_path.isSet()) { importTicket(tik_path.get()); } // this will populate known keys if they aren't supplied by the user provided keyfiles. importKnownKeys(isDev); } void nstool::KeyBagInitializer::importBaseKeyFile(const tc::io::Path& keyfile_path, bool isDev) { std::shared_ptr keyfile_stream = std::make_shared(tc::io::FileStream(keyfile_path, tc::io::FileMode::Open, tc::io::FileAccess::Read)); // import keyfile into a dictionary std::map keyfile_dict; processResFile(keyfile_stream, keyfile_dict); // sources for key derivation std::map master_key; tc::Optional package2_key_source; tc::Optional ticket_titlekek_source; std::array, 3> key_area_key_source; tc::Optional aes_kek_generation_source; tc::Optional aes_key_generation_source; tc::Optional nca_header_kek_source; tc::Optional nca_header_key_source; tc::Optional pki_root_sign_key; // macros for importing #define _SAVE_AES128KEY(key_name, dst) \ { \ std::string key,val; \ tc::ByteData dec_val; \ aes128_key_t tmp_aes128_key; \ key = (key_name); \ val = keyfile_dict[key]; \ if (val.empty() == false) { \ dec_val = tc::cli::FormatUtil::hexStringToBytes(val); \ if (dec_val.size() != tmp_aes128_key.size()) \ throw tc::ArgumentException("nstool::KeyBagInitializer", "Key: \"" + key_name + "\" has incorrect length"); \ memcpy(tmp_aes128_key.data(), dec_val.data(), tmp_aes128_key.size()); \ (dst) = tmp_aes128_key; \ } \ } #define _SAVE_AES128XTSKEY(key_name, dst) \ { \ std::string key,val; \ tc::ByteData dec_val; \ aes128_xtskey_t tmp_aes128_xtskey; \ key = (key_name); \ val = keyfile_dict[key]; \ if (val.empty() == false) { \ dec_val = tc::cli::FormatUtil::hexStringToBytes(val); \ if (dec_val.size() != sizeof(tmp_aes128_xtskey)) \ throw tc::ArgumentException("nstool::KeyBagInitializer", "Key: \"" + key_name + "\" has incorrect length"); \ memcpy(tmp_aes128_xtskey[0].data(), dec_val.data(), tmp_aes128_xtskey[0].size()); \ memcpy(tmp_aes128_xtskey[1].data(), dec_val.data()+tmp_aes128_xtskey[0].size(), tmp_aes128_xtskey[1].size()); \ (dst) = tmp_aes128_xtskey; \ } \ } #define _SAVE_RSAKEY(key_name, dst, bitsize) \ { \ std::string key_mod,key_prv,val_mod,val_prv; \ tc::ByteData dec_val; \ rsa_key_t tmp_rsa_key; \ key_mod = fmt::format("{:s}_modulus", (key_name)); \ key_prv = fmt::format("{:s}_private", (key_name)); \ val_mod = keyfile_dict[key_mod]; \ val_prv = keyfile_dict[key_prv]; \ if (val_mod.empty() == false) { \ dec_val = tc::cli::FormatUtil::hexStringToBytes(val_mod); \ if (dec_val.size() == (bitsize) >> 3) { \ tmp_rsa_key.n = dec_val; \ if (val_prv.empty() == false) { \ dec_val = tc::cli::FormatUtil::hexStringToBytes(val_prv); \ if (dec_val.size() == (bitsize) >> 3) { \ tmp_rsa_key.d = dec_val; \ (dst) = tc::crypto::RsaPrivateKey(tmp_rsa_key.n.data(), tmp_rsa_key.n.size(), tmp_rsa_key.d.data(), tmp_rsa_key.d.size()); \ } \ else { \ fmt::print("[WARNING] Key: \"{:s}\" has incorrect length (was: {:d}, expected {:d})\n", key_prv, val_prv.size(), ((bitsize) >> 3)*2); \ } \ } \ else { \ (dst) = tc::crypto::RsaPublicKey(tmp_rsa_key.n.data(), tmp_rsa_key.n.size()); \ } \ } \ else {\ fmt::print("[WARNING] Key: \"{:s}\" has incorrect length (was: {:d}, expected {:d})\n", key_mod, val_mod.size(), ((bitsize) >> 3)*2); \ } \ } \ } // keynames enum NameVariantIndex { NNTOOLS, LEGACY_HACTOOL, LEGACY_0 }; static const size_t kNameVariantNum = 3; std::vector kMasterBase = { "master" }; std::vector kPkg1Base = { "package1" }; std::vector kPkg2Base = { "package2" }; std::vector kXciHeaderBase = { "xci_header" }; std::vector kXciInitialDataBase = { "xci_initial_data" }; std::vector kXciCertBase = { "xci_cert" }; std::vector kContentArchiveHeaderBase = { "nca_header", "header" }; std::vector kAcidBase = { "acid" }; std::vector kNrrCertBase = { "nrr_certificate" }; std::vector kPkiRootBase = { "pki_root" }; std::vector kTicketCommonKeyBase = { "ticket_commonkey", "titlekek" }; std::vector kNcaKeyAreaEncKeyBase = { "nca_key_area_key", "key_area_key", "nca_body_keak" }; std::vector kNcaKeyAreaEncKeyHwBase = { "nca_key_area_key_hw", "key_area_hw_key" }; std::vector kKekGenBase = { "aes_kek_generation" }; std::vector kKeyGenBase = { "aes_key_generation" }; // misc str const std::string kKeyStr = "key"; const std::string kKekStr = "kek"; const std::string kSourceStr = "source"; const std::string kSignKey = "sign_key"; const std::string kModulusStr = "modulus"; const std::string kPrivateStr = "private"; std::vector kNcaKeyAreaKeyIndexStr = { "application", "ocean", "system" }; static const size_t kKeyGenerationNum = 0x100; /**/ // import key data for (size_t name_idx = 0; name_idx < kNameVariantNum; name_idx++) { /* internal key sources */ if (name_idx < kMasterBase.size()) { for (size_t keygen_rev = 0; keygen_rev < kKeyGenerationNum; keygen_rev++) { // std::map master_key; //fmt::print("{:s}_key_{:02x}\n", kMasterBase[name_idx], keygen_rev); _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:02x}", kMasterBase[name_idx], kKeyStr, keygen_rev), master_key[(byte_t)keygen_rev]); } } if (name_idx < kPkg2Base.size()) { // tc::Optional package2_key_source; //fmt::print("{:s}_key_source\n", kPkg2Base[name_idx]); _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:s}", kPkg2Base[name_idx], kKeyStr, kSourceStr), package2_key_source); } if (name_idx < kTicketCommonKeyBase.size()) { // tc::Optional ticket_titlekek_source; //fmt::print("{:s}_source\n", kTicketCommonKeyBase[name_idx]); _SAVE_AES128KEY(fmt::format("{:s}_{:s}", kTicketCommonKeyBase[name_idx], kSourceStr), ticket_titlekek_source); } if (name_idx < kNcaKeyAreaEncKeyBase.size()) { // std::array, 3> key_area_key_source; for (size_t keak_idx = 0; keak_idx < kNcaKeyAreaKeyIndexStr.size(); keak_idx++) { //fmt::print("{:s}_{:s}_source\n", kNcaKeyAreaEncKeyBase[name_idx], kNcaKeyAreaKeyIndexStr[keak_idx]); _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:s}", kNcaKeyAreaEncKeyBase[name_idx], kNcaKeyAreaKeyIndexStr[keak_idx], kSourceStr), key_area_key_source[keak_idx]); } } if (name_idx < kKekGenBase.size()) { // tc::Optional aes_kek_generation_source; //fmt::print("{:s}_source\n", kKekGenBase[name_idx]); _SAVE_AES128KEY(fmt::format("{:s}_{:s}", kKekGenBase[name_idx], kSourceStr), aes_kek_generation_source); } if (name_idx < kKeyGenBase.size()) { // tc::Optional aes_key_generation_source; //fmt::print("{:s}_source\n", kKeyGenBase[name_idx]); _SAVE_AES128KEY(fmt::format("{:s}_{:s}", kKeyGenBase[name_idx], kSourceStr), aes_key_generation_source); } if (name_idx < kContentArchiveHeaderBase.size()) { // tc::Optional nca_header_kek_source; //fmt::print("{:s}_kek_source\n", kContentArchiveHeaderBase[name_idx]); _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:s}", kContentArchiveHeaderBase[name_idx], kKekStr, kSourceStr), nca_header_kek_source); } if (name_idx < kContentArchiveHeaderBase.size()) { // tc::Optional nca_header_key_source; //fmt::print("{:s}_key_source\n", kContentArchiveHeaderBase[name_idx]); _SAVE_AES128XTSKEY(fmt::format("{:s}_{:s}_{:s}", kContentArchiveHeaderBase[name_idx], kKeyStr, kSourceStr), nca_header_key_source); } /* package1 */ // package1_key_xx if (name_idx < kPkg1Base.size()) { for (size_t keygen_rev = 0; keygen_rev < kKeyGenerationNum; keygen_rev++) { //fmt::print("{:s}_key_{:02x}\n", kPkg1Base[name_idx], keygen_rev); _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:02x}", kPkg1Base[name_idx], kKeyStr, keygen_rev), pkg1_key[(byte_t)keygen_rev]); } } /* package2 */ if (name_idx < kPkg2Base.size()) { // package2_key_xx for (size_t keygen_rev = 0; keygen_rev < kKeyGenerationNum; keygen_rev++) { //fmt::print("{:s}_key_{:02x}\n", kPkg2Base[name_idx], keygen_rev); _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:02x}", kPkg2Base[name_idx], kKeyStr, keygen_rev), pkg2_key[(byte_t)keygen_rev]); } // package2_sign_key //fmt::print("{:s}_{:s}_{:s}\n", kPkg2Base[name_idx], kSignKey, kPrivateStr); //fmt::print("{:s}_{:s}_{:s}\n", kPkg2Base[name_idx], kSignKey, kModulusStr); _SAVE_RSAKEY(fmt::format("{:s}_{:s}", kPkg2Base[name_idx], kSignKey), pkg2_sign_key, 2048); } /* eticket */ // ticket common key if (name_idx < kTicketCommonKeyBase.size()) { for (size_t keygen_rev = 0; keygen_rev < kKeyGenerationNum; keygen_rev++) { //fmt::print("{:s}_{:02x}\n", kTicketCommonKeyBase[name_idx], keygen_rev); _SAVE_AES128KEY(fmt::format("{:s}_{:02x}", kTicketCommonKeyBase[name_idx], keygen_rev), etik_common_key[(byte_t)keygen_rev]); } } /* NCA keys */ if (name_idx < kContentArchiveHeaderBase.size()) { // nca header key //fmt::print("{:s}_{:s}\n", kContentArchiveHeaderBase[name_idx], kKeyStr); //_SAVE_AES128XTSKEY(fmt::format("{:s}_{:s}", kContentArchiveHeaderBase[name_idx], kKeyStr), nca_header_key); // nca header sign0 key (generations) for (size_t keygen_rev = 0; keygen_rev < kKeyGenerationNum; keygen_rev++) { //fmt::print("{:s}_{:s}_{:02x}_{:s}\n", kContentArchiveHeaderBase[name_idx], kSignKey, keygen_rev, kPrivateStr); //fmt::print("{:s}_{:s}_{:02x}_{:s}\n", kContentArchiveHeaderBase[name_idx], kSignKey, keygen_rev, kModulusStr); _SAVE_RSAKEY(fmt::format("{:s}_{:s}_{:02x}", kContentArchiveHeaderBase[name_idx], kSignKey, keygen_rev), nca_header_sign0_key[(byte_t)keygen_rev], 2048); } // nca header sign0 key (generation 0) //fmt::print("{:s}_{:s}_{:s}\n", kContentArchiveHeaderBase[name_idx], kSignKey, kPrivateStr); //fmt::print("{:s}_{:s}_{:s}\n", kContentArchiveHeaderBase[name_idx], kSignKey, kModulusStr); _SAVE_RSAKEY(fmt::format("{:s}_{:s}", kContentArchiveHeaderBase[name_idx], kSignKey), nca_header_sign0_key[0], 2048); } // nca body key (unused since prototype format) // nca key area encryption keys if (name_idx < kNcaKeyAreaEncKeyBase.size()) { for (size_t keygen_rev = 0; keygen_rev < kKeyGenerationNum; keygen_rev++) { for (size_t keak_idx = 0; keak_idx < kNcaKeyAreaKeyIndexStr.size(); keak_idx++) { //fmt::print("{:s}_{:s}_{:02x}\n", kNcaKeyAreaEncKeyBase[name_idx], kNcaKeyAreaKeyIndexStr[keak_idx], keygen_rev); _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:02x}", kNcaKeyAreaEncKeyBase[name_idx], kNcaKeyAreaKeyIndexStr[keak_idx], keygen_rev), nca_key_area_encryption_key[keak_idx][(byte_t)keygen_rev]); } } } // nca key area "hw" encryption keys if (name_idx < kNcaKeyAreaEncKeyHwBase.size()) { for (size_t keygen_rev = 0; keygen_rev < kKeyGenerationNum; keygen_rev++) { for (size_t keak_idx = 0; keak_idx < kNcaKeyAreaKeyIndexStr.size(); keak_idx++) { //fmt::print("{:s}_{:s}_{:02x}\n", kNcaKeyAreaEncKeyHwBase[name_idx], kNcaKeyAreaKeyIndexStr[keak_idx], keygen_rev); _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:02x}", kNcaKeyAreaEncKeyHwBase[name_idx], kNcaKeyAreaKeyIndexStr[keak_idx], keygen_rev), nca_key_area_encryption_key_hw[keak_idx][(byte_t)keygen_rev]); } } } /* ACID */ if (name_idx < kAcidBase.size()) { // acid sign key (generations) for (size_t keygen_rev = 0; keygen_rev < kKeyGenerationNum; keygen_rev++) { //fmt::print("{:s}_{:s}_{:02x}_{:s}\n", kAcidBase[name_idx], kSignKey, keygen_rev, kPrivateStr); //fmt::print("{:s}_{:s}_{:02x}_{:s}\n", kAcidBase[name_idx], kSignKey, keygen_rev, kModulusStr); _SAVE_RSAKEY(fmt::format("{:s}_{:s}_{:02x}", kAcidBase[name_idx], kSignKey, keygen_rev), acid_sign_key[(byte_t)keygen_rev], 2048); } // acid sign key (generation 0) //fmt::print("{:s}_{:s}_{:s}\n", kAcidBase[name_idx], kSignKey, kPrivateStr); //fmt::print("{:s}_{:s}_{:s}\n", kAcidBase[name_idx], kSignKey, kModulusStr); _SAVE_RSAKEY(fmt::format("{:s}_{:s}", kAcidBase[name_idx], kSignKey), acid_sign_key[0], 2048); } /* NRR certificate */ if (name_idx < kNrrCertBase.size()) { // nrr certificate sign key (generations) for (size_t keygen_rev = 0; keygen_rev < kKeyGenerationNum; keygen_rev++) { //fmt::print("{:s}_{:s}_{:02x}_{:s}\n", kNrrCertBase[name_idx], kSignKey, keygen_rev, kPrivateStr); //fmt::print("{:s}_{:s}_{:02x}_{:s}\n", kNrrCertBase[name_idx], kSignKey, keygen_rev, kModulusStr); _SAVE_RSAKEY(fmt::format("{:s}_{:s}_{:02x}", kNrrCertBase[name_idx], kSignKey, keygen_rev), nrr_certificate_sign_key[(byte_t)keygen_rev], 2048); } // nrr certificate sign key (generation 0) //fmt::print("{:s}_{:s}_{:s}\n", kNrrCertBase[name_idx], kSignKey, kPrivateStr); //fmt::print("{:s}_{:s}_{:s}\n", kNrrCertBase[name_idx], kSignKey, kModulusStr); _SAVE_RSAKEY(fmt::format("{:s}_{:s}", kNrrCertBase[name_idx], kSignKey), nrr_certificate_sign_key[0], 2048); } /* XCI header */ if (name_idx < kXciHeaderBase.size()) { // xci header key (based on index) for (byte_t kek_index = 0; kek_index < 8; kek_index++) { //fmt::print("{:s}_{:s}_{:02x}\n", kXciHeaderBase[name_idx], kKeyStr, kek_index); _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:02x}", kXciHeaderBase[name_idx], kKeyStr, kek_index), xci_header_key[kek_index]); } // xci header key (old label, prod/dev keys are actually a fake distinction, the are different key indexes available to both?, so select correct index when importing) //fmt::print("{:s}_{:s}\n", kXciHeaderBase[name_idx], kKeyStr); _SAVE_AES128KEY(fmt::format("{:s}_{:s}", kXciHeaderBase[name_idx], kKeyStr), xci_header_key[isDev ? nn::hac::gc::KEK_DEV : nn::hac::gc::KEK_PROD]); // xci header sign key //fmt::print("{:s}_{:s}_{:s}\n", kXciHeaderBase[name_idx], kSignKey, kPrivateStr); //fmt::print("{:s}_{:s}_{:s}\n", kXciHeaderBase[name_idx], kSignKey, kModulusStr); _SAVE_RSAKEY(fmt::format("{:s}_{:s}", kXciHeaderBase[name_idx], kSignKey), xci_header_sign_key, 2048); } /* XCI InitialData */ if (name_idx < kXciInitialDataBase.size()) { // xci initial data key (based on index) for (byte_t kek_index = 0; kek_index < 8; kek_index++) { //fmt::print("{:s}_{:s}_{:02x}\n", kXciInitialDataBase[name_idx], kKekStr, kek_index); _SAVE_AES128KEY(fmt::format("{:s}_{:s}_{:02x}", kXciInitialDataBase[name_idx], kKekStr, kek_index), xci_initial_data_kek[kek_index]); } } /* XCI cert */ if (name_idx < kXciCertBase.size()) { // xci cert sign key _SAVE_RSAKEY(fmt::format("{:s}_{:s}", kXciCertBase[name_idx], kSignKey), xci_cert_sign_key, 2048); } /* PKI */ if (name_idx < kPkiRootBase.size()) { // tc::Optional pki_root_sign_key; //fmt::print("{:s}_{:s}_{:s}\n", kPkiRootBase[name_idx], kSignKey, kPrivateStr); //fmt::print("{:s}_{:s}_{:s}\n", kPkiRootBase[name_idx], kSignKey, kModulusStr); _SAVE_RSAKEY(fmt::format("{:s}_{:s}", kPkiRootBase[name_idx], kSignKey), pki_root_sign_key, 4096); } } #undef _SAVE_RSAKEY #undef _SAVE_AES128XTSKEY #undef _SAVE_AES128KEY // Derive Keys for (auto itr = master_key.begin(); itr != master_key.end(); itr++) { if (aes_kek_generation_source.isSet() && aes_key_generation_source.isSet()) { if (itr->first == 0 && nca_header_kek_source.isSet() && nca_header_key_source.isSet()) { if (nca_header_key.isNull()) { aes128_key_t nca_header_kek_tmp; nn::hac::AesKeygen::generateKey(nca_header_kek_tmp.data(), aes_kek_generation_source.get().data(), nca_header_kek_source.get().data(), aes_key_generation_source.get().data(), itr->second.data()); aes128_xtskey_t nca_header_key_tmp; nn::hac::AesKeygen::generateKey(nca_header_key_tmp[0].data(), nca_header_key_source.get()[0].data(), nca_header_kek_tmp.data()); nn::hac::AesKeygen::generateKey(nca_header_key_tmp[1].data(), nca_header_key_source.get()[1].data(), nca_header_kek_tmp.data()); nca_header_key = nca_header_key_tmp; } } for (size_t keak_idx = 0; keak_idx < nn::hac::nca::kKeyAreaEncryptionKeyNum; keak_idx++) { if (key_area_key_source[keak_idx].isSet() && nca_key_area_encryption_key[keak_idx].find(itr->first) != nca_key_area_encryption_key[keak_idx].end()) { aes128_key_t nca_key_area_encryption_key_tmp; nn::hac::AesKeygen::generateKey(nca_key_area_encryption_key_tmp.data(), aes_kek_generation_source.get().data(), key_area_key_source[keak_idx].get().data(), aes_key_generation_source.get().data(), itr->second.data()); nca_key_area_encryption_key[keak_idx][itr->first] = nca_key_area_encryption_key_tmp; } } } if (ticket_titlekek_source.isSet() && etik_common_key.find(itr->first) == etik_common_key.end()) { aes128_key_t etik_common_key_tmp; nn::hac::AesKeygen::generateKey(etik_common_key_tmp.data(), ticket_titlekek_source.get().data(), itr->second.data()); etik_common_key[itr->first] = etik_common_key_tmp; } if (package2_key_source.isSet() && pkg2_key.find(itr->first) == pkg2_key.end()) { aes128_key_t pkg2_key_tmp; nn::hac::AesKeygen::generateKey(pkg2_key_tmp.data(), package2_key_source.get().data(), itr->second.data()); pkg2_key[itr->first] = pkg2_key_tmp; } } // Save PKI Root Key if (pki_root_sign_key.isSet()) { broadon_signer["Root"] = { tc::ByteData(), nn::pki::sign::SIGN_ALGO_RSA4096, pki_root_sign_key.get() }; } } void nstool::KeyBagInitializer::importTitleKeyFile(const tc::io::Path& keyfile_path) { } void nstool::KeyBagInitializer::importCertificateChain(const tc::io::Path& cert_path) { // save file path string for error messages std::string cert_path_str; tc::io::PathUtil::pathToUnixUTF8(cert_path, cert_path_str); // open cert file std::shared_ptr certfile_stream; try { certfile_stream = std::make_shared(tc::io::FileStream(cert_path, tc::io::FileMode::Open, tc::io::FileAccess::Read)); } catch (tc::io::FileNotFoundException& e) { fmt::print("[WARNING] Failed to open certificate file \"{:s}\" ({:s}).\n", cert_path_str, e.error()); return; } // check size size_t cert_raw_size = tc::io::IOUtil::castInt64ToSize(certfile_stream->length()); if (cert_raw_size > 0x10000) { fmt::print("[WARNING] Certificate file \"{:s}\" was too large.\n", cert_path_str); return; } // import cert data tc::ByteData cert_raw = tc::ByteData(cert_raw_size); certfile_stream->seek(0, tc::io::SeekOrigin::Begin); certfile_stream->read(cert_raw.data(), cert_raw.size()); nn::pki::SignedData cert; try { for (size_t f_pos = 0; f_pos < cert_raw.size(); f_pos += cert.getBytes().size()) { cert.fromBytes(cert_raw.data() + f_pos, cert_raw.size() - f_pos); std::string cert_identity = fmt::format("{:s}-{:s}", cert.getBody().getIssuer(), cert.getBody().getSubject()); switch (cert.getBody().getPublicKeyType()) { case nn::pki::cert::PublicKeyType::RSA2048: broadon_signer[cert_identity] = { cert.getBytes(), nn::pki::sign::SIGN_ALGO_RSA2048, cert.getBody().getRsa2048PublicKey() }; break; case nn::pki::cert::PublicKeyType::RSA4096: broadon_signer[cert_identity] = { cert.getBytes(), nn::pki::sign::SIGN_ALGO_RSA4096, cert.getBody().getRsa4096PublicKey() }; break; case nn::pki::cert::PublicKeyType::ECDSA240: // broadon_signer[cert_identity] = { cert.getBytes(), nn::pki::sign::SIGN_ALGO_ECDSA240, cert.getBody().getRsa4096PublicKey() }; fmt::print("[WARNING] Certificate {:s} will not be imported. ecc233 public keys are not supported yet.\n", cert_identity); break; default: fmt::print("[WARNING] Certificate {:s} will not be imported. Unknown public key type.\n", cert_identity); } } } catch (tc::Exception& e) { fmt::print("[WARNING] Certificate file \"{:s}\" is corrupted ({:s}).\n", cert_path_str, e.error()); return; } } void nstool::KeyBagInitializer::importTicket(const tc::io::Path& tik_path) { // save file path string for error messages std::string tik_path_str; tc::io::PathUtil::pathToUnixUTF8(tik_path, tik_path_str); // open cert file std::shared_ptr tik_stream; try { tik_stream = std::make_shared(tc::io::FileStream(tik_path, tc::io::FileMode::Open, tc::io::FileAccess::Read)); } catch (tc::io::FileNotFoundException& e) { fmt::print("[WARNING] Failed to open ticket \"{:s}\" ({:s}).\n", tik_path_str, e.error()); return; } // check size size_t tik_raw_size = tc::io::IOUtil::castInt64ToSize(tik_stream->length()); if (tik_raw_size > 0x10000) { fmt::print("[WARNING] Ticket \"{:s}\" was too large.\n", tik_path_str); return; } // import cert data tc::ByteData tik_raw = tc::ByteData(tik_raw_size); tik_stream->seek(0, tc::io::SeekOrigin::Begin); tik_stream->read(tik_raw.data(), tik_raw.size()); nn::pki::SignedData tik; try { // de serialise ticket tik.fromBytes(tik_raw.data(), tik_raw.size()); // save rights id rights_id_t rights_id; memcpy(rights_id.data(), tik.getBody().getRightsId(), rights_id.size()); // check ticket is not personalised if (tik.getBody().getTitleKeyEncType() != nn::es::ticket::AES128_CBC) { fmt::print("[WARNING] Ticket \"{:s}\" will not be imported. Personalised tickets are not supported.\n", tc::cli::FormatUtil::formatBytesAsString(rights_id.data(), rights_id.size(), true, "")); return; } // save enc title key aes128_key_t enc_title_key; memcpy(enc_title_key.data(), tik.getBody().getEncTitleKey(), enc_title_key.size()); // save the encrypted title key as the fallback enc content key incase the ticket was malformed and workarounds to decrypt it in isolation fail if (fallback_enc_content_key.isNull()) { fallback_enc_content_key = enc_title_key; } // determine key to decrypt title key byte_t common_key_index = tik.getBody().getCommonKeyId(); // work around for bad scene tickets where they don't set the commonkey id field (detect scene ticket with ffff.... signature) if (common_key_index != rights_id[15] && tik.getSignature().getBytes()[0x00] == 0xff && tik.getSignature().getBytes()[0x01] == 0xff) { common_key_index = rights_id[15]; } if (etik_common_key.find(tik.getBody().getCommonKeyId()) == etik_common_key.end()) { fmt::print("[WARNING] Ticket \"{:s}\" will not be imported. Could not decrypt title key.\n", tc::cli::FormatUtil::formatBytesAsString(rights_id.data(), rights_id.size(), true, "")); return; } // decrypt title key aes128_key_t dec_title_key; tc::crypto::DecryptAes128Ecb(dec_title_key.data(), enc_title_key.data(), sizeof(aes128_key_t), etik_common_key[common_key_index].data(), sizeof(aes128_key_t)); // add to key dict external_content_keys[rights_id] = dec_title_key; } catch (tc::Exception& e) { fmt::print("[WARNING] Ticket \"{:s}\" is corrupted ({:s}).\n", tik_path_str, e.error()); return; } } void nstool::KeyBagInitializer::importKnownKeys(bool isDev) { static const nn::hac::detail::rsa2048_block_t kXciHeaderSignModulus = { 0x98, 0xC7, 0x26, 0xB6, 0x0D, 0x0A, 0x50, 0xA7, 0x39, 0x21, 0x0A, 0xE3, 0x2F, 0xE4, 0x3E, 0x2E, 0x5B, 0xA2, 0x86, 0x75, 0xAA, 0x5C, 0xEE, 0x34, 0xF1, 0xA3, 0x3A, 0x7E, 0xBD, 0x90, 0x4E, 0xF7, 0x8D, 0xFA, 0x17, 0xAA, 0x6B, 0xC6, 0x36, 0x6D, 0x4C, 0x9A, 0x6D, 0x57, 0x2F, 0x80, 0xA2, 0xBC, 0x38, 0x4D, 0xDA, 0x99, 0xA1, 0xD8, 0xC3, 0xE2, 0x99, 0x79, 0x36, 0x71, 0x90, 0x20, 0x25, 0x9D, 0x4D, 0x11, 0xB8, 0x2E, 0x63, 0x6B, 0x5A, 0xFA, 0x1E, 0x9C, 0x04, 0xD1, 0xC5, 0xF0, 0x9C, 0xB1, 0x0F, 0xB8, 0xC1, 0x7B, 0xBF, 0xE8, 0xB0, 0xD2, 0x2B, 0x47, 0x01, 0x22, 0x6B, 0x23, 0xC9, 0xD0, 0xBC, 0xEB, 0x75, 0x6E, 0x41, 0x7D, 0x4C, 0x26, 0xA4, 0x73, 0x21, 0xB4, 0xF0, 0x14, 0xE5, 0xD9, 0x8D, 0xB3, 0x64, 0xEE, 0xA8, 0xFA, 0x84, 0x1B, 0xB8, 0xB8, 0x7C, 0x88, 0x6B, 0xEF, 0xCC, 0x97, 0x04, 0x04, 0x9A, 0x67, 0x2F, 0xDF, 0xEC, 0x0D, 0xB2, 0x5F, 0xB5, 0xB2, 0xBD, 0xB5, 0x4B, 0xDE, 0x0E, 0x88, 0xA3, 0xBA, 0xD1, 0xB4, 0xE0, 0x91, 0x81, 0xA7, 0x84, 0xEB, 0x77, 0x85, 0x8B, 0xEF, 0xA5, 0xE3, 0x27, 0xB2, 0xF2, 0x82, 0x2B, 0x29, 0xF1, 0x75, 0x2D, 0xCE, 0xCC, 0xAE, 0x9B, 0x8D, 0xED, 0x5C, 0xF1, 0x8E, 0xDB, 0x9A, 0xD7, 0xAF, 0x42, 0x14, 0x52, 0xCD, 0xE3, 0xC5, 0xDD, 0xCE, 0x08, 0x12, 0x17, 0xD0, 0x7F, 0x1A, 0xAA, 0x1F, 0x7D, 0xE0, 0x93, 0x54, 0xC8, 0xBC, 0x73, 0x8A, 0xCB, 0xAD, 0x6E, 0x93, 0xE2, 0x19, 0x72, 0x6B, 0xD3, 0x45, 0xF8, 0x73, 0x3D, 0x2B, 0x6A, 0x55, 0xD2, 0x3A, 0x8B, 0xB0, 0x8A, 0x42, 0xE3, 0x3D, 0xF1, 0x92, 0x23, 0x42, 0x2E, 0xBA, 0xCC, 0x9C, 0x9A, 0xC1, 0xDD, 0x62, 0x86, 0x9C, 0x2E, 0xE1, 0x2D, 0x6F, 0x62, 0x67, 0x51, 0x08, 0x0E, 0xCF }; static const nn::hac::detail::rsa2048_block_t kXciCertSignModulus = { 0xCD, 0xF3, 0x2C, 0xB0, 0xF5, 0x14, 0x78, 0x34, 0xE5, 0x02, 0xD0, 0x29, 0x6A, 0xA5, 0xFD, 0x97, 0x6A, 0xE0, 0xB0, 0xBB, 0xB0, 0x3B, 0x1A, 0x80, 0xB7, 0xD7, 0x58, 0x92, 0x79, 0x84, 0xC0, 0x36, 0xB1, 0x55, 0x23, 0xD8, 0xA5, 0x60, 0x91, 0x26, 0x48, 0x1A, 0x80, 0x4A, 0xEA, 0x00, 0x98, 0x2A, 0xEC, 0x52, 0x17, 0x72, 0x92, 0x4D, 0xF5, 0x42, 0xA7, 0x8A, 0x6F, 0x7F, 0xD2, 0x48, 0x51, 0x8E, 0xDF, 0xCB, 0xBF, 0x77, 0xF6, 0x18, 0xBD, 0xE5, 0x00, 0xD9, 0x70, 0x8C, 0xEF, 0x57, 0xB2, 0x96, 0xD0, 0x36, 0x83, 0x88, 0x9C, 0xC5, 0xFB, 0xA0, 0x33, 0x81, 0xA2, 0x12, 0x23, 0xC6, 0xC7, 0x86, 0x0A, 0x98, 0x57, 0x4D, 0x2E, 0xB5, 0xAE, 0x64, 0xE4, 0x6F, 0xC2, 0xC5, 0xAC, 0x6A, 0x1D, 0xDB, 0xA5, 0xAF, 0x12, 0x22, 0xAB, 0x1F, 0x51, 0xC8, 0x0E, 0x0D, 0xC9, 0xF5, 0x03, 0xE8, 0xD2, 0xFC, 0x84, 0x62, 0x26, 0x55, 0xA4, 0xC3, 0xE2, 0xA8, 0x98, 0x05, 0x67, 0x23, 0xFD, 0xA5, 0x46, 0x40, 0x78, 0x51, 0x09, 0x3D, 0x91, 0x74, 0xD6, 0xD0, 0x54, 0x23, 0x0D, 0xA0, 0xFB, 0x07, 0xD0, 0xAA, 0x9D, 0x50, 0x4E, 0x2B, 0x26, 0x9A, 0x14, 0xE5, 0x6C, 0x73, 0x66, 0x24, 0x18, 0xA1, 0x93, 0x9C, 0x2A, 0x40, 0x40, 0x05, 0x6B, 0xF1, 0x45, 0xDF, 0x22, 0x8B, 0x40, 0x61, 0xA4, 0x11, 0x06, 0x03, 0xA5, 0x53, 0x84, 0xC0, 0x12, 0xE1, 0x88, 0x9D, 0x55, 0x55, 0x07, 0x40, 0x88, 0x01, 0x8C, 0xAB, 0xA2, 0xFD, 0xFD, 0x19, 0x48, 0x25, 0xAB, 0x59, 0x59, 0x28, 0x63, 0x68, 0x69, 0x1B, 0x99, 0x73, 0x8D, 0xAB, 0x5A, 0xFA, 0x71, 0x60, 0x1B, 0x12, 0xE7, 0x99, 0x70, 0xF1, 0x99, 0x2A, 0x50, 0x18, 0x8B, 0x6B, 0x61, 0x90, 0xE2, 0x7E, 0x8B, 0x90, 0xD4, 0xD5, 0xC0, 0xCB, 0x7C, 0x08, 0x06, 0xD9 }; /* Keydata for very early beta NCA0 archives' RSA-OAEP. */ /* static const nn::hac::detail::rsa2048_block_t beta_nca0_modulus = { 0xAD, 0x58, 0xEE, 0x97, 0xF9, 0x47, 0x90, 0x7D, 0xF9, 0x29, 0x5F, 0x1F, 0x39, 0x68, 0xEE, 0x49, 0x4C, 0x1E, 0x8D, 0x84, 0x91, 0x31, 0x5D, 0xE5, 0x96, 0x27, 0xB2, 0xB3, 0x59, 0x7B, 0xDE, 0xFD, 0xB7, 0xEB, 0x40, 0xA1, 0xE7, 0xEB, 0xDC, 0x60, 0xD0, 0x3D, 0xC5, 0x50, 0x92, 0xAD, 0x3D, 0xC4, 0x8C, 0x17, 0xD2, 0x37, 0x66, 0xE3, 0xF7, 0x14, 0x34, 0x38, 0x6B, 0xA7, 0x2B, 0x21, 0x10, 0x9B, 0x73, 0x49, 0x15, 0xD9, 0x2A, 0x90, 0x86, 0x76, 0x81, 0x6A, 0x10, 0xBD, 0x74, 0xC4, 0x20, 0x55, 0x25, 0xA8, 0x02, 0xC5, 0xA0, 0x34, 0x36, 0x7B, 0x66, 0x47, 0x2C, 0x7E, 0x47, 0x82, 0xA5, 0xD4, 0xA3, 0x42, 0x45, 0xE8, 0xFD, 0x65, 0x72, 0x48, 0xA1, 0xB0, 0x44, 0x10, 0xEF, 0xAC, 0x1D, 0x0F, 0xB5, 0x12, 0x19, 0xA8, 0x41, 0x0B, 0x76, 0x3B, 0xBC, 0xF1, 0x4A, 0x10, 0x46, 0x22, 0xB8, 0xF1, 0xBC, 0x21, 0x81, 0x69, 0x9B, 0x63, 0x6F, 0xD7, 0xB9, 0x60, 0x2A, 0x9A, 0xE5, 0x2C, 0x47, 0x72, 0x59, 0x65, 0xA2, 0x21, 0x60, 0xC4, 0xFC, 0xB0, 0xD7, 0x6F, 0x42, 0xC9, 0x0C, 0xF5, 0x76, 0x7D, 0xF2, 0x5C, 0xE0, 0x80, 0x0F, 0xEE, 0x45, 0x7E, 0x4E, 0x3A, 0x8D, 0x9C, 0x5B, 0x5B, 0xD9, 0xD1, 0x43, 0x94, 0x2C, 0xC7, 0x2E, 0xB9, 0x4A, 0xE5, 0x3E, 0x15, 0xDD, 0x43, 0x00, 0xF7, 0x78, 0xE7, 0x7C, 0x39, 0xB0, 0x4D, 0xC5, 0xD1, 0x1C, 0xF2, 0xB4, 0x7A, 0x2A, 0xEA, 0x0A, 0x8E, 0xB9, 0x13, 0xB4, 0x4F, 0xD7, 0x5B, 0x4D, 0x7B, 0x43, 0xB0, 0x3A, 0x9A, 0x60, 0x22, 0x47, 0x91, 0x78, 0xC7, 0x10, 0x64, 0xE0, 0x2C, 0x69, 0xD1, 0x66, 0x3C, 0x42, 0x2E, 0xEF, 0x19, 0x21, 0x89, 0x8E, 0xE1, 0xB0, 0xB4, 0xD0, 0x17, 0xA1, 0x0F, 0x73, 0x98, 0x5A, 0xF6, 0xEE, 0xC0, 0x2F, 0x9E, 0xCE, 0xC5 }; static const nn::hac::detail::sha256_hash_t beta_nca0_label_hash = { 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55 }; */ struct sRsaKeyForGeneration { byte_t generation; nn::hac::detail::rsa2048_block_t modulus; }; static const nn::hac::detail::rsa2048_block_t kProdPackage2HeaderModulus = { 0x8D, 0x13, 0xA7, 0x77, 0x6A, 0xE5, 0xDC, 0xC0, 0x3B, 0x25, 0xD0, 0x58, 0xE4, 0x20, 0x69, 0x59, 0x55, 0x4B, 0xAB, 0x70, 0x40, 0x08, 0x28, 0x07, 0xA8, 0xA7, 0xFD, 0x0F, 0x31, 0x2E, 0x11, 0xFE, 0x47, 0xA0, 0xF9, 0x9D, 0xDF, 0x80, 0xDB, 0x86, 0x5A, 0x27, 0x89, 0xCD, 0x97, 0x6C, 0x85, 0xC5, 0x6C, 0x39, 0x7F, 0x41, 0xF2, 0xFF, 0x24, 0x20, 0xC3, 0x95, 0xA6, 0xF7, 0x9D, 0x4A, 0x45, 0x74, 0x8B, 0x5D, 0x28, 0x8A, 0xC6, 0x99, 0x35, 0x68, 0x85, 0xA5, 0x64, 0x32, 0x80, 0x9F, 0xD3, 0x48, 0x39, 0xA2, 0x1D, 0x24, 0x67, 0x69, 0xDF, 0x75, 0xAC, 0x12, 0xB5, 0xBD, 0xC3, 0x29, 0x90, 0xBE, 0x37, 0xE4, 0xA0, 0x80, 0x9A, 0xBE, 0x36, 0xBF, 0x1F, 0x2C, 0xAB, 0x2B, 0xAD, 0xF5, 0x97, 0x32, 0x9A, 0x42, 0x9D, 0x09, 0x8B, 0x08, 0xF0, 0x63, 0x47, 0xA3, 0xE9, 0x1B, 0x36, 0xD8, 0x2D, 0x8A, 0xD7, 0xE1, 0x54, 0x11, 0x95, 0xE4, 0x45, 0x88, 0x69, 0x8A, 0x2B, 0x35, 0xCE, 0xD0, 0xA5, 0x0B, 0xD5, 0x5D, 0xAC, 0xDB, 0xAF, 0x11, 0x4D, 0xCA, 0xB8, 0x1E, 0xE7, 0x01, 0x9E, 0xF4, 0x46, 0xA3, 0x8A, 0x94, 0x6D, 0x76, 0xBD, 0x8A, 0xC8, 0x3B, 0xD2, 0x31, 0x58, 0x0C, 0x79, 0xA8, 0x26, 0xE9, 0xD1, 0x79, 0x9C, 0xCB, 0xD4, 0x2B, 0x6A, 0x4F, 0xC6, 0xCC, 0xCF, 0x90, 0xA7, 0xB9, 0x98, 0x47, 0xFD, 0xFA, 0x4C, 0x6C, 0x6F, 0x81, 0x87, 0x3B, 0xCA, 0xB8, 0x50, 0xF6, 0x3E, 0x39, 0x5D, 0x4D, 0x97, 0x3F, 0x0F, 0x35, 0x39, 0x53, 0xFB, 0xFA, 0xCD, 0xAB, 0xA8, 0x7A, 0x62, 0x9A, 0x3F, 0xF2, 0x09, 0x27, 0x96, 0x3F, 0x07, 0x9A, 0x91, 0xF7, 0x16, 0xBF, 0xC6, 0x3A, 0x82, 0x5A, 0x4B, 0xCF, 0x49, 0x50, 0x95, 0x8C, 0x55, 0x80, 0x7E, 0x39, 0xB1, 0x48, 0x05, 0x1E, 0x21, 0xC7, 0x24, 0x4F }; static const std::vector kProdNcaHeaderSign0Modulus = { { 0x00, {0xBF, 0xBE, 0x40, 0x6C, 0xF4, 0xA7, 0x80, 0xE9, 0xF0, 0x7D, 0x0C, 0x99, 0x61, 0x1D, 0x77, 0x2F, 0x96, 0xBC, 0x4B, 0x9E, 0x58, 0x38, 0x1B, 0x03, 0xAB, 0xB1, 0x75, 0x49, 0x9F, 0x2B, 0x4D, 0x58, 0x34, 0xB0, 0x05, 0xA3, 0x75, 0x22, 0xBE, 0x1A, 0x3F, 0x03, 0x73, 0xAC, 0x70, 0x68, 0xD1, 0x16, 0xB9, 0x04, 0x46, 0x5E, 0xB7, 0x07, 0x91, 0x2F, 0x07, 0x8B, 0x26, 0xDE, 0xF6, 0x00, 0x07, 0xB2, 0xB4, 0x51, 0xF8, 0x0D, 0x0A, 0x5E, 0x58, 0xAD, 0xEB, 0xBC, 0x9A, 0xD6, 0x49, 0xB9, 0x64, 0xEF, 0xA7, 0x82, 0xB5, 0xCF, 0x6D, 0x70, 0x13, 0xB0, 0x0F, 0x85, 0xF6, 0xA9, 0x08, 0xAA, 0x4D, 0x67, 0x66, 0x87, 0xFA, 0x89, 0xFF, 0x75, 0x90, 0x18, 0x1E, 0x6B, 0x3D, 0xE9, 0x8A, 0x68, 0xC9, 0x26, 0x04, 0xD9, 0x80, 0xCE, 0x3F, 0x5E, 0x92, 0xCE, 0x01, 0xFF, 0x06, 0x3B, 0xF2, 0xC1, 0xA9, 0x0C, 0xCE, 0x02, 0x6F, 0x16, 0xBC, 0x92, 0x42, 0x0A, 0x41, 0x64, 0xCD, 0x52, 0xB6, 0x34, 0x4D, 0xAE, 0xC0, 0x2E, 0xDE, 0xA4, 0xDF, 0x27, 0x68, 0x3C, 0xC1, 0xA0, 0x60, 0xAD, 0x43, 0xF3, 0xFC, 0x86, 0xC1, 0x3E, 0x6C, 0x46, 0xF7, 0x7C, 0x29, 0x9F, 0xFA, 0xFD, 0xF0, 0xE3, 0xCE, 0x64, 0xE7, 0x35, 0xF2, 0xF6, 0x56, 0x56, 0x6F, 0x6D, 0xF1, 0xE2, 0x42, 0xB0, 0x83, 0x40, 0xA5, 0xC3, 0x20, 0x2B, 0xCC, 0x9A, 0xAE, 0xCA, 0xED, 0x4D, 0x70, 0x30, 0xA8, 0x70, 0x1C, 0x70, 0xFD, 0x13, 0x63, 0x29, 0x02, 0x79, 0xEA, 0xD2, 0xA7, 0xAF, 0x35, 0x28, 0x32, 0x1C, 0x7B, 0xE6, 0x2F, 0x1A, 0xAA, 0x40, 0x7E, 0x32, 0x8C, 0x27, 0x42, 0xFE, 0x82, 0x78, 0xEC, 0x0D, 0xEB, 0xE6, 0x83, 0x4B, 0x6D, 0x81, 0x04, 0x40, 0x1A, 0x9E, 0x9A, 0x67, 0xF6, 0x72, 0x29, 0xFA, 0x04, 0xF0, 0x9D, 0xE4, 0xF4, 0x03,} }, { 0x01, {0xAD, 0xE3, 0xE1, 0xFA, 0x04, 0x35, 0xE5, 0xB6, 0xDD, 0x49, 0xEA, 0x89, 0x29, 0xB1, 0xFF, 0xB6, 0x43, 0xDF, 0xCA, 0x96, 0xA0, 0x4A, 0x13, 0xDF, 0x43, 0xD9, 0x94, 0x97, 0x96, 0x43, 0x65, 0x48, 0x70, 0x58, 0x33, 0xA2, 0x7D, 0x35, 0x7B, 0x96, 0x74, 0x5E, 0x0B, 0x5C, 0x32, 0x18, 0x14, 0x24, 0xC2, 0x58, 0xB3, 0x6C, 0x22, 0x7A, 0xA1, 0xB7, 0xCB, 0x90, 0xA7, 0xA3, 0xF9, 0x7D, 0x45, 0x16, 0xA5, 0xC8, 0xED, 0x8F, 0xAD, 0x39, 0x5E, 0x9E, 0x4B, 0x51, 0x68, 0x7D, 0xF8, 0x0C, 0x35, 0xC6, 0x3F, 0x91, 0xAE, 0x44, 0xA5, 0x92, 0x30, 0x0D, 0x46, 0xF8, 0x40, 0xFF, 0xD0, 0xFF, 0x06, 0xD2, 0x1C, 0x7F, 0x96, 0x18, 0xDC, 0xB7, 0x1D, 0x66, 0x3E, 0xD1, 0x73, 0xBC, 0x15, 0x8A, 0x2F, 0x94, 0xF3, 0x00, 0xC1, 0x83, 0xF1, 0xCD, 0xD7, 0x81, 0x88, 0xAB, 0xDF, 0x8C, 0xEF, 0x97, 0xDD, 0x1B, 0x17, 0x5F, 0x58, 0xF6, 0x9A, 0xE9, 0xE8, 0xC2, 0x2F, 0x38, 0x15, 0xF5, 0x21, 0x07, 0xF8, 0x37, 0x90, 0x5D, 0x2E, 0x02, 0x40, 0x24, 0x15, 0x0D, 0x25, 0xB7, 0x26, 0x5D, 0x09, 0xCC, 0x4C, 0xF4, 0xF2, 0x1B, 0x94, 0x70, 0x5A, 0x9E, 0xEE, 0xED, 0x77, 0x77, 0xD4, 0x51, 0x99, 0xF5, 0xDC, 0x76, 0x1E, 0xE3, 0x6C, 0x8C, 0xD1, 0x12, 0xD4, 0x57, 0xD1, 0xB6, 0x83, 0xE4, 0xE4, 0xFE, 0xDA, 0xE9, 0xB4, 0x3B, 0x33, 0xE5, 0x37, 0x8A, 0xDF, 0xB5, 0x7F, 0x89, 0xF1, 0x9B, 0x9E, 0xB0, 0x15, 0xB2, 0x3A, 0xFE, 0xEA, 0x61, 0x84, 0x5B, 0x7D, 0x4B, 0x23, 0x12, 0x0B, 0x83, 0x12, 0xF2, 0x22, 0x6B, 0xB9, 0x22, 0x96, 0x4B, 0x26, 0x0B, 0x63, 0x5E, 0x96, 0x57, 0x52, 0xA3, 0x67, 0x64, 0x22, 0xCA, 0xD0, 0x56, 0x3E, 0x74, 0xB5, 0x98, 0x1F, 0x0D, 0xF8, 0xB3, 0x34, 0xE6, 0x98, 0x68, 0x5A, 0xAD,} }, }; static const std::vector kProdAcidSignModulus = { { 0x00, {0xDD, 0xC8, 0xDD, 0xF2, 0x4E, 0x6D, 0xF0, 0xCA, 0x9E, 0xC7, 0x5D, 0xC7, 0x7B, 0xAD, 0xFE, 0x7D, 0x23, 0x89, 0x69, 0xB6, 0xF2, 0x06, 0xA2, 0x02, 0x88, 0xE1, 0x55, 0x91, 0xAB, 0xCB, 0x4D, 0x50, 0x2E, 0xFC, 0x9D, 0x94, 0x76, 0xD6, 0x4C, 0xD8, 0xFF, 0x10, 0xFA, 0x5E, 0x93, 0x0A, 0xB4, 0x57, 0xAC, 0x51, 0xC7, 0x16, 0x66, 0xF4, 0x1A, 0x54, 0xC2, 0xC5, 0x04, 0x3D, 0x1B, 0xFE, 0x30, 0x20, 0x8A, 0xAC, 0x6F, 0x6F, 0xF5, 0xC7, 0xB6, 0x68, 0xB8, 0xC9, 0x40, 0x6B, 0x42, 0xAD, 0x11, 0x21, 0xE7, 0x8B, 0xE9, 0x75, 0x01, 0x86, 0xE4, 0x48, 0x9B, 0x0A, 0x0A, 0xF8, 0x7F, 0xE8, 0x87, 0xF2, 0x82, 0x01, 0xE6, 0xA3, 0x0F, 0xE4, 0x66, 0xAE, 0x83, 0x3F, 0x4E, 0x9F, 0x5E, 0x01, 0x30, 0xA4, 0x00, 0xB9, 0x9A, 0xAE, 0x5F, 0x03, 0xCC, 0x18, 0x60, 0xE5, 0xEF, 0x3B, 0x5E, 0x15, 0x16, 0xFE, 0x1C, 0x82, 0x78, 0xB5, 0x2F, 0x47, 0x7C, 0x06, 0x66, 0x88, 0x5D, 0x35, 0xA2, 0x67, 0x20, 0x10, 0xE7, 0x6C, 0x43, 0x68, 0xD3, 0xE4, 0x5A, 0x68, 0x2A, 0x5A, 0xE2, 0x6D, 0x73, 0xB0, 0x31, 0x53, 0x1C, 0x20, 0x09, 0x44, 0xF5, 0x1A, 0x9D, 0x22, 0xBE, 0x12, 0xA1, 0x77, 0x11, 0xE2, 0xA1, 0xCD, 0x40, 0x9A, 0xA2, 0x8B, 0x60, 0x9B, 0xEF, 0xA0, 0xD3, 0x48, 0x63, 0xA2, 0xF8, 0xA3, 0x2C, 0x08, 0x56, 0x52, 0x2E, 0x60, 0x19, 0x67, 0x5A, 0xA7, 0x9F, 0xDC, 0x3F, 0x3F, 0x69, 0x2B, 0x31, 0x6A, 0xB7, 0x88, 0x4A, 0x14, 0x84, 0x80, 0x33, 0x3C, 0x9D, 0x44, 0xB7, 0x3F, 0x4C, 0xE1, 0x75, 0xEA, 0x37, 0xEA, 0xE8, 0x1E, 0x7C, 0x77, 0xB7, 0xC6, 0x1A, 0xA2, 0xF0, 0x9F, 0x10, 0x61, 0xCD, 0x7B, 0x5B, 0x32, 0x4C, 0x37, 0xEF, 0xB1, 0x71, 0x68, 0x53, 0x0A, 0xED, 0x51, 0x7D, 0x35, 0x22, 0xFD,} }, { 0x01, {0xE7, 0xAA, 0x25, 0xC8, 0x01, 0xA5, 0x14, 0x6B, 0x01, 0x60, 0x3E, 0xD9, 0x96, 0x5A, 0xBF, 0x90, 0xAC, 0xA7, 0xFD, 0x9B, 0x5B, 0xBD, 0x8A, 0x26, 0xB0, 0xCB, 0x20, 0x28, 0x9A, 0x72, 0x12, 0xF5, 0x20, 0x65, 0xB3, 0xB9, 0x84, 0x58, 0x1F, 0x27, 0xBC, 0x7C, 0xA2, 0xC9, 0x9E, 0x18, 0x95, 0xCF, 0xC2, 0x73, 0x2E, 0x74, 0x8C, 0x66, 0xE5, 0x9E, 0x79, 0x2B, 0xB8, 0x07, 0x0C, 0xB0, 0x4E, 0x8E, 0xAB, 0x85, 0x21, 0x42, 0xC4, 0xC5, 0x6D, 0x88, 0x9C, 0xDB, 0x15, 0x95, 0x3F, 0x80, 0xDB, 0x7A, 0x9A, 0x7D, 0x41, 0x56, 0x25, 0x17, 0x18, 0x42, 0x4D, 0x8C, 0xAC, 0xA5, 0x7B, 0xDB, 0x42, 0x5D, 0x59, 0x35, 0x45, 0x5D, 0x8A, 0x02, 0xB5, 0x70, 0xC0, 0x72, 0x35, 0x46, 0xD0, 0x1D, 0x60, 0x01, 0x4A, 0xCC, 0x1C, 0x46, 0xD3, 0xD6, 0x35, 0x52, 0xD6, 0xE1, 0xF8, 0x3B, 0x5D, 0xEA, 0xDD, 0xB8, 0xFE, 0x7D, 0x50, 0xCB, 0x35, 0x23, 0x67, 0x8B, 0xB6, 0xE4, 0x74, 0xD2, 0x60, 0xFC, 0xFD, 0x43, 0xBF, 0x91, 0x08, 0x81, 0xC5, 0x4F, 0x5D, 0x16, 0x9A, 0xC4, 0x9A, 0xC6, 0xF6, 0xF3, 0xE1, 0xF6, 0x5C, 0x07, 0xAA, 0x71, 0x6C, 0x13, 0xA4, 0xB1, 0xB3, 0x66, 0xBF, 0x90, 0x4C, 0x3D, 0xA2, 0xC4, 0x0B, 0xB8, 0x3D, 0x7A, 0x8C, 0x19, 0xFA, 0xFF, 0x6B, 0xB9, 0x1F, 0x02, 0xCC, 0xB6, 0xD3, 0x0C, 0x7D, 0x19, 0x1F, 0x47, 0xF9, 0xC7, 0x40, 0x01, 0xFA, 0x46, 0xEA, 0x0B, 0xD4, 0x02, 0xE0, 0x3D, 0x30, 0x9A, 0x1A, 0x0F, 0xEA, 0xA7, 0x66, 0x55, 0xF7, 0xCB, 0x28, 0xE2, 0xBB, 0x99, 0xE4, 0x83, 0xC3, 0x43, 0x03, 0xEE, 0xDC, 0x1F, 0x02, 0x23, 0xDD, 0xD1, 0x2D, 0x39, 0xA4, 0x65, 0x75, 0x03, 0xEF, 0x37, 0x9C, 0x06, 0xD6, 0xFA, 0xA1, 0x15, 0xF0, 0xDB, 0x17, 0x47, 0x26, 0x4F, 0x49, 0x03} }, }; static const nn::hac::detail::rsa2048_block_t kDevPackage2HeaderModulus = { 0xB3, 0x65, 0x54, 0xFB, 0x0A, 0xB0, 0x1E, 0x85, 0xA7, 0xF6, 0xCF, 0x91, 0x8E, 0xBA, 0x96, 0x99, 0x0D, 0x8B, 0x91, 0x69, 0x2A, 0xEE, 0x01, 0x20, 0x4F, 0x34, 0x5C, 0x2C, 0x4F, 0x4E, 0x37, 0xC7, 0xF1, 0x0B, 0xD4, 0xCD, 0xA1, 0x7F, 0x93, 0xF1, 0x33, 0x59, 0xCE, 0xB1, 0xE9, 0xDD, 0x26, 0xE6, 0xF3, 0xBB, 0x77, 0x87, 0x46, 0x7A, 0xD6, 0x4E, 0x47, 0x4A, 0xD1, 0x41, 0xB7, 0x79, 0x4A, 0x38, 0x06, 0x6E, 0xCF, 0x61, 0x8F, 0xCD, 0xC1, 0x40, 0x0B, 0xFA, 0x26, 0xDC, 0xC0, 0x34, 0x51, 0x83, 0xD9, 0x3B, 0x11, 0x54, 0x3B, 0x96, 0x27, 0x32, 0x9A, 0x95, 0xBE, 0x1E, 0x68, 0x11, 0x50, 0xA0, 0x6B, 0x10, 0xA8, 0x83, 0x8B, 0xF5, 0xFC, 0xBC, 0x90, 0x84, 0x7A, 0x5A, 0x5C, 0x43, 0x52, 0xE6, 0xC8, 0x26, 0xE9, 0xFE, 0x06, 0xA0, 0x8B, 0x53, 0x0F, 0xAF, 0x1E, 0xC4, 0x1C, 0x0B, 0xCF, 0x50, 0x1A, 0xA4, 0xF3, 0x5C, 0xFB, 0xF0, 0x97, 0xE4, 0xDE, 0x32, 0x0A, 0x9F, 0xE3, 0x5A, 0xAA, 0xB7, 0x44, 0x7F, 0x5C, 0x33, 0x60, 0xB9, 0x0F, 0x22, 0x2D, 0x33, 0x2A, 0xE9, 0x69, 0x79, 0x31, 0x42, 0x8F, 0xE4, 0x3A, 0x13, 0x8B, 0xE7, 0x26, 0xBD, 0x08, 0x87, 0x6C, 0xA6, 0xF2, 0x73, 0xF6, 0x8E, 0xA7, 0xF2, 0xFE, 0xFB, 0x6C, 0x28, 0x66, 0x0D, 0xBD, 0xD7, 0xEB, 0x42, 0xA8, 0x78, 0xE6, 0xB8, 0x6B, 0xAE, 0xC7, 0xA9, 0xE2, 0x40, 0x6E, 0x89, 0x20, 0x82, 0x25, 0x8E, 0x3C, 0x6A, 0x60, 0xD7, 0xF3, 0x56, 0x8E, 0xEC, 0x8D, 0x51, 0x8A, 0x63, 0x3C, 0x04, 0x78, 0x23, 0x0E, 0x90, 0x0C, 0xB4, 0xE7, 0x86, 0x3B, 0x4F, 0x8E, 0x13, 0x09, 0x47, 0x32, 0x0E, 0x04, 0xB8, 0x4D, 0x5B, 0xB0, 0x46, 0x71, 0xB0, 0x5C, 0xF4, 0xAD, 0x63, 0x4F, 0xC5, 0xE2, 0xAC, 0x1E, 0xC4, 0x33, 0x96, 0x09, 0x7B }; static const std::vector kDevNcaHeaderSign0Modulus = { { 0x00, {0xD8, 0xF1, 0x18, 0xEF, 0x32, 0x72, 0x4C, 0xA7, 0x47, 0x4C, 0xB9, 0xEA, 0xB3, 0x04, 0xA8, 0xA4, 0xAC, 0x99, 0x08, 0x08, 0x04, 0xBF, 0x68, 0x57, 0xB8, 0x43, 0x94, 0x2B, 0xC7, 0xB9, 0x66, 0x49, 0x85, 0xE5, 0x8A, 0x9B, 0xC1, 0x00, 0x9A, 0x6A, 0x8D, 0xD0, 0xEF, 0xCE, 0xFF, 0x86, 0xC8, 0x5C, 0x5D, 0xE9, 0x53, 0x7B, 0x19, 0x2A, 0xA8, 0xC0, 0x22, 0xD1, 0xF3, 0x22, 0x0A, 0x50, 0xF2, 0x2B, 0x65, 0x05, 0x1B, 0x9E, 0xEC, 0x61, 0xB5, 0x63, 0xA3, 0x6F, 0x3B, 0xBA, 0x63, 0x3A, 0x53, 0xF4, 0x49, 0x2F, 0xCF, 0x03, 0xCC, 0xD7, 0x50, 0x82, 0x1B, 0x29, 0x4F, 0x08, 0xDE, 0x1B, 0x6D, 0x47, 0x4F, 0xA8, 0xB6, 0x6A, 0x26, 0xA0, 0x83, 0x3F, 0x1A, 0xAF, 0x83, 0x8F, 0x0E, 0x17, 0x3F, 0xFE, 0x44, 0x1C, 0x56, 0x94, 0x2E, 0x49, 0x83, 0x83, 0x03, 0xE9, 0xB6, 0xAD, 0xD5, 0xDE, 0xE3, 0x2D, 0xA1, 0xD9, 0x66, 0x20, 0x5D, 0x1F, 0x5E, 0x96, 0x5D, 0x5B, 0x55, 0x0D, 0xD4, 0xB4, 0x77, 0x6E, 0xAE, 0x1B, 0x69, 0xF3, 0xA6, 0x61, 0x0E, 0x51, 0x62, 0x39, 0x28, 0x63, 0x75, 0x76, 0xBF, 0xB0, 0xD2, 0x22, 0xEF, 0x98, 0x25, 0x02, 0x05, 0xC0, 0xD7, 0x6A, 0x06, 0x2C, 0xA5, 0xD8, 0x5A, 0x9D, 0x7A, 0xA4, 0x21, 0x55, 0x9F, 0xF9, 0x3E, 0xBF, 0x16, 0xF6, 0x07, 0xC2, 0xB9, 0x6E, 0x87, 0x9E, 0xB5, 0x1C, 0xBE, 0x97, 0xFA, 0x82, 0x7E, 0xED, 0x30, 0xD4, 0x66, 0x3F, 0xDE, 0xD8, 0x1B, 0x4B, 0x15, 0xD9, 0xFB, 0x2F, 0x50, 0xF0, 0x9D, 0x1D, 0x52, 0x4C, 0x1C, 0x4D, 0x8D, 0xAE, 0x85, 0x1E, 0xEA, 0x7F, 0x86, 0xF3, 0x0B, 0x7B, 0x87, 0x81, 0x98, 0x23, 0x80, 0x63, 0x4F, 0x2F, 0xB0, 0x62, 0xCC, 0x6E, 0xD2, 0x46, 0x13, 0x65, 0x2B, 0xD6, 0x44, 0x33, 0x59, 0xB5, 0x8F, 0xB9, 0x4A, 0xA9,} }, { 0x01, {0x9A, 0xBC, 0x88, 0xBD, 0x0A, 0xBE, 0xD7, 0x0C, 0x9B, 0x42, 0x75, 0x65, 0x38, 0x5E, 0xD1, 0x01, 0xCD, 0x12, 0xAE, 0xEA, 0xE9, 0x4B, 0xDB, 0xB4, 0x5E, 0x36, 0x10, 0x96, 0xDA, 0x3D, 0x2E, 0x66, 0xD3, 0x99, 0x13, 0x8A, 0xBE, 0x67, 0x41, 0xC8, 0x93, 0xD9, 0x3E, 0x42, 0xCE, 0x34, 0xCE, 0x96, 0xFA, 0x0B, 0x23, 0xCC, 0x2C, 0xDF, 0x07, 0x3F, 0x3B, 0x24, 0x4B, 0x12, 0x67, 0x3A, 0x29, 0x36, 0xA3, 0xAA, 0x06, 0xF0, 0x65, 0xA5, 0x85, 0xBA, 0xFD, 0x12, 0xEC, 0xF1, 0x60, 0x67, 0xF0, 0x8F, 0xD3, 0x5B, 0x01, 0x1B, 0x1E, 0x84, 0xA3, 0x5C, 0x65, 0x36, 0xF9, 0x23, 0x7E, 0xF3, 0x26, 0x38, 0x64, 0x98, 0xBA, 0xE4, 0x19, 0x91, 0x4C, 0x02, 0xCF, 0xC9, 0x6D, 0x86, 0xEC, 0x1D, 0x41, 0x69, 0xDD, 0x56, 0xEA, 0x5C, 0xA3, 0x2A, 0x58, 0xB4, 0x39, 0xCC, 0x40, 0x31, 0xFD, 0xFB, 0x42, 0x74, 0xF8, 0xEC, 0xEA, 0x00, 0xF0, 0xD9, 0x28, 0xEA, 0xFA, 0x2D, 0x00, 0xE1, 0x43, 0x53, 0xC6, 0x32, 0xF4, 0xA2, 0x07, 0xD4, 0x5F, 0xD4, 0xCB, 0xAC, 0xCA, 0xFF, 0xDF, 0x84, 0xD2, 0x86, 0x14, 0x3C, 0xDE, 0x22, 0x75, 0xA5, 0x73, 0xFF, 0x68, 0x07, 0x4A, 0xF9, 0x7C, 0x2C, 0xCC, 0xDE, 0x45, 0xB6, 0x54, 0x82, 0x90, 0x36, 0x1F, 0x2C, 0x51, 0x96, 0xC5, 0x0A, 0x53, 0x5B, 0xF0, 0x8B, 0x4A, 0xAA, 0x3B, 0x68, 0x97, 0x19, 0x17, 0x1F, 0x01, 0xB8, 0xED, 0xB9, 0x9A, 0x5E, 0x08, 0xC5, 0x20, 0x1E, 0x6A, 0x09, 0xF0, 0xE9, 0x73, 0xA3, 0xBE, 0x10, 0x06, 0x02, 0xE9, 0xFB, 0x85, 0xFA, 0x5F, 0x01, 0xAC, 0x60, 0xE0, 0xED, 0x7D, 0xB9, 0x49, 0xA8, 0x9E, 0x98, 0x7D, 0x91, 0x40, 0x05, 0xCF, 0xF9, 0x1A, 0xFC, 0x40, 0x22, 0xA8, 0x96, 0x5B, 0xB0, 0xDC, 0x7A, 0xF5, 0xB7, 0xE9, 0x91, 0x4C, 0x49,} }, }; static const std::vector kDevAcidSignModulus = { { 0x00, {0xD6, 0x34, 0xA5, 0x78, 0x6C, 0x68, 0xCE, 0x5A, 0xC2, 0x37, 0x17, 0xF3, 0x82, 0x45, 0xC6, 0x89, 0xE1, 0x2D, 0x06, 0x67, 0xBF, 0xB4, 0x06, 0x19, 0x55, 0x6B, 0x27, 0x66, 0x0C, 0xA4, 0xB5, 0x87, 0x81, 0x25, 0xF4, 0x30, 0xBC, 0x53, 0x08, 0x68, 0xA2, 0x48, 0x49, 0x8C, 0x3F, 0x38, 0x40, 0x9C, 0xC4, 0x26, 0xF4, 0x79, 0xE2, 0xA1, 0x85, 0xF5, 0x5C, 0x7F, 0x58, 0xBA, 0xA6, 0x1C, 0xA0, 0x8B, 0x84, 0x16, 0x14, 0x6F, 0x85, 0xD9, 0x7C, 0xE1, 0x3C, 0x67, 0x22, 0x1E, 0xFB, 0xD8, 0xA7, 0xA5, 0x9A, 0xBF, 0xEC, 0x0E, 0xCF, 0x96, 0x7E, 0x85, 0xC2, 0x1D, 0x49, 0x5D, 0x54, 0x26, 0xCB, 0x32, 0x7C, 0xF6, 0xBB, 0x58, 0x03, 0x80, 0x2B, 0x5D, 0xF7, 0xFB, 0xD1, 0x9D, 0xC7, 0xC6, 0x2E, 0x53, 0xC0, 0x6F, 0x39, 0x2C, 0x1F, 0xA9, 0x92, 0xF2, 0x4D, 0x7D, 0x4E, 0x74, 0xFF, 0xE4, 0xEF, 0xE4, 0x7C, 0x3D, 0x34, 0x2A, 0x71, 0xA4, 0x97, 0x59, 0xFF, 0x4F, 0xA2, 0xF4, 0x66, 0x78, 0xD8, 0xBA, 0x99, 0xE3, 0xE6, 0xDB, 0x54, 0xB9, 0xE9, 0x54, 0xA1, 0x70, 0xFC, 0x05, 0x1F, 0x11, 0x67, 0x4B, 0x26, 0x8C, 0x0C, 0x3E, 0x03, 0xD2, 0xA3, 0x55, 0x5C, 0x7D, 0xC0, 0x5D, 0x9D, 0xFF, 0x13, 0x2F, 0xFD, 0x19, 0xBF, 0xED, 0x44, 0xC3, 0x8C, 0xA7, 0x28, 0xCB, 0xE5, 0xE0, 0xB1, 0xA7, 0x9C, 0x33, 0x8D, 0xB8, 0x6E, 0xDE, 0x87, 0x18, 0x22, 0x60, 0xC4, 0xAE, 0xF2, 0x87, 0x9F, 0xCE, 0x09, 0x5C, 0xB5, 0x99, 0xA5, 0x9F, 0x49, 0xF2, 0xD7, 0x58, 0xFA, 0xF9, 0xC0, 0x25, 0x7D, 0xD6, 0xCB, 0xF3, 0xD8, 0x6C, 0xA2, 0x69, 0x91, 0x68, 0x73, 0xB1, 0x94, 0x6F, 0xA3, 0xF3, 0xB9, 0x7D, 0xF8, 0xE0, 0x72, 0x9E, 0x93, 0x7B, 0x7A, 0xA2, 0x57, 0x60, 0xB7, 0x5B, 0xA9, 0x84, 0xAE, 0x64, 0x88, 0x69} }, { 0x01, {0xBC, 0xA5, 0x6A, 0x7E, 0xEA, 0x38, 0x34, 0x62, 0xA6, 0x10, 0x18, 0x3C, 0xE1, 0x63, 0x7B, 0xF0, 0xD3, 0x08, 0x8C, 0xF5, 0xC5, 0xC4, 0xC7, 0x93, 0xE9, 0xD9, 0xE6, 0x32, 0xF3, 0xA0, 0xF6, 0x6E, 0x8A, 0x98, 0x76, 0x47, 0x33, 0x47, 0x65, 0x02, 0x70, 0xDC, 0x86, 0x5F, 0x3D, 0x61, 0x5A, 0x70, 0xBC, 0x5A, 0xCA, 0xCA, 0x50, 0xAD, 0x61, 0x7E, 0xC9, 0xEC, 0x27, 0xFF, 0xE8, 0x64, 0x42, 0x9A, 0xEE, 0xBE, 0xC3, 0xD1, 0x0B, 0xC0, 0xE9, 0xBF, 0x83, 0x8D, 0xC0, 0x0C, 0xD8, 0x00, 0x5B, 0x76, 0x90, 0xD2, 0x4B, 0x30, 0x84, 0x35, 0x8B, 0x1E, 0x20, 0xB7, 0xE4, 0xDC, 0x63, 0xE5, 0xDF, 0xCD, 0x00, 0x5F, 0x81, 0x5F, 0x67, 0xC5, 0x8B, 0xDF, 0xFC, 0xE1, 0x37, 0x5F, 0x07, 0xD9, 0xDE, 0x4F, 0xE6, 0x7B, 0xF1, 0xFB, 0xA1, 0x5A, 0x71, 0x40, 0xFE, 0xBA, 0x1E, 0xAE, 0x13, 0x22, 0xD2, 0xFE, 0x37, 0xA2, 0xB6, 0x8B, 0xAB, 0xEB, 0x84, 0x81, 0x4E, 0x7C, 0x1E, 0x02, 0xD1, 0xFB, 0xD7, 0x5D, 0x11, 0x84, 0x64, 0xD2, 0x4D, 0xBB, 0x50, 0x00, 0x67, 0x54, 0xE2, 0x77, 0x89, 0xBA, 0x0B, 0xE7, 0x05, 0x57, 0x9A, 0x22, 0x5A, 0xEC, 0x76, 0x1C, 0xFD, 0xE8, 0xA8, 0x18, 0x16, 0x41, 0x65, 0x03, 0xFA, 0xC4, 0xA6, 0x31, 0x5C, 0x1A, 0x7F, 0xAB, 0x11, 0xC8, 0x4A, 0x99, 0xB9, 0xE6, 0xCF, 0x62, 0x21, 0xA6, 0x72, 0x47, 0xDB, 0xBA, 0x96, 0x26, 0x4E, 0x2E, 0xD4, 0x8C, 0x46, 0xD6, 0xA7, 0x1A, 0x6C, 0x32, 0xA7, 0xDF, 0x85, 0x1C, 0x03, 0xC3, 0x6D, 0xA9, 0xE9, 0x68, 0xF4, 0x17, 0x1E, 0xB2, 0x70, 0x2A, 0xA1, 0xE5, 0xE1, 0xF3, 0x8F, 0x6F, 0x63, 0xAC, 0xEB, 0x72, 0x0B, 0x4C, 0x4A, 0x36, 0x3C, 0x60, 0x91, 0x9F, 0x6E, 0x1C, 0x71, 0xEA, 0xD0, 0x78, 0x78, 0xA0, 0x2E, 0xC6, 0x32, 0x6B} }, }; if (isDev) { if (xci_header_sign_key.isNull()) xci_header_sign_key = tc::crypto::RsaPublicKey(kXciHeaderSignModulus.data(), kXciHeaderSignModulus.size()); if (xci_cert_sign_key.isNull()) xci_cert_sign_key = tc::crypto::RsaPublicKey(kXciCertSignModulus.data(), kXciCertSignModulus.size()); if (pkg2_sign_key.isNull()) pkg2_sign_key = tc::crypto::RsaPublicKey(kDevPackage2HeaderModulus.data(), kDevPackage2HeaderModulus.size()); for (auto itr = kDevNcaHeaderSign0Modulus.begin(); itr != kDevNcaHeaderSign0Modulus.end(); itr++) { if (nca_header_sign0_key.find(itr->generation) == nca_header_sign0_key.end()) nca_header_sign0_key[itr->generation] = tc::crypto::RsaPublicKey(itr->modulus.data(), itr->modulus.size()); } for (auto itr = kDevAcidSignModulus.begin(); itr != kDevAcidSignModulus.end(); itr++) { if (acid_sign_key.find(itr->generation) == acid_sign_key.end()) acid_sign_key[itr->generation] = tc::crypto::RsaPublicKey(itr->modulus.data(), itr->modulus.size()); } } else { if (xci_header_sign_key.isNull()) xci_header_sign_key = tc::crypto::RsaPublicKey(kXciHeaderSignModulus.data(), kXciHeaderSignModulus.size()); if (xci_cert_sign_key.isNull()) xci_cert_sign_key = tc::crypto::RsaPublicKey(kXciCertSignModulus.data(), kXciCertSignModulus.size()); if (pkg2_sign_key.isNull()) pkg2_sign_key = tc::crypto::RsaPublicKey(kProdPackage2HeaderModulus.data(), kProdPackage2HeaderModulus.size()); for (auto itr = kProdNcaHeaderSign0Modulus.begin(); itr != kProdNcaHeaderSign0Modulus.end(); itr++) { if (nca_header_sign0_key.find(itr->generation) == nca_header_sign0_key.end()) nca_header_sign0_key[itr->generation] = tc::crypto::RsaPublicKey(itr->modulus.data(), itr->modulus.size()); } for (auto itr = kProdAcidSignModulus.begin(); itr != kProdAcidSignModulus.end(); itr++) { if (acid_sign_key.find(itr->generation) == acid_sign_key.end()) acid_sign_key[itr->generation] = tc::crypto::RsaPublicKey(itr->modulus.data(), itr->modulus.size()); } } }