mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-19 20:19:13 +12:00
Merge branch 'master' into shader-decomp
This commit is contained in:
commit
ffcf352dd2
5 changed files with 156 additions and 57 deletions
|
@ -1,13 +1,15 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "crypto/aes_engine.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <tuple>
|
||||
|
||||
#include "helpers.hpp"
|
||||
|
||||
namespace Crypto {
|
||||
void AESEngine::loadKeys(const std::filesystem::path& path) {
|
||||
std::ifstream file(path, std::ios::in);
|
||||
|
||||
|
||||
if (file.fail()) {
|
||||
Helpers::warn("Keys: Couldn't read key file: %s", path.c_str());
|
||||
return;
|
||||
|
@ -58,18 +60,10 @@ namespace Crypto {
|
|||
}
|
||||
|
||||
switch (keyType) {
|
||||
case 'X':
|
||||
setKeyX(slotId, key.value());
|
||||
break;
|
||||
case 'Y':
|
||||
setKeyY(slotId, key.value());
|
||||
break;
|
||||
case 'N':
|
||||
setNormalKey(slotId, key.value());
|
||||
break;
|
||||
default:
|
||||
Helpers::warn("Keys: Invalid key type %c", keyType);
|
||||
break;
|
||||
case 'X': setKeyX(slotId, key.value()); break;
|
||||
case 'Y': setKeyY(slotId, key.value()); break;
|
||||
case 'N': setNormalKey(slotId, key.value()); break;
|
||||
default: Helpers::warn("Keys: Invalid key type %c", keyType); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,4 +74,65 @@ namespace Crypto {
|
|||
|
||||
keysLoaded = true;
|
||||
}
|
||||
};
|
||||
|
||||
void AESEngine::setSeedPath(const std::filesystem::path& path) { seedDatabase.open(path, "rb"); }
|
||||
|
||||
// Loads seeds from a seed file, return true on success and false on failure
|
||||
bool AESEngine::loadSeeds() {
|
||||
if (!seedDatabase.isOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The # of seeds is stored at offset 0
|
||||
u32_le seedCount = 0;
|
||||
|
||||
if (!seedDatabase.rewind()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto [success, size] = seedDatabase.readBytes(&seedCount, sizeof(u32));
|
||||
if (!success || size != sizeof(u32)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Key data starts from offset 16
|
||||
if (!seedDatabase.seek(16)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Crypto::Seed seed;
|
||||
for (uint i = 0; i < seedCount; i++) {
|
||||
std::tie(success, size) = seedDatabase.readBytes(&seed, sizeof(seed));
|
||||
if (!success || size != sizeof(seed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
seeds.push_back(seed);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<Crypto::AESKey> AESEngine::getSeedFromDB(u64 titleID) {
|
||||
// We don't have a seed db nor any seeds loaded, return nullopt
|
||||
if (!seedDatabase.isOpen() && seeds.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// We have a seed DB but haven't loaded the seeds yet, so load them
|
||||
if (seedDatabase.isOpen() && seeds.empty()) {
|
||||
bool success = loadSeeds();
|
||||
if (!success) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
for (Crypto::Seed& seed : seeds) {
|
||||
if (seed.titleID == titleID) {
|
||||
return seed.seed;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
}; // namespace Crypto
|
|
@ -1,12 +1,15 @@
|
|||
#include "loader/ncch.hpp"
|
||||
|
||||
#include <cryptopp/aes.h>
|
||||
#include <cryptopp/modes.h>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include "loader/lz77.hpp"
|
||||
#include "loader/ncch.hpp"
|
||||
#include "memory.hpp"
|
||||
#include <cryptopp/sha.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "loader/lz77.hpp"
|
||||
#include "memory.hpp"
|
||||
|
||||
bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSInfo &info) {
|
||||
// 0x200 bytes for the NCCH header
|
||||
|
@ -70,8 +73,26 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn
|
|||
if (!seedCrypto) {
|
||||
secondaryKeyY = primaryKeyY;
|
||||
} else {
|
||||
Helpers::warn("Seed crypto is not supported");
|
||||
gotCryptoKeys = false;
|
||||
// In seed crypto mode, the secondary key is computed through a SHA256 hash of the primary key and a title-specific seed, which we fetch
|
||||
// from seeddb.bin
|
||||
std::optional<Crypto::AESKey> seedOptional = aesEngine.getSeedFromDB(programID);
|
||||
if (seedOptional.has_value()) {
|
||||
auto seed = *seedOptional;
|
||||
|
||||
CryptoPP::SHA256 shaEngine;
|
||||
std::array<u8, 32> data;
|
||||
std::array<u8, CryptoPP::SHA256::DIGESTSIZE> hash;
|
||||
|
||||
std::memcpy(&data[0], primaryKeyY.data(), primaryKeyY.size());
|
||||
std::memcpy(&data[16], seed.data(), seed.size());
|
||||
shaEngine.CalculateDigest(hash.data(), data.data(), data.size());
|
||||
// Note that SHA256 will produce a 256-bit hash, while we only need 128 bits cause this is an AES key
|
||||
// So the latter 16 bytes of the SHA256 are thrown out.
|
||||
std::memcpy(secondaryKeyY.data(), hash.data(), secondaryKeyY.size());
|
||||
} else {
|
||||
Helpers::warn("Couldn't find a seed value for this title. Make sure you have a seeddb.bin file alongside your aes_keys.txt");
|
||||
gotCryptoKeys = false;
|
||||
}
|
||||
}
|
||||
|
||||
auto primaryResult = getPrimaryKey(aesEngine, primaryKeyY);
|
||||
|
|
|
@ -220,6 +220,8 @@ bool Emulator::loadROM(const std::filesystem::path& path) {
|
|||
const std::filesystem::path appDataPath = getAppDataRoot();
|
||||
const std::filesystem::path dataPath = appDataPath / path.filename().stem();
|
||||
const std::filesystem::path aesKeysPath = appDataPath / "sysdata" / "aes_keys.txt";
|
||||
const std::filesystem::path seedDBPath = appDataPath / "sysdata" / "seeddb.bin";
|
||||
|
||||
IOFile::setAppDataDir(dataPath);
|
||||
|
||||
// Open the text file containing our AES keys if it exists. We use the std::filesystem::exists overload that takes an error code param to
|
||||
|
@ -229,6 +231,10 @@ bool Emulator::loadROM(const std::filesystem::path& path) {
|
|||
aesEngine.loadKeys(aesKeysPath);
|
||||
}
|
||||
|
||||
if (std::filesystem::exists(seedDBPath, ec) && !ec) {
|
||||
aesEngine.setSeedPath(seedDBPath);
|
||||
}
|
||||
|
||||
kernel.initializeFS();
|
||||
auto extension = path.extension();
|
||||
bool success; // Tracks if we loaded the ROM successfully
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue