/*
* Creation date : May 29 15:33:10 2007
* Last modified : %modify_time%
*/
/** @file
* \brief This file contains implementation of 
* LLF_CMLA() function. 
*
* \version LLF_CMLA.c#1:csrc:1
* \author Yermalayeu Ihar
* \remarks Copyright (C) 2007 by Discretix Technologies Ltd.
* All Rights reserved
*/

/************************ Include Files ***********************/

#include "LLF_CMLA.h"
#include "LLF_RSA_Common.h"
#include "LLF_HASH.h"
#include "CE2_AES.h"
#include "CE2_public.h"
#include "tomcrypt.h"
#include "tommath.h"

/************************ Defines *****************************/

#define LLF_CMLA_KDF_XI_SIZE 64
#define LLF_CMLA_KDF_AB_SIZE 32

#define LLF_CMLA_WRAP_KI_SIZE 16

#define LLF_CMLA_RSA_ENCRYPT_MI_SIZE 64

/************************ Enums *******************************/
/************************ Typedefs ****************************/
/************************ Global Data *************************/
/************************ Private function prototype **********/
/************************ Private Functions *******************/

/**
****************************************************************
* Function Name: 
*  LLF_CMLA_DDT_Perm
*
*  @param[in]  b - Input bit string of length 64;
*  @param[out] B - Output bit string of length 64;
*  
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - error code:
*
* \brief \b 
* Description:
*  CMLA_DDT_Perm is the CMLA Data-dependent Transformation with Permutation. 
*  It permutes last 56 bits of 64-bit input according to the first 8 bits.
*
*  \b 
* Algorithm:
*  -# Let b = (b0, b1, ... , b63). 
*  -# For 0 <= i <= 7, set Gi = (b[8 + 7i], b[9 + 7i], ..., b[14 + 7i]), 
*     bit string of length 7. 
*  -# The transformation works as follows for i = 0, 1, ... , 7.
*     - If bi = 0, let Hi = Gi.
*     - If bi = 1, let Hi = Pi (Gi), where Pi is defined below.
*         Input a b c d e f g
*         P0    f a e b d g c
*         P1    g f d a b c e
*         P2    c g b f a e d
*         P3    e c a g f d b
*         P4    d e f c g b a
*         P5    b d g e c a f
*         P6    e c a g f d b
*         P7    c g b f a e d
*  -# Let B = (b0, b1, ..., b7) || H0 || H1 || ... || H7.
***************************************************************/
CE2Error_t LLF_CMLA_DDT_Perm(DxUint8_t *b, DxUint8_t *B)
{
  DxInt32_t i, j;
  DxUint8_t b_bits[64], *G[8], Hi[7];
  const DxUint8_t P[8][7] = {
    5, 0, 4, 1, 3, 6, 2,
    6, 5, 3, 0, 1, 2, 4,
    2, 6, 1, 5, 0, 4, 3,
    4, 2, 0, 6, 5, 3, 1, 
    3, 4, 5, 2, 6, 1, 0, 
    1, 3, 6, 4, 2, 0, 5,
    4, 2, 0, 6, 5, 3, 1, 
    2, 6, 1, 5, 0, 4, 3
  };

  /* Let b = (b0, b1, ... , b63). */
  for (i = 0; i < 8; i++) {
    for (j = 0; j < 8; j++) {
      b_bits[i*8 + j] = ((0x80 >> j)&b[i]);
    }
  }

  /* For 0 <= i <= 7,                                  */ 
  /* set Gi = (b[8 + 7i], b[9 + 7i], ..., b[14 + 7i]), */ 
  /* bit string of length 7.                           */
  for (i = 0; i < 8; i++) 
    G[i] = b_bits + 8 + 7*i;

  /* The transformation works as follows for i = 0, 1, ... , 7 */
  for (i = 0; i < 8; i++) {
    if (b_bits[i] == 0) {
      /* If bi = 0, let Hi = Gi. */
      /* Nothing to do... */
    } else {
      /* If bi = 1, let Hi = Pi (Gi) */
      for(j = 0; j < 7; j++)
        Hi[j] = G[i][P[i][j]];  
      memcpy(G[i], Hi, 7);
    }
  }

  /* Let B = (b0, b1, ..., b7) || H0 || H1 || ... || H7 */
  for (i = 0; i < 8; i++) {
    B[i] = 0;
    for (j = 0; j < 8; j++) {
      B[i] <<= 1;
      if (b_bits[i*8 + j] != 0)
        B[i]++;
    }
  }

  return CE2_OK;
} /* End of LLF_CMLA_DDT_Perm */

/**
****************************************************************
* Function Name: 
*  LLF_CMLA_DDT_Perm_Inv
*
*  @param[in]  B - Input bit string of length 64;
*  @param[out] b - Output bit string of length 64;
*  
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - error code:
*
* \brief \b 
* Description:
*  CMLA_DDT_Perm_Inv is the inverse transformation of CMLA_DDT_Perm.
*
*  \b 
* Algorithm:
*  -# Let B = (B0, B1, ... , B63).
*  -# For 0 <= i <= 7, set Si = (B[8 + 7i], B[9 + 7i], ... , B[14 + 7i])
*     bit string of length 7.
*  -# The transformation works as follows for each i=0, 1, ... , 7.
*     - If Bi = 0, let Ti = Si.
*     - If Bi = 1, let Ti = Ri (Si), where Ri is defined below.
*         Input a b c d e f g
*         R0    b d g e c a f
*         R1    d e f c g b a
*         R2    e c a g f d b
*         R3    c g b f a e d
*         R4    g f d a b c e
*         R5    f a e b d g c
*         R6    c g b f a e d
*         R7    e c a g f d b
*  -# Let b = (B0, B1, ..., B7) || T0 || T1 || ... || T7. 
***************************************************************/
CE2Error_t LLF_CMLA_DDT_Perm_Inv(DxUint8_t *B, DxUint8_t *b)
{
  DxInt32_t i, j;
  DxUint8_t B_bits[64], *S[8], Ti[7];
  const DxUint8_t R[8][7] = {
    1, 3, 6, 4, 2, 0, 5,
    3, 4, 5, 2, 6, 1, 0,
    4, 2, 0, 6, 5, 3, 1,
    2, 6, 1, 5, 0, 4, 3,
    6, 5, 3, 0, 1, 2, 4,
    5, 0, 4, 1, 3, 6, 2,
    2, 6, 1, 5, 0, 4, 3,
    4, 2, 0, 6, 5, 3, 1
  };

  /* Let B = (B0, B1, ... , B63). */
  for (i = 0; i < 8; i++) {
    for (j = 0; j < 8; j++) {
      B_bits[i*8 + j] = ((0x80 >> j)&B[i]);
    }
  }

  /*  For 0 <= i <= 7,                                  */ 
  /*  set Si = (B[8 + 7i], B[9 + 7i], ... , B[14 + 7i]) */
  /*  bit string of length 7.                           */
  for (i = 0; i < 8; i++) 
    S[i] = B_bits + 8 + 7*i;


  /* The transformation works as follows for each i=0, 1, ... , 7. */
  for (i = 0; i < 8; i++) {
    if (B_bits[i] == 0) {
      /* If Bi = 0, let Ti = Si. */
      /* Nothing to do... */
    } else {
      /* If Bi = 1, let Ti = Ri (Si) */
      for(j = 0; j < 7; j++)
        Ti[j] = S[i][R[i][j]];  
      memcpy(S[i], Ti, 7);
    }
  }

  /* Let b = (B0, B1, ..., B7) || T0 || T1 || ... || T7 */
  for (i = 0; i < 8; i++) {
    b[i] = 0;
    for (j = 0; j < 8; j++) {
      b[i] <<= 1;
      if (B_bits[i*8 + j] != 0)
        b[i]++;
    }
  }

  return CE2_OK;
} /* End of LLF_CMLA_DDT_Perm_Inv */

/**
****************************************************************
* Function Name: 
*  LLF_CMLA_DDT_Exp
*
*  @param[in]  b - Input bit string of length 24;
*  @param[out] B - Output bit string of length 24;
*  
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - error code:
*
* \brief \b 
* Description:
*  LLF_CMLA_DDT_Exp is the CMLA Data-dependent Transformation with 
*  Exponentiation. It permutes last 16 bits of 24-bit input according 
*  to the first 8 bits.
*
*  \b 
* Algorithm:
*  -# Let b = (b0, b1, ... , b23).
*  -# Set L = (b0, b1, ... , b7), bit string of length 8, and 
*     set R = (b8, b9, ... , b23), bit string of length 16.
*  -# Regarding R and L as integer, compute Y = ((R+1)^(2L+1) mod 65537) – 1.
*  -# Let B = L || Y.
***************************************************************/
CE2Error_t LLF_CMLA_DDT_Exp(DxUint8_t *b, DxUint8_t *B)
{
  CE2Error_t result = CE2_OK;
  void *L, *R, *Y, *p;
  int error_code;
  DxUint32_t size;

  /* Initialize LibTomCrypt variables */
  ltc_mp = ltm_desc;
  error_code = ltc_init_multi(&L, &R, &Y, &p, NULL);
  if (error_code != CRYPT_OK) {
    return CE2_LLF_CMLA_MODULE_ERROR_BASE;
  }

  /* Let b = (b0, b1, ... , b23).                        */
  /* Set L = (b0, b1, ... , b7), bit string of length 8  */ 
  error_code = ltc_mp.unsigned_read(L, b, 1);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* Set R = (b8, b9, ... , b23), bit string of length 16. */
  error_code = ltc_mp.unsigned_read(R, b + 1, 2);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }

  /* Compute Y = ((R+1)^(2L+1) mod 65537) – 1. */
  /* Set p = 65537 */
  error_code = ltc_mp.set_int(p, 65537);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* R = R + 1 */
  error_code = ltc_mp.addi(R, 1, R);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* L = 2L */
  error_code = ltc_mp.muli(L, 2, L);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* L = 2L + 1 */
  error_code = ltc_mp.addi(L, 1, L);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* Y = ((R+1)^(2L+1) mod 65537). */
  error_code = ltc_mp.exptmod(R, L, p, Y);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* Y = ((R+1)^(2L+1) mod 65537) – 1. */
  error_code = ltc_mp.subi(Y, 1, Y);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }

  /* Let B = L || Y. */
  /* B = L */
  B[0] = b[0];
  /* B = L || Y. */
  size = 2;
  error_code = mp_to_unsigned_bin_n(Y, B + 1, &size);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }

error_case:
  ltc_deinit_multi(L, R, Y, p, NULL);
  return result;
} /* End of LLF_CMLA_DDT_Exp */

/**
****************************************************************
* Function Name: 
*  LLF_CMLA_DDT_Exp_Inv
*
*  @param[in]  B - Input bit string of length 24;
*  @param[out] b - Output bit string of length 24;
*  
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - error code:
*
* \brief \b 
* Description:
*  LLF_CMLA_DDT_Exp_Inv is the inverse transformation of CMLA_DDT_Exp.
*
*  \b 
* Algorithm:
*  -# Let B = (B0, B1, ... , B23).
*  -# Set L = (B0, B1, ... , B7), an integer, and 
*     set R = (B8, B9, ... , B23), an integer.
*  -# Compute e as the inverse of 2L+1 modulo 2^16: 
*     e*(2L+1) = 1 modulo 2^16.
*  -# Compute X = ((R+1)^e mod 65537) – 1.
*  -# Let b = L || X.
***************************************************************/
CE2Error_t LLF_CMLA_DDT_Exp_Inv(DxUint8_t *B, DxUint8_t *b)
{
  CE2Error_t result = CE2_OK;
  void *L, *R, *e, *p, *X;
  int error_code;
  DxUint32_t size;

  /* Initialize LibTomCrypt variables */
  ltc_mp = ltm_desc;
  error_code = ltc_init_multi(&L, &R, &e, &p, &X, NULL);
  if (error_code != CRYPT_OK) {
    return CE2_LLF_CMLA_MODULE_ERROR_BASE;
  }

  /* Let B = (B0, B1, ... , B23).             */
  /* Set L = (B0, B1, ... , B7), an integer   */ 
  error_code = ltc_mp.unsigned_read(L, B, 1);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* Set R = (B8, B9, ... , B23), an integer. */
  error_code = ltc_mp.unsigned_read(R, B + 1, 2);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }

  /* Compute e as the inverse of 2L+1 modulo 2^16: */ 
  /* e*(2L+1) = 1 modulo 2^16.                     */
  /* Set p = 2^16 = 65536 */
  error_code = ltc_mp.set_int(p, 65536);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* L = 2L */
  error_code = ltc_mp.muli(L, 2, L);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* L = 2L + 1 */
  error_code = ltc_mp.addi(L, 1, L);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* e = 1/(2L+1) modulo 2^16 */
  error_code = ltc_mp.invmod(L, p, e);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }

  /* Compute X = ((R+1)^e mod 65537) – 1. */
  /* Set p = 65537 */
  error_code = ltc_mp.set_int(p, 65537);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* R = R + 1 */
  error_code = ltc_mp.addi(R, 1, R);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* X = ((R+1)^e mod 65537) */
  error_code = ltc_mp.exptmod(R, e, p, X);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* X = ((R+1)^e mod 65537) – 1 */
  error_code = ltc_mp.subi(X, 1, X);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }

  /* Let b = L || X. */
  /* b = L */
  b[0] = B[0];
  /* b = L || X. */
  size = 2;
  error_code = mp_to_unsigned_bin_n(X, b + 1, &size);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }

error_case:
  ltc_deinit_multi(L, R, e, p, X, NULL);
  return result;
} /* End of LLF_CMLA_DDT_Exp_Inv */


/************************ Public Functions ********************/

/**
****************************************************************
* Function Name: 
*  LLF_CMLA_KDF
*
*  @param[in]  X        - Seed value, an octet string of length 128.
*  @param[out] KEK      - Key Encryption Key, an octet string of length 16.
*  
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - error code:
*
* \brief \b 
* Description:
*  CMLA Key Derivation Function produce the Key Encrypting Key [CMLA v1.0-051221].
*  LLF_CMLA_KDF operates on an octet string of length 128.
*  The input splits in two blocks of equal length. A constant value is concatenated
*  to the first block. Then SHA-1 is applied to the preceding result. The result
*  and two integers derived from the second block are used in a modulus calculation
*  to produce the Key Encrypting Key. The output shall be 16 bytes.
*
*  \b 
* Algorithm:
*  -# Let X = X0 || X1, where each Xi consists of 64 bytes octet for i = 0, 1.
*  -# Let C=(0x)00 00 00 01 (4 bytes).
*  -# Compute Y = SHA-1(X0||C) (160 bits).
*  -# Let A be the first 32 bytes and B be the last 32 bytes of X1, respectively.
*  -# Regarding Y, A, and B as integers, derive key encryption key KEK taking the 
*     least significant 128 bits of A*Y + B mod p, where p = 2^192 - 2^64 - 1.
***************************************************************/
CE2Error_t LLF_CMLA_KDF(CE2_CMLA_SEED_t      X ,       /*in*/
                        CE2_CMLA_KEK_t       KEK      /*out*/)
{
  /* Let C=(0x)00 00 00 01 (4 bytes). */
  DxUint8_t C[] = {0x00, 0x00, 0x00, 0x01};
  DxUint8_t buffer[LLF_CMLA_KDF_XI_SIZE + sizeof(C)];
  CE2_HASH_Result_t Y;
  CE2Error_t result = CE2_OK, error;
  void *a, *b, *y, *p, *t;
  DxUint32_t size;
  int error_code;

  /* Compute Y = SHA-1(X0||C) (160 bits). */
  /* buffer = X0 */
  memcpy(buffer, X, LLF_CMLA_KDF_XI_SIZE);
  /* buffer = X0||C */
  memcpy(buffer + LLF_CMLA_KDF_XI_SIZE, C, sizeof(C));
  /* Y = SHA-1(X0||C). */
  error = CE2_HASH(CE2_HASH_SHA1_mode, buffer, sizeof(buffer), Y);
  if (error != CE2_OK)
    return error;

  /* Initialize LibTomCrypt variables: */
  ltc_mp = ltm_desc;
  error_code = ltc_init_multi(&a, &b, &y, &p, &t, NULL);
  if (error_code != CRYPT_OK) {
    return CE2_LLF_CMLA_MODULE_ERROR_BASE;
  }

  /* Set A as integer; A is the first 32 bytes of X1. */
  error_code = ltc_mp.unsigned_read(a, X + LLF_CMLA_KDF_XI_SIZE, 
    LLF_CMLA_KDF_AB_SIZE);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }

  /* Set B as integer; B is the last 32 bytes of X1. */
  error_code = ltc_mp.unsigned_read(b, X + LLF_CMLA_KDF_XI_SIZE + 
    LLF_CMLA_KDF_AB_SIZE, LLF_CMLA_KDF_AB_SIZE);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }

  /* Set Y as integer. */
  error_code = ltc_mp.unsigned_read(y, (unsigned char*)Y, 
    CE2_HASH_SHA1_DIGEST_SIZE_IN_BYTES);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }

  /* Set p = 2^192 - 2^64 - 1. */
  error_code = ltc_mp.read_radix(p, 
    "fffffffffffffffffffffffffffffffeffffffffffffffff", 16);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }

  /* t = A*Y */
  error_code = ltc_mp.mul(a, y, t);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* t = A*Y + B */
  error_code = ltc_mp.add(b, t, t);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* t = A*Y + B mod p */
  error_code = ltc_mp.mpdiv(t, p, NULL, t);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }

  /* KEK taking the least significant 128 bits of t */
  /* Convert t to big-endian format*/
  size = sizeof(buffer);
  error_code = mp_to_unsigned_bin_n(t, buffer, &size);
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_CMLA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* Taking the least significant 128 bits of t */
  if (size >= CE2_CMLA_KEK_SIZE_IN_BYTES) {
    memcpy(KEK, buffer + (size - CE2_CMLA_KEK_SIZE_IN_BYTES), 
      CE2_CMLA_KEK_SIZE_IN_BYTES);
  } else {
    memset(KEK, 0, CE2_CMLA_KEK_SIZE_IN_BYTES - size);  
    memcpy(KEK + (CE2_CMLA_KEK_SIZE_IN_BYTES - size), buffer, size);
  }

error_case:
  ltc_deinit_multi(a, b, y, p, t, NULL);
  return result;
} /* End of LLF_CMLA_KDF */

/**
****************************************************************
* Function Name: 
*  LLF_CMLA_Wrap
*
*  @param[in]  KEK      - Key Encryption Key, an octet string of length 16 bytes.
*  @param[in]  Key      - Plain key, an octet string of length 32 bytes.
*  @param[out] WrapKey  - Wrapped Key, an octet string of length 40 bytes.
*  
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - error code:
*
* \brief \b 
* Description:
*  The LLF_CMLA_Wrap primitive composing CE2 AES Key Wrap Algorithm
*  and CMLA_DDT_Perm according to CMLA algorithm [CMLA v1.0-051221].
*
*  \b 
* Algorithm:
*  -# Let Key = K0 || K1, where each Ki consists of 16 bytes octet for i = 0, 1. 
*  -# Apply LLF_CMLA_DDT_Perm to the first 8 bytes of Ki, keeping the rest of 
*     Ki unchanged, to produce 16-byte octet string ki for i = 0, 1. 
*  -# Let k = k0 || k1. 
*  -# Compute CE2_AES_Wrap(KEK, k) to produce an octet string WrapKey of 40 bytes. 
***************************************************************/
CE2Error_t LLF_CMLA_Wrap(CE2_CMLA_KEK_t            KEK,    /*in*/
                         CE2_CMLA_UNWRAPPED_KEY_t  Key,    /*in*/
                         CE2_CMLA_WRAPPED_KEY_t    WrapKey /*out*/ )
{
  DxUint8_t k[CE2_CMLA_UNWRAPPED_KEY_SIZE_IN_BYTES];
  DxUint32_t wrapKeySize = CE2_CMLA_WRAPPED_KEY_SIZE_IN_BYTES;

  /* Let Key = K0 || K1, where each Ki consists of 16 bytes octet for i = 0, 1. */
  /* Apply LLF_CMLA_DDT_Perm to the first 8 bytes of Ki, keeping the rest of    */ 
  /* Ki unchanged, to produce 16-byte octet string ki for i = 0, 1.             */
  /* Let k = k0 || k1. */
  memcpy(k, Key, CE2_CMLA_UNWRAPPED_KEY_SIZE_IN_BYTES);
  /* i = 0 */
  LLF_CMLA_DDT_Perm(k, k);
  /* i = 1 */
  LLF_CMLA_DDT_Perm(k + LLF_CMLA_WRAP_KI_SIZE, k + LLF_CMLA_WRAP_KI_SIZE);

  /* Compute CE2_AES_Wrap(KEK, k) to produce an octet string WrapKey of */
  /* 40 bytes. */ 
  return CE2_AES_Wrap(k, CE2_CMLA_UNWRAPPED_KEY_SIZE_IN_BYTES, 
    KEK, CE2_AES_Key128BitSize, WrapKey, &wrapKeySize);
} /* End of LLF_CMLA_Wrap */

/**
****************************************************************
* Function Name: 
*  LLF_CMLA_Unwrap
*
*  @param[in]  KEK      - Key Encryption Key, an octet string of length 16 bytes.
*  @param[in]  WrapKey  - Wrapped Key, an octet string of length 40 bytes.
*  @param[out] Key      - Plain key, an octet string of length 32 bytes.
*  
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - error code:
*
* \brief \b 
* Description:
*  The LLF_CMLA_Unwrap primitive performs inverse CE2_CMLA_Wrap 
*  transformation [CMLA v1.0-051221].
*
*  \b 
* Algorithm:
*  -# Compute CE2_AES_Unwrap(KEK, WrapKey) to produce an octet string k of 
*     length 32 octets.
*  -# Let k = k0||k1, where each ki consists of 16 bytes for i = 0, 1.
*  -# Apply LLF_CMLA_DDT_Perm_Inv to the first 8 bytes of ki, keeping the 
*     rest of ki unchanged, to produce 16-byte octet string Ki for i = 0, 1.
*  -# Let Key = K0 || K1.
***************************************************************/
CE2Error_t LLF_CMLA_Unwrap(CE2_CMLA_KEK_t            KEK,      /*in*/
                           CE2_CMLA_WRAPPED_KEY_t    WrapKey,  /*in*/
                           CE2_CMLA_UNWRAPPED_KEY_t  Key       /*out*/ )
{
  CE2Error_t error;
  DxUint32_t unwrapKeySize = CE2_CMLA_UNWRAPPED_KEY_SIZE_IN_BYTES;

  /* Compute CE2_AES_Unwrap(KEK, WrapKey) to produce an octet */
  /* string Key of length 32 octets.                          */
  error = CE2_AES_Unwrap(WrapKey, CE2_CMLA_WRAPPED_KEY_SIZE_IN_BYTES,
    KEK, CE2_AES_Key128BitSize, Key, &unwrapKeySize);
  if (error != CE2_OK)
    return error;

  /* Let k = k0||k1, where each ki consists of 16 bytes for i = 0, 1.       */ 
  /* Apply LLF_CMLA_DDT_Perm_Inv to the first 8 bytes of ki, keeping the    */
  /* rest of ki unchanged, to produce 16-byte octet string Ki for i = 0, 1. */
  /* Let Key = K0 || K1.                                                    */
  /* i = 0 */
  LLF_CMLA_DDT_Perm_Inv(Key, Key);
  /* i = 1 */
  LLF_CMLA_DDT_Perm_Inv(Key + LLF_CMLA_WRAP_KI_SIZE, Key + LLF_CMLA_WRAP_KI_SIZE);

  return CE2_OK;
} /* End of LLF_CMLA_Unwrap */

/**
****************************************************************
* Function Name: 
*  LLF_CMLA_RSA_Encrypt
*
*  @param[in]  PublKey     - A pointer to to structure containing user RSA Public Key.
*  @param[in]  Message	   - A pointer to message of length 128 bytes.
*  @param[out] EncrMessage - A pointer to output encrypted message of length 128 bytes.
*  
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - error code:
*
* \brief \b 
* Description:
*  The LLF_CMLA_RSA_Encrypt primitive implements algorithm CMLA_RSA_Encrypt
*  [CMLA v1.0-051221].
*
*  \b 
* Algorithm:
*  -# Let Message = M0 || M1, where each Mi consists of 64 bytes 
*     octet for i = 0, 1. 
*  -# Apply LLF_CMLA_DDT_Exp to the first 3 bytes of Mi, keeping the 
*     rest of Mi unchanged, to produce octet string mi for i = 0, 1.
*  -# Let m = m0 || m1. 
*  -# If the integer representative of m is not strictly less than 
*     the RSA modulus, output error and stop. 
*  -# Encrypt m under device public key UserPublKey_ptr with 
*     CE2_RSA_PRIM_Encrypt to produce the octet string EncrMessage  
*     of length 128. 
***************************************************************/
CE2Error_t  LLF_CMLA_RSA_Encrypt(CE2_RSAUserPubKey_t      *UserPublKey_ptr, /*in*/
                                 CE2_CMLA_RSA_MESSAGE_t    Message,         /*in*/
                                 CE2_CMLA_RSA_MESSAGE_t    EncrMessage     /*out*/)
{
  CE2Error_t error;
  DxUint8_t M[CE2_CMLA_RSA_MESSAGE_LEN_BYTES];
  DxUint32_t size;

  /* Let Message = M0 || M1, where each Mi consists of 64 bytes     */
  /* octet for i = 0, 1.                                            */ 
  memcpy(M, Message, CE2_CMLA_RSA_MESSAGE_LEN_BYTES);
  /* Apply LLF_CMLA_DDT_Exp to the first 3 bytes of Mi, keeping the */ 
  /* rest of Mi unchanged, to produce octet string mi for i = 0, 1. */
  /* Let m = m0 || m1. 
  /* i = 0 */
  error = LLF_CMLA_DDT_Exp(M, M);
  if (error != CE2_OK)
    return error;
  /* i = 1 */
  error = LLF_CMLA_DDT_Exp(M + LLF_CMLA_RSA_ENCRYPT_MI_SIZE, 
    M + LLF_CMLA_RSA_ENCRYPT_MI_SIZE);
  if (error != CE2_OK)
    return error;

  /* Verify if the integer representative of m is not strictly */
  /* less than the RSA modulus.                                */
  /* Encrypt M under device public key UserPublKey_ptr with RSA encryption */
  /* to produce the octet string EncrMessage of length 128.                */
  size = CE2_CMLA_RSA_MESSAGE_LEN_BYTES;
  error = LLF_RSA_Encrypt(M, CE2_CMLA_RSA_MESSAGE_LEN_BYTES, M,
    &size, UserPublKey_ptr);
  if (error != CE2_OK)
    return error;
  zeromem(EncrMessage, CE2_CMLA_RSA_MESSAGE_LEN_BYTES - size);
  memcpy(EncrMessage + (CE2_CMLA_RSA_MESSAGE_LEN_BYTES - size), M, size);
 
  return CE2_OK;
} /* End of LLF_CMLA_RSA_Encrypt */


/**
****************************************************************
* Function Name: 
*  LLF_CMLA_RSA_Decrypt
*
*  @param[in]  PrivKey     - A pointer to to structure containing user RSA Private Key.
*  @param[in]  EncrMessage - A pointer to input encrypted message of length 128 bytes.
*  @param[out] Message     - A pointer to output decrypted message of length 128 bytes.
*  
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - error code:
*
* \brief \b 
* Description:
*  The LLF_CMLA_RSA_Decrypt primitive implements algorithm CMLA_RSA_Decrypt
*  [CMLA v1.0-051221].
*
*  \b 
* Algorithm:
*  -# Decrypt EncrMessage under device private key UserPrivKey_ptr with 
*     CE2_RSA_PRIM_Decrypt to produce the octet string m of length 128. 
*  -# Let m = m0 || m1, where each mi consists of 64 bytes octet for i = 0, 1. 
*  -# Apply LLF_CMLA_DDT_Exp_Inv to the first 3 bytes of mi, keeping 
*     the rest of mi unchanged, to produce octet string Mi for i = 0, 1. 
*  -# Let Message = M0 || M1. 
***************************************************************/
CE2Error_t  LLF_CMLA_RSA_Decrypt(CE2_RSAUserPrivKey_t     *UserPrivKey_ptr, /*in*/
                                 CE2_CMLA_RSA_MESSAGE_t    EncrMessage,     /*in*/
                                 CE2_CMLA_RSA_MESSAGE_t    Message         /*out*/)
{
  CE2Error_t error;
  DxUint8_t M[CE2_CMLA_RSA_MESSAGE_LEN_BYTES];

  DxUint32_t size;

  /* Decrypt EncrMessage under device private key UserPrivKey_ptr     */ 
  /* with RSA decryption to produce the octet string m of length 128. */
  size = CE2_CMLA_RSA_MESSAGE_LEN_BYTES;
  error = LLF_RSA_Decrypt(EncrMessage, CE2_CMLA_RSA_MESSAGE_LEN_BYTES,
    M,	&size, UserPrivKey_ptr);
  if (error != CE2_OK)
    return error;
  zeromem(Message, CE2_CMLA_RSA_MESSAGE_LEN_BYTES - size);
  memcpy(Message + (CE2_CMLA_RSA_MESSAGE_LEN_BYTES - size), M, size);

  /* Let m = m0 || m1, where each mi consists of 64 bytes octet for i = 0, 1. */
  /* Apply LLF_CMLA_DDT_Exp_Inv to the first 3 bytes of mi, keeping           */
  /* the rest of mi unchanged, to produce octet string Mi for i = 0, 1.       */
  /* Let Message = M0 || M1.                                                  */
  /* i = 0 */
  error = LLF_CMLA_DDT_Exp_Inv(Message, Message);
  if (error != CE2_OK)
    return error;
  /* i = 1 */
  error = LLF_CMLA_DDT_Exp_Inv(Message + LLF_CMLA_RSA_ENCRYPT_MI_SIZE, 
    Message + LLF_CMLA_RSA_ENCRYPT_MI_SIZE);
  if (error != CE2_OK)
    return error;

  return CE2_OK;
} /* End of LLF_CMLA_RSA_Decrypt */

