1/* SPDX-License-Identifier: BSD-3-Clause */
2/* Copyright(c) 2007-2022 Intel Corporation */
3
4/**
5 ***************************************************************************
6 * @file lac_sym_auth_enc.c
7 *
8 * @ingroup LacAuthEnc
9 *
10 * @description
11 *  Authenticated encryption specific functionality.
12 *  For CCM related code NIST SP 800-38C is followed.
13 *  For GCM related code NIST SP 800-38D is followed.
14 ***************************************************************************/
15
16/*
17*******************************************************************************
18* Include public/global header files
19*******************************************************************************
20*/
21
22#include "cpa.h"
23#include "cpa_cy_sym.h"
24
25#include "icp_accel_devices.h"
26#include "icp_adf_init.h"
27#include "icp_adf_transport.h"
28#include "icp_adf_debug.h"
29/*
30*******************************************************************************
31* Include private header files
32*******************************************************************************
33*/
34#include "lac_log.h"
35#include "lac_common.h"
36#include "lac_session.h"
37#include "lac_sym_auth_enc.h"
38
39/* These defines describe position of the flag fields
40 * in B0 block for CCM algorithm*/
41#define LAC_ALG_CHAIN_CCM_B0_FLAGS_ADATA_SHIFT 6
42#define LAC_ALG_CHAIN_CCM_B0_FLAGS_T_SHIFT 3
43
44/* This macro builds flags field to be put in B0 block for CCM algorithm */
45#define LAC_ALG_CHAIN_CCM_BUILD_B0_FLAGS(Adata, t, q)                          \
46	((((Adata) > 0 ? 1 : 0) << LAC_ALG_CHAIN_CCM_B0_FLAGS_ADATA_SHIFT) |   \
47	 ((((t)-2) >> 1) << LAC_ALG_CHAIN_CCM_B0_FLAGS_T_SHIFT) | ((q)-1))
48
49/**
50 * @ingroup LacAuthEnc
51 */
52CpaStatus
53LacSymAlgChain_CheckCCMData(Cpa8U *pAdditionalAuthData,
54			    Cpa8U *pIv,
55			    Cpa32U messageLenToCipherInBytes,
56			    Cpa32U ivLenInBytes)
57{
58	Cpa8U q = 0;
59
60	LAC_CHECK_NULL_PARAM(pIv);
61	LAC_CHECK_NULL_PARAM(pAdditionalAuthData);
62
63	/* check if n is within permitted range */
64	if (ivLenInBytes < LAC_ALG_CHAIN_CCM_N_LEN_IN_BYTES_MIN ||
65	    ivLenInBytes > LAC_ALG_CHAIN_CCM_N_LEN_IN_BYTES_MAX) {
66		LAC_INVALID_PARAM_LOG2("ivLenInBytes for CCM algorithm  "
67				       "must be between %d and %d inclusive",
68				       LAC_ALG_CHAIN_CCM_N_LEN_IN_BYTES_MIN,
69				       LAC_ALG_CHAIN_CCM_N_LEN_IN_BYTES_MAX);
70		return CPA_STATUS_INVALID_PARAM;
71	}
72
73	q = LAC_ALG_CHAIN_CCM_NQ_CONST - ivLenInBytes;
74
75	/* Check if q is big enough to hold actual length of message to cipher
76	 * if q = 8 -> maxlen = 2^64 always good as
77	 * messageLenToCipherInBytes is 32 bits
78	 * if q = 7 -> maxlen = 2^56 always good
79	 * if q = 6 -> maxlen = 2^48 always good
80	 * if q = 5 -> maxlen = 2^40 always good
81	 * if q = 4 -> maxlen = 2^32 always good.
82	 */
83	if ((messageLenToCipherInBytes >= (1 << (q * LAC_NUM_BITS_IN_BYTE))) &&
84	    (q < sizeof(Cpa32U))) {
85		LAC_INVALID_PARAM_LOG(
86		    "messageLenToCipherInBytes too long for the given"
87		    " ivLenInBytes for CCM algorithm\n");
88		return CPA_STATUS_INVALID_PARAM;
89	}
90
91	return CPA_STATUS_SUCCESS;
92}
93
94
95/**
96 * @ingroup LacAuthEnc
97 */
98void
99LacSymAlgChain_PrepareCCMData(lac_session_desc_t *pSessionDesc,
100			      Cpa8U *pAdditionalAuthData,
101			      Cpa8U *pIv,
102			      Cpa32U messageLenToCipherInBytes,
103			      Cpa32U ivLenInBytes)
104{
105	Cpa8U n =
106	    ivLenInBytes; /* assumes ivLenInBytes has been param checked */
107	Cpa8U q = LAC_ALG_CHAIN_CCM_NQ_CONST - n;
108	Cpa8U lenOfEncodedLen = 0;
109	Cpa16U lenAEncoded = 0;
110	Cpa32U bitStrQ = 0;
111
112	/* populate Ctr0 block - stored in pIv */
113	pIv[0] = (q - 1);
114	/* bytes 1 to n are already set with nonce by the user */
115	/* set last q bytes with 0 */
116	memset(pIv + n + 1, 0, q);
117
118	/* Encode the length of associated data 'a'. As the API limits the
119	 * length
120	 * of an array pointed by pAdditionalAuthData to be 240 bytes max, the
121	 * maximum length of 'a' might be 240 - 16 - 2 = 222. Hence the encoding
122	 * below is simplified. */
123	if (pSessionDesc->aadLenInBytes > 0) {
124		lenOfEncodedLen = sizeof(Cpa16U);
125		lenAEncoded = QAT_UTILS_HOST_TO_NW_16(
126		    (Cpa16U)pSessionDesc->aadLenInBytes);
127	}
128
129	/* populate B0 block */
130	/* first, set the flags field */
131	pAdditionalAuthData[0] =
132	    LAC_ALG_CHAIN_CCM_BUILD_B0_FLAGS(lenOfEncodedLen,
133					     pSessionDesc->hashResultSize,
134					     q);
135	/* bytes 1 to n are already set with nonce by the user*/
136	/* put Q in bytes 16-q...15 */
137	bitStrQ = QAT_UTILS_HOST_TO_NW_32(messageLenToCipherInBytes);
138
139	if (q > sizeof(bitStrQ)) {
140		memset(pAdditionalAuthData + n + 1, 0, q);
141		memcpy(pAdditionalAuthData + n + 1 + (q - sizeof(bitStrQ)),
142		       (Cpa8U *)&bitStrQ,
143		       sizeof(bitStrQ));
144	} else {
145		memcpy(pAdditionalAuthData + n + 1,
146		       ((Cpa8U *)&bitStrQ) + (sizeof(bitStrQ) - q),
147		       q);
148	}
149
150	/* populate B1-Bn blocks */
151	if (lenAEncoded > 0) {
152		*(Cpa16U
153		      *)(&pAdditionalAuthData[1 + LAC_ALG_CHAIN_CCM_NQ_CONST]) =
154		    lenAEncoded;
155		/* Next bytes are already set by the user with
156		 * the associated data 'a' */
157
158		/* Check if padding is required */
159		if (((pSessionDesc->aadLenInBytes + lenOfEncodedLen) %
160		     LAC_HASH_AES_CCM_BLOCK_SIZE) != 0) {
161			Cpa8U paddingLen = 0;
162			Cpa8U paddingIndex = 0;
163
164			paddingLen = LAC_HASH_AES_CCM_BLOCK_SIZE -
165			    ((pSessionDesc->aadLenInBytes + lenOfEncodedLen) %
166			     LAC_HASH_AES_CCM_BLOCK_SIZE);
167
168			paddingIndex = 1 + LAC_ALG_CHAIN_CCM_NQ_CONST;
169			paddingIndex +=
170			    lenOfEncodedLen + pSessionDesc->aadLenInBytes;
171
172			memset(&pAdditionalAuthData[paddingIndex],
173			       0,
174			       paddingLen);
175		}
176	}
177}
178
179/**
180 * @ingroup LacAuthEnc
181 */
182void
183LacSymAlgChain_PrepareGCMData(lac_session_desc_t *pSessionDesc,
184			      Cpa8U *pAdditionalAuthData)
185{
186	Cpa8U paddingLen = 0;
187
188	if ((pSessionDesc->aadLenInBytes % LAC_HASH_AES_GCM_BLOCK_SIZE) != 0) {
189		paddingLen = LAC_HASH_AES_GCM_BLOCK_SIZE -
190		    (pSessionDesc->aadLenInBytes % LAC_HASH_AES_GCM_BLOCK_SIZE);
191
192		memset(&pAdditionalAuthData[pSessionDesc->aadLenInBytes],
193		       0,
194		       paddingLen);
195	}
196}
197