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  */
52 CpaStatus
53 LacSymAlgChain_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  */
98 void
99 LacSymAlgChain_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  */
182 void
183 LacSymAlgChain_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