1 /*
2  * Copyright (c) 2016 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Crypto Cipher APIs
10  *
11  * This file contains the Crypto Abstraction layer APIs.
12  *
13  * [Experimental] Users should note that the APIs can change
14  * as a part of ongoing development.
15  */
16 
17 #ifndef ZEPHYR_INCLUDE_CRYPTO_H_
18 #define ZEPHYR_INCLUDE_CRYPTO_H_
19 
20 #include <zephyr/device.h>
21 #include <errno.h>
22 #include <zephyr/sys/util.h>
23 #include <zephyr/sys/__assert.h>
24 #include <zephyr/crypto/hash.h>
25 #include "cipher.h"
26 
27 /**
28  * @brief Crypto APIs
29  * @defgroup crypto Crypto
30  * @since 1.7
31  * @version 1.0.0
32  * @ingroup os_services
33  * @{
34  */
35 
36 
37 /* ctx.flags values. Not all drivers support all flags.
38  * A user app can query the supported hw / driver
39  * capabilities via provided API (crypto_query_hwcaps()), and choose a
40  * supported config during the session setup.
41  */
42 #define CAP_OPAQUE_KEY_HNDL		BIT(0)
43 #define CAP_RAW_KEY			BIT(1)
44 
45 /* TBD to define */
46 #define CAP_KEY_LOADING_API		BIT(2)
47 
48 /** Whether the output is placed in separate buffer or not */
49 #define CAP_INPLACE_OPS			BIT(3)
50 #define CAP_SEPARATE_IO_BUFS		BIT(4)
51 
52 /**
53  * These denotes if the output (completion of a cipher_xxx_op) is conveyed
54  * by the op function returning, or it is conveyed by an async notification
55  */
56 #define CAP_SYNC_OPS			BIT(5)
57 #define CAP_ASYNC_OPS			BIT(6)
58 
59 /** Whether the hardware/driver supports autononce feature */
60 #define CAP_AUTONONCE			BIT(7)
61 
62 /** Don't prefix IV to cipher blocks */
63 #define CAP_NO_IV_PREFIX		BIT(8)
64 
65 /* More flags to be added as necessary */
66 
67 /** @brief Crypto driver API definition. */
68 __subsystem struct crypto_driver_api {
69 	int (*query_hw_caps)(const struct device *dev);
70 
71 	/* Setup a crypto session */
72 	int (*cipher_begin_session)(const struct device *dev, struct cipher_ctx *ctx,
73 			     enum cipher_algo algo, enum cipher_mode mode,
74 			     enum cipher_op op_type);
75 
76 	/* Tear down an established session */
77 	int (*cipher_free_session)(const struct device *dev, struct cipher_ctx *ctx);
78 
79 	/* Register async crypto op completion callback with the driver */
80 	int (*cipher_async_callback_set)(const struct device *dev,
81 					 cipher_completion_cb cb);
82 
83 	/* Setup a hash session */
84 	int (*hash_begin_session)(const struct device *dev, struct hash_ctx *ctx,
85 				  enum hash_algo algo);
86 	/* Tear down an established hash session */
87 	int (*hash_free_session)(const struct device *dev, struct hash_ctx *ctx);
88 	/* Register async hash op completion callback with the driver */
89 	int (*hash_async_callback_set)(const struct device *dev,
90 					 hash_completion_cb cb);
91 };
92 
93 /* Following are the public API a user app may call.
94  * The first two relate to crypto "session" setup / teardown. Further we
95  * have four cipher mode specific (CTR, CCM, CBC ...) calls to perform the
96  * actual crypto operation in the context of a session. Also we have an
97  * API to provide the callback for async operations.
98  */
99 
100 /**
101  * @brief Query the crypto hardware capabilities
102  *
103  * This API is used by the app to query the capabilities supported by the
104  * crypto device. Based on this the app can specify a subset of the supported
105  * options to be honored for a session during cipher_begin_session().
106  *
107  * @param dev Pointer to the device structure for the driver instance.
108  *
109  * @return bitmask of supported options.
110  */
crypto_query_hwcaps(const struct device * dev)111 static inline int crypto_query_hwcaps(const struct device *dev)
112 {
113 	struct crypto_driver_api *api;
114 	int tmp;
115 
116 	api = (struct crypto_driver_api *) dev->api;
117 
118 	tmp = api->query_hw_caps(dev);
119 
120 	__ASSERT((tmp & (CAP_OPAQUE_KEY_HNDL | CAP_RAW_KEY)) != 0,
121 		 "Driver should support at least one key type: RAW/Opaque");
122 
123 	__ASSERT((tmp & (CAP_INPLACE_OPS | CAP_SEPARATE_IO_BUFS)) != 0,
124 	     "Driver should support at least one IO buf type: Inplace/separate");
125 
126 	__ASSERT((tmp & (CAP_SYNC_OPS | CAP_ASYNC_OPS)) != 0,
127 		"Driver should support at least one op-type: sync/async");
128 	return tmp;
129 
130 }
131 
132 /**
133  * @}
134  */
135 
136 /**
137  * @brief Crypto Cipher APIs
138  * @defgroup crypto_cipher Cipher
139  * @ingroup crypto
140  * @{
141  */
142 
143 /**
144  * @brief Setup a crypto session
145  *
146  * Initializes one time parameters, like the session key, algorithm and cipher
147  * mode which may remain constant for all operations in the session. The state
148  * may be cached in hardware and/or driver data state variables.
149  *
150  * @param  dev      Pointer to the device structure for the driver instance.
151  * @param  ctx      Pointer to the context structure. Various one time
152  *			parameters like key, keylength, etc. are supplied via
153  *			this structure. The structure documentation specifies
154  *			which fields are to be populated by the app before
155  *			making this call.
156  * @param  algo     The crypto algorithm to be used in this session. e.g AES
157  * @param  mode     The cipher mode to be used in this session. e.g CBC, CTR
158  * @param  optype   Whether we should encrypt or decrypt in this session
159  *
160  * @return 0 on success, negative errno code on fail.
161  */
cipher_begin_session(const struct device * dev,struct cipher_ctx * ctx,enum cipher_algo algo,enum cipher_mode mode,enum cipher_op optype)162 static inline int cipher_begin_session(const struct device *dev,
163 				       struct cipher_ctx *ctx,
164 				       enum cipher_algo algo,
165 				       enum cipher_mode  mode,
166 				       enum cipher_op optype)
167 {
168 	struct crypto_driver_api *api;
169 	uint32_t flags;
170 
171 	api = (struct crypto_driver_api *) dev->api;
172 	ctx->device = dev;
173 	ctx->ops.cipher_mode = mode;
174 
175 	flags = (ctx->flags & (CAP_OPAQUE_KEY_HNDL | CAP_RAW_KEY));
176 	__ASSERT(flags != 0U, "Keytype missing: RAW Key or OPAQUE handle");
177 	__ASSERT(flags != (CAP_OPAQUE_KEY_HNDL | CAP_RAW_KEY),
178 			 "conflicting options for keytype");
179 
180 	flags = (ctx->flags & (CAP_INPLACE_OPS | CAP_SEPARATE_IO_BUFS));
181 	__ASSERT(flags != 0U, "IO buffer type missing");
182 	__ASSERT(flags != (CAP_INPLACE_OPS | CAP_SEPARATE_IO_BUFS),
183 			"conflicting options for IO buffer type");
184 
185 	flags = (ctx->flags & (CAP_SYNC_OPS | CAP_ASYNC_OPS));
186 	__ASSERT(flags != 0U, "sync/async type missing");
187 	__ASSERT(flags != (CAP_SYNC_OPS |  CAP_ASYNC_OPS),
188 			"conflicting options for sync/async");
189 
190 	return api->cipher_begin_session(dev, ctx, algo, mode, optype);
191 }
192 
193 /**
194  * @brief Cleanup a crypto session
195  *
196  * Clears the hardware and/or driver state of a previous session.
197  *
198  * @param  dev      Pointer to the device structure for the driver instance.
199  * @param  ctx      Pointer to the crypto context structure of the session
200  *			to be freed.
201  *
202  * @return 0 on success, negative errno code on fail.
203  */
cipher_free_session(const struct device * dev,struct cipher_ctx * ctx)204 static inline int cipher_free_session(const struct device *dev,
205 				      struct cipher_ctx *ctx)
206 {
207 	struct crypto_driver_api *api;
208 
209 	api = (struct crypto_driver_api *) dev->api;
210 
211 	return api->cipher_free_session(dev, ctx);
212 }
213 
214 /**
215  * @brief Registers an async crypto op completion callback with the driver
216  *
217  * The application can register an async crypto op completion callback handler
218  * to be invoked by the driver, on completion of a prior request submitted via
219  * cipher_do_op(). Based on crypto device hardware semantics, this is likely to
220  * be invoked from an ISR context.
221  *
222  * @param  dev   Pointer to the device structure for the driver instance.
223  * @param  cb    Pointer to application callback to be called by the driver.
224  *
225  * @return 0 on success, -ENOTSUP if the driver does not support async op,
226  *			  negative errno code on other error.
227  */
cipher_callback_set(const struct device * dev,cipher_completion_cb cb)228 static inline int cipher_callback_set(const struct device *dev,
229 				      cipher_completion_cb cb)
230 {
231 	struct crypto_driver_api *api;
232 
233 	api = (struct crypto_driver_api *) dev->api;
234 
235 	if (api->cipher_async_callback_set) {
236 		return api->cipher_async_callback_set(dev, cb);
237 	}
238 
239 	return -ENOTSUP;
240 
241 }
242 
243 /**
244  * @brief Perform single-block crypto operation (ECB cipher mode). This
245  * should not be overloaded to operate on multiple blocks for security reasons.
246  *
247  * @param  ctx       Pointer to the crypto context of this op.
248  * @param  pkt   Structure holding the input/output buffer pointers.
249  *
250  * @return 0 on success, negative errno code on fail.
251  */
cipher_block_op(struct cipher_ctx * ctx,struct cipher_pkt * pkt)252 static inline int cipher_block_op(struct cipher_ctx *ctx,
253 				     struct cipher_pkt *pkt)
254 {
255 	__ASSERT(ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_ECB, "ECB mode "
256 		 "session invoking a different mode handler");
257 
258 	pkt->ctx = ctx;
259 	return ctx->ops.block_crypt_hndlr(ctx, pkt);
260 }
261 
262 /**
263  * @brief Perform Cipher Block Chaining (CBC) crypto operation.
264  *
265  * @param  ctx       Pointer to the crypto context of this op.
266  * @param  pkt   Structure holding the input/output buffer pointers.
267  * @param  iv        Initialization Vector (IV) for the operation. Same
268  *			 IV value should not be reused across multiple
269  *			 operations (within a session context) for security.
270  *
271  * @return 0 on success, negative errno code on fail.
272  */
cipher_cbc_op(struct cipher_ctx * ctx,struct cipher_pkt * pkt,uint8_t * iv)273 static inline int cipher_cbc_op(struct cipher_ctx *ctx,
274 				struct cipher_pkt *pkt, uint8_t *iv)
275 {
276 	__ASSERT(ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_CBC, "CBC mode "
277 		 "session invoking a different mode handler");
278 
279 	pkt->ctx = ctx;
280 	return ctx->ops.cbc_crypt_hndlr(ctx, pkt, iv);
281 }
282 
283 /**
284  * @brief Perform Counter (CTR) mode crypto operation.
285  *
286  * @param  ctx       Pointer to the crypto context of this op.
287  * @param  pkt   Structure holding the input/output buffer pointers.
288  * @param  iv        Initialization Vector (IV) for the operation. We use a
289  *			 split counter formed by appending IV and ctr.
290  *			 Consequently  ivlen = keylen - ctrlen. 'ctrlen' is
291  *			 specified during session setup through the
292  *			 'ctx.mode_params.ctr_params.ctr_len' parameter. IV
293  *			 should not be reused across multiple operations
294  *			 (within a session context) for security. The non-IV
295  *			 part of the split counter is transparent to the caller
296  *			 and is fully managed by the crypto provider.
297  *
298  * @return 0 on success, negative errno code on fail.
299  */
cipher_ctr_op(struct cipher_ctx * ctx,struct cipher_pkt * pkt,uint8_t * iv)300 static inline int cipher_ctr_op(struct cipher_ctx *ctx,
301 				struct cipher_pkt *pkt, uint8_t *iv)
302 {
303 	__ASSERT(ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_CTR, "CTR mode "
304 		 "session invoking a different mode handler");
305 
306 	pkt->ctx = ctx;
307 	return ctx->ops.ctr_crypt_hndlr(ctx, pkt, iv);
308 }
309 
310 /**
311  * @brief Perform Counter with CBC-MAC (CCM) mode crypto operation
312  *
313  * @param  ctx       Pointer to the crypto context of this op.
314  * @param  pkt   Structure holding the input/output, Associated
315  *			 Data (AD) and auth tag buffer pointers.
316  * @param  nonce     Nonce for the operation. Same nonce value should not
317  *			 be reused across multiple operations (within a
318  *			 session context) for security.
319  *
320  * @return 0 on success, negative errno code on fail.
321  */
cipher_ccm_op(struct cipher_ctx * ctx,struct cipher_aead_pkt * pkt,uint8_t * nonce)322 static inline int cipher_ccm_op(struct cipher_ctx *ctx,
323 				struct cipher_aead_pkt *pkt, uint8_t *nonce)
324 {
325 	__ASSERT(ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_CCM, "CCM mode "
326 		 "session invoking a different mode handler");
327 
328 	pkt->pkt->ctx = ctx;
329 	return ctx->ops.ccm_crypt_hndlr(ctx, pkt, nonce);
330 }
331 
332 /**
333  * @brief Perform Galois/Counter Mode (GCM) crypto operation
334  *
335  * @param  ctx       Pointer to the crypto context of this op.
336  * @param  pkt   Structure holding the input/output, Associated
337  *			 Data (AD) and auth tag buffer pointers.
338  * @param  nonce     Nonce for the operation. Same nonce value should not
339  *			 be reused across multiple operations (within a
340  *			 session context) for security.
341  *
342  * @return 0 on success, negative errno code on fail.
343  */
cipher_gcm_op(struct cipher_ctx * ctx,struct cipher_aead_pkt * pkt,uint8_t * nonce)344 static inline int cipher_gcm_op(struct cipher_ctx *ctx,
345 				struct cipher_aead_pkt *pkt, uint8_t *nonce)
346 {
347 	__ASSERT(ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_GCM, "GCM mode "
348 		 "session invoking a different mode handler");
349 
350 	pkt->pkt->ctx = ctx;
351 	return ctx->ops.gcm_crypt_hndlr(ctx, pkt, nonce);
352 }
353 
354 
355 /**
356  * @}
357  */
358 
359 /**
360  * @brief Crypto Hash APIs
361  * @defgroup crypto_hash Hash
362  * @ingroup crypto
363  * @{
364  */
365 
366 
367 /**
368  * @brief Setup a hash session
369  *
370  * Initializes one time parameters, like the algorithm which may
371  * remain constant for all operations in the session. The state may be
372  * cached in hardware and/or driver data state variables.
373  *
374  * @param  dev      Pointer to the device structure for the driver instance.
375  * @param  ctx      Pointer to the context structure. Various one time
376  *			parameters like session capabilities and algorithm are
377  *			supplied via this structure. The structure documentation
378  *			specifies which fields are to be populated by the app
379  *			before making this call.
380  * @param  algo     The hash algorithm to be used in this session. e.g sha256
381  *
382  * @return 0 on success, negative errno code on fail.
383  */
hash_begin_session(const struct device * dev,struct hash_ctx * ctx,enum hash_algo algo)384 static inline int hash_begin_session(const struct device *dev,
385 				     struct hash_ctx *ctx,
386 				     enum hash_algo algo)
387 {
388 	uint32_t flags;
389 	struct crypto_driver_api *api;
390 
391 	api = (struct crypto_driver_api *) dev->api;
392 	ctx->device = dev;
393 
394 	flags = (ctx->flags & (CAP_INPLACE_OPS | CAP_SEPARATE_IO_BUFS));
395 	__ASSERT(flags != 0U, "IO buffer type missing");
396 	__ASSERT(flags != (CAP_INPLACE_OPS | CAP_SEPARATE_IO_BUFS),
397 			"conflicting options for IO buffer type");
398 
399 	flags = (ctx->flags & (CAP_SYNC_OPS | CAP_ASYNC_OPS));
400 	__ASSERT(flags != 0U, "sync/async type missing");
401 	__ASSERT(flags != (CAP_SYNC_OPS |  CAP_ASYNC_OPS),
402 			"conflicting options for sync/async");
403 
404 
405 	return api->hash_begin_session(dev, ctx, algo);
406 }
407 
408 /**
409  * @brief Cleanup a hash session
410  *
411  * Clears the hardware and/or driver state of a session. @see hash_begin_session
412  *
413  * @param  dev      Pointer to the device structure for the driver instance.
414  * @param  ctx      Pointer to the crypto hash  context structure of the session
415  *		    to be freed.
416  *
417  * @return 0 on success, negative errno code on fail.
418  */
hash_free_session(const struct device * dev,struct hash_ctx * ctx)419 static inline int hash_free_session(const struct device *dev,
420 				    struct hash_ctx *ctx)
421 {
422 	struct crypto_driver_api *api;
423 
424 	api = (struct crypto_driver_api *) dev->api;
425 
426 	return api->hash_free_session(dev, ctx);
427 }
428 
429 /**
430  * @brief Registers an async hash completion callback with the driver
431  *
432  * The application can register an async hash completion callback handler
433  * to be invoked by the driver, on completion of a prior request submitted via
434  * hash_compute(). Based on crypto device hardware semantics, this is likely to
435  * be invoked from an ISR context.
436  *
437  * @param  dev   Pointer to the device structure for the driver instance.
438  * @param  cb    Pointer to application callback to be called by the driver.
439  *
440  * @return 0 on success, -ENOTSUP if the driver does not support async op,
441  *			  negative errno code on other error.
442  */
hash_callback_set(const struct device * dev,hash_completion_cb cb)443 static inline int hash_callback_set(const struct device *dev,
444 				    hash_completion_cb cb)
445 {
446 	struct crypto_driver_api *api;
447 
448 	api = (struct crypto_driver_api *) dev->api;
449 
450 	if (api->hash_async_callback_set) {
451 		return api->hash_async_callback_set(dev, cb);
452 	}
453 
454 	return -ENOTSUP;
455 
456 }
457 
458 /**
459  * @brief Perform  a cryptographic hash function.
460  *
461  * @param  ctx       Pointer to the hash context of this op.
462  * @param  pkt       Structure holding the input/output.
463 
464  * @return 0 on success, negative errno code on fail.
465  */
hash_compute(struct hash_ctx * ctx,struct hash_pkt * pkt)466 static inline int hash_compute(struct hash_ctx *ctx, struct hash_pkt *pkt)
467 {
468 	pkt->ctx = ctx;
469 
470 	return ctx->hash_hndlr(ctx, pkt, true);
471 }
472 
473 /**
474  * @brief Perform  a cryptographic multipart hash operation.
475  *
476  * This function can be called zero or more times, passing a slice of
477  * the data. The hash is calculated using all the given pieces.
478  * To calculate the hash call @c hash_compute().
479  *
480  * @param  ctx       Pointer to the hash context of this op.
481  * @param  pkt       Structure holding the input.
482 
483  * @return 0 on success, negative errno code on fail.
484  */
hash_update(struct hash_ctx * ctx,struct hash_pkt * pkt)485 static inline int hash_update(struct hash_ctx *ctx, struct hash_pkt *pkt)
486 {
487 	pkt->ctx = ctx;
488 
489 	return ctx->hash_hndlr(ctx, pkt, false);
490 }
491 
492 /**
493  * @}
494  */
495 
496 #endif /* ZEPHYR_INCLUDE_CRYPTO_H_ */
497