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

/*
//
//  Purpose:
//     Cryptography Primitive.
//     AES-GCM
//
//  Contents:
//        ippsAES_GCMGetTag()
//
*/

#include "owndefs.h"
#include "owncp.h"
#include "pcpaesm.h"
#include "pcptool.h"

#if(_IPP32E>=_IPP32E_K0)
#include "pcpaesauthgcm_avx512.h"
#else
#include "pcpaesauthgcm.h"
#endif /* #if(_IPP32E>=_IPP32E_K0) */

/*F*
//    Name: ippsAES_GCMGetTag
//
// Purpose: Generates authentication tag in the GCM mode.
//
// Returns:                Reason:
//    ippStsNullPtrErr        pDstTag == NULL
//                            pState == NULL
//    ippStsLengthErr         tagLen<=0 || tagLen>16
//    ippStsContextMatchErr  !AESGCM_VALID_ID()
//    ippStsNoErr             no errors
//
// Parameters:
//    pDstTag     pointer to the authentication tag.
//    tagLen      length of the authentication tag *pDstTag in bytes
//    pState      pointer to the context
//
*F*/

IPPFUN(IppStatus, ippsAES_GCMGetTag,(Ipp8u* pDstTag, int tagLen, const IppsAES_GCMState* pState))
{
   /* test State pointer */
   IPP_BAD_PTR1_RET(pState);
   /* use aligned context */
   pState = (IppsAES_GCMState*)( IPP_ALIGNED_PTR(pState, AESGCM_ALIGNMENT) );
   /* test state ID */
   IPP_BADARG_RET(!AESGCM_VALID_ID(pState), ippStsContextMatchErr);

   /* test tag pointer and length */
   IPP_BAD_PTR1_RET(pDstTag);
   IPP_BADARG_RET(tagLen<=0 || tagLen>BLOCK_SIZE, ippStsLengthErr);

#if(_IPP32E>=_IPP32E_K0)
   GetTag_ getTag = AES_GCM_GET_TAG(pState);
   getTag(&AES_GCM_KEY_DATA(pState), &AES_GCM_CONTEXT_DATA(pState), pDstTag, (Ipp64u)tagLen);
#else
   /* get method */
   MulGcm_ hashFunc = AESGCM_HASH(pState);

   __ALIGN16 Ipp8u tmpHash[BLOCK_SIZE];
   Ipp8u tmpCntr[BLOCK_SIZE];

   /* local copy of AAD and text counters (in bits) */
   Ipp64u aadBitLen = AESGCM_AAD_LEN(pState)*BYTESIZE;
   Ipp64u txtBitLen = AESGCM_TXT_LEN(pState)*BYTESIZE;

   /* do local copy of ghash */
   CopyBlock16(AESGCM_GHASH(pState), tmpHash);

   /* complete text processing */
   if(AESGCM_BUFLEN(pState)) {
      hashFunc(tmpHash, AESGCM_HKEY(pState), AesGcmConst_table);
   }

   /* process lengths of AAD and text */
   U32_TO_HSTRING(tmpCntr,   IPP_HIDWORD(aadBitLen));
   U32_TO_HSTRING(tmpCntr+4, IPP_LODWORD(aadBitLen));
   U32_TO_HSTRING(tmpCntr+8, IPP_HIDWORD(txtBitLen));
   U32_TO_HSTRING(tmpCntr+12,IPP_LODWORD(txtBitLen));

   XorBlock16(tmpHash, tmpCntr, tmpHash);
   hashFunc(tmpHash, AESGCM_HKEY(pState), AesGcmConst_table);

   /* add encrypted initial counter */
   XorBlock16(tmpHash, AESGCM_ECOUNTER0(pState), tmpHash);

   /* return tag of required length */
   CopyBlock(tmpHash, pDstTag, tagLen);
#endif /* #if(_IPP32E>=_IPP32E_K0) */

   return ippStsNoErr;
}
