1d4afb5ceSopenharmony_ci /*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci *
24d4afb5ceSopenharmony_ci *  lws_genaes provides an abstraction api for AES in lws that works the
25d4afb5ceSopenharmony_ci *  same whether you are using openssl or mbedtls hash functions underneath.
26d4afb5ceSopenharmony_ci */
27d4afb5ceSopenharmony_ci#include "private-lib-core.h"
28d4afb5ceSopenharmony_ci#if defined(LWS_WITH_JOSE)
29d4afb5ceSopenharmony_ci#include "private-lib-jose.h"
30d4afb5ceSopenharmony_ci#endif
31d4afb5ceSopenharmony_ci
32d4afb5ceSopenharmony_cistatic int operation_map[] = { MBEDTLS_AES_ENCRYPT, MBEDTLS_AES_DECRYPT };
33d4afb5ceSopenharmony_ci
34d4afb5ceSopenharmony_cistatic unsigned int
35d4afb5ceSopenharmony_ci_write_pkcs7_pad(uint8_t *p, int len)
36d4afb5ceSopenharmony_ci{
37d4afb5ceSopenharmony_ci	unsigned int n = 0, padlen = LWS_AES_CBC_BLOCKLEN * ((unsigned int)len /
38d4afb5ceSopenharmony_ci					LWS_AES_CBC_BLOCKLEN + 1) - (unsigned int)len;
39d4afb5ceSopenharmony_ci
40d4afb5ceSopenharmony_ci	p += len;
41d4afb5ceSopenharmony_ci
42d4afb5ceSopenharmony_ci	while (n++ < padlen)
43d4afb5ceSopenharmony_ci		*p++ = (uint8_t)padlen;
44d4afb5ceSopenharmony_ci
45d4afb5ceSopenharmony_ci	return padlen;
46d4afb5ceSopenharmony_ci}
47d4afb5ceSopenharmony_ci
48d4afb5ceSopenharmony_ciint
49d4afb5ceSopenharmony_cilws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op,
50d4afb5ceSopenharmony_ci		  enum enum_aes_modes mode, struct lws_gencrypto_keyelem *el,
51d4afb5ceSopenharmony_ci		  enum enum_aes_padding padding, void *engine)
52d4afb5ceSopenharmony_ci{
53d4afb5ceSopenharmony_ci	int n = 0;
54d4afb5ceSopenharmony_ci
55d4afb5ceSopenharmony_ci	ctx->mode = mode;
56d4afb5ceSopenharmony_ci	ctx->k = el;
57d4afb5ceSopenharmony_ci	ctx->op = (enum enum_aes_operation)operation_map[op];
58d4afb5ceSopenharmony_ci	ctx->underway = 0;
59d4afb5ceSopenharmony_ci	ctx->padding = padding == LWS_GAESP_WITH_PADDING;
60d4afb5ceSopenharmony_ci
61d4afb5ceSopenharmony_ci	switch (ctx->mode) {
62d4afb5ceSopenharmony_ci	case LWS_GAESM_XTS:
63d4afb5ceSopenharmony_ci#if defined(MBEDTLS_CIPHER_MODE_XTS)
64d4afb5ceSopenharmony_ci		mbedtls_aes_xts_init(&ctx->u.ctx_xts);
65d4afb5ceSopenharmony_ci		break;
66d4afb5ceSopenharmony_ci#else
67d4afb5ceSopenharmony_ci		return -1;
68d4afb5ceSopenharmony_ci#endif
69d4afb5ceSopenharmony_ci	case LWS_GAESM_GCM:
70d4afb5ceSopenharmony_ci		mbedtls_gcm_init(&ctx->u.ctx_gcm);
71d4afb5ceSopenharmony_ci		n = mbedtls_gcm_setkey(&ctx->u.ctx_gcm, MBEDTLS_CIPHER_ID_AES,
72d4afb5ceSopenharmony_ci				       ctx->k->buf, ctx->k->len * 8);
73d4afb5ceSopenharmony_ci		if (n) {
74d4afb5ceSopenharmony_ci			lwsl_notice("%s: mbedtls_gcm_setkey: -0x%x\n",
75d4afb5ceSopenharmony_ci				    __func__, -n);
76d4afb5ceSopenharmony_ci			return n;
77d4afb5ceSopenharmony_ci		}
78d4afb5ceSopenharmony_ci		return n;
79d4afb5ceSopenharmony_ci	default:
80d4afb5ceSopenharmony_ci		mbedtls_aes_init(&ctx->u.ctx);
81d4afb5ceSopenharmony_ci		break;
82d4afb5ceSopenharmony_ci	}
83d4afb5ceSopenharmony_ci
84d4afb5ceSopenharmony_ci	switch (op) {
85d4afb5ceSopenharmony_ci	case LWS_GAESO_ENC:
86d4afb5ceSopenharmony_ci		if (ctx->mode == LWS_GAESM_XTS)
87d4afb5ceSopenharmony_ci#if defined(MBEDTLS_CIPHER_MODE_XTS)
88d4afb5ceSopenharmony_ci			n = mbedtls_aes_xts_setkey_enc(&ctx->u.ctx_xts,
89d4afb5ceSopenharmony_ci						       ctx->k->buf,
90d4afb5ceSopenharmony_ci						       ctx->k->len * 8);
91d4afb5ceSopenharmony_ci#else
92d4afb5ceSopenharmony_ci			return -1;
93d4afb5ceSopenharmony_ci#endif
94d4afb5ceSopenharmony_ci		else
95d4afb5ceSopenharmony_ci			n = mbedtls_aes_setkey_enc(&ctx->u.ctx, ctx->k->buf,
96d4afb5ceSopenharmony_ci						   ctx->k->len * 8);
97d4afb5ceSopenharmony_ci		break;
98d4afb5ceSopenharmony_ci	case LWS_GAESO_DEC:
99d4afb5ceSopenharmony_ci		switch (ctx->mode) {
100d4afb5ceSopenharmony_ci		case LWS_GAESM_XTS:
101d4afb5ceSopenharmony_ci#if defined(MBEDTLS_CIPHER_MODE_XTS)
102d4afb5ceSopenharmony_ci			n = mbedtls_aes_xts_setkey_dec(&ctx->u.ctx_xts,
103d4afb5ceSopenharmony_ci						       ctx->k->buf,
104d4afb5ceSopenharmony_ci						       ctx->k->len * 8);
105d4afb5ceSopenharmony_ci			break;
106d4afb5ceSopenharmony_ci#else
107d4afb5ceSopenharmony_ci			return -1;
108d4afb5ceSopenharmony_ci#endif
109d4afb5ceSopenharmony_ci
110d4afb5ceSopenharmony_ci		case LWS_GAESM_CFB128:
111d4afb5ceSopenharmony_ci		case LWS_GAESM_CFB8:
112d4afb5ceSopenharmony_ci		case LWS_GAESM_CTR:
113d4afb5ceSopenharmony_ci		case LWS_GAESM_OFB:
114d4afb5ceSopenharmony_ci			n = mbedtls_aes_setkey_enc(&ctx->u.ctx, ctx->k->buf,
115d4afb5ceSopenharmony_ci						   ctx->k->len * 8);
116d4afb5ceSopenharmony_ci			break;
117d4afb5ceSopenharmony_ci		default:
118d4afb5ceSopenharmony_ci			n = mbedtls_aes_setkey_dec(&ctx->u.ctx, ctx->k->buf,
119d4afb5ceSopenharmony_ci						   ctx->k->len * 8);
120d4afb5ceSopenharmony_ci			break;
121d4afb5ceSopenharmony_ci		}
122d4afb5ceSopenharmony_ci		break;
123d4afb5ceSopenharmony_ci	}
124d4afb5ceSopenharmony_ci
125d4afb5ceSopenharmony_ci	if (n)
126d4afb5ceSopenharmony_ci		lwsl_notice("%s: setting key: -0x%x\n", __func__, -n);
127d4afb5ceSopenharmony_ci
128d4afb5ceSopenharmony_ci	return n;
129d4afb5ceSopenharmony_ci}
130d4afb5ceSopenharmony_ci
131d4afb5ceSopenharmony_ciint
132d4afb5ceSopenharmony_cilws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen)
133d4afb5ceSopenharmony_ci{
134d4afb5ceSopenharmony_ci#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
135d4afb5ceSopenharmony_ci	size_t last_len = 0;
136d4afb5ceSopenharmony_ci	uint8_t last[16];
137d4afb5ceSopenharmony_ci#endif
138d4afb5ceSopenharmony_ci	int n;
139d4afb5ceSopenharmony_ci
140d4afb5ceSopenharmony_ci	if (ctx->mode == LWS_GAESM_GCM) {
141d4afb5ceSopenharmony_ci#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
142d4afb5ceSopenharmony_ci		n = mbedtls_gcm_finish(&ctx->u.ctx_gcm, last, sizeof(last),
143d4afb5ceSopenharmony_ci					&last_len, tag, tlen);
144d4afb5ceSopenharmony_ci#else
145d4afb5ceSopenharmony_ci		n = mbedtls_gcm_finish(&ctx->u.ctx_gcm, tag, tlen);
146d4afb5ceSopenharmony_ci#endif
147d4afb5ceSopenharmony_ci
148d4afb5ceSopenharmony_ci		if (n)
149d4afb5ceSopenharmony_ci			lwsl_notice("%s: mbedtls_gcm_finish: -0x%x\n",
150d4afb5ceSopenharmony_ci				    __func__, -n);
151d4afb5ceSopenharmony_ci		if (tag && ctx->op == MBEDTLS_AES_DECRYPT && !n) {
152d4afb5ceSopenharmony_ci			if (lws_timingsafe_bcmp(ctx->tag, tag, (unsigned int)ctx->taglen)) {
153d4afb5ceSopenharmony_ci				lwsl_err("%s: lws_genaes_crypt tag "
154d4afb5ceSopenharmony_ci					 "mismatch (bad first)\n",
155d4afb5ceSopenharmony_ci						__func__);
156d4afb5ceSopenharmony_ci				lwsl_hexdump_notice(tag, tlen);
157d4afb5ceSopenharmony_ci				lwsl_hexdump_notice(ctx->tag, (unsigned int)ctx->taglen);
158d4afb5ceSopenharmony_ci				n = -1;
159d4afb5ceSopenharmony_ci			}
160d4afb5ceSopenharmony_ci		}
161d4afb5ceSopenharmony_ci		mbedtls_gcm_free(&ctx->u.ctx_gcm);
162d4afb5ceSopenharmony_ci		return n;
163d4afb5ceSopenharmony_ci	}
164d4afb5ceSopenharmony_ci	if (ctx->mode == LWS_GAESM_XTS)
165d4afb5ceSopenharmony_ci#if defined(MBEDTLS_CIPHER_MODE_XTS)
166d4afb5ceSopenharmony_ci		mbedtls_aes_xts_free(&ctx->u.ctx_xts);
167d4afb5ceSopenharmony_ci#else
168d4afb5ceSopenharmony_ci		return -1;
169d4afb5ceSopenharmony_ci#endif
170d4afb5ceSopenharmony_ci	else
171d4afb5ceSopenharmony_ci		mbedtls_aes_free(&ctx->u.ctx);
172d4afb5ceSopenharmony_ci
173d4afb5ceSopenharmony_ci	return 0;
174d4afb5ceSopenharmony_ci}
175d4afb5ceSopenharmony_ci
176d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_mbedtls_internal_aes_encrypt)
177d4afb5ceSopenharmony_cistatic int
178d4afb5ceSopenharmony_cilws_genaes_rfc3394_wrap(int wrap, int cek_bits, const uint8_t *kek,
179d4afb5ceSopenharmony_ci			int kek_bits, const uint8_t *in, uint8_t *out)
180d4afb5ceSopenharmony_ci{
181d4afb5ceSopenharmony_ci	int n, m, ret = -1, c64 = cek_bits / 64;
182d4afb5ceSopenharmony_ci	mbedtls_aes_context ctx;
183d4afb5ceSopenharmony_ci	uint8_t a[8], b[16];
184d4afb5ceSopenharmony_ci
185d4afb5ceSopenharmony_ci	/*
186d4afb5ceSopenharmony_ci	 * notice the KEK key used to perform the wrapping or unwrapping is
187d4afb5ceSopenharmony_ci	 * always the size of the AES key used, eg, A128KW == 128 bits.  The
188d4afb5ceSopenharmony_ci	 * key being wrapped or unwrapped may be larger and is set by the
189d4afb5ceSopenharmony_ci	 * 'bits' parameter.
190d4afb5ceSopenharmony_ci	 *
191d4afb5ceSopenharmony_ci	 * If it's larger than the KEK key size bits, we iterate over it
192d4afb5ceSopenharmony_ci	 */
193d4afb5ceSopenharmony_ci
194d4afb5ceSopenharmony_ci	mbedtls_aes_init(&ctx);
195d4afb5ceSopenharmony_ci
196d4afb5ceSopenharmony_ci	if (wrap) {
197d4afb5ceSopenharmony_ci		/*
198d4afb5ceSopenharmony_ci		 * The inputs to the key wrapping process are the KEK and the
199d4afb5ceSopenharmony_ci		 * plaintext to be wrapped.  The plaintext consists of n 64-bit
200d4afb5ceSopenharmony_ci		 * blocks, containing the key data being wrapped.
201d4afb5ceSopenharmony_ci		 *
202d4afb5ceSopenharmony_ci		 * Inputs:      Plaintext, n 64-bit values {P1, P2, ..., Pn},
203d4afb5ceSopenharmony_ci		 *		and Key, K (the KEK).
204d4afb5ceSopenharmony_ci		 * Outputs:     Ciphertext, (n+1) 64-bit values
205d4afb5ceSopenharmony_ci		 *		{C0, C1, ..., Cn}.
206d4afb5ceSopenharmony_ci		 *
207d4afb5ceSopenharmony_ci		 * The default initial value (IV) is defined to be the
208d4afb5ceSopenharmony_ci		 * hexadecimal constant:
209d4afb5ceSopenharmony_ci		 *
210d4afb5ceSopenharmony_ci		 * A[0] = IV = A6A6A6A6A6A6A6A6
211d4afb5ceSopenharmony_ci		 */
212d4afb5ceSopenharmony_ci		memset(out, 0xa6, 8);
213d4afb5ceSopenharmony_ci		memcpy(out + 8, in, 8 * (unsigned int)c64);
214d4afb5ceSopenharmony_ci		n = mbedtls_aes_setkey_enc(&ctx, kek, (unsigned int)kek_bits);
215d4afb5ceSopenharmony_ci	} else {
216d4afb5ceSopenharmony_ci		/*
217d4afb5ceSopenharmony_ci		 * 2.2.2 Key Unwrap
218d4afb5ceSopenharmony_ci		 *
219d4afb5ceSopenharmony_ci		 * The inputs to the unwrap process are the KEK and (n+1)
220d4afb5ceSopenharmony_ci		 * 64-bit blocks of ciphertext consisting of previously
221d4afb5ceSopenharmony_ci		 * wrapped key.  It returns n blocks of plaintext consisting
222d4afb5ceSopenharmony_ci		 * of the n 64-bit blocks of the decrypted key data.
223d4afb5ceSopenharmony_ci		 *
224d4afb5ceSopenharmony_ci		 * Inputs:  Ciphertext, (n+1) 64-bit values {C0, C1, ..., Cn},
225d4afb5ceSopenharmony_ci		 * and Key, K (the KEK).
226d4afb5ceSopenharmony_ci		 *
227d4afb5ceSopenharmony_ci		 * Outputs: Plaintext, n 64-bit values {P1, P2, ..., Pn}.
228d4afb5ceSopenharmony_ci		 */
229d4afb5ceSopenharmony_ci		memcpy(a, in, 8);
230d4afb5ceSopenharmony_ci		memcpy(out, in + 8, 8 * (unsigned int)c64);
231d4afb5ceSopenharmony_ci		n = mbedtls_aes_setkey_dec(&ctx, kek, (unsigned int)kek_bits);
232d4afb5ceSopenharmony_ci	}
233d4afb5ceSopenharmony_ci
234d4afb5ceSopenharmony_ci	if (n < 0) {
235d4afb5ceSopenharmony_ci		lwsl_err("%s: setkey failed\n", __func__);
236d4afb5ceSopenharmony_ci		goto bail;
237d4afb5ceSopenharmony_ci	}
238d4afb5ceSopenharmony_ci
239d4afb5ceSopenharmony_ci	if (wrap) {
240d4afb5ceSopenharmony_ci		for (n = 0; n <= 5; n++) {
241d4afb5ceSopenharmony_ci			uint8_t *r = out + 8;
242d4afb5ceSopenharmony_ci			for (m = 1; m <= c64; m++) {
243d4afb5ceSopenharmony_ci				memcpy(b, out, 8);
244d4afb5ceSopenharmony_ci				memcpy(b + 8, r, 8);
245d4afb5ceSopenharmony_ci				if (mbedtls_internal_aes_encrypt(&ctx, b, b))
246d4afb5ceSopenharmony_ci					goto bail;
247d4afb5ceSopenharmony_ci
248d4afb5ceSopenharmony_ci				memcpy(out, b, 8);
249d4afb5ceSopenharmony_ci				out[7] ^= (uint8_t)(c64 * n + m);
250d4afb5ceSopenharmony_ci				memcpy(r, b + 8, 8);
251d4afb5ceSopenharmony_ci				r += 8;
252d4afb5ceSopenharmony_ci			}
253d4afb5ceSopenharmony_ci		}
254d4afb5ceSopenharmony_ci		ret = 0;
255d4afb5ceSopenharmony_ci	} else {
256d4afb5ceSopenharmony_ci		/*
257d4afb5ceSopenharmony_ci		 *
258d4afb5ceSopenharmony_ci		 */
259d4afb5ceSopenharmony_ci		for (n = 5; n >= 0; n--) {
260d4afb5ceSopenharmony_ci			uint8_t *r = out + (c64 - 1) * 8;
261d4afb5ceSopenharmony_ci			for (m = c64; m >= 1; m--) {
262d4afb5ceSopenharmony_ci				memcpy(b, a, 8);
263d4afb5ceSopenharmony_ci				b[7] ^= (uint8_t)(c64 * n + m);
264d4afb5ceSopenharmony_ci				memcpy(b + 8, r, 8);
265d4afb5ceSopenharmony_ci				if (mbedtls_internal_aes_decrypt(&ctx, b, b))
266d4afb5ceSopenharmony_ci					goto bail;
267d4afb5ceSopenharmony_ci
268d4afb5ceSopenharmony_ci				memcpy(a, b, 8);
269d4afb5ceSopenharmony_ci				memcpy(r, b + 8, 8);
270d4afb5ceSopenharmony_ci				r -= 8;
271d4afb5ceSopenharmony_ci			}
272d4afb5ceSopenharmony_ci		}
273d4afb5ceSopenharmony_ci
274d4afb5ceSopenharmony_ci		ret = 0;
275d4afb5ceSopenharmony_ci		for (n = 0; n < 8; n++)
276d4afb5ceSopenharmony_ci			if (a[n] != 0xa6)
277d4afb5ceSopenharmony_ci				ret = -1;
278d4afb5ceSopenharmony_ci	}
279d4afb5ceSopenharmony_ci
280d4afb5ceSopenharmony_cibail:
281d4afb5ceSopenharmony_ci	if (ret)
282d4afb5ceSopenharmony_ci		lwsl_notice("%s: failed\n", __func__);
283d4afb5ceSopenharmony_ci	mbedtls_aes_free(&ctx);
284d4afb5ceSopenharmony_ci
285d4afb5ceSopenharmony_ci	return ret;
286d4afb5ceSopenharmony_ci}
287d4afb5ceSopenharmony_ci#endif
288d4afb5ceSopenharmony_ci
289d4afb5ceSopenharmony_ciint
290d4afb5ceSopenharmony_cilws_genaes_crypt(struct lws_genaes_ctx *ctx, const uint8_t *in, size_t len,
291d4afb5ceSopenharmony_ci		 uint8_t *out, uint8_t *iv_or_nonce_ctr_or_data_unit_16,
292d4afb5ceSopenharmony_ci		 uint8_t *stream_block_16, size_t *nc_or_iv_off, int taglen)
293d4afb5ceSopenharmony_ci{
294d4afb5ceSopenharmony_ci	uint8_t iv[LWS_JWE_AES_IV_BYTES], sb[16];
295d4afb5ceSopenharmony_ci	int n = 0;
296d4afb5ceSopenharmony_ci
297d4afb5ceSopenharmony_ci	switch (ctx->mode) {
298d4afb5ceSopenharmony_ci	case LWS_GAESM_KW:
299d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_mbedtls_internal_aes_encrypt)
300d4afb5ceSopenharmony_ci		/* a key of length ctx->k->len is wrapped by a 128-bit KEK */
301d4afb5ceSopenharmony_ci		n = lws_genaes_rfc3394_wrap(ctx->op == MBEDTLS_AES_ENCRYPT,
302d4afb5ceSopenharmony_ci				(ctx->op == MBEDTLS_AES_ENCRYPT ? (int)len * 8 :
303d4afb5ceSopenharmony_ci						((int)len - 8) * 8), ctx->k->buf,
304d4afb5ceSopenharmony_ci						(int)ctx->k->len * 8,
305d4afb5ceSopenharmony_ci				in, out);
306d4afb5ceSopenharmony_ci		break;
307d4afb5ceSopenharmony_ci#else
308d4afb5ceSopenharmony_ci		lwsl_err("%s: your mbedtls is too old\n", __func__);
309d4afb5ceSopenharmony_ci		return -1;
310d4afb5ceSopenharmony_ci#endif
311d4afb5ceSopenharmony_ci	case LWS_GAESM_CBC:
312d4afb5ceSopenharmony_ci		memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16);
313d4afb5ceSopenharmony_ci
314d4afb5ceSopenharmony_ci		/*
315d4afb5ceSopenharmony_ci		 * If encrypting, we do the PKCS#7 padding.
316d4afb5ceSopenharmony_ci		 * During decryption, the caller will need to unpad.
317d4afb5ceSopenharmony_ci		 */
318d4afb5ceSopenharmony_ci		if (ctx->padding && ctx->op == MBEDTLS_AES_ENCRYPT) {
319d4afb5ceSopenharmony_ci			/*
320d4afb5ceSopenharmony_ci			 * Since we don't want to burden the caller with
321d4afb5ceSopenharmony_ci			 * the over-allocation at the end of the input,
322d4afb5ceSopenharmony_ci			 * we have to allocate a temp with space for it
323d4afb5ceSopenharmony_ci			 */
324d4afb5ceSopenharmony_ci			uint8_t *padin = (uint8_t *)lws_malloc(
325d4afb5ceSopenharmony_ci				lws_gencrypto_padded_length(LWS_AES_CBC_BLOCKLEN, len),
326d4afb5ceSopenharmony_ci								__func__);
327d4afb5ceSopenharmony_ci
328d4afb5ceSopenharmony_ci			if (!padin)
329d4afb5ceSopenharmony_ci				return -1;
330d4afb5ceSopenharmony_ci
331d4afb5ceSopenharmony_ci			memcpy(padin, in, len);
332d4afb5ceSopenharmony_ci			len += _write_pkcs7_pad((uint8_t *)padin, (int)len);
333d4afb5ceSopenharmony_ci			n = mbedtls_aes_crypt_cbc(&ctx->u.ctx, (int)ctx->op, len, iv,
334d4afb5ceSopenharmony_ci						  padin, out);
335d4afb5ceSopenharmony_ci			lws_free(padin);
336d4afb5ceSopenharmony_ci		} else
337d4afb5ceSopenharmony_ci			n = mbedtls_aes_crypt_cbc(&ctx->u.ctx, (int)ctx->op, len, iv,
338d4afb5ceSopenharmony_ci                                      in, out);
339d4afb5ceSopenharmony_ci
340d4afb5ceSopenharmony_ci		break;
341d4afb5ceSopenharmony_ci
342d4afb5ceSopenharmony_ci	case LWS_GAESM_CFB128:
343d4afb5ceSopenharmony_ci		memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16);
344d4afb5ceSopenharmony_ci		n = mbedtls_aes_crypt_cfb128(&ctx->u.ctx, (int)ctx->op, len,
345d4afb5ceSopenharmony_ci					     nc_or_iv_off, iv, in, out);
346d4afb5ceSopenharmony_ci		break;
347d4afb5ceSopenharmony_ci
348d4afb5ceSopenharmony_ci	case LWS_GAESM_CFB8:
349d4afb5ceSopenharmony_ci		memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16);
350d4afb5ceSopenharmony_ci		n = mbedtls_aes_crypt_cfb8(&ctx->u.ctx, (int)ctx->op, len, iv,
351d4afb5ceSopenharmony_ci					   in, out);
352d4afb5ceSopenharmony_ci		break;
353d4afb5ceSopenharmony_ci
354d4afb5ceSopenharmony_ci	case LWS_GAESM_CTR:
355d4afb5ceSopenharmony_ci		memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16);
356d4afb5ceSopenharmony_ci		memcpy(sb, stream_block_16, 16);
357d4afb5ceSopenharmony_ci		n = mbedtls_aes_crypt_ctr(&ctx->u.ctx, len, nc_or_iv_off,
358d4afb5ceSopenharmony_ci					  iv, sb, in, out);
359d4afb5ceSopenharmony_ci		memcpy(iv_or_nonce_ctr_or_data_unit_16, iv, 16);
360d4afb5ceSopenharmony_ci		memcpy(stream_block_16, sb, 16);
361d4afb5ceSopenharmony_ci		break;
362d4afb5ceSopenharmony_ci
363d4afb5ceSopenharmony_ci	case LWS_GAESM_ECB:
364d4afb5ceSopenharmony_ci		n = mbedtls_aes_crypt_ecb(&ctx->u.ctx, (int)ctx->op, in, out);
365d4afb5ceSopenharmony_ci		break;
366d4afb5ceSopenharmony_ci
367d4afb5ceSopenharmony_ci	case LWS_GAESM_OFB:
368d4afb5ceSopenharmony_ci#if defined(MBEDTLS_CIPHER_MODE_OFB)
369d4afb5ceSopenharmony_ci		memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16);
370d4afb5ceSopenharmony_ci		n = mbedtls_aes_crypt_ofb(&ctx->u.ctx, len, nc_or_iv_off, iv,
371d4afb5ceSopenharmony_ci					  in, out);
372d4afb5ceSopenharmony_ci		break;
373d4afb5ceSopenharmony_ci#else
374d4afb5ceSopenharmony_ci		return -1;
375d4afb5ceSopenharmony_ci#endif
376d4afb5ceSopenharmony_ci
377d4afb5ceSopenharmony_ci	case LWS_GAESM_XTS:
378d4afb5ceSopenharmony_ci#if defined(MBEDTLS_CIPHER_MODE_XTS)
379d4afb5ceSopenharmony_ci		memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16);
380d4afb5ceSopenharmony_ci		n = mbedtls_aes_crypt_xts(&ctx->u.ctx_xts, (int)ctx->op, len, iv,
381d4afb5ceSopenharmony_ci					  in, out);
382d4afb5ceSopenharmony_ci		break;
383d4afb5ceSopenharmony_ci#else
384d4afb5ceSopenharmony_ci		return -1;
385d4afb5ceSopenharmony_ci#endif
386d4afb5ceSopenharmony_ci	case LWS_GAESM_GCM:
387d4afb5ceSopenharmony_ci		if (!ctx->underway) {
388d4afb5ceSopenharmony_ci			ctx->underway = 1;
389d4afb5ceSopenharmony_ci
390d4afb5ceSopenharmony_ci			memcpy(ctx->tag, stream_block_16, (unsigned int)taglen);
391d4afb5ceSopenharmony_ci			ctx->taglen = taglen;
392d4afb5ceSopenharmony_ci
393d4afb5ceSopenharmony_ci			/*
394d4afb5ceSopenharmony_ci			 * iv:                   iv_or_nonce_ctr_or_data_unit_16
395d4afb5ceSopenharmony_ci			 * iv_len:               *nc_or_iv_off
396d4afb5ceSopenharmony_ci			 * stream_block_16:      pointer to tag
397d4afb5ceSopenharmony_ci			 * additional data:      in
398d4afb5ceSopenharmony_ci			 * additional data len:  len
399d4afb5ceSopenharmony_ci			 */
400d4afb5ceSopenharmony_ci
401d4afb5ceSopenharmony_ci#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
402d4afb5ceSopenharmony_ci			n = mbedtls_gcm_starts(&ctx->u.ctx_gcm, (int)ctx->op,
403d4afb5ceSopenharmony_ci					       iv_or_nonce_ctr_or_data_unit_16,
404d4afb5ceSopenharmony_ci					       *nc_or_iv_off);
405d4afb5ceSopenharmony_ci			if (!n)
406d4afb5ceSopenharmony_ci				n = mbedtls_gcm_update_ad(&ctx->u.ctx_gcm,
407d4afb5ceSopenharmony_ci							  in, len);
408d4afb5ceSopenharmony_ci#else
409d4afb5ceSopenharmony_ci			n = mbedtls_gcm_starts(&ctx->u.ctx_gcm, (int)ctx->op,
410d4afb5ceSopenharmony_ci					       iv_or_nonce_ctr_or_data_unit_16,
411d4afb5ceSopenharmony_ci					       *nc_or_iv_off, in, len);
412d4afb5ceSopenharmony_ci#endif
413d4afb5ceSopenharmony_ci			if (n) {
414d4afb5ceSopenharmony_ci				lwsl_notice("%s: mbedtls_gcm_starts: -0x%x\n",
415d4afb5ceSopenharmony_ci					    __func__, -n);
416d4afb5ceSopenharmony_ci
417d4afb5ceSopenharmony_ci				return -1;
418d4afb5ceSopenharmony_ci			}
419d4afb5ceSopenharmony_ci			break;
420d4afb5ceSopenharmony_ci		}
421d4afb5ceSopenharmony_ci
422d4afb5ceSopenharmony_ci#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
423d4afb5ceSopenharmony_ci		{
424d4afb5ceSopenharmony_ci			size_t al;
425d4afb5ceSopenharmony_ci
426d4afb5ceSopenharmony_ci			n = mbedtls_gcm_update(&ctx->u.ctx_gcm, in, len, out, len, &al);
427d4afb5ceSopenharmony_ci		}
428d4afb5ceSopenharmony_ci#else
429d4afb5ceSopenharmony_ci		n = mbedtls_gcm_update(&ctx->u.ctx_gcm, len, in, out);
430d4afb5ceSopenharmony_ci#endif
431d4afb5ceSopenharmony_ci		if (n) {
432d4afb5ceSopenharmony_ci			lwsl_notice("%s: mbedtls_gcm_update: -0x%x\n",
433d4afb5ceSopenharmony_ci				    __func__, -n);
434d4afb5ceSopenharmony_ci
435d4afb5ceSopenharmony_ci			return -1;
436d4afb5ceSopenharmony_ci		}
437d4afb5ceSopenharmony_ci		break;
438d4afb5ceSopenharmony_ci	}
439d4afb5ceSopenharmony_ci
440d4afb5ceSopenharmony_ci	if (n) {
441d4afb5ceSopenharmony_ci		lwsl_notice("%s: failed: -0x%x, len %d\n", __func__, -n, (int)len);
442d4afb5ceSopenharmony_ci
443d4afb5ceSopenharmony_ci		return -1;
444d4afb5ceSopenharmony_ci	}
445d4afb5ceSopenharmony_ci
446d4afb5ceSopenharmony_ci	return 0;
447d4afb5ceSopenharmony_ci}
448