diff --git a/stratosphere/spl/source/spl_api.cpp b/stratosphere/spl/source/spl_api.cpp
new file mode 100644
index 000000000..b43eccab9
--- /dev/null
+++ b/stratosphere/spl/source/spl_api.cpp
@@ -0,0 +1,937 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+
+#include "spl_api.hpp"
+#include "spl_smc.hpp"
+
+#include "spl_ctr_drbg.hpp"
+
+namespace sts::spl {
+
+ namespace {
+
+ /* Convenient defines. */
+ constexpr size_t DeviceAddressSpaceAlignSize = 0x400000;
+ constexpr size_t DeviceAddressSpaceAlignMask = DeviceAddressSpaceAlignSize - 1;
+ constexpr u32 WorkBufferMapBase = 0x80000000u;
+ constexpr u32 CryptAesInMapBase = 0x90000000u;
+ constexpr u32 CryptAesOutMapBase = 0xC0000000u;
+ constexpr size_t CryptAesSizeMax = static_cast(CryptAesOutMapBase - CryptAesInMapBase);
+
+ constexpr size_t RsaPrivateKeySize = 0x100;
+ constexpr size_t RsaPrivateKeyMetaSize = 0x30;
+ constexpr size_t LabelDigestSizeMax = 0x20;
+
+ constexpr size_t WorkBufferSizeMax = 0x800;
+
+ constexpr size_t MaxAesKeyslots = 6;
+ constexpr size_t MaxAesKeyslotsDeprecated = 4;
+
+ /* Max Keyslots helper. */
+ inline size_t GetMaxKeyslots() {
+ return (GetRuntimeFirmwareVersion() >= FirmwareVersion_600) ? MaxAesKeyslots : MaxAesKeyslotsDeprecated;
+ }
+
+ /* Type definitions. */
+ class ScopedAesKeyslot {
+ private:
+ u32 slot;
+ bool has_slot;
+ public:
+ ScopedAesKeyslot() : slot(0), has_slot(false) {
+ /* ... */
+ }
+ ~ScopedAesKeyslot() {
+ if (has_slot) {
+ spl::FreeAesKeyslot(slot, this);
+ }
+ }
+
+ u32 GetKeyslot() const {
+ return this->slot;
+ }
+
+ Result Allocate() {
+ R_TRY(spl::AllocateAesKeyslot(&this->slot, this));
+ this->has_slot = true;
+ return ResultSuccess;
+ }
+ };
+
+ struct SeLinkedListEntry {
+ u32 num_entries;
+ u32 address;
+ u32 size;
+ };
+
+ struct SeCryptContext {
+ SeLinkedListEntry in;
+ SeLinkedListEntry out;
+ };
+
+ class DeviceAddressSpaceMapHelper {
+ private:
+ Handle das_hnd;
+ u64 dst_addr;
+ u64 src_addr;
+ size_t size;
+ u32 perm;
+ public:
+ DeviceAddressSpaceMapHelper(Handle h, u64 dst, u64 src, size_t sz, u32 p) : das_hnd(h), dst_addr(dst), src_addr(src), size(sz), perm(p) {
+ R_ASSERT(svcMapDeviceAddressSpaceAligned(this->das_hnd, CUR_PROCESS_HANDLE, this->src_addr, this->size, this->dst_addr, this->perm));
+ }
+ ~DeviceAddressSpaceMapHelper() {
+ R_ASSERT(svcUnmapDeviceAddressSpace(this->das_hnd, CUR_PROCESS_HANDLE, this->src_addr, this->size, this->dst_addr));
+ }
+ };
+
+ /* Global variables. */
+ CtrDrbg g_drbg;
+ Event g_se_event;
+ IEvent *g_se_keyslot_available_event;
+
+ Handle g_se_das_hnd;
+ u32 g_se_mapped_work_buffer_addr;
+ u8 __attribute__((aligned(0x1000))) g_work_buffer[2 * WorkBufferSizeMax];
+
+ HosMutex g_async_op_lock;
+
+ const void *g_keyslot_owners[MaxAesKeyslots];
+ BootReasonValue g_boot_reason;
+ bool g_boot_reason_set;
+
+ /* Boot Reason accessors. */
+ BootReasonValue GetBootReason() {
+ return g_boot_reason;
+ }
+
+ bool IsBootReasonSet() {
+ return g_boot_reason_set;
+ }
+
+ /* Initialization functionality. */
+ void InitializeCtrDrbg() {
+ u8 seed[CtrDrbg::SeedSize];
+
+ if (smc::GenerateRandomBytes(seed, sizeof(seed)) != smc::Result::Success) {
+ std::abort();
+ }
+
+ g_drbg.Initialize(seed);
+ }
+
+ void InitializeSeEvents() {
+ u64 irq_num;
+ smc::GetConfig(&irq_num, 1, SplConfigItem_SecurityEngineIrqNumber);
+ Handle hnd;
+ R_ASSERT(svcCreateInterruptEvent(&hnd, irq_num, 1));
+ eventLoadRemote(&g_se_event, hnd, true);
+
+ g_se_keyslot_available_event = CreateWriteOnlySystemEvent();
+ g_se_keyslot_available_event->Signal();
+ }
+
+ void InitializeDeviceAddressSpace() {
+ constexpr u64 DeviceName_SE = 29;
+
+ /* Create Address Space. */
+ R_ASSERT(svcCreateDeviceAddressSpace(&g_se_das_hnd, 0, (1ul << 32)));
+
+ /* Attach it to the SE. */
+ R_ASSERT(svcAttachDeviceAddressSpace(DeviceName_SE, g_se_das_hnd));
+
+ const u64 work_buffer_addr = reinterpret_cast(g_work_buffer);
+ g_se_mapped_work_buffer_addr = WorkBufferMapBase + (work_buffer_addr & DeviceAddressSpaceAlignMask);
+
+ /* Map the work buffer for the SE. */
+ R_ASSERT(svcMapDeviceAddressSpaceAligned(g_se_das_hnd, CUR_PROCESS_HANDLE, work_buffer_addr, sizeof(g_work_buffer), g_se_mapped_work_buffer_addr, 3));
+ }
+
+ /* RSA OAEP implementation helpers. */
+ void CalcMgf1AndXor(void *dst, size_t dst_size, const void *src, size_t src_size) {
+ uint8_t *dst_u8 = reinterpret_cast(dst);
+
+ u32 ctr = 0;
+ while (dst_size > 0) {
+ size_t cur_size = SHA256_HASH_SIZE;
+ if (cur_size > dst_size) {
+ cur_size = dst_size;
+ }
+ dst_size -= cur_size;
+
+ u32 ctr_be = __builtin_bswap32(ctr++);
+ u8 hash[SHA256_HASH_SIZE];
+ {
+ Sha256Context ctx;
+ sha256ContextCreate(&ctx);
+ sha256ContextUpdate(&ctx, src, src_size);
+ sha256ContextUpdate(&ctx, &ctr_be, sizeof(ctr_be));
+ sha256ContextGetHash(&ctx, hash);
+ }
+
+ for (size_t i = 0; i < cur_size; i++) {
+ *(dst_u8++) ^= hash[i];
+ }
+ }
+ }
+
+ size_t DecodeRsaOaep(void *dst, size_t dst_size, const void *label_digest, size_t label_digest_size, const void *src, size_t src_size) {
+ /* Very basic validation. */
+ if (dst_size == 0 || src_size != 0x100 || label_digest_size != SHA256_HASH_SIZE) {
+ return 0;
+ }
+
+ u8 block[0x100];
+ std::memcpy(block, src, sizeof(block));
+
+ /* First, validate byte 0 == 0, and unmask DB. */
+ int invalid = block[0];
+ u8 *salt = block + 1;
+ u8 *db = salt + SHA256_HASH_SIZE;
+ CalcMgf1AndXor(salt, SHA256_HASH_SIZE, db, src_size - (1 + SHA256_HASH_SIZE));
+ CalcMgf1AndXor(db, src_size - (1 + SHA256_HASH_SIZE), salt, SHA256_HASH_SIZE);
+
+ /* Validate label digest. */
+ for (size_t i = 0; i < SHA256_HASH_SIZE; i++) {
+ invalid |= db[i] ^ reinterpret_cast(label_digest)[i];
+ }
+
+ /* Locate message after 00...0001 padding. */
+ const u8 *padded_msg = db + SHA256_HASH_SIZE;
+ size_t padded_msg_size = src_size - (1 + 2 * SHA256_HASH_SIZE);
+ size_t msg_ind = 0;
+ int not_found = 1;
+ int wrong_padding = 0;
+ size_t i = 0;
+ while (i < padded_msg_size) {
+ int zero = (padded_msg[i] == 0);
+ int one = (padded_msg[i] == 1);
+ msg_ind += static_cast(not_found & one) * (++i);
+ not_found &= ~one;
+ wrong_padding |= (not_found & ~zero);
+ }
+
+ if (invalid | not_found | wrong_padding) {
+ return 0;
+ }
+
+ /* Copy message out. */
+ size_t msg_size = padded_msg_size - msg_ind;
+ if (msg_size > dst_size) {
+ return 0;
+ }
+ std::memcpy(dst, padded_msg + msg_ind, msg_size);
+ return msg_size;
+ }
+
+ /* Internal RNG functionality. */
+ Result GenerateRandomBytesInternal(void *out, size_t size) {
+ if (!g_drbg.GenerateRandomBytes(out, size)) {
+ /* We need to reseed. */
+ {
+ u8 seed[CtrDrbg::SeedSize];
+
+ smc::Result res = smc::GenerateRandomBytes(seed, sizeof(seed));
+ if (res != smc::Result::Success) {
+ return smc::ConvertResult(res);
+ }
+
+ g_drbg.Reseed(seed);
+ g_drbg.GenerateRandomBytes(out, size);
+ }
+ }
+
+ return ResultSuccess;
+ }
+
+ /* Internal async implementation functionality. */
+ void WaitSeOperationComplete() {
+ eventWait(&g_se_event, U64_MAX);
+ }
+
+ smc::Result WaitCheckStatus(smc::AsyncOperationKey op_key) {
+ WaitSeOperationComplete();
+
+ smc::Result op_res;
+ smc::Result res = smc::CheckStatus(&op_res, op_key);
+ if (res != smc::Result::Success) {
+ return res;
+ }
+
+ return op_res;
+ }
+
+ smc::Result WaitGetResult(void *out_buf, size_t out_buf_size, smc::AsyncOperationKey op_key) {
+ WaitSeOperationComplete();
+
+ smc::Result op_res;
+ smc::Result res = smc::GetResult(&op_res, out_buf, out_buf_size, op_key);
+ if (res != smc::Result::Success) {
+ return res;
+ }
+
+ return op_res;
+ }
+
+ /* Internal Keyslot utility. */
+ Result ValidateAesKeyslot(u32 keyslot, const void *owner) {
+ if (keyslot >= GetMaxKeyslots()) {
+ return ResultSplInvalidKeyslot;
+ }
+ if (g_keyslot_owners[keyslot] != owner && GetRuntimeFirmwareVersion() > FirmwareVersion_100) {
+ return ResultSplInvalidKeyslot;
+ }
+ return ResultSuccess;
+ }
+
+ /* Helper to do a single AES block decryption. */
+ smc::Result DecryptAesBlock(u32 keyslot, void *dst, const void *src) {
+ struct DecryptAesBlockLayout {
+ SeCryptContext crypt_ctx;
+ u8 in_block[AES_BLOCK_SIZE] __attribute__((aligned(AES_BLOCK_SIZE)));
+ u8 out_block[AES_BLOCK_SIZE] __attribute__((aligned(AES_BLOCK_SIZE)));
+ };
+ DecryptAesBlockLayout *layout = reinterpret_cast(g_work_buffer);
+
+ layout->crypt_ctx.in.num_entries = 0;
+ layout->crypt_ctx.in.address = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, in_block);
+ layout->crypt_ctx.in.size = sizeof(layout->in_block);
+ layout->crypt_ctx.out.num_entries = 0;
+ layout->crypt_ctx.out.address = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, out_block);
+ layout->crypt_ctx.out.size = sizeof(layout->out_block);
+
+ std::memcpy(layout->in_block, src, sizeof(layout->in_block));
+
+ armDCacheFlush(layout, sizeof(*layout));
+ {
+ std::scoped_lock lk(g_async_op_lock);
+ smc::AsyncOperationKey op_key;
+ const IvCtr iv_ctr = {};
+ const u32 mode = smc::GetCryptAesMode(smc::CipherMode::CbcDecrypt, keyslot);
+ const u32 dst_ll_addr = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, crypt_ctx.out);
+ const u32 src_ll_addr = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, crypt_ctx.in);
+
+ smc::Result res = smc::CryptAes(&op_key, mode, iv_ctr, dst_ll_addr, src_ll_addr, sizeof(layout->in_block));
+ if (res != smc::Result::Success) {
+ return res;
+ }
+
+ if ((res = WaitCheckStatus(op_key)) != smc::Result::Success) {
+ return res;
+ }
+ }
+ armDCacheFlush(layout, sizeof(*layout));
+
+ std::memcpy(dst, layout->out_block, sizeof(layout->out_block));
+ return smc::Result::Success;
+ }
+
+ /* Implementation wrappers for API commands. */
+ Result ImportSecureExpModKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
+ struct ImportSecureExpModKeyLayout {
+ u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10];
+ };
+ ImportSecureExpModKeyLayout *layout = reinterpret_cast(g_work_buffer);
+
+ /* Validate size. */
+ if (src_size > sizeof(ImportSecureExpModKeyLayout)) {
+ return ResultSplInvalidSize;
+ }
+
+ std::memcpy(layout, src, src_size);
+
+ armDCacheFlush(layout, sizeof(*layout));
+ smc::Result smc_res;
+ if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) {
+ smc_res = smc::DecryptOrImportRsaPrivateKey(layout->data, src_size, access_key, key_source, static_cast(option));
+ } else {
+ smc_res = smc::ImportSecureExpModKey(layout->data, src_size, access_key, key_source, option);
+ }
+
+ return smc::ConvertResult(smc_res);
+ }
+
+ Result SecureExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size, smc::SecureExpModMode mode) {
+ struct SecureExpModLayout {
+ u8 base[0x100];
+ u8 mod[0x100];
+ };
+ SecureExpModLayout *layout = reinterpret_cast(g_work_buffer);
+
+ /* Validate sizes. */
+ if (base_size > sizeof(layout->base)) {
+ return ResultSplInvalidSize;
+ }
+ if (mod_size > sizeof(layout->mod)) {
+ return ResultSplInvalidSize;
+ }
+ if (out_size > WorkBufferSizeMax) {
+ return ResultSplInvalidSize;
+ }
+
+ /* Copy data into work buffer. */
+ const size_t base_ofs = sizeof(layout->base) - base_size;
+ const size_t mod_ofs = sizeof(layout->mod) - mod_size;
+ std::memset(layout, 0, sizeof(*layout));
+ std::memcpy(layout->base + base_ofs, base, base_size);
+ std::memcpy(layout->mod + mod_ofs, mod, mod_size);
+
+ /* Do exp mod operation. */
+ armDCacheFlush(layout, sizeof(*layout));
+ {
+ std::scoped_lock lk(g_async_op_lock);
+ smc::AsyncOperationKey op_key;
+
+ smc::Result res = smc::SecureExpMod(&op_key, layout->base, layout->mod, mode);
+ if (res != smc::Result::Success) {
+ return smc::ConvertResult(res);
+ }
+
+ if ((res = WaitGetResult(g_work_buffer, out_size, op_key)) != smc::Result::Success) {
+ return smc::ConvertResult(res);
+ }
+ }
+ armDCacheFlush(g_work_buffer, sizeof(out_size));
+
+ std::memcpy(out, g_work_buffer, out_size);
+ return ResultSuccess;
+ }
+
+ Result UnwrapEsRsaOaepWrappedKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation, smc::EsKeyType type) {
+ struct UnwrapEsKeyLayout {
+ u8 base[0x100];
+ u8 mod[0x100];
+ };
+ UnwrapEsKeyLayout *layout = reinterpret_cast(g_work_buffer);
+
+ /* Validate sizes. */
+ if (base_size > sizeof(layout->base)) {
+ return ResultSplInvalidSize;
+ }
+ if (mod_size > sizeof(layout->mod)) {
+ return ResultSplInvalidSize;
+ }
+ if (label_digest_size > LabelDigestSizeMax) {
+ return ResultSplInvalidSize;
+ }
+
+ /* Copy data into work buffer. */
+ const size_t base_ofs = sizeof(layout->base) - base_size;
+ const size_t mod_ofs = sizeof(layout->mod) - mod_size;
+ std::memset(layout, 0, sizeof(*layout));
+ std::memcpy(layout->base + base_ofs, base, base_size);
+ std::memcpy(layout->mod + mod_ofs, mod, mod_size);
+
+ /* Do exp mod operation. */
+ armDCacheFlush(layout, sizeof(*layout));
+ {
+ std::scoped_lock lk(g_async_op_lock);
+ smc::AsyncOperationKey op_key;
+
+ smc::Result res = smc::UnwrapTitleKey(&op_key, layout->base, layout->mod, label_digest, label_digest_size, smc::GetUnwrapEsKeyOption(type, generation));
+ if (res != smc::Result::Success) {
+ return smc::ConvertResult(res);
+ }
+
+ if ((res = WaitGetResult(g_work_buffer, sizeof(*out_access_key), op_key)) != smc::Result::Success) {
+ return smc::ConvertResult(res);
+ }
+ }
+ armDCacheFlush(g_work_buffer, sizeof(*out_access_key));
+
+ std::memcpy(out_access_key, g_work_buffer, sizeof(*out_access_key));
+ return ResultSuccess;
+ }
+
+
+ }
+
+ /* Initialization. */
+ void Initialize() {
+ /* Initialize the Drbg. */
+ InitializeCtrDrbg();
+ /* Initialize SE interrupt + keyslot events. */
+ InitializeSeEvents();
+ /* Initialize DAS for the SE. */
+ InitializeDeviceAddressSpace();
+ }
+
+ /* General. */
+ Result GetConfig(u64 *out, SplConfigItem which) {
+ /* Nintendo explicitly blacklists package2 hash here, amusingly. */
+ /* This is not blacklisted in safemode, but we're never in safe mode... */
+ if (which == SplConfigItem_Package2Hash) {
+ return ResultSplInvalidArgument;
+ }
+
+ smc::Result res = smc::GetConfig(out, 1, which);
+
+ /* Nintendo has some special handling here for hardware type/is_retail. */
+ if (which == SplConfigItem_HardwareType && res == smc::Result::InvalidArgument) {
+ *out = 0;
+ res = smc::Result::Success;
+ }
+ if (which == SplConfigItem_IsRetail && res == smc::Result::InvalidArgument) {
+ *out = 0;
+ res = smc::Result::Success;
+ }
+
+ return smc::ConvertResult(res);
+ }
+
+ Result ExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *exp, size_t exp_size, const void *mod, size_t mod_size) {
+ struct ExpModLayout {
+ u8 base[0x100];
+ u8 exp[0x100];
+ u8 mod[0x100];
+ };
+ ExpModLayout *layout = reinterpret_cast(g_work_buffer);
+
+ /* Validate sizes. */
+ if (base_size > sizeof(layout->base)) {
+ return ResultSplInvalidSize;
+ }
+ if (exp_size > sizeof(layout->exp)) {
+ return ResultSplInvalidSize;
+ }
+ if (mod_size > sizeof(layout->mod)) {
+ return ResultSplInvalidSize;
+ }
+ if (out_size > WorkBufferSizeMax) {
+ return ResultSplInvalidSize;
+ }
+
+ /* Copy data into work buffer. */
+ const size_t base_ofs = sizeof(layout->base) - base_size;
+ const size_t mod_ofs = sizeof(layout->mod) - mod_size;
+ std::memset(layout, 0, sizeof(*layout));
+ std::memcpy(layout->base + base_ofs, base, base_size);
+ std::memcpy(layout->exp, exp, exp_size);
+ std::memcpy(layout->mod + mod_ofs, mod, mod_size);
+
+ /* Do exp mod operation. */
+ armDCacheFlush(layout, sizeof(*layout));
+ {
+ std::scoped_lock lk(g_async_op_lock);
+ smc::AsyncOperationKey op_key;
+
+ smc::Result res = smc::ExpMod(&op_key, layout->base, layout->exp, exp_size, layout->mod);
+ if (res != smc::Result::Success) {
+ return smc::ConvertResult(res);
+ }
+
+ if ((res = WaitGetResult(g_work_buffer, out_size, op_key)) != smc::Result::Success) {
+ return smc::ConvertResult(res);
+ }
+ }
+ armDCacheFlush(g_work_buffer, sizeof(out_size));
+
+ std::memcpy(out, g_work_buffer, out_size);
+ return ResultSuccess;
+ }
+
+ Result SetConfig(SplConfigItem which, u64 value) {
+ return smc::ConvertResult(smc::SetConfig(which, &value, 1));
+ }
+
+ Result GenerateRandomBytes(void *out, size_t size) {
+ u8 *cur_dst = reinterpret_cast(out);
+
+ for (size_t ofs = 0; ofs < size; ofs += CtrDrbg::MaxRequestSize) {
+ const size_t cur_size = std::min(size - ofs, CtrDrbg::MaxRequestSize);
+
+ R_TRY(GenerateRandomBytesInternal(cur_dst, size));
+ cur_dst += cur_size;
+ }
+
+ return ResultSuccess;
+ }
+
+ Result IsDevelopment(bool *out) {
+ u64 is_retail;
+ R_TRY(GetConfig(&is_retail, SplConfigItem_IsRetail));
+
+ *out = (is_retail == 0);
+ return ResultSuccess;
+ }
+
+ Result SetBootReason(BootReasonValue boot_reason) {
+ if (IsBootReasonSet()) {
+ return ResultSplBootReasonAlreadySet;
+ }
+
+ g_boot_reason = boot_reason;
+ g_boot_reason_set = true;
+ return ResultSuccess;
+ }
+
+ Result GetBootReason(BootReasonValue *out) {
+ if (!IsBootReasonSet()) {
+ return ResultSplBootReasonNotSet;
+ }
+
+ *out = GetBootReason();
+ return ResultSuccess;
+ }
+
+ /* Crypto. */
+ Result GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option) {
+ return smc::ConvertResult(smc::GenerateAesKek(out_access_key, key_source, generation, option));
+ }
+
+ Result LoadAesKey(u32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source) {
+ R_TRY(ValidateAesKeyslot(keyslot, owner));
+ return smc::ConvertResult(smc::LoadAesKey(keyslot, access_key, key_source));
+ }
+
+ Result GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source) {
+ smc::Result smc_rc;
+
+ static const KeySource s_generate_aes_key_source = {
+ .data = {0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}
+ };
+
+ ScopedAesKeyslot keyslot_holder;
+ R_TRY(keyslot_holder.Allocate());
+
+ smc_rc = smc::LoadAesKey(keyslot_holder.GetKeyslot(), access_key, s_generate_aes_key_source);
+ if (smc_rc == smc::Result::Success) {
+ smc_rc = DecryptAesBlock(keyslot_holder.GetKeyslot(), out_key, &key_source);
+ }
+
+ return smc::ConvertResult(smc_rc);
+ }
+
+ Result DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option) {
+ static const KeySource s_decrypt_aes_key_source = {
+ .data = {0x11, 0x70, 0x24, 0x2B, 0x48, 0x69, 0x11, 0xF1, 0x11, 0xB0, 0x0C, 0x47, 0x7C, 0xC3, 0xEF, 0x7E}
+ };
+
+ AccessKey access_key;
+ R_TRY(GenerateAesKek(&access_key, s_decrypt_aes_key_source, generation, option));
+
+ return GenerateAesKey(out_key, access_key, key_source);
+ }
+
+ Result CryptAesCtr(void *dst, size_t dst_size, u32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr) {
+ R_TRY(ValidateAesKeyslot(keyslot, owner));
+
+ /* Succeed immediately if there's nothing to crypt. */
+ if (src_size == 0) {
+ return ResultSuccess;
+ }
+
+ /* Validate sizes. */
+ if (src_size > dst_size || src_size % AES_BLOCK_SIZE != 0) {
+ return ResultSplInvalidSize;
+ }
+
+ /* We can only map 0x400000 aligned buffers for the SE. With that in mind, we have some math to do. */
+ const uintptr_t src_addr = reinterpret_cast(src);
+ const uintptr_t dst_addr = reinterpret_cast(dst);
+ const uintptr_t src_addr_page_aligned = src_addr & ~0xFFFul;
+ const uintptr_t dst_addr_page_aligned = dst_addr & ~0xFFFul;
+ const size_t src_size_page_aligned = ((src_addr + src_size + 0xFFFul) & ~0xFFFul) - src_addr_page_aligned;
+ const size_t dst_size_page_aligned = ((dst_addr + dst_size + 0xFFFul) & ~0xFFFul) - dst_addr_page_aligned;
+ const u32 src_se_map_addr = CryptAesInMapBase + (src_addr_page_aligned & DeviceAddressSpaceAlignMask);
+ const u32 dst_se_map_addr = CryptAesOutMapBase + (dst_addr_page_aligned & DeviceAddressSpaceAlignMask);
+ const u32 src_se_addr = CryptAesInMapBase + (src_addr & DeviceAddressSpaceAlignMask);
+ const u32 dst_se_addr = CryptAesOutMapBase + (dst_addr & DeviceAddressSpaceAlignMask);
+
+ /* Validate aligned sizes. */
+ if (src_size_page_aligned > CryptAesSizeMax || dst_size_page_aligned > CryptAesSizeMax) {
+ return ResultSplInvalidSize;
+ }
+
+ /* Helpers for mapping/unmapping. */
+ DeviceAddressSpaceMapHelper in_mapper(g_se_das_hnd, src_se_map_addr, src_addr_page_aligned, src_size_page_aligned, 1);
+ DeviceAddressSpaceMapHelper out_mapper(g_se_das_hnd, dst_se_map_addr, dst_addr_page_aligned, dst_size_page_aligned, 2);
+
+ /* Setup SE linked list entries. */
+ SeCryptContext *crypt_ctx = reinterpret_cast(g_work_buffer);
+ crypt_ctx->in.num_entries = 0;
+ crypt_ctx->in.address = src_se_addr;
+ crypt_ctx->in.size = src_size;
+ crypt_ctx->out.num_entries = 0;
+ crypt_ctx->out.address = dst_se_addr;
+ crypt_ctx->out.size = dst_size;
+
+ armDCacheFlush(crypt_ctx, sizeof(*crypt_ctx));
+ armDCacheFlush(const_cast(src), src_size);
+ armDCacheFlush(dst, dst_size);
+ {
+ std::scoped_lock lk(g_async_op_lock);
+ smc::AsyncOperationKey op_key;
+ const u32 mode = smc::GetCryptAesMode(smc::CipherMode::Ctr, keyslot);
+ const u32 dst_ll_addr = g_se_mapped_work_buffer_addr + offsetof(SeCryptContext, out);
+ const u32 src_ll_addr = g_se_mapped_work_buffer_addr + offsetof(SeCryptContext, in);
+
+ smc::Result res = smc::CryptAes(&op_key, mode, iv_ctr, dst_ll_addr, src_ll_addr, src_size);
+ if (res != smc::Result::Success) {
+ return smc::ConvertResult(res);
+ }
+
+ if ((res = WaitCheckStatus(op_key)) != smc::Result::Success) {
+ return smc::ConvertResult(res);
+ }
+ }
+ armDCacheFlush(dst, dst_size);
+
+ return ResultSuccess;
+ }
+
+ Result ComputeCmac(Cmac *out_cmac, u32 keyslot, const void *owner, const void *data, size_t size) {
+ R_TRY(ValidateAesKeyslot(keyslot, owner));
+
+ if (size > WorkBufferSizeMax) {
+ return ResultSplInvalidSize;
+ }
+
+ std::memcpy(g_work_buffer, data, size);
+ return smc::ConvertResult(smc::ComputeCmac(out_cmac, keyslot, g_work_buffer, size));
+ }
+
+ Result AllocateAesKeyslot(u32 *out_keyslot, const void *owner) {
+ if (GetRuntimeFirmwareVersion() <= FirmwareVersion_100) {
+ /* On 1.0.0, keyslots were kind of a wild west. */
+ *out_keyslot = 0;
+ return ResultSuccess;
+ }
+
+ for (size_t i = 0; i < GetMaxKeyslots(); i++) {
+ if (g_keyslot_owners[i] == 0) {
+ g_keyslot_owners[i] = owner;
+ *out_keyslot = static_cast(i);
+ return ResultSuccess;
+ }
+ }
+
+ g_se_keyslot_available_event->Clear();
+ return ResultSplOutOfKeyslots;
+ }
+
+ Result FreeAesKeyslot(u32 keyslot, const void *owner) {
+ if (GetRuntimeFirmwareVersion() <= FirmwareVersion_100) {
+ /* On 1.0.0, keyslots were kind of a wild west. */
+ return ResultSuccess;
+ }
+
+ R_TRY(ValidateAesKeyslot(keyslot, owner));
+
+ /* Clear the keyslot. */
+ {
+ AccessKey access_key = {};
+ KeySource key_source = {};
+
+ smc::LoadAesKey(keyslot, access_key, key_source);
+ }
+ g_keyslot_owners[keyslot] = nullptr;
+ g_se_keyslot_available_event->Signal();
+ return ResultSuccess;
+ }
+
+ /* RSA. */
+ Result DecryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
+ struct DecryptRsaPrivateKeyLayout {
+ u8 data[RsaPrivateKeySize + RsaPrivateKeyMetaSize];
+ };
+ DecryptRsaPrivateKeyLayout *layout = reinterpret_cast(g_work_buffer);
+
+ /* Validate size. */
+ if (src_size < RsaPrivateKeyMetaSize || src_size > sizeof(DecryptRsaPrivateKeyLayout)) {
+ return ResultSplInvalidSize;
+ }
+
+ std::memcpy(layout->data, src, src_size);
+ armDCacheFlush(layout, sizeof(*layout));
+
+ smc::Result smc_res;
+ size_t copy_size = 0;
+ if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) {
+ copy_size = std::min(dst_size, src_size - RsaPrivateKeyMetaSize);
+ smc_res = smc::DecryptOrImportRsaPrivateKey(layout->data, src_size, access_key, key_source, smc::DecryptOrImportMode::DecryptRsaPrivateKey);
+ } else {
+ smc_res = smc::DecryptRsaPrivateKey(©_size, layout->data, src_size, access_key, key_source, option);
+ copy_size = std::min(dst_size, copy_size);
+ }
+
+ armDCacheFlush(layout, sizeof(*layout));
+ if (smc_res == smc::Result::Success) {
+ std::memcpy(dst, layout->data, copy_size);
+ }
+
+ return smc::ConvertResult(smc_res);
+ }
+
+ /* SSL */
+ Result ImportSslKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) {
+ return ImportSecureExpModKey(src, src_size, access_key, key_source, static_cast(smc::DecryptOrImportMode::ImportSslKey));
+ }
+
+ Result SslExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) {
+ return SecureExpMod(out, out_size, base, base_size, mod, mod_size, smc::SecureExpModMode::Ssl);
+ }
+
+ /* ES */
+ Result ImportEsKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
+ if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) {
+ return ImportSecureExpModKey(src, src_size, access_key, key_source, static_cast(smc::DecryptOrImportMode::ImportEsKey));
+ } else {
+ struct ImportEsKeyLayout {
+ u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10];
+ };
+ ImportEsKeyLayout *layout = reinterpret_cast(g_work_buffer);
+
+ /* Validate size. */
+ if (src_size > sizeof(ImportEsKeyLayout)) {
+ return ResultSplInvalidSize;
+ }
+
+ std::memcpy(layout, src, src_size);
+
+ armDCacheFlush(layout, sizeof(*layout));
+ return smc::ConvertResult(smc::ImportEsKey(layout->data, src_size, access_key, key_source, option));
+ }
+ }
+
+ Result UnwrapTitleKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation) {
+ return UnwrapEsRsaOaepWrappedKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation, smc::EsKeyType::TitleKey);
+ }
+
+ Result UnwrapCommonTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation) {
+ return smc::ConvertResult(smc::UnwrapCommonTitleKey(out_access_key, key_source, generation));
+ }
+
+ Result ImportDrmKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) {
+ return ImportSecureExpModKey(src, src_size, access_key, key_source, static_cast(smc::DecryptOrImportMode::ImportDrmKey));
+ }
+
+ Result DrmExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) {
+ return SecureExpMod(out, out_size, base, base_size, mod, mod_size, smc::SecureExpModMode::Drm);
+ }
+
+ Result UnwrapElicenseKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation) {
+ return UnwrapEsRsaOaepWrappedKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation, smc::EsKeyType::ElicenseKey);
+ }
+
+ Result LoadElicenseKey(u32 keyslot, const void *owner, const AccessKey &access_key) {
+ /* Right now, this is just literally the same function as LoadTitleKey in N's impl. */
+ return LoadTitleKey(keyslot, owner, access_key);
+ }
+
+ /* FS */
+ Result ImportLotusKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
+ if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) {
+ option = static_cast(smc::DecryptOrImportMode::ImportLotusKey);
+ }
+ return ImportSecureExpModKey(src, src_size, access_key, key_source, option);
+ }
+
+ Result DecryptLotusMessage(u32 *out_size, void *dst, size_t dst_size, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size) {
+ /* Validate sizes. */
+ if (dst_size > WorkBufferSizeMax || label_digest_size != LabelDigestSizeMax) {
+ return ResultSplInvalidSize;
+ }
+
+ /* Nintendo doesn't check this result code, but we will. */
+ R_TRY(SecureExpMod(g_work_buffer, 0x100, base, base_size, mod, mod_size, smc::SecureExpModMode::Lotus));
+
+ size_t data_size = DecodeRsaOaep(dst, dst_size, label_digest, label_digest_size, g_work_buffer, 0x100);
+ if (data_size == 0) {
+ return ResultSplDecryptionFailed;
+ }
+
+ *out_size = static_cast(data_size);
+ return ResultSuccess;
+ }
+
+ Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 which) {
+ return smc::ConvertResult(smc::GenerateSpecificAesKey(out_key, key_source, generation, which));
+ }
+
+ Result LoadTitleKey(u32 keyslot, const void *owner, const AccessKey &access_key) {
+ R_TRY(ValidateAesKeyslot(keyslot, owner));
+ return smc::ConvertResult(smc::LoadTitleKey(keyslot, access_key));
+ }
+
+ Result GetPackage2Hash(void *dst, const size_t size) {
+ u64 hash[4];
+
+ if (size < sizeof(hash)) {
+ return ResultSplInvalidSize;
+ }
+
+ smc::Result smc_res;
+ if ((smc_res = smc::GetConfig(hash, 4, SplConfigItem_Package2Hash)) != smc::Result::Success) {
+ return smc::ConvertResult(smc_res);
+ }
+
+ std::memcpy(dst, hash, sizeof(hash));
+ return ResultSuccess;
+ }
+
+ /* Manu. */
+ Result ReEncryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option) {
+ struct ReEncryptRsaPrivateKeyLayout {
+ u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10];
+ AccessKey access_key_dec;
+ KeySource source_dec;
+ AccessKey access_key_enc;
+ KeySource source_enc;
+ };
+ ReEncryptRsaPrivateKeyLayout *layout = reinterpret_cast(g_work_buffer);
+
+ /* Validate size. */
+ if (src_size < RsaPrivateKeyMetaSize || src_size > sizeof(ReEncryptRsaPrivateKeyLayout)) {
+ return ResultSplInvalidSize;
+ }
+
+ std::memcpy(layout, src, src_size);
+ layout->access_key_dec = access_key_dec;
+ layout->source_dec = source_dec;
+ layout->access_key_enc = access_key_enc;
+ layout->source_enc = source_enc;
+
+ armDCacheFlush(layout, sizeof(*layout));
+
+ smc::Result smc_res = smc::ReEncryptRsaPrivateKey(layout->data, src_size, layout->access_key_dec, layout->source_dec, layout->access_key_enc, layout->source_enc, option);
+ if (smc_res == smc::Result::Success) {
+ size_t copy_size = std::min(dst_size, src_size);
+ armDCacheFlush(layout, copy_size);
+ std::memcpy(dst, layout->data, copy_size);
+ }
+
+ return smc::ConvertResult(smc_res);
+ }
+
+ /* Helper. */
+ Result FreeAesKeyslots(const void *owner) {
+ for (size_t i = 0; i < GetMaxKeyslots(); i++) {
+ if (g_keyslot_owners[i] == owner) {
+ FreeAesKeyslot(i, owner);
+ }
+ }
+ return ResultSuccess;
+ }
+
+ Handle GetAesKeyslotAvailableEventHandle() {
+ return g_se_keyslot_available_event->GetHandle();
+ }
+
+}
diff --git a/stratosphere/spl/source/spl_api.hpp b/stratosphere/spl/source/spl_api.hpp
new file mode 100644
index 000000000..63aaaed67
--- /dev/null
+++ b/stratosphere/spl/source/spl_api.hpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include
+#include
+
+#include "spl_types.hpp"
+
+namespace sts::spl {
+
+ /* Initialization. */
+ void Initialize();
+
+ /* General. */
+ Result GetConfig(u64 *out, SplConfigItem which);
+ Result ExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *exp, size_t exp_size, const void *mod, size_t mod_size);
+ Result SetConfig(SplConfigItem which, u64 value);
+ Result GenerateRandomBytes(void *out, size_t size);
+ Result IsDevelopment(bool *out);
+ Result SetBootReason(BootReasonValue boot_reason);
+ Result GetBootReason(BootReasonValue *out);
+
+ /* Crypto. */
+ Result GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option);
+ Result LoadAesKey(u32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source);
+ Result GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source);
+ Result DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option);
+ Result CryptAesCtr(void *dst, size_t dst_size, u32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr);
+ Result ComputeCmac(Cmac *out_cmac, u32 keyslot, const void *owner, const void *data, size_t size);
+ Result AllocateAesKeyslot(u32 *out_keyslot, const void *owner);
+ Result FreeAesKeyslot(u32 keyslot, const void *owner);
+
+ /* RSA. */
+ Result DecryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
+
+ /* SSL */
+ Result ImportSslKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source);
+ Result SslExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size);
+
+ /* ES */
+ Result ImportEsKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
+ Result UnwrapTitleKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation);
+ Result UnwrapCommonTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation);
+ Result ImportDrmKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source);
+ Result DrmExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size);
+ Result UnwrapElicenseKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation);
+ Result LoadElicenseKey(u32 keyslot, const void *owner, const AccessKey &access_key);
+
+ /* FS */
+ Result ImportLotusKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
+ Result DecryptLotusMessage(u32 *out_size, void *dst, size_t dst_size, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size);
+ Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 which);
+ Result LoadTitleKey(u32 keyslot, const void *owner, const AccessKey &access_key);
+ Result GetPackage2Hash(void *dst, const size_t size);
+
+ /* Manu. */
+ Result ReEncryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option);
+
+ /* Helper. */
+ Result FreeAesKeyslots(const void *owner);
+ Handle GetAesKeyslotAvailableEventHandle();
+
+}
diff --git a/stratosphere/spl/source/spl_crypto_service.cpp b/stratosphere/spl/source/spl_crypto_service.cpp
index 1e3522865..86e445eea 100644
--- a/stratosphere/spl/source/spl_crypto_service.cpp
+++ b/stratosphere/spl/source/spl_crypto_service.cpp
@@ -18,39 +18,49 @@
#include
#include "spl_crypto_service.hpp"
+#include "spl_api.hpp"
-Result CryptoService::GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option) {
- return this->GetSecureMonitorWrapper()->GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
-}
+namespace sts::spl {
-Result CryptoService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) {
- return this->GetSecureMonitorWrapper()->LoadAesKey(keyslot, this, access_key, key_source);
-}
+ CryptoService::~CryptoService() {
+ /* Free any keyslots this service is using. */
+ spl::FreeAesKeyslots(this);
+ }
-Result CryptoService::GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source) {
- return this->GetSecureMonitorWrapper()->GenerateAesKey(out_key.GetPointer(), access_key, key_source);
-}
+ Result CryptoService::GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option) {
+ return spl::GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
+ }
-Result CryptoService::DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option) {
- return this->GetSecureMonitorWrapper()->DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
-}
+ Result CryptoService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) {
+ return spl::LoadAesKey(keyslot, this, access_key, key_source);
+ }
-Result CryptoService::CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr) {
- return this->GetSecureMonitorWrapper()->CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr);
-}
+ Result CryptoService::GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source) {
+ return spl::GenerateAesKey(out_key.GetPointer(), access_key, key_source);
+ }
-Result CryptoService::ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf) {
- return this->GetSecureMonitorWrapper()->ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.pointer, in_buf.num_elements);
-}
+ Result CryptoService::DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option) {
+ return spl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
+ }
-Result CryptoService::AllocateAesKeyslot(Out out_keyslot) {
- return this->GetSecureMonitorWrapper()->AllocateAesKeyslot(out_keyslot.GetPointer(), this);
-}
+ Result CryptoService::CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr) {
+ return spl::CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr);
+ }
-Result CryptoService::FreeAesKeyslot(u32 keyslot) {
- return this->GetSecureMonitorWrapper()->FreeAesKeyslot(keyslot, this);
-}
+ Result CryptoService::ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf) {
+ return spl::ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.pointer, in_buf.num_elements);
+ }
+
+ Result CryptoService::AllocateAesKeyslot(Out out_keyslot) {
+ return spl::AllocateAesKeyslot(out_keyslot.GetPointer(), this);
+ }
+
+ Result CryptoService::FreeAesKeyslot(u32 keyslot) {
+ return spl::FreeAesKeyslot(keyslot, this);
+ }
+
+ void CryptoService::GetAesKeyslotAvailableEvent(Out out_hnd) {
+ out_hnd.SetValue(spl::GetAesKeyslotAvailableEventHandle());
+ }
-void CryptoService::GetAesKeyslotAvailableEvent(Out out_hnd) {
- out_hnd.SetValue(this->GetSecureMonitorWrapper()->GetAesKeyslotAvailableEventHandle());
}
diff --git a/stratosphere/spl/source/spl_crypto_service.hpp b/stratosphere/spl/source/spl_crypto_service.hpp
index 2f56df6ec..3acfb1f1d 100644
--- a/stratosphere/spl/source/spl_crypto_service.hpp
+++ b/stratosphere/spl/source/spl_crypto_service.hpp
@@ -21,44 +21,42 @@
#include "spl_types.hpp"
#include "spl_general_service.hpp"
-class CryptoService : public GeneralService {
- public:
- CryptoService(SecureMonitorWrapper *sw) : GeneralService(sw) {
- /* ... */
- }
+namespace sts::spl {
- virtual ~CryptoService() {
- this->GetSecureMonitorWrapper()->FreeAesKeyslots(this);
- }
- protected:
- /* Actual commands. */
- virtual Result GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option);
- virtual Result LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source);
- virtual Result GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source);
- virtual Result DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option);
- virtual Result CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr);
- virtual Result ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf);
- virtual Result AllocateAesKeyslot(Out out_keyslot);
- virtual Result FreeAesKeyslot(u32 keyslot);
- virtual void GetAesKeyslotAvailableEvent(Out out_hnd);
- public:
- DEFINE_SERVICE_DISPATCH_TABLE {
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
- MakeServiceCommandMetaEx(),
+ class CryptoService : public GeneralService {
+ public:
+ CryptoService() : GeneralService() { /* ... */ }
+ virtual ~CryptoService();
+ protected:
+ /* Actual commands. */
+ virtual Result GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option);
+ virtual Result LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source);
+ virtual Result GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source);
+ virtual Result DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option);
+ virtual Result CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr);
+ virtual Result ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf);
+ virtual Result AllocateAesKeyslot(Out out_keyslot);
+ virtual Result FreeAesKeyslot(u32 keyslot);
+ virtual void GetAesKeyslotAvailableEvent(Out out_hnd);
+ public:
+ DEFINE_SERVICE_DISPATCH_TABLE {
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ MakeServiceCommandMetaEx(),
+ };
+ };
- };
-};
+}
diff --git a/stratosphere/spl/source/spl_ctr_drbg.cpp b/stratosphere/spl/source/spl_ctr_drbg.cpp
index a468d2dcf..c9bc73271 100644
--- a/stratosphere/spl/source/spl_ctr_drbg.cpp
+++ b/stratosphere/spl/source/spl_ctr_drbg.cpp
@@ -20,62 +20,66 @@
#include "spl_types.hpp"
#include "spl_ctr_drbg.hpp"
-void CtrDrbg::Update(const void *data) {
- aes128ContextCreate(&this->aes_ctx, this->key, true);
- for (size_t offset = 0; offset < sizeof(this->work[1]); offset += BlockSize) {
- IncrementCounter(this->counter);
- aes128EncryptBlock(&this->aes_ctx, &this->work[1][offset], this->counter);
+namespace sts::spl {
+
+ void CtrDrbg::Update(const void *data) {
+ aes128ContextCreate(&this->aes_ctx, this->key, true);
+ for (size_t offset = 0; offset < sizeof(this->work[1]); offset += BlockSize) {
+ IncrementCounter(this->counter);
+ aes128EncryptBlock(&this->aes_ctx, &this->work[1][offset], this->counter);
+ }
+
+ Xor(this->work[1], data, sizeof(this->work[1]));
+
+ std::memcpy(this->key, &this->work[1][0], sizeof(this->key));
+ std::memcpy(this->counter, &this->work[1][BlockSize], sizeof(this->key));
}
- Xor(this->work[1], data, sizeof(this->work[1]));
+ void CtrDrbg::Initialize(const void *seed) {
+ std::memcpy(this->work[0], seed, sizeof(this->work[0]));
+ std::memset(this->key, 0, sizeof(this->key));
+ std::memset(this->counter, 0, sizeof(this->counter));
+ this->Update(this->work[0]);
+ this->reseed_counter = 1;
+ }
+
+ void CtrDrbg::Reseed(const void *seed) {
+ std::memcpy(this->work[0], seed, sizeof(this->work[0]));
+ this->Update(this->work[0]);
+ this->reseed_counter = 1;
+ }
+
+ bool CtrDrbg::GenerateRandomBytes(void *out, size_t size) {
+ if (size > MaxRequestSize) {
+ return false;
+ }
+
+ if (this->reseed_counter > ReseedInterval) {
+ return false;
+ }
+
+ aes128ContextCreate(&this->aes_ctx, this->key, true);
+ u8 *cur_dst = reinterpret_cast(out);
+
+ size_t aligned_size = (size & ~(BlockSize - 1));
+ for (size_t offset = 0; offset < aligned_size; offset += BlockSize) {
+ IncrementCounter(this->counter);
+ aes128EncryptBlock(&this->aes_ctx, cur_dst, this->counter);
+ cur_dst += BlockSize;
+ }
+
+ if (size > aligned_size) {
+ IncrementCounter(this->counter);
+ aes128EncryptBlock(&this->aes_ctx, this->work[1], this->counter);
+ std::memcpy(cur_dst, this->work[1], size - aligned_size);
+ }
+
+ std::memset(this->work[0], 0, sizeof(this->work[0]));
+ this->Update(this->work[0]);
+
+ this->reseed_counter++;
+ return true;
+
+ }
- std::memcpy(this->key, &this->work[1][0], sizeof(this->key));
- std::memcpy(this->counter, &this->work[1][BlockSize], sizeof(this->key));
}
-
-void CtrDrbg::Initialize(const void *seed) {
- std::memcpy(this->work[0], seed, sizeof(this->work[0]));
- std::memset(this->key, 0, sizeof(this->key));
- std::memset(this->counter, 0, sizeof(this->counter));
- this->Update(this->work[0]);
- this->reseed_counter = 1;
-}
-
-void CtrDrbg::Reseed(const void *seed) {
- std::memcpy(this->work[0], seed, sizeof(this->work[0]));
- this->Update(this->work[0]);
- this->reseed_counter = 1;
-}
-
-bool CtrDrbg::GenerateRandomBytes(void *out, size_t size) {
- if (size > MaxRequestSize) {
- return false;
- }
-
- if (this->reseed_counter > ReseedInterval) {
- return false;
- }
-
- aes128ContextCreate(&this->aes_ctx, this->key, true);
- u8 *cur_dst = reinterpret_cast(out);
-
- size_t aligned_size = (size & ~(BlockSize - 1));
- for (size_t offset = 0; offset < aligned_size; offset += BlockSize) {
- IncrementCounter(this->counter);
- aes128EncryptBlock(&this->aes_ctx, cur_dst, this->counter);
- cur_dst += BlockSize;
- }
-
- if (size > aligned_size) {
- IncrementCounter(this->counter);
- aes128EncryptBlock(&this->aes_ctx, this->work[1], this->counter);
- std::memcpy(cur_dst, this->work[1], size - aligned_size);
- }
-
- std::memset(this->work[0], 0, sizeof(this->work[0]));
- this->Update(this->work[0]);
-
- this->reseed_counter++;
- return true;
-
-}
\ No newline at end of file
diff --git a/stratosphere/spl/source/spl_ctr_drbg.hpp b/stratosphere/spl/source/spl_ctr_drbg.hpp
index 39f82ae0a..462c3c2e6 100644
--- a/stratosphere/spl/source/spl_ctr_drbg.hpp
+++ b/stratosphere/spl/source/spl_ctr_drbg.hpp
@@ -20,41 +20,45 @@
#include "spl_types.hpp"
-/* Nintendo implements CTR_DRBG for their csrng. We will do the same. */
-class CtrDrbg {
- public:
- static constexpr size_t MaxRequestSize = 0x10000;
- static constexpr size_t ReseedInterval = 0x7FFFFFF0;
- static constexpr size_t BlockSize = AES_BLOCK_SIZE;
- static constexpr size_t SeedSize = 2 * AES_BLOCK_SIZE;
- private:
- Aes128Context aes_ctx;
- u8 counter[BlockSize];
- u8 key[BlockSize];
- u8 work[2][SeedSize];
- u32 reseed_counter;
- private:
- static void Xor(void *dst, const void *src, size_t size) {
- const u8 *src_u8 = reinterpret_cast(src);
- u8 *dst_u8 = reinterpret_cast(dst);
+namespace sts::spl {
- for (size_t i = 0; i < size; i++) {
- dst_u8[i] ^= src_u8[i];
+ /* Nintendo implements CTR_DRBG for their csrng. We will do the same. */
+ class CtrDrbg {
+ public:
+ static constexpr size_t MaxRequestSize = 0x10000;
+ static constexpr size_t ReseedInterval = 0x7FFFFFF0;
+ static constexpr size_t BlockSize = AES_BLOCK_SIZE;
+ static constexpr size_t SeedSize = 2 * AES_BLOCK_SIZE;
+ private:
+ Aes128Context aes_ctx;
+ u8 counter[BlockSize];
+ u8 key[BlockSize];
+ u8 work[2][SeedSize];
+ u32 reseed_counter;
+ private:
+ static void Xor(void *dst, const void *src, size_t size) {
+ const u8 *src_u8 = reinterpret_cast(src);
+ u8 *dst_u8 = reinterpret_cast(dst);
+
+ for (size_t i = 0; i < size; i++) {
+ dst_u8[i] ^= src_u8[i];
+ }
}
- }
- static void IncrementCounter(void *ctr) {
- u64 *ctr_64 = reinterpret_cast(ctr);
+ static void IncrementCounter(void *ctr) {
+ u64 *ctr_64 = reinterpret_cast(ctr);
- ctr_64[1] = __builtin_bswap64(__builtin_bswap64(ctr_64[1]) + 1);
- if (!ctr_64[1]) {
- ctr_64[0] = __builtin_bswap64(__builtin_bswap64(ctr_64[0]) + 1);
+ ctr_64[1] = __builtin_bswap64(__builtin_bswap64(ctr_64[1]) + 1);
+ if (!ctr_64[1]) {
+ ctr_64[0] = __builtin_bswap64(__builtin_bswap64(ctr_64[0]) + 1);
+ }
}
- }
- private:
- void Update(const void *data);
- public:
- void Initialize(const void *seed);
- void Reseed(const void *seed);
- bool GenerateRandomBytes(void *out, size_t size);
-};
\ No newline at end of file
+ private:
+ void Update(const void *data);
+ public:
+ void Initialize(const void *seed);
+ void Reseed(const void *seed);
+ bool GenerateRandomBytes(void *out, size_t size);
+ };
+
+}
diff --git a/stratosphere/spl/source/spl_deprecated_service.cpp b/stratosphere/spl/source/spl_deprecated_service.cpp
index 12484385b..5aa7234f0 100644
--- a/stratosphere/spl/source/spl_deprecated_service.cpp
+++ b/stratosphere/spl/source/spl_deprecated_service.cpp
@@ -18,103 +18,108 @@
#include
#include "spl_deprecated_service.hpp"
+#include "spl_api.hpp"
-Result DeprecatedService::GetConfig(Out out, u32 which) {
- return this->GetSecureMonitorWrapper()->GetConfig(out.GetPointer(), static_cast(which));
-}
+namespace sts::spl {
-Result DeprecatedService::ExpMod(OutPointerWithClientSize out, InPointer base, InPointer exp, InPointer mod) {
- return this->GetSecureMonitorWrapper()->ExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, exp.pointer, exp.num_elements, mod.pointer, mod.num_elements);
-}
+ Result DeprecatedService::GetConfig(Out out, u32 which) {
+ return spl::GetConfig(out.GetPointer(), static_cast(which));
+ }
-Result DeprecatedService::GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option) {
- return this->GetSecureMonitorWrapper()->GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
-}
+ Result DeprecatedService::ExpMod(OutPointerWithClientSize out, InPointer base, InPointer exp, InPointer mod) {
+ return spl::ExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, exp.pointer, exp.num_elements, mod.pointer, mod.num_elements);
+ }
-Result DeprecatedService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) {
- return this->GetSecureMonitorWrapper()->LoadAesKey(keyslot, this, access_key, key_source);
-}
+ Result DeprecatedService::GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option) {
+ return spl::GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
+ }
-Result DeprecatedService::GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source) {
- return this->GetSecureMonitorWrapper()->GenerateAesKey(out_key.GetPointer(), access_key, key_source);
-}
+ Result DeprecatedService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) {
+ return spl::LoadAesKey(keyslot, this, access_key, key_source);
+ }
-Result DeprecatedService::SetConfig(u32 which, u64 value) {
- return this->GetSecureMonitorWrapper()->SetConfig(static_cast(which), value);
-}
+ Result DeprecatedService::GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source) {
+ return spl::GenerateAesKey(out_key.GetPointer(), access_key, key_source);
+ }
-Result DeprecatedService::GenerateRandomBytes(OutPointerWithClientSize out) {
- return this->GetSecureMonitorWrapper()->GenerateRandomBytes(out.pointer, out.num_elements);
-}
+ Result DeprecatedService::SetConfig(u32 which, u64 value) {
+ return spl::SetConfig(static_cast(which), value);
+ }
-Result DeprecatedService::ImportLotusKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) {
- return this->GetSecureMonitorWrapper()->ImportLotusKey(src.pointer, src.num_elements, access_key, key_source, option);
-}
+ Result DeprecatedService::GenerateRandomBytes(OutPointerWithClientSize out) {
+ return spl::GenerateRandomBytes(out.pointer, out.num_elements);
+ }
-Result DeprecatedService::DecryptLotusMessage(Out out_size, OutPointerWithClientSize out, InPointer base, InPointer mod, InPointer label_digest) {
- return this->GetSecureMonitorWrapper()->DecryptLotusMessage(out_size.GetPointer(), out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements);
-}
+ Result DeprecatedService::ImportLotusKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) {
+ return spl::ImportLotusKey(src.pointer, src.num_elements, access_key, key_source, option);
+ }
-Result DeprecatedService::IsDevelopment(Out is_dev) {
- return this->GetSecureMonitorWrapper()->IsDevelopment(is_dev.GetPointer());
-}
+ Result DeprecatedService::DecryptLotusMessage(Out out_size, OutPointerWithClientSize out, InPointer base, InPointer mod, InPointer label_digest) {
+ return spl::DecryptLotusMessage(out_size.GetPointer(), out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements);
+ }
-Result DeprecatedService::GenerateSpecificAesKey(Out out_key, KeySource key_source, u32 generation, u32 which) {
- return this->GetSecureMonitorWrapper()->GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which);
-}
+ Result DeprecatedService::IsDevelopment(Out is_dev) {
+ return spl::IsDevelopment(is_dev.GetPointer());
+ }
-Result DeprecatedService::DecryptRsaPrivateKey(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source, u32 option) {
- return this->GetSecureMonitorWrapper()->DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, option);
-}
+ Result DeprecatedService::GenerateSpecificAesKey(Out out_key, KeySource key_source, u32 generation, u32 which) {
+ return spl::GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which);
+ }
-Result DeprecatedService::DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option) {
- return this->GetSecureMonitorWrapper()->DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
-}
+ Result DeprecatedService::DecryptRsaPrivateKey(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source, u32 option) {
+ return spl::DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, option);
+ }
-Result DeprecatedService::CryptAesCtrDeprecated(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr) {
- return this->GetSecureMonitorWrapper()->CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr);
-}
+ Result DeprecatedService::DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option) {
+ return spl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
+ }
-Result DeprecatedService::CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr) {
- return this->GetSecureMonitorWrapper()->CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr);
-}
+ Result DeprecatedService::CryptAesCtrDeprecated(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr) {
+ return spl::CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr);
+ }
-Result DeprecatedService::ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf) {
- return this->GetSecureMonitorWrapper()->ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.pointer, in_buf.num_elements);
-}
+ Result DeprecatedService::CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr) {
+ return spl::CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr);
+ }
-Result DeprecatedService::ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) {
- return this->GetSecureMonitorWrapper()->ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option);
-}
+ Result DeprecatedService::ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf) {
+ return spl::ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.pointer, in_buf.num_elements);
+ }
-Result DeprecatedService::UnwrapTitleKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation) {
- return this->GetSecureMonitorWrapper()->UnwrapTitleKey(out_access_key.GetPointer(), base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements, generation);
-}
+ Result DeprecatedService::ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) {
+ return spl::ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option);
+ }
-Result DeprecatedService::LoadTitleKey(u32 keyslot, AccessKey access_key) {
- return this->GetSecureMonitorWrapper()->LoadTitleKey(keyslot, this, access_key);
-}
+ Result DeprecatedService::UnwrapTitleKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation) {
+ return spl::UnwrapTitleKey(out_access_key.GetPointer(), base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements, generation);
+ }
-Result DeprecatedService::UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation) {
- return this->GetSecureMonitorWrapper()->UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation);
-}
+ Result DeprecatedService::LoadTitleKey(u32 keyslot, AccessKey access_key) {
+ return spl::LoadTitleKey(keyslot, this, access_key);
+ }
-Result DeprecatedService::AllocateAesKeyslot(Out out_keyslot) {
- return this->GetSecureMonitorWrapper()->AllocateAesKeyslot(out_keyslot.GetPointer(), this);
-}
+ Result DeprecatedService::UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation) {
+ return spl::UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation);
+ }
-Result DeprecatedService::FreeAesKeyslot(u32 keyslot) {
- return this->GetSecureMonitorWrapper()->FreeAesKeyslot(keyslot, this);
-}
+ Result DeprecatedService::AllocateAesKeyslot(Out out_keyslot) {
+ return spl::AllocateAesKeyslot(out_keyslot.GetPointer(), this);
+ }
-void DeprecatedService::GetAesKeyslotAvailableEvent(Out out_hnd) {
- out_hnd.SetValue(this->GetSecureMonitorWrapper()->GetAesKeyslotAvailableEventHandle());
-}
+ Result DeprecatedService::FreeAesKeyslot(u32 keyslot) {
+ return spl::FreeAesKeyslot(keyslot, this);
+ }
-Result DeprecatedService::SetBootReason(BootReasonValue boot_reason) {
- return this->GetSecureMonitorWrapper()->SetBootReason(boot_reason);
-}
+ void DeprecatedService::GetAesKeyslotAvailableEvent(Out out_hnd) {
+ out_hnd.SetValue(spl::GetAesKeyslotAvailableEventHandle());
+ }
+
+ Result DeprecatedService::SetBootReason(BootReasonValue boot_reason) {
+ return spl::SetBootReason(boot_reason);
+ }
+
+ Result DeprecatedService::GetBootReason(Out out) {
+ return spl::GetBootReason(out.GetPointer());
+ }
-Result DeprecatedService::GetBootReason(Out out) {
- return this->GetSecureMonitorWrapper()->GetBootReason(out.GetPointer());
}
diff --git a/stratosphere/spl/source/spl_deprecated_service.hpp b/stratosphere/spl/source/spl_deprecated_service.hpp
index cd52d2d0d..d78bb7282 100644
--- a/stratosphere/spl/source/spl_deprecated_service.hpp
+++ b/stratosphere/spl/source/spl_deprecated_service.hpp
@@ -19,74 +19,100 @@
#include
#include "spl_types.hpp"
-#include "spl_secmon_wrapper.hpp"
-class DeprecatedService : public IServiceObject {
- private:
- SecureMonitorWrapper *secmon_wrapper;
- public:
- DeprecatedService(SecureMonitorWrapper *sw) : secmon_wrapper(sw) {
- /* ... */
- }
+namespace sts::spl {
- virtual ~DeprecatedService() { /* ... */ }
- protected:
- SecureMonitorWrapper *GetSecureMonitorWrapper() const {
- return this->secmon_wrapper;
- }
- protected:
- /* Actual commands. */
- virtual Result GetConfig(Out out, u32 which);
- virtual Result ExpMod(OutPointerWithClientSize out, InPointer base, InPointer exp, InPointer mod);
- virtual Result GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option);
- virtual Result LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source);
- virtual Result GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source);
- virtual Result SetConfig(u32 which, u64 value);
- virtual Result GenerateRandomBytes(OutPointerWithClientSize out);
- virtual Result ImportLotusKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option);
- virtual Result DecryptLotusMessage(Out out_size, OutPointerWithClientSize out, InPointer base, InPointer mod, InPointer label_digest);
- virtual Result IsDevelopment(Out is_dev);
- virtual Result GenerateSpecificAesKey(Out out_key, KeySource key_source, u32 generation, u32 which);
- virtual Result DecryptRsaPrivateKey(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source, u32 option);
- virtual Result DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option);
- virtual Result CryptAesCtrDeprecated(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr);
- virtual Result CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr);
- virtual Result ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf);
- virtual Result ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option);
- virtual Result UnwrapTitleKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation);
- virtual Result LoadTitleKey(u32 keyslot, AccessKey access_key);
- virtual Result UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation);
- virtual Result AllocateAesKeyslot(Out out_keyslot);
- virtual Result FreeAesKeyslot(u32 keyslot);
- virtual void GetAesKeyslotAvailableEvent(Out out_hnd);
- virtual Result SetBootReason(BootReasonValue boot_reason);
- virtual Result GetBootReason(Out out);
- public:
- DEFINE_SERVICE_DISPATCH_TABLE {
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- MakeServiceCommandMeta(),
- };
-};
+ class DeprecatedService : public IServiceObject {
+ protected:
+ enum class CommandId {
+ /* 1.0.0+ */
+ GetConfig = 0,
+ ExpMod = 1,
+ GenerateAesKek = 2,
+ LoadAesKey = 3,
+ GenerateAesKey = 4,
+ SetConfig = 5,
+ GenerateRandomBytes = 7,
+ ImportLotusKey = 9,
+ DecryptLotusMessage = 10,
+ IsDevelopment = 11,
+ GenerateSpecificAesKey = 12,
+ DecryptRsaPrivateKey = 13,
+ DecryptAesKey = 14,
+ CryptAesCtr = 15,
+ ComputeCmac = 16,
+ ImportEsKey = 17,
+ UnwrapTitleKey = 18,
+ LoadTitleKey = 19,
+
+ /* 2.0.0+ */
+ UnwrapCommonTitleKey = 20,
+ AllocateAesKeyslot = 21,
+ FreeAesKeyslot = 22,
+ GetAesKeyslotAvailableEvent = 23,
+
+ /* 3.0.0+ */
+ SetBootReason = 24,
+ GetBootReason = 25,
+ };
+ public:
+ DeprecatedService() { /* ... */ }
+ virtual ~DeprecatedService() { /* ... */ }
+ protected:
+ /* Actual commands. */
+ virtual Result GetConfig(Out out, u32 which);
+ virtual Result ExpMod(OutPointerWithClientSize out, InPointer base, InPointer exp, InPointer mod);
+ virtual Result GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option);
+ virtual Result LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source);
+ virtual Result GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source);
+ virtual Result SetConfig(u32 which, u64 value);
+ virtual Result GenerateRandomBytes(OutPointerWithClientSize out);
+ virtual Result ImportLotusKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option);
+ virtual Result DecryptLotusMessage(Out out_size, OutPointerWithClientSize