From e37ebf3ef19943b9cdc532c753fa2176b472ef0d Mon Sep 17 00:00:00 2001 From: yellows8 Date: Sat, 17 Dec 2016 01:38:37 -0500 Subject: [PATCH] Added psInitHandle and psGetSessionHandle. Updated PS_AESAlgorithm comments and added psRSAContext. Added PS_SignRsaSha256 and PS_VerifyRsaSha256. Fixed PS_EncryptDecryptAes and PS_EncryptSignDecryptVerifyAesCcm, these originally implemented pxips9 commands not psps. --- libctru/include/3ds/services/ps.h | 47 ++++++++++++--- libctru/source/services/ps.c | 96 +++++++++++++++++++++++++------ 2 files changed, 118 insertions(+), 25 deletions(-) diff --git a/libctru/include/3ds/services/ps.h b/libctru/include/3ds/services/ps.h index 4d17fee..e138ce5 100644 --- a/libctru/include/3ds/services/ps.h +++ b/libctru/include/3ds/services/ps.h @@ -7,12 +7,12 @@ /// PS AES algorithms. typedef enum { - PS_ALGORITHM_CBC_ENC, ///< CBC encoding. - PS_ALGORITHM_CBC_DEC, ///< CBC decoding. - PS_ALGORITHM_CTR_ENC, ///< CTR encoding. - PS_ALGORITHM_CTR_DEC, ///< CTR decoding. - PS_ALGORITHM_CCM_ENC, ///< CCM encoding. - PS_ALGORITHM_CCM_DEC, ///< CCM decoding. + PS_ALGORITHM_CBC_ENC, ///< CBC encryption. + PS_ALGORITHM_CBC_DEC, ///< CBC decryption. + PS_ALGORITHM_CTR_ENC, ///< CTR encryption. + PS_ALGORITHM_CTR_DEC, ///< CTR decryption(same as PS_ALGORITHM_CTR_ENC). + PS_ALGORITHM_CCM_ENC, ///< CCM encryption. + PS_ALGORITHM_CCM_DEC, ///< CCM decryption. } PS_AESAlgorithm; /// PS key slots. @@ -30,12 +30,45 @@ typedef enum PS_KEYSLOT_39_NFC ///< Key slot 0x39. (NFC) } PS_AESKeyType; +/// RSA context. +typedef struct { + u8 modulo[0x100]; + u8 exponent[0x100]; + u32 rsa_bitsize;//The signature byte size is rsa_bitsize>>3. + u32 unk;//Normally zero? +} psRSAContext; + /// Initializes PS. Result psInit(void); +/** + * @brief Initializes PS with the specified session handle. + * @param handle Session handle. + */ +Result psInitHandle(Handle handle); + /// Exits PS. void psExit(void); +/// Returns the PS session handle. +Handle psGetSessionHandle(); + +/** + * @brief Signs a RSA signature. + * @param hash SHA256 hash to sign. + * @param ctx RSA context. + * @param signature RSA signature. + */ +Result PS_SignRsaSha256(u8 *hash, psRSAContext *ctx, u8 *signature); + +/** + * @brief Verifies a RSA signature. + * @param hash SHA256 hash to compare with. + * @param ctx RSA context. + * @param signature RSA signature. + */ +Result PS_VerifyRsaSha256(u8 *hash, psRSAContext *ctx, u8 *signature); + /** * @brief Encrypts/Decrypts AES data. Does not support AES CCM. * @param size Size of the data. @@ -43,7 +76,7 @@ void psExit(void); * @param out Output buffer. * @param aes_algo AES algorithm to use. * @param key_type Key type to use. - * @param iv Pointer to the CTR/IV. + * @param iv Pointer to the CTR/IV. The output CTR/IV is also written here. */ Result PS_EncryptDecryptAes(u32 size, u8* in, u8* out, PS_AESAlgorithm aes_algo, PS_AESKeyType key_type, u8* iv); diff --git a/libctru/source/services/ps.c b/libctru/source/services/ps.c index ab8520e..2b029ad 100644 --- a/libctru/source/services/ps.c +++ b/libctru/source/services/ps.c @@ -11,19 +11,78 @@ static Handle psHandle; static int psRefCount; +static Result _psInit(Handle handle) +{ + Result res=0; + if (AtomicPostIncrement(&psRefCount)) return 0; + if(handle==0)res = srvGetServiceHandle(&handle, "ps:ps"); + if (R_FAILED(res)) AtomicDecrement(&psRefCount); + if (R_SUCCEEDED(res)) psHandle = handle; + return res; +} + Result psInit(void) { - Result res; - if (AtomicPostIncrement(&psRefCount)) return 0; - res = srvGetServiceHandle(&psHandle, "ps:ps"); - if (R_FAILED(res)) AtomicDecrement(&psRefCount); - return res; + return _psInit(0); +} + +Result psInitHandle(Handle handle) +{ + return _psInit(handle); } void psExit(void) { if (AtomicDecrement(&psRefCount)) return; svcCloseHandle(psHandle); + psHandle = 0; +} + +Handle psGetSessionHandle() +{ + return psHandle; +} + +Result PS_SignRsaSha256(u8 *hash, psRSAContext *ctx, u8 *signature) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 size; + + size = ctx->rsa_bitsize>>3; + + cmdbuf[0] = IPC_MakeHeader(0x1,9,4); // 0x10244 + memcpy(&cmdbuf[1], hash, 32); + cmdbuf[9] = size; + cmdbuf[10] = IPC_Desc_StaticBuffer(0x208, 0); + cmdbuf[11] = (u32)ctx; + cmdbuf[12] = IPC_Desc_Buffer(size, IPC_BUFFER_W); + cmdbuf[13] = (u32)signature; + + if(R_FAILED(ret = svcSendSyncRequest(psHandle)))return ret; + + return (Result)cmdbuf[1]; +} + +Result PS_VerifyRsaSha256(u8 *hash, psRSAContext *ctx, u8 *signature) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 size; + + size = ctx->rsa_bitsize>>3; + + cmdbuf[0] = IPC_MakeHeader(0x2,9,4); // 0x20244 + memcpy(&cmdbuf[1], hash, 32); + cmdbuf[9] = size; + cmdbuf[10] = IPC_Desc_StaticBuffer(0x208, 0); + cmdbuf[11] = (u32)ctx; + cmdbuf[12] = IPC_Desc_Buffer(size, IPC_BUFFER_R); + cmdbuf[13] = (u32)signature; + + if(R_FAILED(ret = svcSendSyncRequest(psHandle)))return ret; + + return (Result)cmdbuf[1]; } Result PS_EncryptDecryptAes(u32 size, u8* in, u8* out, PS_AESAlgorithm aes_algo, PS_AESKeyType key_type, u8* iv) @@ -33,15 +92,16 @@ Result PS_EncryptDecryptAes(u32 size, u8* in, u8* out, PS_AESAlgorithm aes_algo, u32 *_iv = (u32*)iv; - cmdbuf[0] = IPC_MakeHeader(0x4,7,4); // 0x401C4 + cmdbuf[0] = IPC_MakeHeader(0x4,8,4); // 0x40204 cmdbuf[1] = size; - memcpy(&cmdbuf[2], _iv, 16); - cmdbuf[6] = aes_algo; - cmdbuf[7] = key_type; - cmdbuf[8] = IPC_Desc_PXIBuffer(size,0,false); - cmdbuf[9] = (u32)in; - cmdbuf[10] = IPC_Desc_PXIBuffer(size,1,false); - cmdbuf[11] = (u32)out; + cmdbuf[2] = size; + memcpy(&cmdbuf[3], _iv, 16); + cmdbuf[7] = aes_algo; + cmdbuf[8] = key_type; + cmdbuf[9] = IPC_Desc_Buffer(size, IPC_BUFFER_R); + cmdbuf[10] = (u32)in; + cmdbuf[11] = IPC_Desc_Buffer(size, IPC_BUFFER_W); + cmdbuf[12] = (u32)out; if(R_FAILED(ret = svcSendSyncRequest(psHandle)))return ret; @@ -59,16 +119,16 @@ Result PS_EncryptSignDecryptVerifyAesCcm(u8* in, u32 in_size, u8* out, u32 out_s cmdbuf[0] = IPC_MakeHeader(0x5,10,4); // 0x50284 cmdbuf[1] = in_size; - cmdbuf[2] = out_size; - cmdbuf[3] = mac_data_len; - cmdbuf[4] = data_len; + cmdbuf[2] = mac_data_len; + cmdbuf[3] = data_len; + cmdbuf[4] = out_size; cmdbuf[5] = mac_len; memcpy(&cmdbuf[6], _nonce, 12); cmdbuf[9] = aes_algo; cmdbuf[10] = key_type; - cmdbuf[11] = IPC_Desc_PXIBuffer(in_size,0,false); + cmdbuf[11] = IPC_Desc_Buffer(in_size, IPC_BUFFER_R); cmdbuf[12] = (u32)in; - cmdbuf[13] = IPC_Desc_PXIBuffer(out_size,1,false); + cmdbuf[13] = IPC_Desc_Buffer(out_size, IPC_BUFFER_W); cmdbuf[14] = (u32)out; if(R_FAILED(ret = svcSendSyncRequest(psHandle)))return ret;