spl: continue implementing.

This commit is contained in:
Michael Scire 2019-04-24 05:38:11 -07:00
parent 9858d6fc95
commit 2dfa1c96d1
8 changed files with 628 additions and 10 deletions

View file

@ -0,0 +1,81 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#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);
}
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));
}
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<u8 *>(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;
}

View file

@ -0,0 +1,60 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#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<const u8 *>(src);
u8 *dst_u8 = reinterpret_cast<u8 *>(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<u64 *>(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);
}
}
private:
void Update(const void *data);
public:
void Initialize(const void *seed);
void Reseed(const void *seed);
bool GenerateRandomBytes(void *out, size_t size);
};

View file

@ -89,12 +89,15 @@ static const auto MakeGeneralService = []() { return std::make_shared<GeneralSer
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
consoleDebugInit(debugDevice_SVC); consoleDebugInit(debugDevice_SVC);
/* Initialize global context. */
SecureMonitorWrapper::Initialize();
/* Create server manager. */ /* Create server manager. */
static auto s_server_manager = WaitableManager<SplServerOptions>(1); static auto s_server_manager = WaitableManager<SplServerOptions>(1);
/* Create services. */ /* Create services. */
s_server_manager.AddWaitable(new ServiceServer<RandomService, +MakeRandomService>("csrng", 9)); s_server_manager.AddWaitable(new ServiceServer<RandomService, +MakeRandomService>("csrng", 3));
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_400) { if (GetRuntimeFirmwareVersion() >= FirmwareVersion_400) {
s_server_manager.AddWaitable(new ServiceServer<GeneralService, +MakeGeneralService>("spl:", 9)); s_server_manager.AddWaitable(new ServiceServer<GeneralService, +MakeGeneralService>("spl:", 9));
/* TODO: Other services. */ /* TODO: Other services. */

View file

@ -18,6 +18,40 @@
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "spl_secmon_wrapper.hpp" #include "spl_secmon_wrapper.hpp"
#include "spl_smc_wrapper.hpp"
#include "spl_ctr_drbg.hpp"
/* Globals. */
static CtrDrbg g_drbg;
static Event g_se_event;
static __attribute__((aligned(0x1000))) u8 g_work_buffer[0x1000];
void SecureMonitorWrapper::InitializeCtrDrbg() {
u8 seed[CtrDrbg::SeedSize];
if (SmcWrapper::GenerateRandomBytes(seed, sizeof(seed)) != SmcResult_Success) {
std::abort();
}
g_drbg.Initialize(seed);
}
void SecureMonitorWrapper::InitializeSeInterruptEvent() {
u64 irq_num;
SmcWrapper::GetConfig(&irq_num, 1, SplConfigItem_SecurityEngineIrqNumber);
Handle hnd;
if (R_FAILED(svcCreateInterruptEvent(&hnd, irq_num, 1))) {
std::abort();
}
eventLoadRemote(&g_se_event, hnd, true);
}
void SecureMonitorWrapper::Initialize() {
/* Initialize the Drbg. */
InitializeCtrDrbg();
/* Initialize SE interrupt event. */
InitializeSeInterruptEvent();
}
Result SecureMonitorWrapper::ConvertToSplResult(SmcResult result) { Result SecureMonitorWrapper::ConvertToSplResult(SmcResult result) {
if (result == SmcResult_Success) { if (result == SmcResult_Success) {
@ -30,8 +64,25 @@ Result SecureMonitorWrapper::ConvertToSplResult(SmcResult result) {
} }
Result SecureMonitorWrapper::GetConfig(u64 *out, SplConfigItem which) { Result SecureMonitorWrapper::GetConfig(u64 *out, SplConfigItem which) {
/* TODO */ /* Nintendo explicitly blacklists package2 hash here, amusingly. */
return ResultKernelConnectionClosed; /* This is not blacklisted in safemode, but we're never in safe mode... */
if (which == SplConfigItem_Package2Hash) {
return ResultSplInvalidArgument;
}
SmcResult res = SmcWrapper::GetConfig(out, 1, which);
/* Nintendo has some special handling here for hardware type/is_retail. */
if (which == SplConfigItem_HardwareType && res == SmcResult_InvalidArgument) {
*out = 0;
res = SmcResult_Success;
}
if (which == SplConfigItem_IsRetail && res == SmcResult_InvalidArgument) {
*out = 0;
res = SmcResult_Success;
}
return ConvertToSplResult(res);
} }
Result SecureMonitorWrapper::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 SecureMonitorWrapper::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) {
@ -40,13 +91,42 @@ Result SecureMonitorWrapper::ExpMod(void *out, size_t out_size, const void *base
} }
Result SecureMonitorWrapper::SetConfig(SplConfigItem which, u64 value) { Result SecureMonitorWrapper::SetConfig(SplConfigItem which, u64 value) {
/* TODO */ return ConvertToSplResult(SmcWrapper::SetConfig(which, &value, 1));
return ResultKernelConnectionClosed; }
Result SecureMonitorWrapper::GenerateRandomBytesInternal(void *out, size_t size) {
if (!g_drbg.GenerateRandomBytes(out, size)) {
/* We need to reseed. */
{
u8 seed[CtrDrbg::SeedSize];
SmcResult res = SmcWrapper::GenerateRandomBytes(seed, sizeof(seed));
if (res != SmcResult_Success) {
return ConvertToSplResult(res);
}
g_drbg.Reseed(seed);
g_drbg.GenerateRandomBytes(out, size);
}
}
return ResultSuccess;
} }
Result SecureMonitorWrapper::GenerateRandomBytes(void *out, size_t size) { Result SecureMonitorWrapper::GenerateRandomBytes(void *out, size_t size) {
/* TODO */ u8 *cur_dst = reinterpret_cast<u8 *>(out);
return ResultKernelConnectionClosed;
for (size_t ofs = 0; ofs < size; ofs += CtrDrbg::MaxRequestSize) {
const size_t cur_size = std::min(size - ofs, CtrDrbg::MaxRequestSize);
Result rc = GenerateRandomBytesInternal(cur_dst, size);
if (R_FAILED(rc)) {
return rc;
}
cur_dst += cur_size;
}
return ResultSuccess;
} }
Result SecureMonitorWrapper::IsDevelopment(bool *out) { Result SecureMonitorWrapper::IsDevelopment(bool *out) {

View file

@ -40,8 +40,13 @@ class SecureMonitorWrapper {
return this->boot_reason_set; return this->boot_reason_set;
} }
static Result ConvertToSplResult(SmcResult result); static Result ConvertToSplResult(SmcResult result);
private:
static void InitializeCtrDrbg();
static void InitializeSeInterruptEvent();
public: public:
void Initialize(); static void Initialize();
private:
Result GenerateRandomBytesInternal(void *out, size_t size);
public: public:
Result GetConfig(u64 *out, SplConfigItem which); 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 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);

View file

@ -0,0 +1,334 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include "spl_smc_wrapper.hpp"
enum SmcFunctionId : u32 {
SmcFunctionId_SetConfig = 0xC3000401,
SmcFunctionId_GetConfig = 0xC3000002,
SmcFunctionId_CheckStatus = 0xC3000003,
SmcFunctionId_GetResult = 0xC3000404,
SmcFunctionId_ExpMod = 0xC3000E05,
SmcFunctionId_GenerateRandomBytes = 0xC3000006,
SmcFunctionId_GenerateAesKek = 0xC3000007,
SmcFunctionId_LoadAesKey = 0xC3000008,
SmcFunctionId_CryptAes = 0xC3000009,
SmcFunctionId_GenerateSpecificAesKey = 0xC300000A,
SmcFunctionId_ComputeCmac = 0xC300040B,
SmcFunctionId_ReEncryptRsaPrivateKey = 0xC300D60C,
SmcFunctionId_DecryptOrImportRsaPrivateKey = 0xC300100D,
SmcFunctionId_SecureExpMod = 0xC300060F,
SmcFunctionId_UnwrapTitleKey = 0xC3000610,
SmcFunctionId_LoadTitleKey = 0xC3000011,
SmcFunctionId_UnwrapCommonTitleKey = 0xC3000012,
/* Deprecated functions. */
SmcFunctionId_ImportEsKey = 0xC300100C,
SmcFunctionId_DecryptRsaPrivateKey = 0xC300100D,
SmcFunctionId_ImportSecureExpModKey = 0xC300100E,
};
SmcResult SmcWrapper::SetConfig(SplConfigItem which, const u64 *value, size_t num_qwords) {
SecmonArgs args;
args.X[0] = SmcFunctionId_SetConfig;
args.X[1] = which;
args.X[2] = 0;
for (size_t i = 0; i < std::min(size_t(4), num_qwords); i++) {
args.X[3 + i] = value[i];
}
svcCallSecureMonitor(&args);
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::GetConfig(u64 *out, size_t num_qwords, SplConfigItem which) {
SecmonArgs args;
args.X[0] = SmcFunctionId_GetConfig;
args.X[1] = which;
svcCallSecureMonitor(&args);
for (size_t i = 0; i < std::min(size_t(4), num_qwords); i++) {
out[i] = args.X[1 + i];
}
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::CheckStatus(SmcResult *out, AsyncOperationKey op) {
SecmonArgs args;
args.X[0] = SmcFunctionId_CheckStatus;
args.X[1] = op.value;
svcCallSecureMonitor(&args);
*out = static_cast<SmcResult>(args.X[1]);
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::GetResult(SmcResult *out, void *out_buf, size_t out_buf_size, AsyncOperationKey op) {
SecmonArgs args;
args.X[0] = SmcFunctionId_GetResult;
args.X[1] = op.value;
args.X[2] = reinterpret_cast<u64>(out_buf);
args.X[3] = out_buf_size;
svcCallSecureMonitor(&args);
*out = static_cast<SmcResult>(args.X[1]);
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::ExpMod(AsyncOperationKey *out_op, const void *base, const void *exp, size_t exp_size, const void *mod) {
SecmonArgs args;
args.X[0] = SmcFunctionId_ExpMod;
args.X[1] = reinterpret_cast<u64>(base);
args.X[2] = reinterpret_cast<u64>(exp);
args.X[3] = reinterpret_cast<u64>(mod);
args.X[4] = exp_size;
svcCallSecureMonitor(&args);
out_op->value = args.X[1];
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::GenerateRandomBytes(void *out, size_t size) {
SecmonArgs args;
args.X[0] = SmcFunctionId_GenerateRandomBytes;
args.X[1] = size;
svcCallSecureMonitor(&args);
if (args.X[0] == SmcResult_Success && (size <= sizeof(args) - sizeof(args.X[0]))) {
std::memcpy(out, &args.X[1], size);
}
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::GenerateAesKek(AccessKey *out, const u64 *source, u32 generation, u32 option) {
SecmonArgs args;
args.X[0] = SmcFunctionId_GenerateAesKek;
args.X[1] = source[0];
args.X[2] = source[1];
args.X[3] = generation;
args.X[4] = option;
svcCallSecureMonitor(&args);
out->data64[0] = args.X[1];
out->data64[1] = args.X[2];
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::LoadAesKey(u32 keyslot, const AccessKey &access_key, const u64 *source) {
SecmonArgs args;
args.X[0] = SmcFunctionId_LoadAesKey;
args.X[1] = keyslot;
args.X[2] = access_key.data64[0];
args.X[3] = access_key.data64[1];
args.X[4] = source[0];
args.X[5] = source[1];
svcCallSecureMonitor(&args);
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::CryptAes(AsyncOperationKey *out_op, u32 mode, const u64 *iv_ctr, u32 dst_addr, u32 src_addr, size_t size) {
SecmonArgs args;
args.X[0] = SmcFunctionId_CryptAes;
args.X[1] = mode;
args.X[2] = iv_ctr[0];
args.X[3] = iv_ctr[1];
args.X[4] = src_addr;
args.X[5] = dst_addr;
args.X[6] = size;
svcCallSecureMonitor(&args);
out_op->value = args.X[1];
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::GenerateSpecificAesKey(u64 *out, const u64 *source, u32 generation, u32 which) {
SecmonArgs args;
args.X[0] = SmcFunctionId_GenerateSpecificAesKey;
args.X[1] = source[0];
args.X[2] = source[1];
args.X[3] = generation;
args.X[4] = which;
svcCallSecureMonitor(&args);
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::ComputeCmac(Cmac &out_mac, u32 keyslot, const void *data, size_t size) {
SecmonArgs args;
args.X[0] = SmcFunctionId_ComputeCmac;
args.X[1] = keyslot;
args.X[2] = reinterpret_cast<u64>(data);
args.X[3] = size;
svcCallSecureMonitor(&args);
out_mac.data64[0] = args.X[1];
out_mac.data64[1] = args.X[2];
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::ReEncryptRsaPrivateKey(void *data, size_t size, const AccessKey &access_key_dec, const u64 *source_dec, const AccessKey &access_key_enc, const u64 *source_enc, u32 option) {
SecmonArgs args;
args.X[0] = SmcFunctionId_ReEncryptRsaPrivateKey;
args.X[1] = reinterpret_cast<u64>(&access_key_dec);
args.X[2] = reinterpret_cast<u64>(&access_key_enc);
args.X[3] = option;
args.X[4] = reinterpret_cast<u64>(data);
args.X[5] = size;
args.X[6] = reinterpret_cast<u64>(source_dec);
args.X[7] = reinterpret_cast<u64>(source_enc);
svcCallSecureMonitor(&args);
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::DecryptOrImportRsaPrivateKey(void *data, size_t size, const AccessKey &access_key, const u64 *source, u32 option) {
SecmonArgs args;
args.X[0] = SmcFunctionId_DecryptOrImportRsaPrivateKey;
args.X[1] = access_key.data64[0];
args.X[2] = access_key.data64[1];
args.X[3] = option;
args.X[4] = reinterpret_cast<u64>(data);
args.X[5] = size;
args.X[6] = source[0];
args.X[7] = source[1];
svcCallSecureMonitor(&args);
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::SecureExpMod(AsyncOperationKey *out_op, const void *base, const void *mod, u32 option) {
SecmonArgs args;
args.X[0] = SmcFunctionId_SecureExpMod;
args.X[1] = reinterpret_cast<u64>(base);
args.X[2] = reinterpret_cast<u64>(mod);
args.X[3] = option;
svcCallSecureMonitor(&args);
out_op->value = args.X[1];
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::UnwrapTitleKey(AsyncOperationKey *out_op, const void *base, const void *mod, const void *label_digest, size_t label_digest_size, u32 option) {
SecmonArgs args;
args.X[0] = SmcFunctionId_UnwrapTitleKey;
args.X[1] = reinterpret_cast<u64>(base);
args.X[2] = reinterpret_cast<u64>(mod);
std::memset(&args.X[3], 0, 4 * sizeof(args.X[3]));
std::memcpy(&args.X[3], label_digest, std::min(size_t(4 * sizeof(args.X[3])), label_digest_size));
args.X[7] = option;
svcCallSecureMonitor(&args);
out_op->value = args.X[1];
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::LoadTitleKey(u32 keyslot, const AccessKey &access_key) {
SecmonArgs args;
args.X[0] = SmcFunctionId_LoadTitleKey;
args.X[1] = keyslot;
args.X[2] = access_key.data64[0];
args.X[3] = access_key.data64[1];
svcCallSecureMonitor(&args);
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::UnwrapCommonTitleKey(AccessKey *out, const u64 *source, u32 generation) {
SecmonArgs args;
args.X[0] = SmcFunctionId_UnwrapCommonTitleKey;
args.X[1] = source[0];
args.X[2] = source[1];
args.X[3] = generation;
svcCallSecureMonitor(&args);
out->data64[0] = args.X[1];
out->data64[1] = args.X[2];
return static_cast<SmcResult>(args.X[0]);
}
/* Deprecated functions. */
SmcResult SmcWrapper::ImportEsKey(const void *data, size_t size, const AccessKey &access_key, const u64 *source, u32 option) {
SecmonArgs args;
args.X[0] = SmcFunctionId_ImportEsKey;
args.X[1] = access_key.data64[0];
args.X[2] = access_key.data64[1];
args.X[3] = option;
args.X[4] = reinterpret_cast<u64>(data);
args.X[5] = size;
args.X[6] = source[0];
args.X[7] = source[1];
svcCallSecureMonitor(&args);
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::DecryptRsaPrivateKey(size_t *out_size, void *data, size_t size, const AccessKey &access_key, const u64 *source, u32 option) {
SecmonArgs args;
args.X[0] = SmcFunctionId_DecryptRsaPrivateKey;
args.X[1] = access_key.data64[0];
args.X[2] = access_key.data64[1];
args.X[3] = option;
args.X[4] = reinterpret_cast<u64>(data);
args.X[5] = size;
args.X[6] = source[0];
args.X[7] = source[1];
svcCallSecureMonitor(&args);
*out_size = static_cast<size_t>(args.X[1]);
return static_cast<SmcResult>(args.X[0]);
}
SmcResult SmcWrapper::ImportSecureExpModKey(const void *data, size_t size, const AccessKey &access_key, const u64 *source, u32 option) {
SecmonArgs args;
args.X[0] = SmcFunctionId_ImportSecureExpModKey;
args.X[1] = access_key.data64[0];
args.X[2] = access_key.data64[1];
args.X[3] = option;
args.X[4] = reinterpret_cast<u64>(data);
args.X[5] = size;
args.X[6] = source[0];
args.X[7] = source[1];
svcCallSecureMonitor(&args);
return static_cast<SmcResult>(args.X[0]);
}

View file

@ -0,0 +1,47 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include "spl_types.hpp"
class SmcWrapper {
public:
static SmcResult SetConfig(SplConfigItem which, const u64 *value, size_t num_qwords);
static SmcResult GetConfig(u64 *out, size_t num_qwords, SplConfigItem which);
static SmcResult CheckStatus(SmcResult *out, AsyncOperationKey op);
static SmcResult GetResult(SmcResult *out, void *out_buf, size_t out_buf_size, AsyncOperationKey op);
static SmcResult ExpMod(AsyncOperationKey *out_op, const void *base, const void *exp, size_t exp_size, const void *mod);
static SmcResult GenerateRandomBytes(void *out, size_t size);
static SmcResult GenerateAesKek(AccessKey *out, const u64 *source, u32 generation, u32 option);
static SmcResult LoadAesKey(u32 keyslot, const AccessKey &access_key, const u64 *source);
static SmcResult CryptAes(AsyncOperationKey *out_op, u32 mode, const u64 *iv_ctr, u32 dst_addr, u32 src_addr, size_t size);
static SmcResult GenerateSpecificAesKey(u64 *out, const u64 *source, u32 generation, u32 which);
static SmcResult ComputeCmac(Cmac &out_mac, u32 keyslot, const void *data, size_t size);
static SmcResult ReEncryptRsaPrivateKey(void *data, size_t size, const AccessKey &access_key_dec, const u64 *source_dec, const AccessKey &access_key_enc, const u64 *source_enc, u32 option);
static SmcResult DecryptOrImportRsaPrivateKey(void *data, size_t size, const AccessKey &access_key, const u64 *source, u32 option);
static SmcResult SecureExpMod(AsyncOperationKey *out_op, const void *base, const void *mod, u32 option);
static SmcResult UnwrapTitleKey(AsyncOperationKey *out_op, const void *base, const void *mod, const void *label_digest, size_t label_digest_size, u32 option);
static SmcResult LoadTitleKey(u32 keyslot, const AccessKey &access_key);
static SmcResult UnwrapCommonTitleKey(AccessKey *out, const u64 *source, u32 generation);
/* Deprecated functions. */
static SmcResult ImportEsKey(const void *data, size_t size, const AccessKey &access_key, const u64 *source, u32 option);
static SmcResult DecryptRsaPrivateKey(size_t *out_size, void *data, size_t size, const AccessKey &access_key, const u64 *source, u32 option);
static SmcResult ImportSecureExpModKey(const void *data, size_t size, const AccessKey &access_key, const u64 *source, u32 option);
};

View file

@ -66,12 +66,20 @@ struct IvCtr {
}; };
struct Cmac { struct Cmac {
u8 data[AES_128_KEY_SIZE]; union {
u8 data[AES_128_KEY_SIZE];
u8 data64[AES_128_KEY_SIZE / sizeof(u64)];
};
}; };
static_assert(alignof(Cmac) == alignof(u8), "Cmac definition!");
struct AccessKey { struct AccessKey {
u8 data[AES_128_KEY_SIZE]; union {
u8 data[AES_128_KEY_SIZE];
u8 data64[AES_128_KEY_SIZE / sizeof(u64)];
};
}; };
static_assert(alignof(AccessKey) == alignof(u8), "AccessKey definition!");
struct KeySource { struct KeySource {
u8 data[AES_128_KEY_SIZE]; u8 data[AES_128_KEY_SIZE];