/*************************************************************************
* Copyright (C) 2020 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.
*************************************************************************/

/*!
  *
  *  \file
  *
  *  \brief SMS4 Cipher Block Chaining mode of operation (CBC) example
  *
  *  This example demonstrates usage of SMS4 block cipher
  *  run with CBC mode of operation. Encryption scheme.
  *
  *  The CBC mode of operation is implemented according to the
  *  "NIST Special Publication 800-38A: Recommendation for Block Cipher Modes of
  *  Operation" document:
  *
  *  https://csrc.nist.gov/publications/detail/sp/800-38a/final
  *
  */

#include <string.h>

#include "ippcp.h"
#include "examples_common.h"

/*! SMS4 block size in bytes */
static const int SMS4_BLOCK_SIZE = 16;

/*! Key size in bytes */
static const int KEY_SIZE = 16;

/*! Message size in bytes */
static const int SRC_LEN = 16;

/*! Plain text */
static Ipp8u plainText[SRC_LEN] = { 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xBB,
                                    0xCC, 0xCC, 0xCC, 0xCC, 0xDD, 0xDD, 0xDD, 0xDD };

/*! Cipher text */
static Ipp8u cipherText[SRC_LEN] = { 0x78, 0xEB, 0xB1, 0x1C, 0xC4, 0x0B, 0x0A, 0x48,
                                     0x31, 0x2A, 0xAE, 0xB2, 0x04, 0x02, 0x44, 0xCB };

/*! 128-bit secret key */
static Ipp8u key[KEY_SIZE] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
                               0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 };

/*! Initialization vector for CBC mode.
 *  Size of initialization vector for SMS4-CBC shall be equal to the size of SMS4 block (16 bytes).
 */
static Ipp8u iv[SMS4_BLOCK_SIZE] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                                     0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };

/*! Main function  */
int main(void)
{
    /* Size of SMS4 context structure. It will be set up in ippsSMS4GetSize(). */
    int ctxSize = 0;

    Ipp8u pOut[SRC_LEN] = {};

    /* Internal function status */
    IppStatus status = ippStsNoErr;

    /* Pointer to SMS4 context structure */
    IppsSMS4Spec* pSMS4 = 0;

    do {
        /* 1. Get size needed for SMS4 context structure */
        status = ippsSMS4GetSize(&ctxSize);
        if (!checkStatus("ippsSMS4GetSize", ippStsNoErr, status))
            return status;

        /* 2. Allocate memory for SMS4 context structure */
        pSMS4 = (IppsSMS4Spec*)(new Ipp8u[ctxSize]);
        if (NULL == pSMS4) {
            printf("ERROR: Cannot allocate memory (%d bytes) for SMS4 context\n", ctxSize);
            return -1;
        }

        /* 3. Initialize SMS4 context */
        status = ippsSMS4Init(key, sizeof(key), pSMS4, ctxSize);
        if (!checkStatus("ippsSMS4Init", ippStsNoErr, status))
            break;

        /* 4. Encryption */
        status = ippsSMS4EncryptCBC(plainText, pOut, sizeof(plainText), pSMS4, iv);
        if (!checkStatus("ippsSMS4EncryptCBC", ippStsNoErr, status))
            break;

        /* Compare encrypted message and reference text */
        if (0 != memcmp(pOut, cipherText, sizeof(cipherText))) {
            printf("ERROR: Encrypted and reference messages do not match\n");
            break;
        }
    } while (0);

    /* 5. Remove secret and release resources */
    ippsSMS4Init(0, KEY_SIZE, pSMS4, ctxSize);
    if (pSMS4)
        delete[] (Ipp8u*)pSMS4;

    PRINT_EXAMPLE_STATUS("ippsSMS4EncryptCBC", "SMS4-CBC Encryption", !status)

    return status;
}
