mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-25 11:00:18 +00:00
spl: continue implementing.
This commit is contained in:
parent
9858d6fc95
commit
2dfa1c96d1
8 changed files with 628 additions and 10 deletions
81
stratosphere/spl/source/spl_ctr_drbg.cpp
Normal file
81
stratosphere/spl/source/spl_ctr_drbg.cpp
Normal 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;
|
||||
|
||||
}
|
60
stratosphere/spl/source/spl_ctr_drbg.hpp
Normal file
60
stratosphere/spl/source/spl_ctr_drbg.hpp
Normal 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);
|
||||
};
|
|
@ -89,12 +89,15 @@ static const auto MakeGeneralService = []() { return std::make_shared<GeneralSer
|
|||
int main(int argc, char **argv)
|
||||
{
|
||||
consoleDebugInit(debugDevice_SVC);
|
||||
|
||||
/* Initialize global context. */
|
||||
SecureMonitorWrapper::Initialize();
|
||||
|
||||
/* Create server manager. */
|
||||
static auto s_server_manager = WaitableManager<SplServerOptions>(1);
|
||||
|
||||
/* 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) {
|
||||
s_server_manager.AddWaitable(new ServiceServer<GeneralService, +MakeGeneralService>("spl:", 9));
|
||||
/* TODO: Other services. */
|
||||
|
|
|
@ -18,6 +18,40 @@
|
|||
#include <stratosphere.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) {
|
||||
if (result == SmcResult_Success) {
|
||||
|
@ -30,8 +64,25 @@ Result SecureMonitorWrapper::ConvertToSplResult(SmcResult result) {
|
|||
}
|
||||
|
||||
Result SecureMonitorWrapper::GetConfig(u64 *out, SplConfigItem which) {
|
||||
/* TODO */
|
||||
return ResultKernelConnectionClosed;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -40,13 +91,42 @@ Result SecureMonitorWrapper::ExpMod(void *out, size_t out_size, const void *base
|
|||
}
|
||||
|
||||
Result SecureMonitorWrapper::SetConfig(SplConfigItem which, u64 value) {
|
||||
/* TODO */
|
||||
return ResultKernelConnectionClosed;
|
||||
return ConvertToSplResult(SmcWrapper::SetConfig(which, &value, 1));
|
||||
}
|
||||
|
||||
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) {
|
||||
/* TODO */
|
||||
return ResultKernelConnectionClosed;
|
||||
u8 *cur_dst = reinterpret_cast<u8 *>(out);
|
||||
|
||||
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) {
|
||||
|
|
|
@ -40,8 +40,13 @@ class SecureMonitorWrapper {
|
|||
return this->boot_reason_set;
|
||||
}
|
||||
static Result ConvertToSplResult(SmcResult result);
|
||||
private:
|
||||
static void InitializeCtrDrbg();
|
||||
static void InitializeSeInterruptEvent();
|
||||
public:
|
||||
void Initialize();
|
||||
static void Initialize();
|
||||
private:
|
||||
Result GenerateRandomBytesInternal(void *out, size_t size);
|
||||
public:
|
||||
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);
|
||||
|
|
334
stratosphere/spl/source/spl_smc_wrapper.cpp
Normal file
334
stratosphere/spl/source/spl_smc_wrapper.cpp
Normal 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]);
|
||||
}
|
||||
|
47
stratosphere/spl/source/spl_smc_wrapper.hpp
Normal file
47
stratosphere/spl/source/spl_smc_wrapper.hpp
Normal 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);
|
||||
};
|
|
@ -66,12 +66,20 @@ struct IvCtr {
|
|||
};
|
||||
|
||||
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 {
|
||||
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 {
|
||||
u8 data[AES_128_KEY_SIZE];
|
||||
|
|
Loading…
Reference in a new issue