/* * Copyright (c) 2016 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief Crypto Cipher APIs * * This file contains the Crypto Abstraction layer APIs. * * [Experimental] Users should note that the APIs can change * as a part of ongoing development. */ #ifndef ZEPHYR_INCLUDE_CRYPTO_H_ #define ZEPHYR_INCLUDE_CRYPTO_H_ #include #include #include #include #include #include "cipher.h" /** * @brief Crypto APIs * @defgroup crypto Crypto * @since 1.7 * @version 1.0.0 * @ingroup os_services * @{ */ /* ctx.flags values. Not all drivers support all flags. * A user app can query the supported hw / driver * capabilities via provided API (crypto_query_hwcaps()), and choose a * supported config during the session setup. */ #define CAP_OPAQUE_KEY_HNDL BIT(0) #define CAP_RAW_KEY BIT(1) /* TBD to define */ #define CAP_KEY_LOADING_API BIT(2) /** Whether the output is placed in separate buffer or not */ #define CAP_INPLACE_OPS BIT(3) #define CAP_SEPARATE_IO_BUFS BIT(4) /** * These denotes if the output (completion of a cipher_xxx_op) is conveyed * by the op function returning, or it is conveyed by an async notification */ #define CAP_SYNC_OPS BIT(5) #define CAP_ASYNC_OPS BIT(6) /** Whether the hardware/driver supports autononce feature */ #define CAP_AUTONONCE BIT(7) /** Don't prefix IV to cipher blocks */ #define CAP_NO_IV_PREFIX BIT(8) /* More flags to be added as necessary */ /** @brief Crypto driver API definition. */ __subsystem struct crypto_driver_api { int (*query_hw_caps)(const struct device *dev); /* Setup a crypto session */ int (*cipher_begin_session)(const struct device *dev, struct cipher_ctx *ctx, enum cipher_algo algo, enum cipher_mode mode, enum cipher_op op_type); /* Tear down an established session */ int (*cipher_free_session)(const struct device *dev, struct cipher_ctx *ctx); /* Register async crypto op completion callback with the driver */ int (*cipher_async_callback_set)(const struct device *dev, cipher_completion_cb cb); /* Setup a hash session */ int (*hash_begin_session)(const struct device *dev, struct hash_ctx *ctx, enum hash_algo algo); /* Tear down an established hash session */ int (*hash_free_session)(const struct device *dev, struct hash_ctx *ctx); /* Register async hash op completion callback with the driver */ int (*hash_async_callback_set)(const struct device *dev, hash_completion_cb cb); }; /* Following are the public API a user app may call. * The first two relate to crypto "session" setup / teardown. Further we * have four cipher mode specific (CTR, CCM, CBC ...) calls to perform the * actual crypto operation in the context of a session. Also we have an * API to provide the callback for async operations. */ /** * @brief Query the crypto hardware capabilities * * This API is used by the app to query the capabilities supported by the * crypto device. Based on this the app can specify a subset of the supported * options to be honored for a session during cipher_begin_session(). * * @param dev Pointer to the device structure for the driver instance. * * @return bitmask of supported options. */ static inline int crypto_query_hwcaps(const struct device *dev) { struct crypto_driver_api *api; int tmp; api = (struct crypto_driver_api *) dev->api; tmp = api->query_hw_caps(dev); __ASSERT((tmp & (CAP_OPAQUE_KEY_HNDL | CAP_RAW_KEY)) != 0, "Driver should support at least one key type: RAW/Opaque"); __ASSERT((tmp & (CAP_INPLACE_OPS | CAP_SEPARATE_IO_BUFS)) != 0, "Driver should support at least one IO buf type: Inplace/separate"); __ASSERT((tmp & (CAP_SYNC_OPS | CAP_ASYNC_OPS)) != 0, "Driver should support at least one op-type: sync/async"); return tmp; } /** * @} */ /** * @brief Crypto Cipher APIs * @defgroup crypto_cipher Cipher * @ingroup crypto * @{ */ /** * @brief Setup a crypto session * * Initializes one time parameters, like the session key, algorithm and cipher * mode which may remain constant for all operations in the session. The state * may be cached in hardware and/or driver data state variables. * * @param dev Pointer to the device structure for the driver instance. * @param ctx Pointer to the context structure. Various one time * parameters like key, keylength, etc. are supplied via * this structure. The structure documentation specifies * which fields are to be populated by the app before * making this call. * @param algo The crypto algorithm to be used in this session. e.g AES * @param mode The cipher mode to be used in this session. e.g CBC, CTR * @param optype Whether we should encrypt or decrypt in this session * * @return 0 on success, negative errno code on fail. */ static inline int cipher_begin_session(const struct device *dev, struct cipher_ctx *ctx, enum cipher_algo algo, enum cipher_mode mode, enum cipher_op optype) { struct crypto_driver_api *api; uint32_t flags; api = (struct crypto_driver_api *) dev->api; ctx->device = dev; ctx->ops.cipher_mode = mode; flags = (ctx->flags & (CAP_OPAQUE_KEY_HNDL | CAP_RAW_KEY)); __ASSERT(flags != 0U, "Keytype missing: RAW Key or OPAQUE handle"); __ASSERT(flags != (CAP_OPAQUE_KEY_HNDL | CAP_RAW_KEY), "conflicting options for keytype"); flags = (ctx->flags & (CAP_INPLACE_OPS | CAP_SEPARATE_IO_BUFS)); __ASSERT(flags != 0U, "IO buffer type missing"); __ASSERT(flags != (CAP_INPLACE_OPS | CAP_SEPARATE_IO_BUFS), "conflicting options for IO buffer type"); flags = (ctx->flags & (CAP_SYNC_OPS | CAP_ASYNC_OPS)); __ASSERT(flags != 0U, "sync/async type missing"); __ASSERT(flags != (CAP_SYNC_OPS | CAP_ASYNC_OPS), "conflicting options for sync/async"); return api->cipher_begin_session(dev, ctx, algo, mode, optype); } /** * @brief Cleanup a crypto session * * Clears the hardware and/or driver state of a previous session. * * @param dev Pointer to the device structure for the driver instance. * @param ctx Pointer to the crypto context structure of the session * to be freed. * * @return 0 on success, negative errno code on fail. */ static inline int cipher_free_session(const struct device *dev, struct cipher_ctx *ctx) { struct crypto_driver_api *api; api = (struct crypto_driver_api *) dev->api; return api->cipher_free_session(dev, ctx); } /** * @brief Registers an async crypto op completion callback with the driver * * The application can register an async crypto op completion callback handler * to be invoked by the driver, on completion of a prior request submitted via * cipher_do_op(). Based on crypto device hardware semantics, this is likely to * be invoked from an ISR context. * * @param dev Pointer to the device structure for the driver instance. * @param cb Pointer to application callback to be called by the driver. * * @return 0 on success, -ENOTSUP if the driver does not support async op, * negative errno code on other error. */ static inline int cipher_callback_set(const struct device *dev, cipher_completion_cb cb) { struct crypto_driver_api *api; api = (struct crypto_driver_api *) dev->api; if (api->cipher_async_callback_set) { return api->cipher_async_callback_set(dev, cb); } return -ENOTSUP; } /** * @brief Perform single-block crypto operation (ECB cipher mode). This * should not be overloaded to operate on multiple blocks for security reasons. * * @param ctx Pointer to the crypto context of this op. * @param pkt Structure holding the input/output buffer pointers. * * @return 0 on success, negative errno code on fail. */ static inline int cipher_block_op(struct cipher_ctx *ctx, struct cipher_pkt *pkt) { __ASSERT(ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_ECB, "ECB mode " "session invoking a different mode handler"); pkt->ctx = ctx; return ctx->ops.block_crypt_hndlr(ctx, pkt); } /** * @brief Perform Cipher Block Chaining (CBC) crypto operation. * * @param ctx Pointer to the crypto context of this op. * @param pkt Structure holding the input/output buffer pointers. * @param iv Initialization Vector (IV) for the operation. Same * IV value should not be reused across multiple * operations (within a session context) for security. * * @return 0 on success, negative errno code on fail. */ static inline int cipher_cbc_op(struct cipher_ctx *ctx, struct cipher_pkt *pkt, uint8_t *iv) { __ASSERT(ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_CBC, "CBC mode " "session invoking a different mode handler"); pkt->ctx = ctx; return ctx->ops.cbc_crypt_hndlr(ctx, pkt, iv); } /** * @brief Perform Counter (CTR) mode crypto operation. * * @param ctx Pointer to the crypto context of this op. * @param pkt Structure holding the input/output buffer pointers. * @param iv Initialization Vector (IV) for the operation. We use a * split counter formed by appending IV and ctr. * Consequently ivlen = keylen - ctrlen. 'ctrlen' is * specified during session setup through the * 'ctx.mode_params.ctr_params.ctr_len' parameter. IV * should not be reused across multiple operations * (within a session context) for security. The non-IV * part of the split counter is transparent to the caller * and is fully managed by the crypto provider. * * @return 0 on success, negative errno code on fail. */ static inline int cipher_ctr_op(struct cipher_ctx *ctx, struct cipher_pkt *pkt, uint8_t *iv) { __ASSERT(ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_CTR, "CTR mode " "session invoking a different mode handler"); pkt->ctx = ctx; return ctx->ops.ctr_crypt_hndlr(ctx, pkt, iv); } /** * @brief Perform Counter with CBC-MAC (CCM) mode crypto operation * * @param ctx Pointer to the crypto context of this op. * @param pkt Structure holding the input/output, Associated * Data (AD) and auth tag buffer pointers. * @param nonce Nonce for the operation. Same nonce value should not * be reused across multiple operations (within a * session context) for security. * * @return 0 on success, negative errno code on fail. */ static inline int cipher_ccm_op(struct cipher_ctx *ctx, struct cipher_aead_pkt *pkt, uint8_t *nonce) { __ASSERT(ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_CCM, "CCM mode " "session invoking a different mode handler"); pkt->pkt->ctx = ctx; return ctx->ops.ccm_crypt_hndlr(ctx, pkt, nonce); } /** * @brief Perform Galois/Counter Mode (GCM) crypto operation * * @param ctx Pointer to the crypto context of this op. * @param pkt Structure holding the input/output, Associated * Data (AD) and auth tag buffer pointers. * @param nonce Nonce for the operation. Same nonce value should not * be reused across multiple operations (within a * session context) for security. * * @return 0 on success, negative errno code on fail. */ static inline int cipher_gcm_op(struct cipher_ctx *ctx, struct cipher_aead_pkt *pkt, uint8_t *nonce) { __ASSERT(ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_GCM, "GCM mode " "session invoking a different mode handler"); pkt->pkt->ctx = ctx; return ctx->ops.gcm_crypt_hndlr(ctx, pkt, nonce); } /** * @} */ /** * @brief Crypto Hash APIs * @defgroup crypto_hash Hash * @ingroup crypto * @{ */ /** * @brief Setup a hash session * * Initializes one time parameters, like the algorithm which may * remain constant for all operations in the session. The state may be * cached in hardware and/or driver data state variables. * * @param dev Pointer to the device structure for the driver instance. * @param ctx Pointer to the context structure. Various one time * parameters like session capabilities and algorithm are * supplied via this structure. The structure documentation * specifies which fields are to be populated by the app * before making this call. * @param algo The hash algorithm to be used in this session. e.g sha256 * * @return 0 on success, negative errno code on fail. */ static inline int hash_begin_session(const struct device *dev, struct hash_ctx *ctx, enum hash_algo algo) { uint32_t flags; struct crypto_driver_api *api; api = (struct crypto_driver_api *) dev->api; ctx->device = dev; flags = (ctx->flags & (CAP_INPLACE_OPS | CAP_SEPARATE_IO_BUFS)); __ASSERT(flags != 0U, "IO buffer type missing"); __ASSERT(flags != (CAP_INPLACE_OPS | CAP_SEPARATE_IO_BUFS), "conflicting options for IO buffer type"); flags = (ctx->flags & (CAP_SYNC_OPS | CAP_ASYNC_OPS)); __ASSERT(flags != 0U, "sync/async type missing"); __ASSERT(flags != (CAP_SYNC_OPS | CAP_ASYNC_OPS), "conflicting options for sync/async"); return api->hash_begin_session(dev, ctx, algo); } /** * @brief Cleanup a hash session * * Clears the hardware and/or driver state of a session. @see hash_begin_session * * @param dev Pointer to the device structure for the driver instance. * @param ctx Pointer to the crypto hash context structure of the session * to be freed. * * @return 0 on success, negative errno code on fail. */ static inline int hash_free_session(const struct device *dev, struct hash_ctx *ctx) { struct crypto_driver_api *api; api = (struct crypto_driver_api *) dev->api; return api->hash_free_session(dev, ctx); } /** * @brief Registers an async hash completion callback with the driver * * The application can register an async hash completion callback handler * to be invoked by the driver, on completion of a prior request submitted via * hash_compute(). Based on crypto device hardware semantics, this is likely to * be invoked from an ISR context. * * @param dev Pointer to the device structure for the driver instance. * @param cb Pointer to application callback to be called by the driver. * * @return 0 on success, -ENOTSUP if the driver does not support async op, * negative errno code on other error. */ static inline int hash_callback_set(const struct device *dev, hash_completion_cb cb) { struct crypto_driver_api *api; api = (struct crypto_driver_api *) dev->api; if (api->hash_async_callback_set) { return api->hash_async_callback_set(dev, cb); } return -ENOTSUP; } /** * @brief Perform a cryptographic hash function. * * @param ctx Pointer to the hash context of this op. * @param pkt Structure holding the input/output. * @return 0 on success, negative errno code on fail. */ static inline int hash_compute(struct hash_ctx *ctx, struct hash_pkt *pkt) { pkt->ctx = ctx; return ctx->hash_hndlr(ctx, pkt, true); } /** * @brief Perform a cryptographic multipart hash operation. * * This function can be called zero or more times, passing a slice of * the data. The hash is calculated using all the given pieces. * To calculate the hash call @c hash_compute(). * * @param ctx Pointer to the hash context of this op. * @param pkt Structure holding the input. * @return 0 on success, negative errno code on fail. */ static inline int hash_update(struct hash_ctx *ctx, struct hash_pkt *pkt) { pkt->ctx = ctx; return ctx->hash_hndlr(ctx, pkt, false); } /** * @} */ #endif /* ZEPHYR_INCLUDE_CRYPTO_H_ */