/*************************************************************************
* Copyright (C) 2023 Intel Corporation
*
* Licensed under the Apache License,  Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 	http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law  or agreed  to  in  writing,  software
* distributed under  the License  is  distributed  on  an  "AS IS"  BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the  specific  language  governing  permissions  and
* limitations under the License.
*************************************************************************/

#ifdef IPPCP_FIPS_MODE
#include "ippcp.h"
#include "owndefs.h"
#include "dispatcher.h"

// FIPS selftests are not processed by dispatcher.
// Prevent several copies of the same functions.
#ifdef _IPP_DATA

#include "ippcp/fips_cert.h"
#include "fips_cert_internal/common.h"
#include "fips_cert_internal/bn_common.h"

/*
 * KAT
 * vectors are taken from Wycheproof testing
*/
// KAT plaintext
__ALIGN64 static const Ipp8u pMsg[]  = { 0x31,0x32,0x33,0x34,0x30,0x30 };
// KAT seed (all 1)
__ALIGN64 static const Ipp8u seed[]  = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
                                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
                                       "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
                                       "\xff\xff";
// KAT ciphertext
__ALIGN64 static const Ipp8u ctext[] = { 0x50,0xc2,0x3e,0x2a,0xd6,0xe3,0xf3,0xb1,0x0a,0x57,0x16,0xcb,0xf6,0x0e,0xfc,0xc9,
                                         0xf6,0x6d,0x2c,0x6f,0x17,0xbf,0x05,0x0b,0xa0,0x15,0x3b,0x87,0x7b,0xa2,0x75,0x5e,
                                         0x8a,0x0d,0x54,0x06,0x00,0x34,0x56,0x22,0x66,0x15,0x57,0x44,0xef,0x80,0x54,0x7b,
                                         0x8a,0xf7,0x77,0xb0,0xff,0x76,0x4f,0xbb,0x12,0xba,0xae,0x49,0xd0,0x2b,0x4f,0x6d,
                                         0x65,0xb6,0xcd,0x8f,0x0a,0x39,0x78,0x39,0x10,0x1d,0x32,0xae,0x16,0x3f,0xf2,0xe6,
                                         0x07,0x27,0x48,0xd6,0xb8,0x01,0x7e,0x5e,0x73,0xe3,0x32,0xd5,0x3f,0x4e,0x91,0xfe,
                                         0x62,0x33,0xa8,0x2d,0xbf,0x54,0xf3,0x14,0x6b,0x48,0x98,0x03,0x57,0x5c,0x5e,0xa3,
                                         0x7a,0xb5,0x5a,0x9e,0xa7,0xea,0xe4,0x7a,0xd4,0xf1,0x72,0x7d,0x45,0x82,0x2b,0x56,
                                         0x9c,0xd6,0xe5,0xd4,0xb6,0xab,0x75,0x98,0x50,0x94,0x81,0x86,0x61,0x6b,0x5d,0xa2,
                                         0xa9,0xa3,0x16,0xf5,0x7d,0x89,0x9f,0x91,0x93,0x4b,0xbb,0x27,0xed,0xcd,0xfa,0x19,
                                         0x53,0x2b,0xa1,0xc0,0x1f,0x37,0x24,0x73,0x8d,0xaf,0xfd,0xd8,0x8c,0x9a,0x18,0x56,
                                         0x2e,0xbc,0xbc,0x49,0x18,0x5b,0x0a,0x81,0x74,0x07,0x90,0x34,0x76,0xd4,0x42,0xc4,
                                         0x24,0xc8,0x1b,0x63,0xae,0xb8,0xf9,0xd1,0xb1,0x84,0x75,0x6e,0x0c,0xc0,0xa3,0x81,
                                         0xea,0xba,0x45,0xa8,0x5c,0x8b,0xbc,0x67,0x70,0xfd,0x04,0x7f,0xf1,0xa6,0x40,0x4a,
                                         0x38,0x45,0x99,0xfb,0xbd,0x6a,0x40,0xb2,0x12,0xa0,0x66,0xe2,0x3f,0x6a,0x15,0xcf,
                                         0x13,0xe4,0x2c,0x0e,0xa8,0x8c,0x71,0x0e,0x4d,0x70,0xc6,0x12,0x07,0x49,0x68,0xe5 };
// KAT modulus, public and private exponents
__ALIGN64 static const Ipp8u dataN[] = { 0xd5,0xb9,0x42,0xf7,0x83,0x02,0x82,0xf7,0x9c,0x2e,0x4c,0x5b,0x1f,0x3d,0x45,0x6f,
                                         0x06,0x73,0xe7,0x30,0xa5,0xe5,0x02,0x9a,0x3b,0x7d,0x80,0x62,0x9a,0x56,0x12,0x5d,
                                         0xa4,0xc1,0xf7,0xc0,0x5a,0x4e,0x2c,0xc2,0x9b,0x5d,0x00,0x75,0x79,0x5e,0xf8,0xf9,
                                         0xd8,0x60,0xd4,0x79,0xae,0x9c,0x4d,0x1b,0xba,0xcb,0x8b,0x69,0x48,0x6f,0x81,0x69,
                                         0x19,0x5a,0x97,0x90,0xf5,0x22,0x64,0x12,0xf1,0xa0,0xad,0x09,0x3e,0xfc,0x7a,0xfd,
                                         0x05,0xaf,0x8d,0x87,0xeb,0x11,0x54,0xed,0xd4,0x95,0x34,0x5d,0x5b,0x14,0x03,0x4c,
                                         0x6b,0xce,0x1e,0x4d,0xde,0x82,0xbe,0x12,0x5a,0x94,0x8d,0xa0,0xec,0xfc,0xd0,0x21,
                                         0xc0,0xf5,0x66,0x42,0x59,0x58,0x96,0x7d,0x9c,0xe0,0x28,0x04,0x61,0xda,0x22,0x4c,
                                         0x81,0xd9,0x15,0x96,0x29,0x81,0xed,0x90,0xf4,0x26,0xce,0x8d,0x6a,0xa2,0x1f,0x7a,
                                         0x39,0x29,0xa0,0xe1,0x17,0x8f,0xff,0x3e,0xa0,0x13,0x53,0x76,0xe9,0x2f,0x4a,0x25,
                                         0x8e,0xc9,0x48,0x6e,0xe4,0x42,0x3e,0x3d,0x7f,0x24,0xe8,0x15,0x9c,0xf7,0x20,0xcd,
                                         0xfa,0x53,0x12,0x1a,0x71,0xa7,0xd8,0x2e,0x51,0x92,0xdb,0x89,0x31,0x39,0xab,0xb5,
                                         0x97,0x50,0x84,0xc8,0xea,0xd6,0x89,0x9e,0x42,0x69,0xb4,0x03,0x59,0xf6,0x00,0x17,
                                         0x5a,0xef,0xb6,0x25,0x03,0xd8,0x78,0x18,0xd3,0xaf,0x7c,0x3f,0x6d,0x74,0xf9,0x37,
                                         0xe6,0x24,0x22,0xe8,0xfe,0xa1,0x4f,0x09,0x17,0xf7,0xbe,0x2e,0x46,0x5b,0x8a,0x4a,
                                         0x51,0x50,0x35,0x51,0x71,0x56,0x45,0x6e,0xf9,0xa5,0x0a,0x7d,0xa0,0x51,0xb4,0xa2 };
__ALIGN64 static const Ipp8u dataD[] = { 0xc1,0x67,0xc4,0x89,0x72,0xbe,0xec,0xb1,0xb7,0x1b,0x17,0xdf,0xdc,0xec,0x0e,0x72,
                                         0x00,0xb7,0xf3,0xfe,0xc6,0x04,0x6d,0xf6,0xd6,0xb0,0x85,0x09,0xf5,0x15,0xe7,0xba,
                                         0xf8,0xe6,0xba,0x50,0x69,0xa7,0x8d,0xbc,0x59,0x12,0xc0,0xaf,0xc5,0xf4,0xdf,0xb8,
                                         0x94,0xee,0xe7,0x26,0xa1,0xe5,0x73,0x86,0x6c,0x3b,0xc4,0xd5,0x4a,0xdb,0xe8,0x95,
                                         0x59,0xa9,0x51,0xb6,0xa8,0x9e,0xdb,0xfb,0xc8,0x3a,0x4c,0x07,0x1c,0xd0,0xac,0xa1,
                                         0x0a,0x05,0x51,0x9f,0x38,0x97,0xc1,0x4f,0x23,0x2b,0x75,0x0d,0xbf,0x0b,0xae,0x29,
                                         0xec,0x33,0x62,0xb9,0x96,0x6c,0xf7,0x99,0x43,0xff,0x1e,0x28,0xd9,0x1e,0xcc,0xe6,
                                         0xc2,0x09,0x99,0x5b,0xe0,0x5a,0xd4,0xfd,0xa0,0x66,0x43,0xf4,0x37,0xf5,0x7b,0x51,
                                         0xee,0xeb,0x21,0x78,0x2d,0x24,0x54,0x66,0xff,0xca,0xc8,0x3f,0xac,0x93,0x7d,0x6f,
                                         0x13,0x9f,0x7c,0x79,0x4c,0x05,0xb5,0xff,0xaa,0xaa,0x20,0x10,0xde,0x41,0x47,0x4b,
                                         0x0b,0xe0,0xdb,0x19,0xbf,0xdb,0x42,0xe0,0xcd,0x4a,0xdb,0x67,0x09,0xc1,0xe7,0xc4,
                                         0x99,0xe8,0xc4,0x10,0x03,0x11,0x2e,0x23,0x90,0xb3,0x04,0x72,0xb1,0x68,0x7a,0xac,
                                         0xe2,0x4f,0xc8,0xce,0xcf,0x77,0xf4,0x6f,0x3f,0x82,0x05,0x3d,0xac,0x4d,0x3a,0x54,
                                         0x64,0x9f,0x13,0xe7,0x0a,0xfa,0x0b,0xa0,0xc4,0xf3,0xc6,0xef,0x88,0xfa,0xa4,0x3c,
                                         0x57,0xb7,0x66,0x3c,0x5b,0x6a,0x30,0x9b,0x81,0xee,0xdc,0x9d,0xcb,0x2c,0x17,0xa7,
                                         0xc3,0x31,0xcd,0x3e,0x05,0x52,0x8e,0x26,0x27,0x2a,0x7b,0x56,0xf3,0xee,0x27,0x76 };
__ALIGN64 static const Ipp8u dataE[] = { 0x01, 0x00, 0x01 };


static const unsigned int pubExpBitSize   = 17;
static const unsigned int privExpBitSize  = 2048;
static const unsigned int modulusBitSize  = 2048;

#define IPPCP_MSG_BYTE_LEN       sizeof(pMsg)
#define IPPCP_CTEXT_BYTE_LEN     sizeof(ctext)
#define IPPCP_PRIV_EXP_WORD_SIZE (IPPCP_BITSIZE_2_WORDSIZE(privExpBitSize))
#define IPPCP_PUB_EXP_WORD_SIZE  (IPPCP_BITSIZE_2_WORDSIZE(pubExpBitSize))
#define IPPCP_MODULUS_WORD_SIZE  (IPPCP_BITSIZE_2_WORDSIZE(modulusBitSize))

IPPFUN(fips_test_status, fips_selftest_ippsRSAEncryptDecrypt_OAEP_rmf_get_size_keys, (int *pKeysBufferSize))
{
    /* return bad status if input pointer is NULL */
    IPP_BADARG_RET((NULL == pKeysBufferSize), IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR);

    IppStatus sts = ippStsNoErr;
    int total_size = 0;
    int tmp_size   = 0;

    sts = ippsBigNumGetSize(IPPCP_PUB_EXP_WORD_SIZE, &tmp_size);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    total_size += (tmp_size + IPPCP_BN_ALIGNMENT); // E

    sts = ippsBigNumGetSize(IPPCP_PRIV_EXP_WORD_SIZE, &tmp_size);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    total_size += (tmp_size + IPPCP_BN_ALIGNMENT); // D

    sts = ippsBigNumGetSize(IPPCP_MODULUS_WORD_SIZE, &tmp_size);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    total_size += (tmp_size + IPPCP_BN_ALIGNMENT); // N

    sts = ippsRSA_GetSizePublicKey(modulusBitSize, pubExpBitSize, &tmp_size);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    total_size += (tmp_size + IPPCP_RSA_ALIGNMENT); // pPubKey

    sts = ippsRSA_GetSizePrivateKeyType1(modulusBitSize, privExpBitSize, &tmp_size);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    total_size += (tmp_size + IPPCP_RSA_ALIGNMENT); // pPrivKey

    *pKeysBufferSize = total_size;

    return IPPCP_ALGO_SELFTEST_OK;
}

IPPFUN(fips_test_status, fips_selftest_ippsRSAEncryptDecrypt_OAEP_rmf_get_size, (int *pBufferSize, Ipp8u *pKeysBuffer))
{
    /* return bad status if input pointers are NULL */
    IPP_BADARG_RET((NULL == pBufferSize) || (NULL == pKeysBuffer), IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR);

    IppStatus sts = ippStsNoErr;
    int total_size = 0;

    Ipp8u* pLocKeysBuffer = pKeysBuffer;

    /* Initialize BigNumber-s */
    int eByteSize;
    sts = ippsBigNumGetSize(IPPCP_PUB_EXP_WORD_SIZE, &eByteSize);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnE = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += eByteSize;

    int dByteSize;
    sts = ippsBigNumGetSize(IPPCP_PRIV_EXP_WORD_SIZE, &dByteSize);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnD = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += dByteSize;

    int nByteSize;
    sts = ippsBigNumGetSize(IPPCP_MODULUS_WORD_SIZE, &nByteSize);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnN = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += nByteSize;

    sts = ippcp_init_set_bn(bnE, IPPCP_PUB_EXP_WORD_SIZE,  ippBigNumPOS, (const Ipp32u *)dataE, IPPCP_PUB_EXP_WORD_SIZE);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    sts = ippcp_init_set_bn(bnD, IPPCP_PRIV_EXP_WORD_SIZE, ippBigNumPOS, (const Ipp32u *)dataD, IPPCP_PRIV_EXP_WORD_SIZE);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    sts = ippcp_init_set_bn(bnN, IPPCP_MODULUS_WORD_SIZE,  ippBigNumPOS, (const Ipp32u *)dataN, IPPCP_MODULUS_WORD_SIZE);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;

    /* Initialize key pair - necessary to obtain signature size */
    // private key
    int privKeyByteSize = 0;
    sts = ippsRSA_GetSizePrivateKeyType1(modulusBitSize, privExpBitSize, &privKeyByteSize);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_RSA_ALIGNMENT));
    IppsRSAPrivateKeyState* pPrivKey = (IppsRSAPrivateKeyState*)pLocKeysBuffer;
    sts = ippsRSA_InitPrivateKeyType1(modulusBitSize, privExpBitSize, pPrivKey, privKeyByteSize);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    pLocKeysBuffer+=privKeyByteSize;

    // public key
    int pubKeyByteSize = 0;
    sts = ippsRSA_GetSizePublicKey(modulusBitSize, pubExpBitSize, &pubKeyByteSize);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_RSA_ALIGNMENT));
    IppsRSAPublicKeyState* pPubKey = (IppsRSAPublicKeyState*)pLocKeysBuffer;
    sts = ippsRSA_InitPublicKey(modulusBitSize, pubExpBitSize, pPubKey, pubKeyByteSize);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;

    /* Set key pair */
    sts = ippsRSA_SetPublicKey(bnN, bnE, pPubKey);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    sts = ippsRSA_SetPrivateKeyType1(bnN, bnD, pPrivKey);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;

    /* RSA decryption and encryption buffers */
    int decBufSize;
    sts = ippsRSA_GetBufferSizePrivateKey(&decBufSize, pPrivKey);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    int encBufSize;
    sts = ippsRSA_GetBufferSizePublicKey(&encBufSize, pPubKey);
    if(sts != ippStsNoErr) return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;

    total_size = IPP_MAX(decBufSize, encBufSize) + IPPCP_RSA_ALIGNMENT;
    *pBufferSize = total_size;

    return IPPCP_ALGO_SELFTEST_OK;
}

IPPFUN(fips_test_status, fips_selftest_ippsRSAEncrypt_OAEP_rmf, (Ipp8u *pBuffer, Ipp8u *pKeysBuffer))
{
    IppStatus sts = ippStsNoErr;
    fips_test_status test_result = IPPCP_ALGO_SELFTEST_OK;

    /* Internal memory allocation feature */
    int internalMemMgm = 0;
#if IPPCP_SELFTEST_USE_MALLOC
    if(pBuffer == NULL || pKeysBuffer == NULL) {
        internalMemMgm = 1;

        int keysBuffSize = 0;
        fips_selftest_ippsRSAEncryptDecrypt_OAEP_rmf_get_size_keys(&keysBuffSize);
        pKeysBuffer = malloc((size_t)keysBuffSize);

        int dataBuffSize = 0;
        fips_selftest_ippsRSAEncryptDecrypt_OAEP_rmf_get_size(&dataBuffSize, pKeysBuffer);
        pBuffer = malloc((size_t)dataBuffSize);
    }
#else
    IPP_BADARG_RET((NULL == pBuffer) || (NULL == pKeysBuffer), IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR);
#endif

    /* Buffer for the encrypted text */
    Ipp8u OutCtxt[IPPCP_CTEXT_BYTE_LEN];
    Ipp8u* pOutCtxt = OutCtxt;

    Ipp8u* pLocKeysBuffer = pKeysBuffer;

    /* Initialize BigNumber-s */
    int eByteSize;
    sts = ippsBigNumGetSize(IPPCP_PUB_EXP_WORD_SIZE, &eByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnE = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += eByteSize;

    int nByteSize;
    sts = ippsBigNumGetSize(IPPCP_MODULUS_WORD_SIZE, &nByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnN = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += nByteSize;

    sts = ippcp_init_set_bn(bnE, IPPCP_PUB_EXP_WORD_SIZE,  ippBigNumPOS, (const Ipp32u *)dataE, IPPCP_PUB_EXP_WORD_SIZE);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    sts = ippcp_init_set_bn(bnN, IPPCP_MODULUS_WORD_SIZE, ippBigNumPOS, (const Ipp32u *)dataN, IPPCP_MODULUS_WORD_SIZE);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    /* Initialize public key */
    int pubKeyByteSize = 0;
    sts = ippsRSA_GetSizePublicKey(modulusBitSize, pubExpBitSize, &pubKeyByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_RSA_ALIGNMENT));
    IppsRSAPublicKeyState* pPubKey = (IppsRSAPublicKeyState*)pLocKeysBuffer;
    sts = ippsRSA_InitPublicKey(modulusBitSize, pubExpBitSize, pPubKey, pubKeyByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    /* Set public key */
    sts = ippsRSA_SetPublicKey(bnN, bnE, pPubKey);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    /* RSA encryption */
    int encBufSize;
    sts = ippsRSA_GetBufferSizePublicKey(&encBufSize, pPubKey);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    Ipp8u* encScratchBuffer = (IPP_ALIGNED_PTR(pBuffer, IPPCP_RSA_ALIGNMENT));

    sts = ippsRSAEncrypt_OAEP_rmf(pMsg, IPPCP_MSG_BYTE_LEN, 0, 0, seed, pOutCtxt, pPubKey,
                                  ippsHashMethod_SHA256(), encScratchBuffer);

    int sigFlagErr = ippcp_is_mem_eq(ctext, IPPCP_CTEXT_BYTE_LEN, pOutCtxt, IPPCP_CTEXT_BYTE_LEN);
    if(1 != sigFlagErr || sts != ippStsNoErr) {
        test_result = IPPCP_ALGO_SELFTEST_KAT_ERR;
    }

    MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
    return test_result;
}

IPPFUN(fips_test_status, fips_selftest_ippsRSADecrypt_OAEP_rmf, (Ipp8u *pBuffer, Ipp8u *pKeysBuffer))
{
    IppStatus sts = ippStsNoErr;
    fips_test_status test_result = IPPCP_ALGO_SELFTEST_OK;

    /* Internal memory allocation feature */
    int internalMemMgm = 0;
#if IPPCP_SELFTEST_USE_MALLOC
    if(pBuffer == NULL || pKeysBuffer == NULL) {
        internalMemMgm = 1;

        int keysBuffSize = 0;
        fips_selftest_ippsRSAEncryptDecrypt_OAEP_rmf_get_size_keys(&keysBuffSize);
        pKeysBuffer = malloc((size_t)keysBuffSize);

        int dataBuffSize = 0;
        fips_selftest_ippsRSAEncryptDecrypt_OAEP_rmf_get_size(&dataBuffSize, pKeysBuffer);
        pBuffer = malloc((size_t)dataBuffSize);
    }
#else
    IPP_BADARG_RET((NULL == pBuffer) || (NULL == pKeysBuffer), IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR);
#endif

    /* Buffer for the deciphered text */
    Ipp8u OutPtxt[IPPCP_MSG_BYTE_LEN];
    Ipp8u* pOutPtxt = OutPtxt;

    Ipp8u* pLocKeysBuffer = pKeysBuffer;

    /* Initialize BigNumber-s */
    int dByteSize;
    sts = ippsBigNumGetSize(IPPCP_PRIV_EXP_WORD_SIZE, &dByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnD = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += dByteSize;

    int nByteSize;
    sts = ippsBigNumGetSize(IPPCP_MODULUS_WORD_SIZE, &nByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_BN_ALIGNMENT));
    IppsBigNumState* bnN = (IppsBigNumState *)pLocKeysBuffer;
    pLocKeysBuffer += nByteSize;

    sts = ippcp_init_set_bn(bnD, IPPCP_PRIV_EXP_WORD_SIZE, ippBigNumPOS, (const Ipp32u *)dataD, IPPCP_PRIV_EXP_WORD_SIZE);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    sts = ippcp_init_set_bn(bnN, IPPCP_MODULUS_WORD_SIZE, ippBigNumPOS, (const Ipp32u *)dataN, IPPCP_MODULUS_WORD_SIZE);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    /* Initialize private key */
    int privKeyByteSize = 0;
    sts = ippsRSA_GetSizePrivateKeyType1(modulusBitSize, privExpBitSize, &privKeyByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    pLocKeysBuffer = (IPP_ALIGNED_PTR(pLocKeysBuffer, IPPCP_RSA_ALIGNMENT));
    IppsRSAPrivateKeyState* pPrivKey = (IppsRSAPrivateKeyState*)pLocKeysBuffer;
    sts = ippsRSA_InitPrivateKeyType1(modulusBitSize, privExpBitSize, pPrivKey, privKeyByteSize);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    /* Set private key */
    sts = ippsRSA_SetPrivateKeyType1(bnN, bnD, pPrivKey);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }

    /* RSA decryption */
    int decBufSize;
    sts = ippsRSA_GetBufferSizePrivateKey(&decBufSize, pPrivKey);
    if(sts != ippStsNoErr) {
        MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
        return IPPCP_ALGO_SELFTEST_BAD_ARGS_ERR;
    }
    Ipp8u* decScratchBuffer = (IPP_ALIGNED_PTR(pBuffer, IPPCP_RSA_ALIGNMENT));

    int ptxtLen;

    sts = ippsRSADecrypt_OAEP_rmf(ctext, 0, 0, pOutPtxt, &ptxtLen, pPrivKey,
                                  ippsHashMethod_SHA256(), decScratchBuffer);

    int sigFlagErr = ippcp_is_mem_eq(pMsg, IPPCP_MSG_BYTE_LEN, pOutPtxt, IPPCP_MSG_BYTE_LEN);
    if(1 != sigFlagErr || sts != ippStsNoErr) {
        test_result = IPPCP_ALGO_SELFTEST_KAT_ERR;
    }

    MEMORY_FREE_2(pKeysBuffer, pBuffer, memMgmFlag)
    return test_result;
}

#endif // _IPP_DATA
#endif // IPPCP_FIPS_MODE
