mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Make XCI comply to review and style guidelines
This commit is contained in:
		
							parent
							
								
									22342487e8
								
							
						
					
					
						commit
						239a3113e4
					
				@ -2,58 +2,69 @@
 | 
				
			|||||||
// Licensed under GPLv2 or any later version
 | 
					// Licensed under GPLv2 or any later version
 | 
				
			||||||
// Refer to the license.txt file included.
 | 
					// Refer to the license.txt file included.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mbedtls/cipher.h>
 | 
				
			||||||
#include "core/crypto/aes_util.h"
 | 
					#include "core/crypto/aes_util.h"
 | 
				
			||||||
#include "mbedtls/cipher.h"
 | 
					#include "core/crypto/key_manager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Core::Crypto {
 | 
					namespace Core::Crypto {
 | 
				
			||||||
static_assert(static_cast<size_t>(Mode::CTR) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_CTR), "CTR mode is incorrect.");
 | 
					 | 
				
			||||||
static_assert(static_cast<size_t>(Mode::ECB) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_ECB), "ECB mode is incorrect.");
 | 
					 | 
				
			||||||
static_assert(static_cast<size_t>(Mode::XTS) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_XTS), "XTS mode is incorrect.");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename Key, size_t KeySize>
 | 
					static_assert(static_cast<size_t>(Mode::CTR) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_CTR),
 | 
				
			||||||
Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode) {
 | 
					              "CTR has incorrect value.");
 | 
				
			||||||
    mbedtls_cipher_init(encryption_context.get());
 | 
					static_assert(static_cast<size_t>(Mode::ECB) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_ECB),
 | 
				
			||||||
    mbedtls_cipher_init(decryption_context.get());
 | 
					              "ECB has incorrect value.");
 | 
				
			||||||
 | 
					static_assert(static_cast<size_t>(Mode::XTS) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_XTS),
 | 
				
			||||||
 | 
					              "XTS has incorrect value.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Structure to hide mbedtls types from header file
 | 
				
			||||||
 | 
					struct CipherContext {
 | 
				
			||||||
 | 
					    mbedtls_cipher_context_t encryption_context;
 | 
				
			||||||
 | 
					    mbedtls_cipher_context_t decryption_context;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Key, size_t KeySize>
 | 
				
			||||||
 | 
					Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode)
 | 
				
			||||||
 | 
					    : ctx(std::make_unique<CipherContext>()) {
 | 
				
			||||||
 | 
					    mbedtls_cipher_init(&ctx->encryption_context);
 | 
				
			||||||
 | 
					    mbedtls_cipher_init(&ctx->decryption_context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ASSERT_MSG((mbedtls_cipher_setup(
 | 
					    ASSERT_MSG((mbedtls_cipher_setup(
 | 
				
			||||||
            encryption_context.get(),
 | 
					                    &ctx->encryption_context,
 | 
				
			||||||
            mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode))) ||
 | 
					                    mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode))) ||
 | 
				
			||||||
                mbedtls_cipher_setup(decryption_context.get(),
 | 
					                mbedtls_cipher_setup(
 | 
				
			||||||
                                     mbedtls_cipher_info_from_type(
 | 
					                    &ctx->decryption_context,
 | 
				
			||||||
                                             static_cast<mbedtls_cipher_type_t>(mode)))) == 0,
 | 
					                    mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode)))) == 0,
 | 
				
			||||||
               "Failed to initialize mbedtls ciphers.");
 | 
					               "Failed to initialize mbedtls ciphers.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ASSERT(
 | 
					    ASSERT(
 | 
				
			||||||
            !mbedtls_cipher_setkey(encryption_context.get(), key.data(), KeySize * 8, MBEDTLS_ENCRYPT));
 | 
					        !mbedtls_cipher_setkey(&ctx->encryption_context, key.data(), KeySize * 8, MBEDTLS_ENCRYPT));
 | 
				
			||||||
    ASSERT(
 | 
					    ASSERT(
 | 
				
			||||||
            !mbedtls_cipher_setkey(decryption_context.get(), key.data(), KeySize * 8, MBEDTLS_DECRYPT));
 | 
					        !mbedtls_cipher_setkey(&ctx->decryption_context, key.data(), KeySize * 8, MBEDTLS_DECRYPT));
 | 
				
			||||||
    //"Failed to set key on mbedtls ciphers.");
 | 
					    //"Failed to set key on mbedtls ciphers.");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename Key, size_t KeySize>
 | 
					template <typename Key, size_t KeySize>
 | 
				
			||||||
AESCipher<Key, KeySize>::~AESCipher() {
 | 
					AESCipher<Key, KeySize>::~AESCipher() {
 | 
				
			||||||
    mbedtls_cipher_free(encryption_context.get());
 | 
					    mbedtls_cipher_free(&ctx->encryption_context);
 | 
				
			||||||
    mbedtls_cipher_free(decryption_context.get());
 | 
					    mbedtls_cipher_free(&ctx->decryption_context);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename Key, size_t KeySize>
 | 
					template <typename Key, size_t KeySize>
 | 
				
			||||||
void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) {
 | 
					void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) {
 | 
				
			||||||
    ASSERT_MSG((mbedtls_cipher_set_iv(encryption_context.get(), iv.data(), iv.size()) ||
 | 
					    ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) ||
 | 
				
			||||||
                mbedtls_cipher_set_iv(decryption_context.get(), iv.data(), iv.size())) == 0,
 | 
					                mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0,
 | 
				
			||||||
               "Failed to set IV on mbedtls ciphers.");
 | 
					               "Failed to set IV on mbedtls ciphers.");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename Key, size_t KeySize>
 | 
					template <typename Key, size_t KeySize>
 | 
				
			||||||
void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op op)  {
 | 
					void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op op) {
 | 
				
			||||||
    size_t written = 0;
 | 
					    size_t written = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const auto context = op == Op::Encrypt ? encryption_context.get() : decryption_context.get();
 | 
					    const auto context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mbedtls_cipher_reset(context);
 | 
					    mbedtls_cipher_reset(context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (mbedtls_cipher_get_cipher_mode(context) == MBEDTLS_MODE_XTS) {
 | 
					    if (mbedtls_cipher_get_cipher_mode(context) == MBEDTLS_MODE_XTS) {
 | 
				
			||||||
        mbedtls_cipher_update(context, src, size,
 | 
					        mbedtls_cipher_update(context, src, size, dest, &written);
 | 
				
			||||||
                              dest, &written);
 | 
					 | 
				
			||||||
        if (written != size)
 | 
					        if (written != size)
 | 
				
			||||||
            LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.",
 | 
					            LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.",
 | 
				
			||||||
                        size, written);
 | 
					                        size, written);
 | 
				
			||||||
@ -62,11 +73,9 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        for (size_t offset = 0; offset < size; offset += block_size) {
 | 
					        for (size_t offset = 0; offset < size; offset += block_size) {
 | 
				
			||||||
            auto length = std::min<size_t>(block_size, size - offset);
 | 
					            auto length = std::min<size_t>(block_size, size - offset);
 | 
				
			||||||
            mbedtls_cipher_update(context, src + offset, length,
 | 
					            mbedtls_cipher_update(context, src + offset, length, dest + offset, &written);
 | 
				
			||||||
                                  dest + offset, &written);
 | 
					 | 
				
			||||||
            if (written != length)
 | 
					            if (written != length)
 | 
				
			||||||
                LOG_WARNING(Crypto,
 | 
					                LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.",
 | 
				
			||||||
                            "Not all data was decrypted requested={:016X}, actual={:016X}.",
 | 
					 | 
				
			||||||
                            length, written);
 | 
					                            length, written);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -74,9 +83,9 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op
 | 
				
			|||||||
    mbedtls_cipher_finish(context, nullptr, nullptr);
 | 
					    mbedtls_cipher_finish(context, nullptr, nullptr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename Key, size_t KeySize>
 | 
					template <typename Key, size_t KeySize>
 | 
				
			||||||
void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size,
 | 
					void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id,
 | 
				
			||||||
                                           Op op) {
 | 
					                                           size_t sector_size, Op op) {
 | 
				
			||||||
    if (size % sector_size > 0) {
 | 
					    if (size % sector_size > 0) {
 | 
				
			||||||
        LOG_CRITICAL(Crypto, "Data size must be a multiple of sector size.");
 | 
					        LOG_CRITICAL(Crypto, "Data size must be a multiple of sector size.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
@ -84,12 +93,11 @@ void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    for (size_t i = 0; i < size; i += sector_size) {
 | 
					    for (size_t i = 0; i < size; i += sector_size) {
 | 
				
			||||||
        SetIV(CalculateNintendoTweak(sector_id++));
 | 
					        SetIV(CalculateNintendoTweak(sector_id++));
 | 
				
			||||||
        Transcode<u8, u8>(src + i, sector_size,
 | 
					        Transcode<u8, u8>(src + i, sector_size, dest + i, op);
 | 
				
			||||||
                          dest + i, op);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename Key, size_t KeySize>
 | 
					template <typename Key, size_t KeySize>
 | 
				
			||||||
std::vector<u8> AESCipher<Key, KeySize>::CalculateNintendoTweak(size_t sector_id) {
 | 
					std::vector<u8> AESCipher<Key, KeySize>::CalculateNintendoTweak(size_t sector_id) {
 | 
				
			||||||
    std::vector<u8> out(0x10);
 | 
					    std::vector<u8> out(0x10);
 | 
				
			||||||
    for (size_t i = 0xF; i <= 0xF; --i) {
 | 
					    for (size_t i = 0xF; i <= 0xF; --i) {
 | 
				
			||||||
@ -101,4 +109,4 @@ std::vector<u8> AESCipher<Key, KeySize>::CalculateNintendoTweak(size_t sector_id
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template class AESCipher<Key128>;
 | 
					template class AESCipher<Key128>;
 | 
				
			||||||
template class AESCipher<Key256>;
 | 
					template class AESCipher<Key256>;
 | 
				
			||||||
}
 | 
					} // namespace Core::Crypto
 | 
				
			||||||
@ -20,7 +20,7 @@ enum class Op {
 | 
				
			|||||||
    Decrypt,
 | 
					    Decrypt,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mbedtls_cipher_context_t;
 | 
					struct CipherContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Key, size_t KeySize = sizeof(Key)>
 | 
					template <typename Key, size_t KeySize = sizeof(Key)>
 | 
				
			||||||
class AESCipher {
 | 
					class AESCipher {
 | 
				
			||||||
@ -44,15 +44,16 @@ public:
 | 
				
			|||||||
    template <typename Source, typename Dest>
 | 
					    template <typename Source, typename Dest>
 | 
				
			||||||
    void XTSTranscode(const Source* src, size_t size, Dest* dest, size_t sector_id,
 | 
					    void XTSTranscode(const Source* src, size_t size, Dest* dest, size_t sector_id,
 | 
				
			||||||
                      size_t sector_size, Op op) {
 | 
					                      size_t sector_size, Op op) {
 | 
				
			||||||
        XTSTranscode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), sector_id, sector_size, op);
 | 
					        XTSTranscode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), sector_id,
 | 
				
			||||||
 | 
					                     sector_size, op);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size, Op op);
 | 
					    void XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size,
 | 
				
			||||||
 | 
					                      Op op);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    std::unique_ptr<mbedtls_cipher_context_t> encryption_context;
 | 
					    std::unique_ptr<CipherContext> ctx;
 | 
				
			||||||
    std::unique_ptr<mbedtls_cipher_context_t> decryption_context;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static std::vector<u8> CalculateNintendoTweak(size_t sector_id);
 | 
					    static std::vector<u8> CalculateNintendoTweak(size_t sector_id);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
} // namespace Crypto
 | 
					} // namespace Core::Crypto
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,8 @@
 | 
				
			|||||||
#include "common/assert.h"
 | 
					#include "common/assert.h"
 | 
				
			||||||
#include "core/crypto/ctr_encryption_layer.h"
 | 
					#include "core/crypto/ctr_encryption_layer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Crypto {
 | 
					namespace Core::Crypto {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, size_t base_offset)
 | 
					CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, size_t base_offset)
 | 
				
			||||||
    : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR),
 | 
					    : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR),
 | 
				
			||||||
      iv(16, 0) {}
 | 
					      iv(16, 0) {}
 | 
				
			||||||
@ -21,29 +22,28 @@ size_t CTREncryptionLayer::Read(u8* data, size_t length, size_t offset) const {
 | 
				
			|||||||
        std::vector<u8> raw = base->ReadBytes(length, offset);
 | 
					        std::vector<u8> raw = base->ReadBytes(length, offset);
 | 
				
			||||||
        if (raw.size() != length)
 | 
					        if (raw.size() != length)
 | 
				
			||||||
            return Read(data, raw.size(), offset);
 | 
					            return Read(data, raw.size(), offset);
 | 
				
			||||||
        cipher.Transcode(raw.data(), length, data, Op::DECRYPT);
 | 
					        cipher.Transcode(raw.data(), length, data, Op::Decrypt);
 | 
				
			||||||
        return length;
 | 
					        return length;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // offset does not fall on block boundary (0x10)
 | 
					    // offset does not fall on block boundary (0x10)
 | 
				
			||||||
    std::vector<u8> block = base->ReadBytes(0x10, offset - sector_offset);
 | 
					    std::vector<u8> block = base->ReadBytes(0x10, offset - sector_offset);
 | 
				
			||||||
    UpdateIV(base_offset + offset - sector_offset);
 | 
					    UpdateIV(base_offset + offset - sector_offset);
 | 
				
			||||||
    cipher.Transcode(block.data(), block.size(), block.data(), Op::DECRYPT);
 | 
					    cipher.Transcode(block.data(), block.size(), block.data(), Op::Decrypt);
 | 
				
			||||||
    size_t read = 0x10 - sector_offset;
 | 
					    size_t read = 0x10 - sector_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (length + sector_offset < 0x10) {
 | 
					    if (length + sector_offset < 0x10) {
 | 
				
			||||||
        memcpy_s(data, length, block.data() + sector_offset, std::min<u64>(length, read));
 | 
					        memcpy(data, block.data() + sector_offset, std::min<u64>(length, read));
 | 
				
			||||||
        return read;
 | 
					        return read;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memcpy_s(data, length, block.data() + sector_offset, read);
 | 
					    memcpy(data, block.data() + sector_offset, read);
 | 
				
			||||||
    return read + Read(data + read, length - read, offset + read);
 | 
					    return read + Read(data + read, length - read, offset + read);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CTREncryptionLayer::SetIV(std::vector<u8> iv_) {
 | 
					void CTREncryptionLayer::SetIV(const std::vector<u8>& iv_) {
 | 
				
			||||||
    const auto length = std::min<size_t>(iv_.size(), iv.size());
 | 
					    const auto length = std::min(iv_.size(), iv.size());
 | 
				
			||||||
    for (size_t i = 0; i < length; ++i)
 | 
					    iv.assign(iv_.cbegin(), iv_.cbegin() + length);
 | 
				
			||||||
        iv[i] = iv_[i];
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CTREncryptionLayer::UpdateIV(size_t offset) const {
 | 
					void CTREncryptionLayer::UpdateIV(size_t offset) const {
 | 
				
			||||||
@ -54,4 +54,4 @@ void CTREncryptionLayer::UpdateIV(size_t offset) const {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    cipher.SetIV(iv);
 | 
					    cipher.SetIV(iv);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
} // namespace Crypto
 | 
					} // namespace Core::Crypto
 | 
				
			||||||
 | 
				
			|||||||
@ -4,19 +4,20 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "aes_util.h"
 | 
					#include "core/crypto/aes_util.h"
 | 
				
			||||||
#include "encryption_layer.h"
 | 
					#include "core/crypto/encryption_layer.h"
 | 
				
			||||||
#include "key_manager.h"
 | 
					#include "core/crypto/key_manager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Crypto {
 | 
					namespace Core::Crypto {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Sits on top of a VirtualFile and provides CTR-mode AES decription.
 | 
					// Sits on top of a VirtualFile and provides CTR-mode AES decription.
 | 
				
			||||||
struct CTREncryptionLayer : public EncryptionLayer {
 | 
					class CTREncryptionLayer : public EncryptionLayer {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
    CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, size_t base_offset);
 | 
					    CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, size_t base_offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    size_t Read(u8* data, size_t length, size_t offset) const override;
 | 
					    size_t Read(u8* data, size_t length, size_t offset) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void SetIV(std::vector<u8> iv);
 | 
					    void SetIV(const std::vector<u8>& iv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    size_t base_offset;
 | 
					    size_t base_offset;
 | 
				
			||||||
@ -28,4 +29,4 @@ private:
 | 
				
			|||||||
    void UpdateIV(size_t offset) const;
 | 
					    void UpdateIV(size_t offset) const;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Crypto
 | 
					} // namespace Core::Crypto
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "core/crypto/encryption_layer.h"
 | 
					#include "core/crypto/encryption_layer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Crypto {
 | 
					namespace Core::Crypto {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EncryptionLayer::EncryptionLayer(FileSys::VirtualFile base_) : base(std::move(base_)) {}
 | 
					EncryptionLayer::EncryptionLayer(FileSys::VirtualFile base_) : base(std::move(base_)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -39,4 +39,4 @@ size_t EncryptionLayer::Write(const u8* data, size_t length, size_t offset) {
 | 
				
			|||||||
bool EncryptionLayer::Rename(std::string_view name) {
 | 
					bool EncryptionLayer::Rename(std::string_view name) {
 | 
				
			||||||
    return base->Rename(name);
 | 
					    return base->Rename(name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
} // namespace Crypto
 | 
					} // namespace Core::Crypto
 | 
				
			||||||
 | 
				
			|||||||
@ -3,9 +3,10 @@
 | 
				
			|||||||
// Refer to the license.txt file included.
 | 
					// Refer to the license.txt file included.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/file_sys/vfs.h"
 | 
					#include "core/file_sys/vfs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Crypto {
 | 
					namespace Core::Crypto {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Basically non-functional class that implements all of the methods that are irrelevant to an
 | 
					// Basically non-functional class that implements all of the methods that are irrelevant to an
 | 
				
			||||||
// EncryptionLayer. Reduces duplicate code.
 | 
					// EncryptionLayer. Reduces duplicate code.
 | 
				
			||||||
@ -27,4 +28,4 @@ protected:
 | 
				
			|||||||
    FileSys::VirtualFile base;
 | 
					    FileSys::VirtualFile base;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Crypto
 | 
					} // namespace Core::Crypto
 | 
				
			||||||
 | 
				
			|||||||
@ -5,238 +5,15 @@
 | 
				
			|||||||
#include <fstream>
 | 
					#include <fstream>
 | 
				
			||||||
#include <locale>
 | 
					#include <locale>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <mbedtls/sha256.h>
 | 
				
			||||||
#include "common/assert.h"
 | 
					#include "common/assert.h"
 | 
				
			||||||
 | 
					#include "common/common_paths.h"
 | 
				
			||||||
 | 
					#include "common/file_util.h"
 | 
				
			||||||
#include "common/logging/log.h"
 | 
					#include "common/logging/log.h"
 | 
				
			||||||
#include "core/crypto/key_manager.h"
 | 
					#include "core/crypto/key_manager.h"
 | 
				
			||||||
#include "mbedtls/sha256.h"
 | 
					#include "core/settings.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Crypto {
 | 
					namespace Core::Crypto {
 | 
				
			||||||
KeyManager keys = {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::unordered_map<KeyIndex<S128KeyType>, SHA256Hash> KeyManager::s128_hash_prod = {
 | 
					 | 
				
			||||||
    {{S128KeyType::MASTER, 0, 0},
 | 
					 | 
				
			||||||
     "0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::MASTER, 1, 0},
 | 
					 | 
				
			||||||
     "4FE707B7E4ABDAF727C894AAF13B1351BFE2AC90D875F73B2E20FA94B9CC661E"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::MASTER, 2, 0},
 | 
					 | 
				
			||||||
     "79277C0237A2252EC3DFAC1F7C359C2B3D121E9DB15BB9AB4C2B4408D2F3AE09"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::MASTER, 3, 0},
 | 
					 | 
				
			||||||
     "4F36C565D13325F65EE134073C6A578FFCB0008E02D69400836844EAB7432754"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::MASTER, 4, 0},
 | 
					 | 
				
			||||||
     "75ff1d95d26113550ee6fcc20acb58e97edeb3a2ff52543ed5aec63bdcc3da50"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE1, 0, 0},
 | 
					 | 
				
			||||||
     "4543CD1B7CAD7EE0466A3DE2086A0EF923805DCEA6C741541CDDB14F54F97B40"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE1, 1, 0},
 | 
					 | 
				
			||||||
     "4A11DA019D26470C9B805F1721364830DC0096DD66EAC453B0D14455E5AF5CF8"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE1, 2, 0},
 | 
					 | 
				
			||||||
     "CCA867360B3318246FBF0B8A86473176ED486DFE229772B941A02E84D50A3155"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE1, 3, 0},
 | 
					 | 
				
			||||||
     "E65C383CDF526DFFAA77682868EBFA9535EE60D8075C961BBC1EDE5FBF7E3C5F"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE1, 4, 0},
 | 
					 | 
				
			||||||
     "28ae73d6ae8f7206fca549e27097714e599df1208e57099416ff429b71370162"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE2, 0, 0},
 | 
					 | 
				
			||||||
     "94D6F38B9D0456644E21DFF4707D092B70179B82D1AA2F5B6A76B8F9ED948264"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE2, 1, 0},
 | 
					 | 
				
			||||||
     "7794F24FA879D378FEFDC8776B949B88AD89386410BE9025D463C619F1530509"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE2, 2, 0},
 | 
					 | 
				
			||||||
     "5304BDDE6AC8E462961B5DB6E328B1816D245D36D6574BB78938B74D4418AF35"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE2, 3, 0},
 | 
					 | 
				
			||||||
     "BE1E52C4345A979DDD4924375B91C902052C2E1CF8FBF2FAA42E8F26D5125B60"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE2, 4, 0},
 | 
					 | 
				
			||||||
     "631b45d349ab8f76a050fe59512966fb8dbaf0755ef5b6903048bf036cfa611e"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::TITLEKEK, 0, 0},
 | 
					 | 
				
			||||||
     "C2FA30CAC6AE1680466CB54750C24550E8652B3B6F38C30B49DADF067B5935E9"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::TITLEKEK, 1, 0},
 | 
					 | 
				
			||||||
     "0D6B8F3746AD910D36438A859C11E8BE4310112425D63751D09B5043B87DE598"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::TITLEKEK, 2, 0},
 | 
					 | 
				
			||||||
     "D09E18D3DB6BC7393536896F728528736FBEFCDD15C09D9D612FDE5C7BDCD821"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::TITLEKEK, 3, 0},
 | 
					 | 
				
			||||||
     "47C6F9F7E99BB1F56DCDC93CDBD340EA82DCCD74DD8F3535ADA20ECF79D438ED"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::TITLEKEK, 4, 0},
 | 
					 | 
				
			||||||
     "128610de8424cb29e08f9ee9a81c9e6ffd3c6662854aad0c8f937e0bcedc4d88"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::ETICKET_RSA_KEK, 0, 0},
 | 
					 | 
				
			||||||
     "46cccf288286e31c931379de9efa288c95c9a15e40b00a4c563a8be244ece515"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::Application)},
 | 
					 | 
				
			||||||
     "592957F44FE5DB5EC6B095F568910E31A226D3B7FE42D64CFB9CE4051E90AEB6"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::Application)},
 | 
					 | 
				
			||||||
     "C2252A0FBF9D339ABC3D681351D00452F926E7CA0C6CA85F659078DE3FA647F3"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::Application)},
 | 
					 | 
				
			||||||
     "7C7722824B2F7C4938C40F3EA93E16CB69D3285EB133490EF8ECCD2C4B52DF41"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::Application)},
 | 
					 | 
				
			||||||
     "AFBB8EBFB2094F1CF71E330826AE06D64414FCA128C464618DF30EED92E62BE6"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::Application)},
 | 
					 | 
				
			||||||
     "5dc10eb81918da3f2fa90f69c8542511963656cfb31fb7c779581df8faf1f2f5"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::Ocean)},
 | 
					 | 
				
			||||||
     "AA2C65F0E27F730807A13F2ED5B99BE5183165B87C50B6ED48F5CAC2840687EB"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::Ocean)},
 | 
					 | 
				
			||||||
     "860185F2313A14F7006A029CB21A52750E7718C1E94FFB98C0AE2207D1A60165"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::Ocean)},
 | 
					 | 
				
			||||||
     "7283FB1EFBD42438DADF363FDB776ED355C98737A2AAE75D0E9283CE1C12A2E4"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::Ocean)},
 | 
					 | 
				
			||||||
     "9881C2D3AB70B14C8AA12016FC73ADAD93C6AD9FB59A9ECAD312B6F89E2413EC"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::Ocean)},
 | 
					 | 
				
			||||||
     "eaa6a8d242b89e174928fa9549a0f66ec1562e2576fac896f438a2b3c1fb6005"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::System)},
 | 
					 | 
				
			||||||
     "194CF6BD14554DA8D457E14CBFE04E55C8FB8CA52E0AFB3D7CB7084AE435B801"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::System)},
 | 
					 | 
				
			||||||
     "CE1DB7BB6E5962384889DB7A396AFD614F82F69DC38A33D2DEAF47F3E4B964B7"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::System)},
 | 
					 | 
				
			||||||
     "42238DE5685DEF4FDE7BE42C0097CEB92447006386D6B5D5AAA2C9AFD2E28422"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::System)},
 | 
					 | 
				
			||||||
     "1F6847F268E9D9C5D1AD4D7E226A63B833BF02071446957A962EF065521879C1"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::System)},
 | 
					 | 
				
			||||||
     "644007f9913c3602399d4d75cc34faeb7f1faad18b23e34187b16fdc45f4980f"_array32},
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::unordered_map<KeyIndex<S256KeyType>, SHA256Hash> KeyManager::s256_hash_prod = {
 | 
					 | 
				
			||||||
    {{S256KeyType::HEADER, 0, 0},
 | 
					 | 
				
			||||||
     "8E03DE24818D96CE4F2A09B43AF979E679974F7570713A61EED8B314864A11D5"_array32},
 | 
					 | 
				
			||||||
    {{S256KeyType::SD_SAVE, 0, 0},
 | 
					 | 
				
			||||||
     "13020ee72d0f8b8f9112dc738b829fdb017102499a7c2259b52aeefc0a273f5c"_array32},
 | 
					 | 
				
			||||||
    {{S256KeyType::SD_NCA, 0, 0},
 | 
					 | 
				
			||||||
     "8a1c05b4f88bae5b04d77f632e6acfc8893c4a05fd701f53585daafc996b532a"_array32},
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO(DarkLordZach): Find missing hashes for dev keys.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::unordered_map<KeyIndex<S128KeyType>, SHA256Hash> KeyManager::s128_hash_dev = {
 | 
					 | 
				
			||||||
    {{S128KeyType::MASTER, 0, 0},
 | 
					 | 
				
			||||||
     "779dd8b533a2fb670f27b308cb8d0151c4a107568b817429172b7f80aa592c25"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::MASTER, 1, 0},
 | 
					 | 
				
			||||||
     "0175c8bc49771576f75527be719098db4ebaf77707206749415663aa3a9ea9cc"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::MASTER, 2, 0},
 | 
					 | 
				
			||||||
     "4f0b4d724e5a8787268157c7ce0767c26d2e2021832aa7020f306d6e260eea42"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::MASTER, 3, 0},
 | 
					 | 
				
			||||||
     "7b5a29586c1f84f66fbfabb94518fc45408bb8e5445253d063dda7cfef2a818c"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::MASTER, 4, 0},
 | 
					 | 
				
			||||||
     "87a61dbb05a8755de7fe069562aab38ebfb266c9eb835f09fa62dacc89c98341"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE1, 0, 0},
 | 
					 | 
				
			||||||
     "166510bc63ae50391ebe4ee4ff90ca31cd0e2dd0ff6be839a2f573ec146cc23a"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE1, 1, 0},
 | 
					 | 
				
			||||||
     "f74cd01b86743139c920ec54a8116c669eea805a0be1583e13fc5bc8de68645b"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE1, 2, 0},
 | 
					 | 
				
			||||||
     "d0cdecd513bb6aa3d9dc6244c977dc8a5a7ea157d0a8747d79e7581146e1f768"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE1, 3, 0},
 | 
					 | 
				
			||||||
     "aa39394d626b3b79f5b7ccc07378b5996b6d09bf0eb6771b0b40c9077fbfde8c"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE1, 4, 0},
 | 
					 | 
				
			||||||
     "8f4754b8988c0e673fc2bbea0534cdd6075c815c9270754ae980aef3e4f0a508"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE2, 0, 0},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE2, 1, 0},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE2, 2, 0},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE2, 3, 0},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::PACKAGE2, 4, 0},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::TITLEKEK, 0, 0},
 | 
					 | 
				
			||||||
     "C2FA30CAC6AE1680466CB54750C24550E8652B3B6F38C30B49DADF067B5935E9"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::TITLEKEK, 1, 0},
 | 
					 | 
				
			||||||
     "0D6B8F3746AD910D36438A859C11E8BE4310112425D63751D09B5043B87DE598"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::TITLEKEK, 2, 0},
 | 
					 | 
				
			||||||
     "D09E18D3DB6BC7393536896F728528736FBEFCDD15C09D9D612FDE5C7BDCD821"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::TITLEKEK, 3, 0},
 | 
					 | 
				
			||||||
     "47C6F9F7E99BB1F56DCDC93CDBD340EA82DCCD74DD8F3535ADA20ECF79D438ED"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::TITLEKEK, 4, 0},
 | 
					 | 
				
			||||||
     "128610de8424cb29e08f9ee9a81c9e6ffd3c6662854aad0c8f937e0bcedc4d88"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::ETICKET_RSA_KEK, 0, 0},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::Application)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::Application)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::Application)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::Application)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::Application)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::Ocean)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::Ocean)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::Ocean)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::Ocean)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::Ocean)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::System)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::System)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::System)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::System)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::System)},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::unordered_map<KeyIndex<S256KeyType>, SHA256Hash> KeyManager::s256_hash_dev = {
 | 
					 | 
				
			||||||
    {{S256KeyType::HEADER, 0, 0},
 | 
					 | 
				
			||||||
     "ecde86a76e37ac4fd7591d3aa55c00cc77d8595fc27968052ec18a177d939060"_array32},
 | 
					 | 
				
			||||||
    {{S256KeyType::SD_SAVE, 0, 0},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
    {{S256KeyType::SD_NCA, 0, 0},
 | 
					 | 
				
			||||||
     "0000000000000000000000000000000000000000000000000000000000000000"_array32},
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::unordered_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = {
 | 
					 | 
				
			||||||
    {"master_key_00", {S128KeyType::MASTER, 0, 0}},
 | 
					 | 
				
			||||||
    {"master_key_01", {S128KeyType::MASTER, 1, 0}},
 | 
					 | 
				
			||||||
    {"master_key_02", {S128KeyType::MASTER, 2, 0}},
 | 
					 | 
				
			||||||
    {"master_key_03", {S128KeyType::MASTER, 3, 0}},
 | 
					 | 
				
			||||||
    {"master_key_04", {S128KeyType::MASTER, 4, 0}},
 | 
					 | 
				
			||||||
    {"package1_key_00", {S128KeyType::PACKAGE1, 0, 0}},
 | 
					 | 
				
			||||||
    {"package1_key_01", {S128KeyType::PACKAGE1, 1, 0}},
 | 
					 | 
				
			||||||
    {"package1_key_02", {S128KeyType::PACKAGE1, 2, 0}},
 | 
					 | 
				
			||||||
    {"package1_key_03", {S128KeyType::PACKAGE1, 3, 0}},
 | 
					 | 
				
			||||||
    {"package1_key_04", {S128KeyType::PACKAGE1, 4, 0}},
 | 
					 | 
				
			||||||
    {"package2_key_00", {S128KeyType::PACKAGE2, 0, 0}},
 | 
					 | 
				
			||||||
    {"package2_key_01", {S128KeyType::PACKAGE2, 1, 0}},
 | 
					 | 
				
			||||||
    {"package2_key_02", {S128KeyType::PACKAGE2, 2, 0}},
 | 
					 | 
				
			||||||
    {"package2_key_03", {S128KeyType::PACKAGE2, 3, 0}},
 | 
					 | 
				
			||||||
    {"package2_key_04", {S128KeyType::PACKAGE2, 4, 0}},
 | 
					 | 
				
			||||||
    {"titlekek_00", {S128KeyType::TITLEKEK, 0, 0}},
 | 
					 | 
				
			||||||
    {"titlekek_01", {S128KeyType::TITLEKEK, 1, 0}},
 | 
					 | 
				
			||||||
    {"titlekek_02", {S128KeyType::TITLEKEK, 2, 0}},
 | 
					 | 
				
			||||||
    {"titlekek_03", {S128KeyType::TITLEKEK, 3, 0}},
 | 
					 | 
				
			||||||
    {"titlekek_04", {S128KeyType::TITLEKEK, 4, 0}},
 | 
					 | 
				
			||||||
    {"eticket_rsa_kek", {S128KeyType::ETICKET_RSA_KEK, 0, 0}},
 | 
					 | 
				
			||||||
    {"key_area_key_application_00",
 | 
					 | 
				
			||||||
     {S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::Application)}},
 | 
					 | 
				
			||||||
    {"key_area_key_application_01",
 | 
					 | 
				
			||||||
     {S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::Application)}},
 | 
					 | 
				
			||||||
    {"key_area_key_application_02",
 | 
					 | 
				
			||||||
     {S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::Application)}},
 | 
					 | 
				
			||||||
    {"key_area_key_application_03",
 | 
					 | 
				
			||||||
     {S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::Application)}},
 | 
					 | 
				
			||||||
    {"key_area_key_application_04",
 | 
					 | 
				
			||||||
     {S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::Application)}},
 | 
					 | 
				
			||||||
    {"key_area_key_ocean_00", {S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::Ocean)}},
 | 
					 | 
				
			||||||
    {"key_area_key_ocean_01", {S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::Ocean)}},
 | 
					 | 
				
			||||||
    {"key_area_key_ocean_02", {S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::Ocean)}},
 | 
					 | 
				
			||||||
    {"key_area_key_ocean_03", {S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::Ocean)}},
 | 
					 | 
				
			||||||
    {"key_area_key_ocean_04", {S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::Ocean)}},
 | 
					 | 
				
			||||||
    {"key_area_key_system_00",
 | 
					 | 
				
			||||||
     {S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::System)}},
 | 
					 | 
				
			||||||
    {"key_area_key_system_01",
 | 
					 | 
				
			||||||
     {S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::System)}},
 | 
					 | 
				
			||||||
    {"key_area_key_system_02",
 | 
					 | 
				
			||||||
     {S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::System)}},
 | 
					 | 
				
			||||||
    {"key_area_key_system_03",
 | 
					 | 
				
			||||||
     {S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::System)}},
 | 
					 | 
				
			||||||
    {"key_area_key_system_04",
 | 
					 | 
				
			||||||
     {S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::System)}},
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::unordered_map<std::string, KeyIndex<S256KeyType>> KeyManager::s256_file_id = {
 | 
					 | 
				
			||||||
    {"header_key", {S256KeyType::HEADER, 0, 0}},
 | 
					 | 
				
			||||||
    {"sd_card_save_key", {S256KeyType::SD_SAVE, 0, 0}},
 | 
					 | 
				
			||||||
    {"sd_card_nca_key", {S256KeyType::SD_NCA, 0, 0}},
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static u8 ToHexNibble(char c1) {
 | 
					static u8 ToHexNibble(char c1) {
 | 
				
			||||||
    if (c1 >= 65 && c1 <= 70)
 | 
					    if (c1 >= 65 && c1 <= 70)
 | 
				
			||||||
@ -271,8 +48,20 @@ std::array<u8, 32> operator""_array32(const char* str, size_t len) {
 | 
				
			|||||||
    return HexStringToArray<32>(str);
 | 
					    return HexStringToArray<32>(str);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void KeyManager::SetValidationMode(bool dev) {
 | 
					KeyManager::KeyManager() {
 | 
				
			||||||
    dev_mode = dev;
 | 
					    // Initialize keys
 | 
				
			||||||
 | 
					    std::string keys_dir = FileUtil::GetHactoolConfigurationPath();
 | 
				
			||||||
 | 
					    if (Settings::values.use_dev_keys) {
 | 
				
			||||||
 | 
					        dev_mode = true;
 | 
				
			||||||
 | 
					        if (FileUtil::Exists(keys_dir + DIR_SEP + "dev.keys"))
 | 
				
			||||||
 | 
					            LoadFromFile(keys_dir + DIR_SEP + "dev.keys", false);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        dev_mode = false;
 | 
				
			||||||
 | 
					        if (FileUtil::Exists(keys_dir + DIR_SEP + "prod.keys"))
 | 
				
			||||||
 | 
					            LoadFromFile(keys_dir + DIR_SEP + "prod.keys", false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (FileUtil::Exists(keys_dir + DIR_SEP + "title.keys"))
 | 
				
			||||||
 | 
					        LoadFromFile(keys_dir + DIR_SEP + "title.keys", true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void KeyManager::LoadFromFile(std::string_view filename_, bool is_title_keys) {
 | 
					void KeyManager::LoadFromFile(std::string_view filename_, bool is_title_keys) {
 | 
				
			||||||
@ -299,7 +88,7 @@ void KeyManager::LoadFromFile(std::string_view filename_, bool is_title_keys) {
 | 
				
			|||||||
            auto rights_id_raw = HexStringToArray<16>(out[0]);
 | 
					            auto rights_id_raw = HexStringToArray<16>(out[0]);
 | 
				
			||||||
            u128 rights_id = *reinterpret_cast<std::array<u64, 2>*>(&rights_id_raw);
 | 
					            u128 rights_id = *reinterpret_cast<std::array<u64, 2>*>(&rights_id_raw);
 | 
				
			||||||
            Key128 key = HexStringToArray<16>(out[1]);
 | 
					            Key128 key = HexStringToArray<16>(out[1]);
 | 
				
			||||||
            SetKey(S128KeyType::TITLEKEY, key, rights_id[1], rights_id[0]);
 | 
					            SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            std::transform(out[0].begin(), out[0].end(), out[0].begin(), ::tolower);
 | 
					            std::transform(out[0].begin(), out[0].end(), out[0].begin(), ::tolower);
 | 
				
			||||||
            if (s128_file_id.find(out[0]) != s128_file_id.end()) {
 | 
					            if (s128_file_id.find(out[0]) != s128_file_id.end()) {
 | 
				
			||||||
@ -315,24 +104,24 @@ void KeyManager::LoadFromFile(std::string_view filename_, bool is_title_keys) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool KeyManager::HasKey(S128KeyType id, u64 field1, u64 field2) {
 | 
					bool KeyManager::HasKey(S128KeyType id, u64 field1, u64 field2) const {
 | 
				
			||||||
    return s128_keys.find({id, field1, field2}) != s128_keys.end();
 | 
					    return s128_keys.find({id, field1, field2}) != s128_keys.end();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool KeyManager::HasKey(S256KeyType id, u64 field1, u64 field2) {
 | 
					bool KeyManager::HasKey(S256KeyType id, u64 field1, u64 field2) const {
 | 
				
			||||||
    return s256_keys.find({id, field1, field2}) != s256_keys.end();
 | 
					    return s256_keys.find({id, field1, field2}) != s256_keys.end();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Key128 KeyManager::GetKey(S128KeyType id, u64 field1, u64 field2) {
 | 
					Key128 KeyManager::GetKey(S128KeyType id, u64 field1, u64 field2) const {
 | 
				
			||||||
    if (!HasKey(id, field1, field2))
 | 
					    if (!HasKey(id, field1, field2))
 | 
				
			||||||
        return {};
 | 
					        return {};
 | 
				
			||||||
    return s128_keys[{id, field1, field2}];
 | 
					    return s128_keys.at({id, field1, field2});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) {
 | 
					Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) const {
 | 
				
			||||||
    if (!HasKey(id, field1, field2))
 | 
					    if (!HasKey(id, field1, field2))
 | 
				
			||||||
        return {};
 | 
					        return {};
 | 
				
			||||||
    return s256_keys[{id, field1, field2}];
 | 
					    return s256_keys.at({id, field1, field2});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
 | 
					void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
 | 
				
			||||||
@ -343,68 +132,53 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
 | 
				
			|||||||
    s256_keys[{id, field1, field2}] = key;
 | 
					    s256_keys[{id, field1, field2}] = key;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool KeyManager::ValidateKey(S128KeyType key, u64 field1, u64 field2) {
 | 
					std::unordered_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = {
 | 
				
			||||||
    auto& hash = dev_mode ? s128_hash_dev : s128_hash_prod;
 | 
					    {"master_key_00", {S128KeyType::Master, 0, 0}},
 | 
				
			||||||
 | 
					    {"master_key_01", {S128KeyType::Master, 1, 0}},
 | 
				
			||||||
 | 
					    {"master_key_02", {S128KeyType::Master, 2, 0}},
 | 
				
			||||||
 | 
					    {"master_key_03", {S128KeyType::Master, 3, 0}},
 | 
				
			||||||
 | 
					    {"master_key_04", {S128KeyType::Master, 4, 0}},
 | 
				
			||||||
 | 
					    {"package1_key_00", {S128KeyType::Package1, 0, 0}},
 | 
				
			||||||
 | 
					    {"package1_key_01", {S128KeyType::Package1, 1, 0}},
 | 
				
			||||||
 | 
					    {"package1_key_02", {S128KeyType::Package1, 2, 0}},
 | 
				
			||||||
 | 
					    {"package1_key_03", {S128KeyType::Package1, 3, 0}},
 | 
				
			||||||
 | 
					    {"package1_key_04", {S128KeyType::Package1, 4, 0}},
 | 
				
			||||||
 | 
					    {"package2_key_00", {S128KeyType::Package2, 0, 0}},
 | 
				
			||||||
 | 
					    {"package2_key_01", {S128KeyType::Package2, 1, 0}},
 | 
				
			||||||
 | 
					    {"package2_key_02", {S128KeyType::Package2, 2, 0}},
 | 
				
			||||||
 | 
					    {"package2_key_03", {S128KeyType::Package2, 3, 0}},
 | 
				
			||||||
 | 
					    {"package2_key_04", {S128KeyType::Package2, 4, 0}},
 | 
				
			||||||
 | 
					    {"titlekek_00", {S128KeyType::Titlekek, 0, 0}},
 | 
				
			||||||
 | 
					    {"titlekek_01", {S128KeyType::Titlekek, 1, 0}},
 | 
				
			||||||
 | 
					    {"titlekek_02", {S128KeyType::Titlekek, 2, 0}},
 | 
				
			||||||
 | 
					    {"titlekek_03", {S128KeyType::Titlekek, 3, 0}},
 | 
				
			||||||
 | 
					    {"titlekek_04", {S128KeyType::Titlekek, 4, 0}},
 | 
				
			||||||
 | 
					    {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
 | 
				
			||||||
 | 
					    {"key_area_key_application_00",
 | 
				
			||||||
 | 
					     {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::Application)}},
 | 
				
			||||||
 | 
					    {"key_area_key_application_01",
 | 
				
			||||||
 | 
					     {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::Application)}},
 | 
				
			||||||
 | 
					    {"key_area_key_application_02",
 | 
				
			||||||
 | 
					     {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::Application)}},
 | 
				
			||||||
 | 
					    {"key_area_key_application_03",
 | 
				
			||||||
 | 
					     {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::Application)}},
 | 
				
			||||||
 | 
					    {"key_area_key_application_04",
 | 
				
			||||||
 | 
					     {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::Application)}},
 | 
				
			||||||
 | 
					    {"key_area_key_ocean_00", {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::Ocean)}},
 | 
				
			||||||
 | 
					    {"key_area_key_ocean_01", {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::Ocean)}},
 | 
				
			||||||
 | 
					    {"key_area_key_ocean_02", {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::Ocean)}},
 | 
				
			||||||
 | 
					    {"key_area_key_ocean_03", {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::Ocean)}},
 | 
				
			||||||
 | 
					    {"key_area_key_ocean_04", {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::Ocean)}},
 | 
				
			||||||
 | 
					    {"key_area_key_system_00", {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::System)}},
 | 
				
			||||||
 | 
					    {"key_area_key_system_01", {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::System)}},
 | 
				
			||||||
 | 
					    {"key_area_key_system_02", {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::System)}},
 | 
				
			||||||
 | 
					    {"key_area_key_system_03", {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::System)}},
 | 
				
			||||||
 | 
					    {"key_area_key_system_04", {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::System)}},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    KeyIndex<S128KeyType> id = {key, field1, field2};
 | 
					std::unordered_map<std::string, KeyIndex<S256KeyType>> KeyManager::s256_file_id = {
 | 
				
			||||||
    if (key == S128KeyType::SD_SEED || key == S128KeyType::TITLEKEY ||
 | 
					    {"header_key", {S256KeyType::Header, 0, 0}},
 | 
				
			||||||
        hash.find(id) == hash.end()) {
 | 
					    {"sd_card_save_key", {S256KeyType::SDSave, 0, 0}},
 | 
				
			||||||
        LOG_WARNING(Crypto, "Could not validate [{}]", id.DebugInfo());
 | 
					    {"sd_card_nca_key", {S256KeyType::SDNCA, 0, 0}},
 | 
				
			||||||
        return true;
 | 
					};
 | 
				
			||||||
    }
 | 
					} // namespace Core::Crypto
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!HasKey(key, field1, field2)) {
 | 
					 | 
				
			||||||
        LOG_CRITICAL(Crypto,
 | 
					 | 
				
			||||||
                     "System has requested validation of [{}], but user has not added it. Add this "
 | 
					 | 
				
			||||||
                     "key to use functionality.",
 | 
					 | 
				
			||||||
                     id.DebugInfo());
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SHA256Hash key_hash{};
 | 
					 | 
				
			||||||
    const auto a_key = GetKey(key, field1, field2);
 | 
					 | 
				
			||||||
    mbedtls_sha256(a_key.data(), a_key.size(), key_hash.data(), 0);
 | 
					 | 
				
			||||||
    if (key_hash != hash[id]) {
 | 
					 | 
				
			||||||
        LOG_CRITICAL(Crypto,
 | 
					 | 
				
			||||||
                     "The hash of the provided key for [{}] does not match the one on file. This "
 | 
					 | 
				
			||||||
                     "means you probably have an incorrect key. If you believe this to be in "
 | 
					 | 
				
			||||||
                     "error, contact the yuzu devs.",
 | 
					 | 
				
			||||||
                     id.DebugInfo());
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool KeyManager::ValidateKey(S256KeyType key, u64 field1, u64 field2) {
 | 
					 | 
				
			||||||
    auto& hash = dev_mode ? s256_hash_dev : s256_hash_prod;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    KeyIndex<S256KeyType> id = {key, field1, field2};
 | 
					 | 
				
			||||||
    if (hash.find(id) == hash.end()) {
 | 
					 | 
				
			||||||
        LOG_ERROR(Crypto, "Could not validate [{}]", id.DebugInfo());
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!HasKey(key, field1, field2)) {
 | 
					 | 
				
			||||||
        LOG_ERROR(Crypto,
 | 
					 | 
				
			||||||
                  "System has requested validation of [{}], but user has not added it. Add this "
 | 
					 | 
				
			||||||
                  "key to use functionality.",
 | 
					 | 
				
			||||||
                  id.DebugInfo());
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SHA256Hash key_hash{};
 | 
					 | 
				
			||||||
    const auto a_key = GetKey(key, field1, field2);
 | 
					 | 
				
			||||||
    mbedtls_sha256(a_key.data(), a_key.size(), key_hash.data(), 0);
 | 
					 | 
				
			||||||
    if (key_hash != hash[id]) {
 | 
					 | 
				
			||||||
        LOG_CRITICAL(Crypto,
 | 
					 | 
				
			||||||
                     "The hash of the provided key for [{}] does not match the one on file. This "
 | 
					 | 
				
			||||||
                     "means you probably have an incorrect key. If you believe this to be in "
 | 
					 | 
				
			||||||
                     "error, contact the yuzu devs.",
 | 
					 | 
				
			||||||
                     id.DebugInfo());
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
} // namespace Crypto
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -3,36 +3,37 @@
 | 
				
			|||||||
// Refer to the license.txt file included.
 | 
					// Refer to the license.txt file included.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <array>
 | 
					#include <array>
 | 
				
			||||||
#include <unordered_map>
 | 
					#include <unordered_map>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
#include <fmt/format.h>
 | 
					#include <fmt/format.h>
 | 
				
			||||||
#include "common/common_types.h"
 | 
					#include "common/common_types.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Crypto {
 | 
					namespace Core::Crypto {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef std::array<u8, 0x10> Key128;
 | 
					using Key128 = std::array<u8, 0x10>;
 | 
				
			||||||
typedef std::array<u8, 0x20> Key256;
 | 
					using Key256 = std::array<u8, 0x20>;
 | 
				
			||||||
typedef std::array<u8, 0x20> SHA256Hash;
 | 
					using SHA256Hash = std::array<u8, 0x20>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big.");
 | 
					static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big.");
 | 
				
			||||||
static_assert(sizeof(Key256) == 32, "Key128 must be 128 bytes big.");
 | 
					static_assert(sizeof(Key256) == 32, "Key128 must be 128 bytes big.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class S256KeyType : u64 {
 | 
					enum class S256KeyType : u64 {
 | 
				
			||||||
    HEADER,  //
 | 
					    Header, //
 | 
				
			||||||
    SD_SAVE, //
 | 
					    SDSave, //
 | 
				
			||||||
    SD_NCA,  //
 | 
					    SDNCA,  //
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class S128KeyType : u64 {
 | 
					enum class S128KeyType : u64 {
 | 
				
			||||||
    MASTER,          // f1=crypto revision
 | 
					    Master,        // f1=crypto revision
 | 
				
			||||||
    PACKAGE1,        // f1=crypto revision
 | 
					    Package1,      // f1=crypto revision
 | 
				
			||||||
    PACKAGE2,        // f1=crypto revision
 | 
					    Package2,      // f1=crypto revision
 | 
				
			||||||
    TITLEKEK,        // f1=crypto revision
 | 
					    Titlekek,      // f1=crypto revision
 | 
				
			||||||
    ETICKET_RSA_KEK, //
 | 
					    ETicketRSAKek, //
 | 
				
			||||||
    KEY_AREA,        // f1=crypto revision f2=type {app, ocean, system}
 | 
					    KeyArea,       // f1=crypto revision f2=type {app, ocean, system}
 | 
				
			||||||
    SD_SEED,         //
 | 
					    SDSeed,        //
 | 
				
			||||||
    TITLEKEY,        // f1=rights id LSB f2=rights id MSB
 | 
					    Titlekey,      // f1=rights id LSB f2=rights id MSB
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class KeyAreaKeyType : u8 {
 | 
					enum class KeyAreaKeyType : u8 {
 | 
				
			||||||
@ -47,7 +48,7 @@ struct KeyIndex {
 | 
				
			|||||||
    u64 field1;
 | 
					    u64 field1;
 | 
				
			||||||
    u64 field2;
 | 
					    u64 field2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string DebugInfo() {
 | 
					    std::string DebugInfo() const {
 | 
				
			||||||
        u8 key_size = 16;
 | 
					        u8 key_size = 16;
 | 
				
			||||||
        if (std::is_same_v<KeyType, S256KeyType>)
 | 
					        if (std::is_same_v<KeyType, S256KeyType>)
 | 
				
			||||||
            key_size = 32;
 | 
					            key_size = 32;
 | 
				
			||||||
@ -60,15 +61,20 @@ struct KeyIndex {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template <typename KeyType>
 | 
					template <typename KeyType>
 | 
				
			||||||
bool operator==(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) {
 | 
					bool operator==(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) {
 | 
				
			||||||
    return lhs.type == rhs.type && lhs.field1 == rhs.field1 && lhs.field2 == rhs.field2;
 | 
					    return std::tie(lhs.type, lhs.field1, lhs.field2) == std::tie(rhs.type, rhs.field1, rhs.field2);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Crypto
 | 
					template <typename KeyType>
 | 
				
			||||||
 | 
					bool operator!=(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) {
 | 
				
			||||||
 | 
					    return !operator==(lhs, rhs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace Core::Crypto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace std {
 | 
					namespace std {
 | 
				
			||||||
template <typename KeyType>
 | 
					template <typename KeyType>
 | 
				
			||||||
struct hash<Crypto::KeyIndex<KeyType>> {
 | 
					struct hash<Core::Crypto::KeyIndex<KeyType>> {
 | 
				
			||||||
    size_t operator()(const Crypto::KeyIndex<KeyType>& k) const {
 | 
					    size_t operator()(const Core::Crypto::KeyIndex<KeyType>& k) const {
 | 
				
			||||||
        using std::hash;
 | 
					        using std::hash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return ((hash<u64>()(static_cast<u64>(k.type)) ^ (hash<u64>()(k.field1) << 1)) >> 1) ^
 | 
					        return ((hash<u64>()(static_cast<u64>(k.type)) ^ (hash<u64>()(k.field1) << 1)) >> 1) ^
 | 
				
			||||||
@ -77,41 +83,32 @@ struct hash<Crypto::KeyIndex<KeyType>> {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
} // namespace std
 | 
					} // namespace std
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Crypto {
 | 
					namespace Core::Crypto {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::array<u8, 0x10> operator"" _array16(const char* str, size_t len);
 | 
					std::array<u8, 0x10> operator"" _array16(const char* str, size_t len);
 | 
				
			||||||
std::array<u8, 0x20> operator"" _array32(const char* str, size_t len);
 | 
					std::array<u8, 0x20> operator"" _array32(const char* str, size_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct KeyManager {
 | 
					class KeyManager {
 | 
				
			||||||
    void SetValidationMode(bool dev);
 | 
					public:
 | 
				
			||||||
    void LoadFromFile(std::string_view filename, bool is_title_keys);
 | 
					    KeyManager();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool HasKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0);
 | 
					    bool HasKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const;
 | 
				
			||||||
    bool HasKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0);
 | 
					    bool HasKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Key128 GetKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0);
 | 
					    Key128 GetKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const;
 | 
				
			||||||
    Key256 GetKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0);
 | 
					    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(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0);
 | 
				
			||||||
    void SetKey(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0);
 | 
					    void SetKey(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool ValidateKey(S128KeyType key, u64 field1 = 0, u64 field2 = 0);
 | 
					 | 
				
			||||||
    bool ValidateKey(S256KeyType key, u64 field1 = 0, u64 field2 = 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    std::unordered_map<KeyIndex<S128KeyType>, Key128> s128_keys;
 | 
					    std::unordered_map<KeyIndex<S128KeyType>, Key128> s128_keys;
 | 
				
			||||||
    std::unordered_map<KeyIndex<S256KeyType>, Key256> s256_keys;
 | 
					    std::unordered_map<KeyIndex<S256KeyType>, Key256> s256_keys;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool dev_mode = false;
 | 
					    bool dev_mode;
 | 
				
			||||||
 | 
					    void LoadFromFile(std::string_view filename, bool is_title_keys);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static std::unordered_map<KeyIndex<S128KeyType>, SHA256Hash> s128_hash_prod;
 | 
					 | 
				
			||||||
    static std::unordered_map<KeyIndex<S256KeyType>, SHA256Hash> s256_hash_prod;
 | 
					 | 
				
			||||||
    static std::unordered_map<KeyIndex<S128KeyType>, SHA256Hash> s128_hash_dev;
 | 
					 | 
				
			||||||
    static std::unordered_map<KeyIndex<S256KeyType>, SHA256Hash> s256_hash_dev;
 | 
					 | 
				
			||||||
    static std::unordered_map<std::string, KeyIndex<S128KeyType>> s128_file_id;
 | 
					    static std::unordered_map<std::string, KeyIndex<S128KeyType>> s128_file_id;
 | 
				
			||||||
    static std::unordered_map<std::string, KeyIndex<S256KeyType>> s256_file_id;
 | 
					    static std::unordered_map<std::string, KeyIndex<S256KeyType>> s256_file_id;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					} // namespace Core::Crypto
 | 
				
			||||||
extern KeyManager keys;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Crypto
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -30,8 +30,8 @@ XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) {
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const static std::array<std::string, 0x4> partition_names = {"update", "normal", "secure",
 | 
					    static constexpr std::array<const char*, 0x4> partition_names = {"update", "normal", "secure",
 | 
				
			||||||
                                                                 "logo"};
 | 
					                                                                     "logo"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (XCIPartition partition :
 | 
					    for (XCIPartition partition :
 | 
				
			||||||
         {XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) {
 | 
					         {XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) {
 | 
				
			||||||
@ -93,12 +93,9 @@ VirtualDir XCI::GetLogoPartition() const {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const {
 | 
					std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const {
 | 
				
			||||||
    for (const auto& nca : ncas) {
 | 
					    auto iter = std::find_if(ncas.begin(), ncas.end(),
 | 
				
			||||||
        if (nca->GetType() == type)
 | 
					                             [type](std::shared_ptr<NCA> nca) { return nca->GetType() == type; });
 | 
				
			||||||
            return nca;
 | 
					    return iter == ncas.end() ? nullptr : *iter;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return nullptr;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VirtualFile XCI::GetNCAFileByType(NCAContentType type) const {
 | 
					VirtualFile XCI::GetNCAFileByType(NCAContentType type) const {
 | 
				
			||||||
@ -133,7 +130,7 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
 | 
				
			|||||||
        return Loader::ResultStatus::ErrorInvalidFormat;
 | 
					        return Loader::ResultStatus::ErrorInvalidFormat;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (VirtualFile file : partitions[static_cast<size_t>(part)]->GetFiles()) {
 | 
					    for (const VirtualFile& file : partitions[static_cast<size_t>(part)]->GetFiles()) {
 | 
				
			||||||
        if (file->GetExtension() != "nca")
 | 
					        if (file->GetExtension() != "nca")
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
        auto nca = std::make_shared<NCA>(file);
 | 
					        auto nca = std::make_shared<NCA>(file);
 | 
				
			||||||
 | 
				
			|||||||
@ -9,10 +9,9 @@
 | 
				
			|||||||
#include "core/crypto/aes_util.h"
 | 
					#include "core/crypto/aes_util.h"
 | 
				
			||||||
#include "core/crypto/ctr_encryption_layer.h"
 | 
					#include "core/crypto/ctr_encryption_layer.h"
 | 
				
			||||||
#include "core/file_sys/content_archive.h"
 | 
					#include "core/file_sys/content_archive.h"
 | 
				
			||||||
 | 
					#include "core/file_sys/romfs.h"
 | 
				
			||||||
#include "core/file_sys/vfs_offset.h"
 | 
					#include "core/file_sys/vfs_offset.h"
 | 
				
			||||||
#include "core/loader/loader.h"
 | 
					#include "core/loader/loader.h"
 | 
				
			||||||
#include "mbedtls/cipher.h"
 | 
					 | 
				
			||||||
#include "romfs.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FileSys {
 | 
					namespace FileSys {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -77,7 +76,7 @@ bool IsValidNCA(const NCAHeader& header) {
 | 
				
			|||||||
    return header.magic == Common::MakeMagic('N', 'C', 'A', '3');
 | 
					    return header.magic == Common::MakeMagic('N', 'C', 'A', '3');
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Crypto::Key128 NCA::GetKeyAreaKey(NCASectionCryptoType type) {
 | 
					Core::Crypto::Key128 NCA::GetKeyAreaKey(NCASectionCryptoType type) {
 | 
				
			||||||
    u8 master_key_id = header.crypto_type;
 | 
					    u8 master_key_id = header.crypto_type;
 | 
				
			||||||
    if (header.crypto_type_2 > master_key_id)
 | 
					    if (header.crypto_type_2 > master_key_id)
 | 
				
			||||||
        master_key_id = header.crypto_type_2;
 | 
					        master_key_id = header.crypto_type_2;
 | 
				
			||||||
@ -85,16 +84,12 @@ Crypto::Key128 NCA::GetKeyAreaKey(NCASectionCryptoType type) {
 | 
				
			|||||||
        --master_key_id;
 | 
					        --master_key_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<u8> key_area(header.key_area.begin(), header.key_area.end());
 | 
					    std::vector<u8> key_area(header.key_area.begin(), header.key_area.end());
 | 
				
			||||||
    if (!Crypto::keys.ValidateKey(Crypto::S128KeyType::KEY_AREA, master_key_id, header.key_index)) {
 | 
					    Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
 | 
				
			||||||
        status = Loader::ResultStatus::ErrorEncrypted;
 | 
					        keys.GetKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index),
 | 
				
			||||||
        return {};
 | 
					        Core::Crypto::Mode::ECB);
 | 
				
			||||||
    }
 | 
					    cipher.Transcode(key_area.data(), key_area.size(), key_area.data(), Core::Crypto::Op::Decrypt);
 | 
				
			||||||
    Crypto::AESCipher<Crypto::Key128> cipher(
 | 
					 | 
				
			||||||
        Crypto::keys.GetKey(Crypto::S128KeyType::KEY_AREA, master_key_id, header.key_index),
 | 
					 | 
				
			||||||
        Crypto::Mode::ECB);
 | 
					 | 
				
			||||||
    cipher.Transcode(key_area.data(), key_area.size(), key_area.data(), Crypto::Op::DECRYPT);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Crypto::Key128 out;
 | 
					    Core::Crypto::Key128 out;
 | 
				
			||||||
    if (type == NCASectionCryptoType::XTS)
 | 
					    if (type == NCASectionCryptoType::XTS)
 | 
				
			||||||
        std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin());
 | 
					        std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin());
 | 
				
			||||||
    else if (type == NCASectionCryptoType::CTR)
 | 
					    else if (type == NCASectionCryptoType::CTR)
 | 
				
			||||||
@ -102,8 +97,8 @@ Crypto::Key128 NCA::GetKeyAreaKey(NCASectionCryptoType type) {
 | 
				
			|||||||
    else
 | 
					    else
 | 
				
			||||||
        LOG_CRITICAL(Crypto, "Called GetKeyAreaKey on invalid NCASectionCryptoType type={:02X}",
 | 
					        LOG_CRITICAL(Crypto, "Called GetKeyAreaKey on invalid NCASectionCryptoType type={:02X}",
 | 
				
			||||||
                     static_cast<u8>(type));
 | 
					                     static_cast<u8>(type));
 | 
				
			||||||
 | 
					    u128 out_128{};
 | 
				
			||||||
    u128 out_128 = *reinterpret_cast<u128*>(&out);
 | 
					    memcpy(out_128.data(), out.data(), 16);
 | 
				
			||||||
    LOG_DEBUG(Crypto, "called with crypto_rev={:02X}, kak_index={:02X}, key={:016X}{:016X}",
 | 
					    LOG_DEBUG(Crypto, "called with crypto_rev={:02X}, kak_index={:02X}, key={:016X}{:016X}",
 | 
				
			||||||
              master_key_id, header.key_index, out_128[1], out_128[0]);
 | 
					              master_key_id, header.key_index, out_128[1], out_128[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -121,9 +116,9 @@ VirtualFile NCA::Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_o
 | 
				
			|||||||
    case NCASectionCryptoType::CTR:
 | 
					    case NCASectionCryptoType::CTR:
 | 
				
			||||||
        LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset);
 | 
					        LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset);
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            auto out = std::make_shared<Crypto::CTREncryptionLayer>(
 | 
					            auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(
 | 
				
			||||||
                std::move(in), GetKeyAreaKey(NCASectionCryptoType::CTR), starting_offset);
 | 
					                std::move(in), GetKeyAreaKey(NCASectionCryptoType::CTR), starting_offset);
 | 
				
			||||||
            std::vector<u8> iv(16, 0);
 | 
					            std::vector<u8> iv(16);
 | 
				
			||||||
            for (u8 i = 0; i < 8; ++i)
 | 
					            for (u8 i = 0; i < 8; ++i)
 | 
				
			||||||
                iv[i] = header.raw.section_ctr[0x8 - i - 1];
 | 
					                iv[i] = header.raw.section_ctr[0x8 - i - 1];
 | 
				
			||||||
            out->SetIV(iv);
 | 
					            out->SetIV(iv);
 | 
				
			||||||
@ -146,13 +141,10 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (!IsValidNCA(header)) {
 | 
					    if (!IsValidNCA(header)) {
 | 
				
			||||||
        NCAHeader dec_header{};
 | 
					        NCAHeader dec_header{};
 | 
				
			||||||
        if (!Crypto::keys.ValidateKey(Crypto::S256KeyType::HEADER)) {
 | 
					        Core::Crypto::AESCipher<Core::Crypto::Key256> cipher(
 | 
				
			||||||
            status = Loader::ResultStatus::ErrorEncrypted;
 | 
					            keys.GetKey(Core::Crypto::S256KeyType::Header), Core::Crypto::Mode::XTS);
 | 
				
			||||||
            return;
 | 
					        cipher.XTSTranscode(&header, sizeof(NCAHeader), &dec_header, 0, 0x200,
 | 
				
			||||||
        }
 | 
					                            Core::Crypto::Op::Decrypt);
 | 
				
			||||||
        Crypto::AESCipher<Crypto::Key256> cipher(Crypto::keys.GetKey(Crypto::S256KeyType::HEADER),
 | 
					 | 
				
			||||||
                                                 Crypto::Mode::XTS);
 | 
					 | 
				
			||||||
        cipher.XTSTranscode(&header, sizeof(NCAHeader), &dec_header, 0, 0x200, Crypto::Op::DECRYPT);
 | 
					 | 
				
			||||||
        if (IsValidNCA(dec_header)) {
 | 
					        if (IsValidNCA(dec_header)) {
 | 
				
			||||||
            header = dec_header;
 | 
					            header = dec_header;
 | 
				
			||||||
            encrypted = true;
 | 
					            encrypted = true;
 | 
				
			||||||
@ -171,14 +163,10 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (encrypted) {
 | 
					    if (encrypted) {
 | 
				
			||||||
        auto raw = file->ReadBytes(length_sections, SECTION_HEADER_OFFSET);
 | 
					        auto raw = file->ReadBytes(length_sections, SECTION_HEADER_OFFSET);
 | 
				
			||||||
        if (!Crypto::keys.ValidateKey(Crypto::S256KeyType::HEADER)) {
 | 
					        Core::Crypto::AESCipher<Core::Crypto::Key256> cipher(
 | 
				
			||||||
            status = Loader::ResultStatus::ErrorEncrypted;
 | 
					            keys.GetKey(Core::Crypto::S256KeyType::Header), Core::Crypto::Mode::XTS);
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        Crypto::AESCipher<Crypto::Key256> cipher(Crypto::keys.GetKey(Crypto::S256KeyType::HEADER),
 | 
					 | 
				
			||||||
                                                 Crypto::Mode::XTS);
 | 
					 | 
				
			||||||
        cipher.XTSTranscode(raw.data(), length_sections, sections.data(), 2, SECTION_HEADER_SIZE,
 | 
					        cipher.XTSTranscode(raw.data(), length_sections, sections.data(), 2, SECTION_HEADER_SIZE,
 | 
				
			||||||
                            Crypto::Op::DECRYPT);
 | 
					                            Core::Crypto::Op::Decrypt);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        file->ReadBytes(sections.data(), length_sections, SECTION_HEADER_OFFSET);
 | 
					        file->ReadBytes(sections.data(), length_sections, SECTION_HEADER_OFFSET);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -9,12 +9,12 @@
 | 
				
			|||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "core/loader/loader.h"
 | 
					 | 
				
			||||||
#include "common/common_funcs.h"
 | 
					#include "common/common_funcs.h"
 | 
				
			||||||
#include "common/common_types.h"
 | 
					#include "common/common_types.h"
 | 
				
			||||||
#include "common/swap.h"
 | 
					#include "common/swap.h"
 | 
				
			||||||
#include "core/crypto/key_manager.h"
 | 
					#include "core/crypto/key_manager.h"
 | 
				
			||||||
#include "core/file_sys/partition_filesystem.h"
 | 
					#include "core/file_sys/partition_filesystem.h"
 | 
				
			||||||
 | 
					#include "core/loader/loader.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FileSys {
 | 
					namespace FileSys {
 | 
				
			||||||
enum class NCAContentType : u8 {
 | 
					enum class NCAContentType : u8 {
 | 
				
			||||||
@ -107,7 +107,8 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    bool encrypted;
 | 
					    bool encrypted;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Crypto::Key128 GetKeyAreaKey(NCASectionCryptoType type);
 | 
					    Core::Crypto::KeyManager keys;
 | 
				
			||||||
 | 
					    Core::Crypto::Key128 GetKeyAreaKey(NCASectionCryptoType type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset);
 | 
					    VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -297,10 +297,9 @@ bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if (f1_vs != f2_vs)
 | 
					        if (f1_vs != f2_vs)
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        for (size_t j = 0; j < f1_vs; ++j) {
 | 
					        auto iters = std::mismatch(f1_v.begin(), f1_v.end(), f2_v.begin(), f2_v.end());
 | 
				
			||||||
            if (f1_v[j] != f2_v[j])
 | 
					        if (iters.first != f1_v.end() && iters.second != f2_v.end())
 | 
				
			||||||
                return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
 | 
				
			|||||||
@ -28,14 +28,17 @@ AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file)
 | 
				
			|||||||
      nca_loader(std::make_unique<AppLoader_NCA>(
 | 
					      nca_loader(std::make_unique<AppLoader_NCA>(
 | 
				
			||||||
          xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {}
 | 
					          xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AppLoader_XCI::~AppLoader_XCI() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) {
 | 
					FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) {
 | 
				
			||||||
    FileSys::XCI xci(file);
 | 
					    FileSys::XCI xci(file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (xci.GetStatus() == ResultStatus::Success &&
 | 
					    if (xci.GetStatus() == ResultStatus::Success &&
 | 
				
			||||||
        xci.GetNCAByType(FileSys::NCAContentType::Program) != nullptr &&
 | 
					        xci.GetNCAByType(FileSys::NCAContentType::Program) != nullptr &&
 | 
				
			||||||
        AppLoader_NCA::IdentifyType(xci.GetNCAFileByType(FileSys::NCAContentType::Program)) ==
 | 
					        AppLoader_NCA::IdentifyType(xci.GetNCAFileByType(FileSys::NCAContentType::Program)) ==
 | 
				
			||||||
            FileType::NCA)
 | 
					            FileType::NCA) {
 | 
				
			||||||
        return FileType::XCI;
 | 
					        return FileType::XCI;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return FileType::Error;
 | 
					    return FileType::Error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -62,6 +65,4 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
 | 
				
			|||||||
    return nca_loader->ReadProgramId(out_program_id);
 | 
					    return nca_loader->ReadProgramId(out_program_id);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AppLoader_XCI::~AppLoader_XCI() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Loader
 | 
					} // namespace Loader
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@ namespace Loader {
 | 
				
			|||||||
class AppLoader_XCI final : public AppLoader {
 | 
					class AppLoader_XCI final : public AppLoader {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    explicit AppLoader_XCI(FileSys::VirtualFile file);
 | 
					    explicit AppLoader_XCI(FileSys::VirtualFile file);
 | 
				
			||||||
 | 
					    ~AppLoader_XCI();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Returns the type of the file
 | 
					     * Returns the type of the file
 | 
				
			||||||
@ -30,8 +31,6 @@ public:
 | 
				
			|||||||
    ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
 | 
					    ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
 | 
				
			||||||
    ResultStatus ReadProgramId(u64& out_program_id) override;
 | 
					    ResultStatus ReadProgramId(u64& out_program_id) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ~AppLoader_XCI();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    FileSys::ProgramMetadata metadata;
 | 
					    FileSys::ProgramMetadata metadata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,6 @@
 | 
				
			|||||||
#include <QMessageBox>
 | 
					#include <QMessageBox>
 | 
				
			||||||
#include <QtGui>
 | 
					#include <QtGui>
 | 
				
			||||||
#include <QtWidgets>
 | 
					#include <QtWidgets>
 | 
				
			||||||
#include <core/crypto/key_manager.h>
 | 
					 | 
				
			||||||
#include "common/common_paths.h"
 | 
					#include "common/common_paths.h"
 | 
				
			||||||
#include "common/logging/backend.h"
 | 
					#include "common/logging/backend.h"
 | 
				
			||||||
#include "common/logging/filter.h"
 | 
					#include "common/logging/filter.h"
 | 
				
			||||||
@ -24,6 +23,7 @@
 | 
				
			|||||||
#include "common/scope_exit.h"
 | 
					#include "common/scope_exit.h"
 | 
				
			||||||
#include "common/string_util.h"
 | 
					#include "common/string_util.h"
 | 
				
			||||||
#include "core/core.h"
 | 
					#include "core/core.h"
 | 
				
			||||||
 | 
					#include "core/crypto/key_manager.h"
 | 
				
			||||||
#include "core/gdbstub/gdbstub.h"
 | 
					#include "core/gdbstub/gdbstub.h"
 | 
				
			||||||
#include "core/loader/loader.h"
 | 
					#include "core/loader/loader.h"
 | 
				
			||||||
#include "core/settings.h"
 | 
					#include "core/settings.h"
 | 
				
			||||||
@ -89,19 +89,6 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
 | 
				
			|||||||
    ui.setupUi(this);
 | 
					    ui.setupUi(this);
 | 
				
			||||||
    statusBar()->hide();
 | 
					    statusBar()->hide();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Initialize keys
 | 
					 | 
				
			||||||
    std::string keys_dir = FileUtil::GetHactoolConfigurationPath();
 | 
					 | 
				
			||||||
    if (Settings::values.use_dev_keys) {
 | 
					 | 
				
			||||||
        Crypto::keys.SetValidationMode(true);
 | 
					 | 
				
			||||||
        if (FileUtil::Exists(keys_dir + DIR_SEP + "dev.keys"))
 | 
					 | 
				
			||||||
            Crypto::keys.LoadFromFile(keys_dir + DIR_SEP + "dev.keys", false);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        if (FileUtil::Exists(keys_dir + DIR_SEP + "prod.keys"))
 | 
					 | 
				
			||||||
            Crypto::keys.LoadFromFile(keys_dir + DIR_SEP + "prod.keys", false);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (FileUtil::Exists(keys_dir + DIR_SEP + "title.keys"))
 | 
					 | 
				
			||||||
        Crypto::keys.LoadFromFile(keys_dir + DIR_SEP + "title.keys", true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    default_theme_paths = QIcon::themeSearchPaths();
 | 
					    default_theme_paths = QIcon::themeSearchPaths();
 | 
				
			||||||
    UpdateUITheme();
 | 
					    UpdateUITheme();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -73,19 +73,6 @@ static void InitializeLogging() {
 | 
				
			|||||||
int main(int argc, char** argv) {
 | 
					int main(int argc, char** argv) {
 | 
				
			||||||
    Config config;
 | 
					    Config config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Initialize keys
 | 
					 | 
				
			||||||
    std::string keys_dir = FileUtil::GetHactoolConfigurationPath();
 | 
					 | 
				
			||||||
    if (Settings::values.use_dev_keys) {
 | 
					 | 
				
			||||||
        Crypto::keys.SetValidationMode(true);
 | 
					 | 
				
			||||||
        if (FileUtil::Exists(keys_dir + DIR_SEP + "dev.keys"))
 | 
					 | 
				
			||||||
            Crypto::keys.LoadFromFile(keys_dir + DIR_SEP + "dev.keys", false);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        if (FileUtil::Exists(keys_dir + DIR_SEP + "prod.keys"))
 | 
					 | 
				
			||||||
            Crypto::keys.LoadFromFile(keys_dir + DIR_SEP + "prod.keys", false);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (FileUtil::Exists(keys_dir + DIR_SEP + "title.keys"))
 | 
					 | 
				
			||||||
        Crypto::keys.LoadFromFile(keys_dir + DIR_SEP + "title.keys", true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int option_index = 0;
 | 
					    int option_index = 0;
 | 
				
			||||||
    bool use_gdbstub = Settings::values.use_gdbstub;
 | 
					    bool use_gdbstub = Settings::values.use_gdbstub;
 | 
				
			||||||
    u32 gdb_port = static_cast<u32>(Settings::values.gdbstub_port);
 | 
					    u32 gdb_port = static_cast<u32>(Settings::values.gdbstub_port);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user