// Copyright 2018 SciresM #include #include "types.h" #include "result.h" #include "arm/atomics.h" #include "kernel/ipc.h" #include "runtime/hosversion.h" #include "services/sm.h" #include "services/spl.h" static Service g_splSrv, g_splCryptoSrv, g_splSslSrv, g_splEsSrv, g_splFsSrv, g_splManuSrv; static u64 g_splRefCnt, g_splCryptoRefCnt, g_splSslRefCnt, g_splEsRefCnt, g_splFsRefCnt, g_splManuRefCnt; /* Helper prototypes for accessing handles. */ static Service* _splGetGeneralSrv(void); static Service* _splGetCryptoSrv(void); static Service* _splGetRsaSrv(void); static Service* _splGetEsSrv(void); static Service* _splGetFsSrv(void); static Service* _splGetSslSrv(void); static Service* _splGetManuSrv(void); Service* _splGetGeneralSrv(void) { if (hosversionBefore(4,0,0)) { return &g_splSrv; } if (serviceIsActive(&g_splSrv)) { return &g_splSrv; } else { return _splGetCryptoSrv(); } } Service* _splGetCryptoSrv(void) { if (hosversionBefore(4,0,0)) { return &g_splSrv; } if (serviceIsActive(&g_splManuSrv)) { return &g_splManuSrv; } else if (serviceIsActive(&g_splFsSrv)) { return &g_splFsSrv; } else if (serviceIsActive(&g_splEsSrv)) { return &g_splEsSrv; } else if (serviceIsActive(&g_splSslSrv)) { return &g_splSslSrv; } else { return &g_splCryptoSrv; } } Service* _splGetRsaSrv(void) { if (hosversionBefore(4,0,0)) { return &g_splSrv; } if (serviceIsActive(&g_splFsSrv)) { return &g_splFsSrv; } else if (serviceIsActive(&g_splEsSrv)) { return &g_splEsSrv; } else { return &g_splSslSrv; } } Service* _splGetEsSrv(void) { return hosversionAtLeast(4,0,0) ? &g_splEsSrv : &g_splSrv; } Service* _splGetFsSrv(void) { return hosversionAtLeast(4,0,0) ? &g_splFsSrv : &g_splSrv; } Service* _splGetSslSrv(void) { return hosversionAtLeast(4,0,0) ? &g_splSslSrv : &g_splSrv; } Service* _splGetManuSrv(void) { return hosversionAtLeast(4,0,0) ? &g_splManuSrv : &g_splSrv; } /* There are like six services, so these helpers will initialize/exit the relevant services. */ static Result _splSrvInitialize(Service* srv, u64 *refcnt, const char *name) { atomicIncrement64(refcnt); if (serviceIsActive(srv)) return 0; return smGetService(srv, name); } static void _splSrvExit(Service* srv, u64 *refcnt) { if (atomicDecrement64(refcnt) == 0) serviceClose(srv); } Result splInitialize(void) { return _splSrvInitialize(&g_splSrv, &g_splRefCnt, "spl:"); } void splExit(void) { return _splSrvExit(&g_splSrv, &g_splRefCnt); } Service* splGetServiceSession(void) { return _splGetGeneralSrv(); } Result splCryptoInitialize(void) { if (hosversionAtLeast(4,0,0)) { return _splSrvInitialize(&g_splCryptoSrv, &g_splCryptoRefCnt, "spl:mig"); } else { return splInitialize(); } } void splCryptoExit(void) { if (hosversionAtLeast(4,0,0)) { return _splSrvExit(&g_splCryptoSrv, &g_splCryptoRefCnt); } else { return splExit(); } } Service* splCryptoGetServiceSession(void) { return _splGetCryptoSrv(); } Result splSslInitialize(void) { if (hosversionAtLeast(4,0,0)) { return _splSrvInitialize(&g_splSslSrv, &g_splSslRefCnt, "spl:ssl"); } else { return splInitialize(); } } void splSslExit(void) { if (hosversionAtLeast(4,0,0)) { return _splSrvExit(&g_splSslSrv, &g_splSslRefCnt); } else { return splExit(); } } Service* splSslGetServiceSession(void) { return _splGetSslSrv(); } Result splEsInitialize(void) { if (hosversionAtLeast(4,0,0)) { return _splSrvInitialize(&g_splEsSrv, &g_splEsRefCnt, "spl:es"); } else { return splInitialize(); } } void splEsExit(void) { if (hosversionAtLeast(4,0,0)) { return _splSrvExit(&g_splEsSrv, &g_splEsRefCnt); } else { return splExit(); } } Service* splEsGetServiceSession(void) { return _splGetEsSrv(); } Result splFsInitialize(void) { if (hosversionAtLeast(4,0,0)) { return _splSrvInitialize(&g_splFsSrv, &g_splFsRefCnt, "spl:fs"); } else { return splInitialize(); } } void splFsExit(void) { if (hosversionAtLeast(4,0,0)) { return _splSrvExit(&g_splFsSrv, &g_splFsRefCnt); } else { return splExit(); } } Service* splFsGetServiceSession(void) { return _splGetFsSrv(); } Result splManuInitialize(void) { return _splSrvInitialize(&g_splManuSrv, &g_splManuRefCnt, "spl:manu"); } void splManuExit(void) { return _splSrvExit(&g_splManuSrv, &g_splManuRefCnt); } Service* splManuGetServiceSession(void) { return _splGetManuSrv(); } /* SPL IGeneralService functionality. */ Result splGetConfig(SplConfigItem config_item, u64 *out_config) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; u32 config_item; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 0; raw->config_item = config_item; Result rc = serviceIpcDispatch(_splGetGeneralSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u64 out; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { *out_config = resp->out; } } return rc; } Result splUserExpMod(const void *input, const void *modulus, const void *exp, size_t exp_size, void *dst) { IpcCommand c; ipcInitialize(&c); ipcAddSendStatic(&c, input, SPL_RSA_BUFFER_SIZE, 0); ipcAddSendStatic(&c, exp, exp_size, 1); ipcAddSendStatic(&c, modulus, SPL_RSA_BUFFER_SIZE, 2); ipcAddRecvStatic(&c, dst, SPL_RSA_BUFFER_SIZE, 0); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 1; Result rc = serviceIpcDispatch(_splGetGeneralSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; } Result splSetConfig(SplConfigItem config_item, u64 value) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; u32 config_item; u64 value; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 5; raw->config_item = config_item; raw->value = value; Result rc = serviceIpcDispatch(_splGetGeneralSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; } Result splGetRandomBytes(void *out, size_t out_size) { IpcCommand c; ipcInitialize(&c); ipcAddRecvStatic(&c, out, out_size, 0); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 7; Result rc = serviceIpcDispatch(_splGetGeneralSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; } Result splIsDevelopment(bool *out_is_development) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 11; Result rc = serviceIpcDispatch(_splGetGeneralSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u8 is_development; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { *out_is_development = resp->is_development != 0; } } return rc; } Result splSetBootReason(u32 value) { if (hosversionBefore(3,0,0)) { return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); } IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; u32 value; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 24; raw->value = value; Result rc = serviceIpcDispatch(_splGetGeneralSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; } Result splGetBootReason(u32 *out_value) { if (hosversionBefore(3,0,0)) { return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); } IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 25; Result rc = serviceIpcDispatch(_splGetGeneralSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u32 value; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { *out_value = resp->value; } } return rc; } /* SPL ICryptoService functionality. */ Result splCryptoGenerateAesKek(const void *wrapped_kek, u32 key_generation, u32 option, void *out_sealed_kek) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; u8 wrapped_kek[0x10]; u32 key_generation; u32 option; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 2; memcpy(raw->wrapped_kek, wrapped_kek, sizeof(raw->wrapped_kek)); raw->key_generation = key_generation; raw->option = option; Result rc = serviceIpcDispatch(_splGetCryptoSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u8 sealed_kek[0x10]; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { memcpy(out_sealed_kek, resp->sealed_kek, sizeof(resp->sealed_kek)); } } return rc; } Result splCryptoLoadAesKey(const void *sealed_kek, const void *wrapped_key, u32 keyslot) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; u8 sealed_kek[0x10]; u8 wrapped_key[0x10]; u32 keyslot; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 3; memcpy(raw->sealed_kek, sealed_kek, sizeof(raw->sealed_kek)); memcpy(raw->wrapped_key, wrapped_key, sizeof(raw->wrapped_key)); raw->keyslot = keyslot; Result rc = serviceIpcDispatch(_splGetCryptoSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; } Result splCryptoGenerateAesKey(const void *sealed_kek, const void *wrapped_key, void *out_sealed_key) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; u8 sealed_kek[0x10]; u8 wrapped_key[0x10]; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 4; memcpy(raw->sealed_kek, sealed_kek, sizeof(raw->sealed_kek)); memcpy(raw->wrapped_key, wrapped_key, sizeof(raw->wrapped_key)); Result rc = serviceIpcDispatch(_splGetCryptoSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u8 sealed_key[0x10]; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { memcpy(out_sealed_key, resp->sealed_key, sizeof(resp->sealed_key)); } } return rc; } Result splCryptoDecryptAesKey(const void *wrapped_key, u32 key_generation, u32 option, void *out_sealed_key) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; u8 wrapped_key[0x10]; u32 key_generation; u32 option; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 14; memcpy(raw->wrapped_key, wrapped_key, sizeof(raw->wrapped_key)); raw->key_generation = key_generation; raw->option = option; Result rc = serviceIpcDispatch(_splGetCryptoSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u8 sealed_key[0x10]; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { memcpy(out_sealed_key, resp->sealed_key, sizeof(resp->sealed_key)); } } return rc; } Result splCryptoCryptAesCtr(const void *input, void *output, size_t size, u32 keyslot, const void *ctr) { IpcCommand c; ipcInitialize(&c); ipcAddSendBuffer(&c, input, size, BufferType_Type1); ipcAddRecvBuffer(&c, output, size, BufferType_Type1); struct { u64 magic; u64 cmd_id; u8 ctr[0x10]; u32 keyslot; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 15; memcpy(raw->ctr, ctr, sizeof(raw->ctr)); raw->keyslot = keyslot; Result rc = serviceIpcDispatch(_splGetCryptoSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; } Result splCryptoComputeCmac(const void *input, size_t size, u32 keyslot, void *out_cmac) { IpcCommand c; ipcInitialize(&c); ipcAddSendStatic(&c, input, size, 0); struct { u64 magic; u64 cmd_id; u32 keyslot; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 16; raw->keyslot = keyslot; Result rc = serviceIpcDispatch(_splGetCryptoSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u8 cmac[0x10]; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { memcpy(out_cmac, resp->cmac, sizeof(resp->cmac)); } } return rc; } Result splCryptoLockAesEngine(u32 *out_keyslot) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 21; Result rc = serviceIpcDispatch(_splGetCryptoSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u32 keyslot; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { *out_keyslot = resp->keyslot; } } return rc; } Result splCryptoUnlockAesEngine(u32 keyslot) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; u32 keyslot; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 22; raw->keyslot = keyslot; Result rc = serviceIpcDispatch(_splGetCryptoSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; } Result splCryptoGetSecurityEngineEvent(Handle *out_event) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 23; Result rc = serviceIpcDispatch(_splGetCryptoSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { *out_event = r.Handles[0]; } } return rc; } /* SPL IRsaService functionality. NOTE: IRsaService is not a real part of inheritance, unlike ICryptoService/IGeneralService. */ Result splRsaDecryptPrivateKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version, void *dst, size_t dst_size) { IpcCommand c; ipcInitialize(&c); ipcAddSendStatic(&c, wrapped_rsa_key, wrapped_rsa_key_size, 0); ipcAddRecvStatic(&c, dst, dst_size, 0); struct { u64 magic; u64 cmd_id; u8 sealed_kek[0x10]; u8 wrapped_key[0x10]; u32 version; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 13; memcpy(raw->sealed_kek, sealed_kek, sizeof(raw->sealed_kek)); memcpy(raw->wrapped_key, wrapped_key, sizeof(raw->wrapped_key)); raw->version = version; Result rc = serviceIpcDispatch(_splGetRsaSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; } /* Helper function for RSA key importing. */ static Result _splImportSecureExpModKey(Service* srv, u64 cmd_id, const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version) { IpcCommand c; ipcInitialize(&c); ipcAddSendStatic(&c, wrapped_rsa_key, wrapped_rsa_key_size, 0); struct { u64 magic; u64 cmd_id; u8 sealed_kek[0x10]; u8 wrapped_key[0x10]; u32 version; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = cmd_id; memcpy(raw->sealed_kek, sealed_kek, sizeof(raw->sealed_kek)); memcpy(raw->wrapped_key, wrapped_key, sizeof(raw->wrapped_key)); raw->version = version; Result rc = serviceIpcDispatch(srv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; } static Result _splSecureExpMod(Service* srv, u64 cmd_id, const void *input, const void *modulus, void *dst) { IpcCommand c; ipcInitialize(&c); ipcAddSendStatic(&c, input, SPL_RSA_BUFFER_SIZE, 0); ipcAddSendStatic(&c, modulus, SPL_RSA_BUFFER_SIZE, 1); ipcAddRecvStatic(&c, dst, SPL_RSA_BUFFER_SIZE, 0); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = cmd_id; Result rc = serviceIpcDispatch(srv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; } /* SPL ISslService functionality. */ Result splSslLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version) { return _splImportSecureExpModKey(&g_splSslSrv, 26, sealed_kek, wrapped_key, wrapped_rsa_key, wrapped_rsa_key_size, version); } Result splSslSecureExpMod(const void *input, const void *modulus, void *dst) { return _splSecureExpMod(&g_splSslSrv, 27, input, modulus, dst); } /* SPL IEsService functionality. */ Result splEsLoadRsaOaepKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version) { return _splImportSecureExpModKey(_splGetEsSrv(), 17, sealed_kek, wrapped_key, wrapped_rsa_key, wrapped_rsa_key_size, version); } Result splEsUnwrapRsaOaepWrappedTitlekey(const void *rsa_wrapped_titlekey, const void *modulus, const void *label_hash, size_t label_hash_size, u32 key_generation, void *out_sealed_titlekey) { IpcCommand c; ipcInitialize(&c); ipcAddSendStatic(&c, rsa_wrapped_titlekey, SPL_RSA_BUFFER_SIZE, 0); ipcAddSendStatic(&c, modulus, SPL_RSA_BUFFER_SIZE, 1); ipcAddSendStatic(&c, label_hash, label_hash_size, 2); struct { u64 magic; u64 cmd_id; u32 key_generation; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 18; raw->key_generation = key_generation; Result rc = serviceIpcDispatch(_splGetEsSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u8 sealed_titlekey[0x10]; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { memcpy(out_sealed_titlekey, resp->sealed_titlekey, sizeof(resp->sealed_titlekey)); } } return rc; } Result splEsUnwrapAesWrappedTitlekey(const void *aes_wrapped_titlekey, u32 key_generation, void *out_sealed_titlekey) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; u8 aes_wrapped_titlekey[0x10]; u32 key_generation; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 20; memcpy(raw->aes_wrapped_titlekey, aes_wrapped_titlekey, sizeof(raw->aes_wrapped_titlekey)); raw->key_generation = key_generation; Result rc = serviceIpcDispatch(_splGetEsSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u8 sealed_titlekey[0x10]; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { memcpy(out_sealed_titlekey, resp->sealed_titlekey, sizeof(resp->sealed_titlekey)); } } return rc; } Result splEsLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version) { return _splImportSecureExpModKey(&g_splEsSrv, 28, sealed_kek, wrapped_key, wrapped_rsa_key, wrapped_rsa_key_size, version); } Result splEsSecureExpMod(const void *input, const void *modulus, void *dst) { return _splSecureExpMod(&g_splEsSrv, 29, input, modulus, dst); } /* SPL IFsService functionality. */ Result splFsLoadSecureExpModKey(const void *sealed_kek, const void *wrapped_key, const void *wrapped_rsa_key, size_t wrapped_rsa_key_size, RsaKeyVersion version) { return _splImportSecureExpModKey(_splGetFsSrv(), 9, sealed_kek, wrapped_key, wrapped_rsa_key, wrapped_rsa_key_size, version); } Result splFsSecureExpMod(const void *input, const void *modulus, void *dst) { return _splSecureExpMod(_splGetFsSrv(), 10, input, modulus, dst); } Result splFsGenerateSpecificAesKey(const void *wrapped_key, u32 key_generation, u32 option, void *out_sealed_key) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; u8 wrapped_key[0x10]; u32 key_generation; u32 option; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 12; memcpy(raw->wrapped_key, wrapped_key, sizeof(raw->wrapped_key)); raw->key_generation = key_generation; raw->option = option; Result rc = serviceIpcDispatch(_splGetFsSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u8 sealed_key[0x10]; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { memcpy(out_sealed_key, resp->sealed_key, sizeof(resp->sealed_key)); } } return rc; } Result splFsLoadTitlekey(const void *sealed_titlekey, u32 keyslot) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; u8 sealed_titlekey[0x10]; u32 keyslot; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 19; memcpy(raw->sealed_titlekey, sealed_titlekey, sizeof(raw->sealed_titlekey)); raw->keyslot = keyslot; Result rc = serviceIpcDispatch(_splGetFsSrv()); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; } Result splFsGetPackage2Hash(void *out_hash) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 31; Result rc = serviceIpcDispatch(&g_splFsSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u8 package2_hash[0x20]; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { memcpy(out_hash, resp->package2_hash, sizeof(resp->package2_hash)); } } return rc; } /* SPL IManuService funcionality. */ Result splManuEncryptRsaKeyForImport(const void *sealed_kek_pre, const void *wrapped_key_pre, const void *sealed_kek_post, const void *wrapped_kek_post, u32 option, const void *wrapped_rsa_key, void *out_wrapped_rsa_key, size_t rsa_key_size) { IpcCommand c; ipcInitialize(&c); ipcAddSendStatic(&c, wrapped_rsa_key, rsa_key_size, 0); ipcAddRecvStatic(&c, out_wrapped_rsa_key, rsa_key_size, 0); struct { u64 magic; u64 cmd_id; u8 sealed_kek_pre[0x10]; u8 wrapped_key_pre[0x10]; u8 sealed_kek_post[0x10]; u8 wrapped_kek_post[0x10]; u32 option; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 30; memcpy(raw->sealed_kek_pre, sealed_kek_pre, sizeof(raw->sealed_kek_pre)); memcpy(raw->wrapped_key_pre, wrapped_key_pre, sizeof(raw->wrapped_key_pre)); memcpy(raw->sealed_kek_post, sealed_kek_post, sizeof(raw->sealed_kek_post)); memcpy(raw->wrapped_kek_post, wrapped_kek_post, sizeof(raw->wrapped_kek_post)); raw->option = option; Result rc = serviceIpcDispatch(&g_splManuSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; }