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