/// 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.
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.
* @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);
static Handle psHandle;
static int psRefCount;
-Result psInit(void)
+static Result _psInit(Handle handle)
{
- Result res;
+ Result res=0;
if (AtomicPostIncrement(&psRefCount)) return 0;
- res = srvGetServiceHandle(&psHandle, "ps:ps");
+ 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)
+{
+ 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)
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;
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;