// Copyright 2018 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #include #include #include #include #include "common/common_types.h" namespace Core::Crypto { using Key128 = std::array; using Key256 = std::array; using SHA256Hash = std::array; static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big."); static_assert(sizeof(Key256) == 32, "Key128 must be 128 bytes big."); enum class S256KeyType : u64 { Header, // SDSave, // SDNCA, // }; enum class S128KeyType : u64 { Master, // f1=crypto revision Package1, // f1=crypto revision Package2, // f1=crypto revision Titlekek, // f1=crypto revision ETicketRSAKek, // KeyArea, // f1=crypto revision f2=type {app, ocean, system} SDSeed, // Titlekey, // f1=rights id LSB f2=rights id MSB }; enum class KeyAreaKeyType : u8 { Application, Ocean, System, }; template struct KeyIndex { KeyType type; u64 field1; u64 field2; std::string DebugInfo() const { u8 key_size = 16; if constexpr (std::is_same_v) key_size = 32; return fmt::format("key_size={:02X}, key={:02X}, field1={:016X}, field2={:016X}", key_size, static_cast(type), field1, field2); } }; // The following two (== and hash) are so KeyIndex can be a key in unordered_map template bool operator==(const KeyIndex& lhs, const KeyIndex& rhs) { return std::tie(lhs.type, lhs.field1, lhs.field2) == std::tie(rhs.type, rhs.field1, rhs.field2); } template bool operator!=(const KeyIndex& lhs, const KeyIndex& rhs) { return !operator==(lhs, rhs); } } // namespace Core::Crypto namespace std { template struct hash> { size_t operator()(const Core::Crypto::KeyIndex& k) const { using std::hash; return ((hash()(static_cast(k.type)) ^ (hash()(k.field1) << 1)) >> 1) ^ (hash()(k.field2) << 1); } }; } // namespace std namespace Core::Crypto { std::array operator"" _array16(const char* str, size_t len); std::array operator"" _array32(const char* str, size_t len); class KeyManager { public: KeyManager(); bool HasKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const; bool HasKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const; Key128 GetKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const; Key256 GetKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const; void SetKey(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0); void SetKey(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0); static bool KeyFileExists(bool title); private: std::unordered_map, Key128> s128_keys; std::unordered_map, Key256> s256_keys; bool dev_mode; void LoadFromFile(const std::string& filename, bool is_title_keys); void AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2, const std::string& filename, bool title); static const std::unordered_map> s128_file_id; static const std::unordered_map> s256_file_id; }; } // namespace Core::Crypto