2021-04-29 11:07:04 -04:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright ( C ) 2021 , Linaro Limited . All rights reserved .
*/
# include <linux/dma-mapping.h>
# include <linux/interrupt.h>
# include <crypto/gcm.h>
# include <crypto/authenc.h>
# include <crypto/internal/aead.h>
# include <crypto/internal/des.h>
# include <crypto/sha1.h>
# include <crypto/sha2.h>
# include <crypto/scatterwalk.h>
# include "aead.h"
# define CCM_NONCE_ADATA_SHIFT 6
# define CCM_NONCE_AUTHSIZE_SHIFT 3
# define MAX_CCM_ADATA_HEADER_LEN 6
static LIST_HEAD ( aead_algs ) ;
static void qce_aead_done ( void * data )
{
struct crypto_async_request * async_req = data ;
struct aead_request * req = aead_request_cast ( async_req ) ;
2022-12-02 17:21:05 +08:00
struct qce_aead_reqctx * rctx = aead_request_ctx_dma ( req ) ;
2021-04-29 11:07:04 -04:00
struct qce_aead_ctx * ctx = crypto_tfm_ctx ( async_req - > tfm ) ;
struct qce_alg_template * tmpl = to_aead_tmpl ( crypto_aead_reqtfm ( req ) ) ;
struct qce_device * qce = tmpl - > qce ;
struct qce_result_dump * result_buf = qce - > dma . result_buf ;
enum dma_data_direction dir_src , dir_dst ;
bool diff_dst ;
int error ;
u32 status ;
unsigned int totallen ;
unsigned char tag [ SHA256_DIGEST_SIZE ] = { 0 } ;
int ret = 0 ;
diff_dst = ( req - > src ! = req - > dst ) ? true : false ;
dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL ;
dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL ;
error = qce_dma_terminate_all ( & qce - > dma ) ;
if ( error )
dev_dbg ( qce - > dev , " aead dma termination error (%d) \n " ,
error ) ;
if ( diff_dst )
dma_unmap_sg ( qce - > dev , rctx - > src_sg , rctx - > src_nents , dir_src ) ;
dma_unmap_sg ( qce - > dev , rctx - > dst_sg , rctx - > dst_nents , dir_dst ) ;
if ( IS_CCM ( rctx - > flags ) ) {
if ( req - > assoclen ) {
sg_free_table ( & rctx - > src_tbl ) ;
if ( diff_dst )
sg_free_table ( & rctx - > dst_tbl ) ;
} else {
if ( ! ( IS_DECRYPT ( rctx - > flags ) & & ! diff_dst ) )
sg_free_table ( & rctx - > dst_tbl ) ;
}
} else {
sg_free_table ( & rctx - > dst_tbl ) ;
}
error = qce_check_status ( qce , & status ) ;
if ( error < 0 & & ( error ! = - EBADMSG ) )
dev_err ( qce - > dev , " aead operation error (%x) \n " , status ) ;
if ( IS_ENCRYPT ( rctx - > flags ) ) {
totallen = req - > cryptlen + req - > assoclen ;
if ( IS_CCM ( rctx - > flags ) )
scatterwalk_map_and_copy ( rctx - > ccmresult_buf , req - > dst ,
totallen , ctx - > authsize , 1 ) ;
else
scatterwalk_map_and_copy ( result_buf - > auth_iv , req - > dst ,
totallen , ctx - > authsize , 1 ) ;
} else if ( ! IS_CCM ( rctx - > flags ) ) {
totallen = req - > cryptlen + req - > assoclen - ctx - > authsize ;
scatterwalk_map_and_copy ( tag , req - > src , totallen , ctx - > authsize , 0 ) ;
ret = memcmp ( result_buf - > auth_iv , tag , ctx - > authsize ) ;
if ( ret ) {
pr_err ( " Bad message error \n " ) ;
2021-05-21 17:44:52 +08:00
error = - EBADMSG ;
2021-04-29 11:07:04 -04:00
}
}
qce - > async_req_done ( qce , error ) ;
}
static struct scatterlist *
qce_aead_prepare_result_buf ( struct sg_table * tbl , struct aead_request * req )
{
2022-12-02 17:21:05 +08:00
struct qce_aead_reqctx * rctx = aead_request_ctx_dma ( req ) ;
2021-04-29 11:07:04 -04:00
struct qce_alg_template * tmpl = to_aead_tmpl ( crypto_aead_reqtfm ( req ) ) ;
struct qce_device * qce = tmpl - > qce ;
sg_init_one ( & rctx - > result_sg , qce - > dma . result_buf , QCE_RESULT_BUF_SZ ) ;
return qce_sgtable_add ( tbl , & rctx - > result_sg , QCE_RESULT_BUF_SZ ) ;
}
static struct scatterlist *
qce_aead_prepare_ccm_result_buf ( struct sg_table * tbl , struct aead_request * req )
{
2022-12-02 17:21:05 +08:00
struct qce_aead_reqctx * rctx = aead_request_ctx_dma ( req ) ;
2021-04-29 11:07:04 -04:00
sg_init_one ( & rctx - > result_sg , rctx - > ccmresult_buf , QCE_BAM_BURST_SIZE ) ;
return qce_sgtable_add ( tbl , & rctx - > result_sg , QCE_BAM_BURST_SIZE ) ;
}
static struct scatterlist *
qce_aead_prepare_dst_buf ( struct aead_request * req )
{
2022-12-02 17:21:05 +08:00
struct qce_aead_reqctx * rctx = aead_request_ctx_dma ( req ) ;
2021-04-29 11:07:04 -04:00
struct qce_alg_template * tmpl = to_aead_tmpl ( crypto_aead_reqtfm ( req ) ) ;
struct qce_device * qce = tmpl - > qce ;
struct scatterlist * sg , * msg_sg , __sg [ 2 ] ;
gfp_t gfp ;
unsigned int assoclen = req - > assoclen ;
unsigned int totallen ;
int ret ;
totallen = rctx - > cryptlen + assoclen ;
rctx - > dst_nents = sg_nents_for_len ( req - > dst , totallen ) ;
if ( rctx - > dst_nents < 0 ) {
dev_err ( qce - > dev , " Invalid numbers of dst SG. \n " ) ;
return ERR_PTR ( - EINVAL ) ;
}
if ( IS_CCM ( rctx - > flags ) )
rctx - > dst_nents + = 2 ;
else
rctx - > dst_nents + = 1 ;
gfp = ( req - > base . flags & CRYPTO_TFM_REQ_MAY_SLEEP ) ?
GFP_KERNEL : GFP_ATOMIC ;
ret = sg_alloc_table ( & rctx - > dst_tbl , rctx - > dst_nents , gfp ) ;
if ( ret )
return ERR_PTR ( ret ) ;
if ( IS_CCM ( rctx - > flags ) & & assoclen ) {
/* Get the dst buffer */
msg_sg = scatterwalk_ffwd ( __sg , req - > dst , assoclen ) ;
sg = qce_sgtable_add ( & rctx - > dst_tbl , & rctx - > adata_sg ,
rctx - > assoclen ) ;
if ( IS_ERR ( sg ) ) {
ret = PTR_ERR ( sg ) ;
goto dst_tbl_free ;
}
/* dst buffer */
sg = qce_sgtable_add ( & rctx - > dst_tbl , msg_sg , rctx - > cryptlen ) ;
if ( IS_ERR ( sg ) ) {
ret = PTR_ERR ( sg ) ;
goto dst_tbl_free ;
}
totallen = rctx - > cryptlen + rctx - > assoclen ;
} else {
if ( totallen ) {
sg = qce_sgtable_add ( & rctx - > dst_tbl , req - > dst , totallen ) ;
if ( IS_ERR ( sg ) )
goto dst_tbl_free ;
}
}
if ( IS_CCM ( rctx - > flags ) )
sg = qce_aead_prepare_ccm_result_buf ( & rctx - > dst_tbl , req ) ;
else
sg = qce_aead_prepare_result_buf ( & rctx - > dst_tbl , req ) ;
if ( IS_ERR ( sg ) )
goto dst_tbl_free ;
sg_mark_end ( sg ) ;
rctx - > dst_sg = rctx - > dst_tbl . sgl ;
rctx - > dst_nents = sg_nents_for_len ( rctx - > dst_sg , totallen ) + 1 ;
return sg ;
dst_tbl_free :
sg_free_table ( & rctx - > dst_tbl ) ;
return sg ;
}
static int
qce_aead_ccm_prepare_buf_assoclen ( struct aead_request * req )
{
struct scatterlist * sg , * msg_sg , __sg [ 2 ] ;
struct crypto_aead * tfm = crypto_aead_reqtfm ( req ) ;
2022-12-02 17:21:05 +08:00
struct qce_aead_reqctx * rctx = aead_request_ctx_dma ( req ) ;
2021-04-29 11:07:04 -04:00
struct qce_aead_ctx * ctx = crypto_aead_ctx ( tfm ) ;
unsigned int assoclen = rctx - > assoclen ;
unsigned int adata_header_len , cryptlen , totallen ;
gfp_t gfp ;
bool diff_dst ;
int ret ;
if ( IS_DECRYPT ( rctx - > flags ) )
cryptlen = rctx - > cryptlen + ctx - > authsize ;
else
cryptlen = rctx - > cryptlen ;
totallen = cryptlen + req - > assoclen ;
/* Get the msg */
msg_sg = scatterwalk_ffwd ( __sg , req - > src , req - > assoclen ) ;
rctx - > adata = kzalloc ( ( ALIGN ( assoclen , 16 ) + MAX_CCM_ADATA_HEADER_LEN ) *
sizeof ( unsigned char ) , GFP_ATOMIC ) ;
if ( ! rctx - > adata )
return - ENOMEM ;
/*
* Format associated data ( RFC3610 and NIST 800 - 38 C )
* Even though specification allows for AAD to be up to 2 ^ 64 - 1 bytes ,
* the assoclen field in aead_request is unsigned int and thus limits
* the AAD to be up to 2 ^ 32 - 1 bytes . So we handle only two scenarios
* while forming the header for AAD .
*/
if ( assoclen < 0xff00 ) {
adata_header_len = 2 ;
* ( __be16 * ) rctx - > adata = cpu_to_be16 ( assoclen ) ;
} else {
adata_header_len = 6 ;
* ( __be16 * ) rctx - > adata = cpu_to_be16 ( 0xfffe ) ;
* ( __be32 * ) ( rctx - > adata + 2 ) = cpu_to_be32 ( assoclen ) ;
}
/* Copy the associated data */
if ( sg_copy_to_buffer ( req - > src , sg_nents_for_len ( req - > src , assoclen ) ,
rctx - > adata + adata_header_len ,
assoclen ) ! = assoclen )
return - EINVAL ;
/* Pad associated data to block size */
rctx - > assoclen = ALIGN ( assoclen + adata_header_len , 16 ) ;
diff_dst = ( req - > src ! = req - > dst ) ? true : false ;
if ( diff_dst )
rctx - > src_nents = sg_nents_for_len ( req - > src , totallen ) + 1 ;
else
rctx - > src_nents = sg_nents_for_len ( req - > src , totallen ) + 2 ;
gfp = ( req - > base . flags & CRYPTO_TFM_REQ_MAY_SLEEP ) ? GFP_KERNEL : GFP_ATOMIC ;
ret = sg_alloc_table ( & rctx - > src_tbl , rctx - > src_nents , gfp ) ;
if ( ret )
return ret ;
/* Associated Data */
sg_init_one ( & rctx - > adata_sg , rctx - > adata , rctx - > assoclen ) ;
sg = qce_sgtable_add ( & rctx - > src_tbl , & rctx - > adata_sg ,
rctx - > assoclen ) ;
if ( IS_ERR ( sg ) ) {
ret = PTR_ERR ( sg ) ;
goto err_free ;
}
/* src msg */
sg = qce_sgtable_add ( & rctx - > src_tbl , msg_sg , cryptlen ) ;
if ( IS_ERR ( sg ) ) {
ret = PTR_ERR ( sg ) ;
goto err_free ;
}
if ( ! diff_dst ) {
/*
* For decrypt , when src and dst buffers are same , there is already space
* in the buffer for padded 0 ' s which is output in lieu of
* the MAC that is input . So skip the below .
*/
if ( ! IS_DECRYPT ( rctx - > flags ) ) {
sg = qce_aead_prepare_ccm_result_buf ( & rctx - > src_tbl , req ) ;
if ( IS_ERR ( sg ) ) {
ret = PTR_ERR ( sg ) ;
goto err_free ;
}
}
}
sg_mark_end ( sg ) ;
rctx - > src_sg = rctx - > src_tbl . sgl ;
totallen = cryptlen + rctx - > assoclen ;
rctx - > src_nents = sg_nents_for_len ( rctx - > src_sg , totallen ) ;
if ( diff_dst ) {
sg = qce_aead_prepare_dst_buf ( req ) ;
2021-05-19 14:16:50 +00:00
if ( IS_ERR ( sg ) ) {
ret = PTR_ERR ( sg ) ;
2021-04-29 11:07:04 -04:00
goto err_free ;
2021-05-19 14:16:50 +00:00
}
2021-04-29 11:07:04 -04:00
} else {
if ( IS_ENCRYPT ( rctx - > flags ) )
rctx - > dst_nents = rctx - > src_nents + 1 ;
else
rctx - > dst_nents = rctx - > src_nents ;
rctx - > dst_sg = rctx - > src_sg ;
}
return 0 ;
err_free :
sg_free_table ( & rctx - > src_tbl ) ;
return ret ;
}
static int qce_aead_prepare_buf ( struct aead_request * req )
{
2022-12-02 17:21:05 +08:00
struct qce_aead_reqctx * rctx = aead_request_ctx_dma ( req ) ;
2021-04-29 11:07:04 -04:00
struct qce_alg_template * tmpl = to_aead_tmpl ( crypto_aead_reqtfm ( req ) ) ;
struct qce_device * qce = tmpl - > qce ;
struct scatterlist * sg ;
bool diff_dst = ( req - > src ! = req - > dst ) ? true : false ;
unsigned int totallen ;
totallen = rctx - > cryptlen + rctx - > assoclen ;
sg = qce_aead_prepare_dst_buf ( req ) ;
if ( IS_ERR ( sg ) )
return PTR_ERR ( sg ) ;
if ( diff_dst ) {
rctx - > src_nents = sg_nents_for_len ( req - > src , totallen ) ;
if ( rctx - > src_nents < 0 ) {
dev_err ( qce - > dev , " Invalid numbers of src SG. \n " ) ;
return - EINVAL ;
}
rctx - > src_sg = req - > src ;
} else {
rctx - > src_nents = rctx - > dst_nents - 1 ;
rctx - > src_sg = rctx - > dst_sg ;
}
return 0 ;
}
static int qce_aead_ccm_prepare_buf ( struct aead_request * req )
{
2022-12-02 17:21:05 +08:00
struct qce_aead_reqctx * rctx = aead_request_ctx_dma ( req ) ;
2021-04-29 11:07:04 -04:00
struct crypto_aead * tfm = crypto_aead_reqtfm ( req ) ;
struct qce_aead_ctx * ctx = crypto_aead_ctx ( tfm ) ;
struct scatterlist * sg ;
bool diff_dst = ( req - > src ! = req - > dst ) ? true : false ;
unsigned int cryptlen ;
if ( rctx - > assoclen )
return qce_aead_ccm_prepare_buf_assoclen ( req ) ;
if ( IS_ENCRYPT ( rctx - > flags ) )
return qce_aead_prepare_buf ( req ) ;
cryptlen = rctx - > cryptlen + ctx - > authsize ;
if ( diff_dst ) {
rctx - > src_nents = sg_nents_for_len ( req - > src , cryptlen ) ;
rctx - > src_sg = req - > src ;
sg = qce_aead_prepare_dst_buf ( req ) ;
if ( IS_ERR ( sg ) )
return PTR_ERR ( sg ) ;
} else {
rctx - > src_nents = sg_nents_for_len ( req - > src , cryptlen ) ;
rctx - > src_sg = req - > src ;
rctx - > dst_nents = rctx - > src_nents ;
rctx - > dst_sg = rctx - > src_sg ;
}
return 0 ;
}
static int qce_aead_create_ccm_nonce ( struct qce_aead_reqctx * rctx , struct qce_aead_ctx * ctx )
{
unsigned int msglen_size , ivsize ;
u8 msg_len [ 4 ] ;
int i ;
if ( ! rctx | | ! rctx - > iv )
return - EINVAL ;
msglen_size = rctx - > iv [ 0 ] + 1 ;
/* Verify that msg len size is valid */
if ( msglen_size < 2 | | msglen_size > 8 )
return - EINVAL ;
ivsize = rctx - > ivsize ;
/*
* Clear the msglen bytes in IV .
* Else the h / w engine and nonce will use any stray value pending there .
*/
if ( ! IS_CCM_RFC4309 ( rctx - > flags ) ) {
for ( i = 0 ; i < msglen_size ; i + + )
rctx - > iv [ ivsize - i - 1 ] = 0 ;
}
/*
* The crypto framework encodes cryptlen as unsigned int . Thus , even though
* spec allows for upto 8 bytes to encode msg_len only 4 bytes are needed .
*/
if ( msglen_size > 4 )
msglen_size = 4 ;
memcpy ( & msg_len [ 0 ] , & rctx - > cryptlen , 4 ) ;
memcpy ( & rctx - > ccm_nonce [ 0 ] , rctx - > iv , rctx - > ivsize ) ;
if ( rctx - > assoclen )
rctx - > ccm_nonce [ 0 ] | = 1 < < CCM_NONCE_ADATA_SHIFT ;
rctx - > ccm_nonce [ 0 ] | = ( ( ctx - > authsize - 2 ) / 2 ) < <
CCM_NONCE_AUTHSIZE_SHIFT ;
for ( i = 0 ; i < msglen_size ; i + + )
rctx - > ccm_nonce [ QCE_MAX_NONCE - i - 1 ] = msg_len [ i ] ;
return 0 ;
}
static int
qce_aead_async_req_handle ( struct crypto_async_request * async_req )
{
struct aead_request * req = aead_request_cast ( async_req ) ;
2022-12-02 17:21:05 +08:00
struct qce_aead_reqctx * rctx = aead_request_ctx_dma ( req ) ;
2021-04-29 11:07:04 -04:00
struct crypto_aead * tfm = crypto_aead_reqtfm ( req ) ;
struct qce_aead_ctx * ctx = crypto_tfm_ctx ( async_req - > tfm ) ;
struct qce_alg_template * tmpl = to_aead_tmpl ( crypto_aead_reqtfm ( req ) ) ;
struct qce_device * qce = tmpl - > qce ;
enum dma_data_direction dir_src , dir_dst ;
bool diff_dst ;
int dst_nents , src_nents , ret ;
if ( IS_CCM_RFC4309 ( rctx - > flags ) ) {
memset ( rctx - > ccm_rfc4309_iv , 0 , QCE_MAX_IV_SIZE ) ;
rctx - > ccm_rfc4309_iv [ 0 ] = 3 ;
memcpy ( & rctx - > ccm_rfc4309_iv [ 1 ] , ctx - > ccm4309_salt , QCE_CCM4309_SALT_SIZE ) ;
memcpy ( & rctx - > ccm_rfc4309_iv [ 4 ] , req - > iv , 8 ) ;
rctx - > iv = rctx - > ccm_rfc4309_iv ;
rctx - > ivsize = AES_BLOCK_SIZE ;
} else {
rctx - > iv = req - > iv ;
rctx - > ivsize = crypto_aead_ivsize ( tfm ) ;
}
if ( IS_CCM_RFC4309 ( rctx - > flags ) )
rctx - > assoclen = req - > assoclen - 8 ;
else
rctx - > assoclen = req - > assoclen ;
diff_dst = ( req - > src ! = req - > dst ) ? true : false ;
dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL ;
dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL ;
if ( IS_CCM ( rctx - > flags ) ) {
ret = qce_aead_create_ccm_nonce ( rctx , ctx ) ;
if ( ret )
return ret ;
}
if ( IS_CCM ( rctx - > flags ) )
ret = qce_aead_ccm_prepare_buf ( req ) ;
else
ret = qce_aead_prepare_buf ( req ) ;
if ( ret )
return ret ;
dst_nents = dma_map_sg ( qce - > dev , rctx - > dst_sg , rctx - > dst_nents , dir_dst ) ;
2022-08-19 08:07:51 +02:00
if ( ! dst_nents ) {
ret = - EIO ;
2021-04-29 11:07:04 -04:00
goto error_free ;
2021-05-19 14:16:50 +00:00
}
2021-04-29 11:07:04 -04:00
if ( diff_dst ) {
src_nents = dma_map_sg ( qce - > dev , rctx - > src_sg , rctx - > src_nents , dir_src ) ;
2021-05-19 14:16:50 +00:00
if ( src_nents < 0 ) {
ret = src_nents ;
2021-04-29 11:07:04 -04:00
goto error_unmap_dst ;
2021-05-19 14:16:50 +00:00
}
2021-04-29 11:07:04 -04:00
} else {
if ( IS_CCM ( rctx - > flags ) & & IS_DECRYPT ( rctx - > flags ) )
src_nents = dst_nents ;
else
src_nents = dst_nents - 1 ;
}
ret = qce_dma_prep_sgs ( & qce - > dma , rctx - > src_sg , src_nents , rctx - > dst_sg , dst_nents ,
qce_aead_done , async_req ) ;
if ( ret )
goto error_unmap_src ;
qce_dma_issue_pending ( & qce - > dma ) ;
ret = qce_start ( async_req , tmpl - > crypto_alg_type ) ;
if ( ret )
goto error_terminate ;
return 0 ;
error_terminate :
qce_dma_terminate_all ( & qce - > dma ) ;
error_unmap_src :
if ( diff_dst )
dma_unmap_sg ( qce - > dev , req - > src , rctx - > src_nents , dir_src ) ;
error_unmap_dst :
dma_unmap_sg ( qce - > dev , rctx - > dst_sg , rctx - > dst_nents , dir_dst ) ;
error_free :
if ( IS_CCM ( rctx - > flags ) & & rctx - > assoclen ) {
sg_free_table ( & rctx - > src_tbl ) ;
if ( diff_dst )
sg_free_table ( & rctx - > dst_tbl ) ;
} else {
sg_free_table ( & rctx - > dst_tbl ) ;
}
return ret ;
}
static int qce_aead_crypt ( struct aead_request * req , int encrypt )
{
struct crypto_aead * tfm = crypto_aead_reqtfm ( req ) ;
2022-12-02 17:21:05 +08:00
struct qce_aead_reqctx * rctx = aead_request_ctx_dma ( req ) ;
2021-04-29 11:07:04 -04:00
struct qce_aead_ctx * ctx = crypto_aead_ctx ( tfm ) ;
struct qce_alg_template * tmpl = to_aead_tmpl ( tfm ) ;
unsigned int blocksize = crypto_aead_blocksize ( tfm ) ;
rctx - > flags = tmpl - > alg_flags ;
rctx - > flags | = encrypt ? QCE_ENCRYPT : QCE_DECRYPT ;
if ( encrypt )
rctx - > cryptlen = req - > cryptlen ;
else
rctx - > cryptlen = req - > cryptlen - ctx - > authsize ;
/* CE does not handle 0 length messages */
if ( ! rctx - > cryptlen ) {
if ( ! ( IS_CCM ( rctx - > flags ) & & IS_DECRYPT ( rctx - > flags ) ) )
2021-04-29 11:07:07 -04:00
ctx - > need_fallback = true ;
}
/* If fallback is needed, schedule and exit */
if ( ctx - > need_fallback ) {
/* Reset need_fallback in case the same ctx is used for another transaction */
ctx - > need_fallback = false ;
aead_request_set_tfm ( & rctx - > fallback_req , ctx - > fallback ) ;
aead_request_set_callback ( & rctx - > fallback_req , req - > base . flags ,
req - > base . complete , req - > base . data ) ;
aead_request_set_crypt ( & rctx - > fallback_req , req - > src ,
req - > dst , req - > cryptlen , req - > iv ) ;
aead_request_set_ad ( & rctx - > fallback_req , req - > assoclen ) ;
return encrypt ? crypto_aead_encrypt ( & rctx - > fallback_req ) :
crypto_aead_decrypt ( & rctx - > fallback_req ) ;
2021-04-29 11:07:04 -04:00
}
/*
* CBC algorithms require message lengths to be
* multiples of block size .
*/
if ( IS_CBC ( rctx - > flags ) & & ! IS_ALIGNED ( rctx - > cryptlen , blocksize ) )
return - EINVAL ;
/* RFC4309 supported AAD size 16 bytes/20 bytes */
if ( IS_CCM_RFC4309 ( rctx - > flags ) )
if ( crypto_ipsec_check_assoclen ( req - > assoclen ) )
return - EINVAL ;
return tmpl - > qce - > async_req_enqueue ( tmpl - > qce , & req - > base ) ;
}
static int qce_aead_encrypt ( struct aead_request * req )
{
return qce_aead_crypt ( req , 1 ) ;
}
static int qce_aead_decrypt ( struct aead_request * req )
{
return qce_aead_crypt ( req , 0 ) ;
}
static int qce_aead_ccm_setkey ( struct crypto_aead * tfm , const u8 * key ,
unsigned int keylen )
{
struct qce_aead_ctx * ctx = crypto_aead_ctx ( tfm ) ;
unsigned long flags = to_aead_tmpl ( tfm ) - > alg_flags ;
if ( IS_CCM_RFC4309 ( flags ) ) {
if ( keylen < QCE_CCM4309_SALT_SIZE )
return - EINVAL ;
keylen - = QCE_CCM4309_SALT_SIZE ;
memcpy ( ctx - > ccm4309_salt , key + keylen , QCE_CCM4309_SALT_SIZE ) ;
}
2021-04-29 11:07:07 -04:00
if ( keylen ! = AES_KEYSIZE_128 & & keylen ! = AES_KEYSIZE_256 & & keylen ! = AES_KEYSIZE_192 )
2021-04-29 11:07:04 -04:00
return - EINVAL ;
ctx - > enc_keylen = keylen ;
ctx - > auth_keylen = keylen ;
memcpy ( ctx - > enc_key , key , keylen ) ;
memcpy ( ctx - > auth_key , key , keylen ) ;
2021-04-29 11:07:07 -04:00
if ( keylen = = AES_KEYSIZE_192 )
ctx - > need_fallback = true ;
return IS_CCM_RFC4309 ( flags ) ?
crypto_aead_setkey ( ctx - > fallback , key , keylen + QCE_CCM4309_SALT_SIZE ) :
crypto_aead_setkey ( ctx - > fallback , key , keylen ) ;
2021-04-29 11:07:04 -04:00
}
static int qce_aead_setkey ( struct crypto_aead * tfm , const u8 * key , unsigned int keylen )
{
struct qce_aead_ctx * ctx = crypto_aead_ctx ( tfm ) ;
struct crypto_authenc_keys authenc_keys ;
unsigned long flags = to_aead_tmpl ( tfm ) - > alg_flags ;
u32 _key [ 6 ] ;
int err ;
err = crypto_authenc_extractkeys ( & authenc_keys , key , keylen ) ;
if ( err )
return err ;
if ( authenc_keys . enckeylen > QCE_MAX_KEY_SIZE | |
authenc_keys . authkeylen > QCE_MAX_KEY_SIZE )
return - EINVAL ;
if ( IS_DES ( flags ) ) {
err = verify_aead_des_key ( tfm , authenc_keys . enckey , authenc_keys . enckeylen ) ;
if ( err )
return err ;
} else if ( IS_3DES ( flags ) ) {
err = verify_aead_des3_key ( tfm , authenc_keys . enckey , authenc_keys . enckeylen ) ;
if ( err )
return err ;
/*
* The crypto engine does not support any two keys
* being the same for triple des algorithms . The
* verify_skcipher_des3_key does not check for all the
2021-04-29 11:07:07 -04:00
* below conditions . Schedule fallback in this case .
2021-04-29 11:07:04 -04:00
*/
memcpy ( _key , authenc_keys . enckey , DES3_EDE_KEY_SIZE ) ;
if ( ! ( ( _key [ 0 ] ^ _key [ 2 ] ) | ( _key [ 1 ] ^ _key [ 3 ] ) ) | |
! ( ( _key [ 2 ] ^ _key [ 4 ] ) | ( _key [ 3 ] ^ _key [ 5 ] ) ) | |
! ( ( _key [ 0 ] ^ _key [ 4 ] ) | ( _key [ 1 ] ^ _key [ 5 ] ) ) )
2021-04-29 11:07:07 -04:00
ctx - > need_fallback = true ;
2021-04-29 11:07:04 -04:00
} else if ( IS_AES ( flags ) ) {
/* No random key sizes */
if ( authenc_keys . enckeylen ! = AES_KEYSIZE_128 & &
2021-04-29 11:07:07 -04:00
authenc_keys . enckeylen ! = AES_KEYSIZE_192 & &
2021-04-29 11:07:04 -04:00
authenc_keys . enckeylen ! = AES_KEYSIZE_256 )
return - EINVAL ;
2021-04-29 11:07:07 -04:00
if ( authenc_keys . enckeylen = = AES_KEYSIZE_192 )
ctx - > need_fallback = true ;
2021-04-29 11:07:04 -04:00
}
ctx - > enc_keylen = authenc_keys . enckeylen ;
ctx - > auth_keylen = authenc_keys . authkeylen ;
memcpy ( ctx - > enc_key , authenc_keys . enckey , authenc_keys . enckeylen ) ;
memset ( ctx - > auth_key , 0 , sizeof ( ctx - > auth_key ) ) ;
memcpy ( ctx - > auth_key , authenc_keys . authkey , authenc_keys . authkeylen ) ;
2021-04-29 11:07:07 -04:00
return crypto_aead_setkey ( ctx - > fallback , key , keylen ) ;
2021-04-29 11:07:04 -04:00
}
static int qce_aead_setauthsize ( struct crypto_aead * tfm , unsigned int authsize )
{
struct qce_aead_ctx * ctx = crypto_aead_ctx ( tfm ) ;
unsigned long flags = to_aead_tmpl ( tfm ) - > alg_flags ;
if ( IS_CCM ( flags ) ) {
if ( authsize < 4 | | authsize > 16 | | authsize % 2 )
return - EINVAL ;
if ( IS_CCM_RFC4309 ( flags ) & & ( authsize < 8 | | authsize % 4 ) )
return - EINVAL ;
}
ctx - > authsize = authsize ;
2021-04-29 11:07:07 -04:00
return crypto_aead_setauthsize ( ctx - > fallback , authsize ) ;
2021-04-29 11:07:04 -04:00
}
static int qce_aead_init ( struct crypto_aead * tfm )
{
2021-04-29 11:07:07 -04:00
struct qce_aead_ctx * ctx = crypto_aead_ctx ( tfm ) ;
ctx - > need_fallback = false ;
ctx - > fallback = crypto_alloc_aead ( crypto_tfm_alg_name ( & tfm - > base ) ,
0 , CRYPTO_ALG_NEED_FALLBACK ) ;
if ( IS_ERR ( ctx - > fallback ) )
return PTR_ERR ( ctx - > fallback ) ;
2022-12-02 17:21:05 +08:00
crypto_aead_set_reqsize_dma ( tfm , sizeof ( struct qce_aead_reqctx ) +
crypto_aead_reqsize ( ctx - > fallback ) ) ;
2021-04-29 11:07:04 -04:00
return 0 ;
}
2021-04-29 11:07:07 -04:00
static void qce_aead_exit ( struct crypto_aead * tfm )
{
struct qce_aead_ctx * ctx = crypto_aead_ctx ( tfm ) ;
crypto_free_aead ( ctx - > fallback ) ;
}
2021-04-29 11:07:04 -04:00
struct qce_aead_def {
unsigned long flags ;
const char * name ;
const char * drv_name ;
unsigned int blocksize ;
unsigned int chunksize ;
unsigned int ivsize ;
unsigned int maxauthsize ;
} ;
static const struct qce_aead_def aead_def [ ] = {
{
. flags = QCE_ALG_DES | QCE_MODE_CBC | QCE_HASH_SHA1_HMAC ,
. name = " authenc(hmac(sha1),cbc(des)) " ,
. drv_name = " authenc-hmac-sha1-cbc-des-qce " ,
. blocksize = DES_BLOCK_SIZE ,
. ivsize = DES_BLOCK_SIZE ,
. maxauthsize = SHA1_DIGEST_SIZE ,
} ,
{
. flags = QCE_ALG_3DES | QCE_MODE_CBC | QCE_HASH_SHA1_HMAC ,
. name = " authenc(hmac(sha1),cbc(des3_ede)) " ,
. drv_name = " authenc-hmac-sha1-cbc-3des-qce " ,
. blocksize = DES3_EDE_BLOCK_SIZE ,
. ivsize = DES3_EDE_BLOCK_SIZE ,
. maxauthsize = SHA1_DIGEST_SIZE ,
} ,
{
. flags = QCE_ALG_DES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC ,
. name = " authenc(hmac(sha256),cbc(des)) " ,
. drv_name = " authenc-hmac-sha256-cbc-des-qce " ,
. blocksize = DES_BLOCK_SIZE ,
. ivsize = DES_BLOCK_SIZE ,
. maxauthsize = SHA256_DIGEST_SIZE ,
} ,
{
. flags = QCE_ALG_3DES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC ,
. name = " authenc(hmac(sha256),cbc(des3_ede)) " ,
. drv_name = " authenc-hmac-sha256-cbc-3des-qce " ,
. blocksize = DES3_EDE_BLOCK_SIZE ,
. ivsize = DES3_EDE_BLOCK_SIZE ,
. maxauthsize = SHA256_DIGEST_SIZE ,
} ,
{
. flags = QCE_ALG_AES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC ,
. name = " authenc(hmac(sha256),cbc(aes)) " ,
. drv_name = " authenc-hmac-sha256-cbc-aes-qce " ,
. blocksize = AES_BLOCK_SIZE ,
. ivsize = AES_BLOCK_SIZE ,
. maxauthsize = SHA256_DIGEST_SIZE ,
} ,
{
. flags = QCE_ALG_AES | QCE_MODE_CCM ,
. name = " ccm(aes) " ,
. drv_name = " ccm-aes-qce " ,
. blocksize = 1 ,
. ivsize = AES_BLOCK_SIZE ,
. maxauthsize = AES_BLOCK_SIZE ,
} ,
{
. flags = QCE_ALG_AES | QCE_MODE_CCM | QCE_MODE_CCM_RFC4309 ,
. name = " rfc4309(ccm(aes)) " ,
. drv_name = " rfc4309-ccm-aes-qce " ,
. blocksize = 1 ,
. ivsize = 8 ,
. maxauthsize = AES_BLOCK_SIZE ,
} ,
} ;
static int qce_aead_register_one ( const struct qce_aead_def * def , struct qce_device * qce )
{
struct qce_alg_template * tmpl ;
struct aead_alg * alg ;
int ret ;
tmpl = kzalloc ( sizeof ( * tmpl ) , GFP_KERNEL ) ;
if ( ! tmpl )
return - ENOMEM ;
alg = & tmpl - > alg . aead ;
snprintf ( alg - > base . cra_name , CRYPTO_MAX_ALG_NAME , " %s " , def - > name ) ;
snprintf ( alg - > base . cra_driver_name , CRYPTO_MAX_ALG_NAME , " %s " ,
def - > drv_name ) ;
alg - > base . cra_blocksize = def - > blocksize ;
alg - > chunksize = def - > chunksize ;
alg - > ivsize = def - > ivsize ;
alg - > maxauthsize = def - > maxauthsize ;
if ( IS_CCM ( def - > flags ) )
alg - > setkey = qce_aead_ccm_setkey ;
else
alg - > setkey = qce_aead_setkey ;
alg - > setauthsize = qce_aead_setauthsize ;
alg - > encrypt = qce_aead_encrypt ;
alg - > decrypt = qce_aead_decrypt ;
alg - > init = qce_aead_init ;
2021-04-29 11:07:07 -04:00
alg - > exit = qce_aead_exit ;
2021-04-29 11:07:04 -04:00
alg - > base . cra_priority = 300 ;
alg - > base . cra_flags = CRYPTO_ALG_ASYNC |
CRYPTO_ALG_ALLOCATES_MEMORY |
2021-04-29 11:07:07 -04:00
CRYPTO_ALG_KERN_DRIVER_ONLY |
CRYPTO_ALG_NEED_FALLBACK ;
2021-04-29 11:07:04 -04:00
alg - > base . cra_ctxsize = sizeof ( struct qce_aead_ctx ) ;
alg - > base . cra_alignmask = 0 ;
alg - > base . cra_module = THIS_MODULE ;
INIT_LIST_HEAD ( & tmpl - > entry ) ;
tmpl - > crypto_alg_type = CRYPTO_ALG_TYPE_AEAD ;
tmpl - > alg_flags = def - > flags ;
tmpl - > qce = qce ;
ret = crypto_register_aead ( alg ) ;
if ( ret ) {
dev_err ( qce - > dev , " %s registration failed \n " , alg - > base . cra_name ) ;
2021-11-04 06:28:07 -07:00
kfree ( tmpl ) ;
2021-04-29 11:07:04 -04:00
return ret ;
}
list_add_tail ( & tmpl - > entry , & aead_algs ) ;
dev_dbg ( qce - > dev , " %s is registered \n " , alg - > base . cra_name ) ;
return 0 ;
}
static void qce_aead_unregister ( struct qce_device * qce )
{
struct qce_alg_template * tmpl , * n ;
list_for_each_entry_safe ( tmpl , n , & aead_algs , entry ) {
crypto_unregister_aead ( & tmpl - > alg . aead ) ;
list_del ( & tmpl - > entry ) ;
kfree ( tmpl ) ;
}
}
static int qce_aead_register ( struct qce_device * qce )
{
int ret , i ;
for ( i = 0 ; i < ARRAY_SIZE ( aead_def ) ; i + + ) {
ret = qce_aead_register_one ( & aead_def [ i ] , qce ) ;
if ( ret )
goto err ;
}
return 0 ;
err :
qce_aead_unregister ( qce ) ;
return ret ;
}
const struct qce_algo_ops aead_ops = {
. type = CRYPTO_ALG_TYPE_AEAD ,
. register_algs = qce_aead_register ,
. unregister_algs = qce_aead_unregister ,
. async_req_handle = qce_aead_async_req_handle ,
} ;