2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2015-06-16 20:30:55 +03:00
/*
* Public Key Encryption
*
* Copyright ( c ) 2015 , Intel Corporation
* Authors : Tadeusz Struk < tadeusz . struk @ intel . com >
*/
2023-02-16 13:35:13 +03:00
# include <crypto/internal/akcipher.h>
# include <linux/cryptouser.h>
2015-06-16 20:30:55 +03:00
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/module.h>
2023-06-15 13:28:46 +03:00
# include <linux/scatterlist.h>
2015-06-16 20:30:55 +03:00
# include <linux/seq_file.h>
# include <linux/slab.h>
# include <linux/string.h>
# include <net/netlink.h>
2023-02-16 13:35:13 +03:00
2015-06-16 20:30:55 +03:00
# include "internal.h"
2023-06-15 13:28:48 +03:00
# define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000e
2023-06-15 13:28:46 +03:00
2023-02-16 13:35:28 +03:00
static int __maybe_unused crypto_akcipher_report (
struct sk_buff * skb , struct crypto_alg * alg )
2015-06-16 20:30:55 +03:00
{
struct crypto_report_akcipher rakcipher ;
2018-11-04 00:56:03 +03:00
memset ( & rakcipher , 0 , sizeof ( rakcipher ) ) ;
2015-06-16 20:30:55 +03:00
2018-11-04 00:56:03 +03:00
strscpy ( rakcipher . type , " akcipher " , sizeof ( rakcipher . type ) ) ;
2015-06-16 20:30:55 +03:00
2018-11-04 00:56:03 +03:00
return nla_put ( skb , CRYPTOCFGA_REPORT_AKCIPHER ,
sizeof ( rakcipher ) , & rakcipher ) ;
2015-06-16 20:30:55 +03:00
}
static void crypto_akcipher_show ( struct seq_file * m , struct crypto_alg * alg )
2016-12-31 18:56:23 +03:00
__maybe_unused ;
2015-06-16 20:30:55 +03:00
static void crypto_akcipher_show ( struct seq_file * m , struct crypto_alg * alg )
{
seq_puts ( m , " type : akcipher \n " ) ;
}
static void crypto_akcipher_exit_tfm ( struct crypto_tfm * tfm )
{
struct crypto_akcipher * akcipher = __crypto_akcipher_tfm ( tfm ) ;
struct akcipher_alg * alg = crypto_akcipher_alg ( akcipher ) ;
alg - > exit ( akcipher ) ;
}
static int crypto_akcipher_init_tfm ( struct crypto_tfm * tfm )
{
struct crypto_akcipher * akcipher = __crypto_akcipher_tfm ( tfm ) ;
struct akcipher_alg * alg = crypto_akcipher_alg ( akcipher ) ;
if ( alg - > exit )
akcipher - > base . exit = crypto_akcipher_exit_tfm ;
if ( alg - > init )
return alg - > init ( akcipher ) ;
return 0 ;
}
2015-12-05 19:09:33 +03:00
static void crypto_akcipher_free_instance ( struct crypto_instance * inst )
{
struct akcipher_instance * akcipher = akcipher_instance ( inst ) ;
akcipher - > free ( akcipher ) ;
}
2023-02-16 13:35:13 +03:00
static int __maybe_unused crypto_akcipher_report_stat (
struct sk_buff * skb , struct crypto_alg * alg )
{
struct akcipher_alg * akcipher = __crypto_akcipher_alg ( alg ) ;
struct crypto_istat_akcipher * istat ;
struct crypto_stat_akcipher rakcipher ;
istat = akcipher_get_stat ( akcipher ) ;
memset ( & rakcipher , 0 , sizeof ( rakcipher ) ) ;
strscpy ( rakcipher . type , " akcipher " , sizeof ( rakcipher . type ) ) ;
rakcipher . stat_encrypt_cnt = atomic64_read ( & istat - > encrypt_cnt ) ;
rakcipher . stat_encrypt_tlen = atomic64_read ( & istat - > encrypt_tlen ) ;
rakcipher . stat_decrypt_cnt = atomic64_read ( & istat - > decrypt_cnt ) ;
rakcipher . stat_decrypt_tlen = atomic64_read ( & istat - > decrypt_tlen ) ;
rakcipher . stat_sign_cnt = atomic64_read ( & istat - > sign_cnt ) ;
rakcipher . stat_verify_cnt = atomic64_read ( & istat - > verify_cnt ) ;
rakcipher . stat_err_cnt = atomic64_read ( & istat - > err_cnt ) ;
return nla_put ( skb , CRYPTOCFGA_STAT_AKCIPHER ,
sizeof ( rakcipher ) , & rakcipher ) ;
}
2015-06-16 20:30:55 +03:00
static const struct crypto_type crypto_akcipher_type = {
. extsize = crypto_alg_extsize ,
. init_tfm = crypto_akcipher_init_tfm ,
2015-12-05 19:09:33 +03:00
. free = crypto_akcipher_free_instance ,
2015-06-16 20:30:55 +03:00
# ifdef CONFIG_PROC_FS
. show = crypto_akcipher_show ,
# endif
2023-05-02 11:02:33 +03:00
# if IS_ENABLED(CONFIG_CRYPTO_USER)
2015-06-16 20:30:55 +03:00
. report = crypto_akcipher_report ,
2023-02-16 13:35:28 +03:00
# endif
2023-02-16 13:35:13 +03:00
# ifdef CONFIG_CRYPTO_STATS
. report_stat = crypto_akcipher_report_stat ,
# endif
2015-06-16 20:30:55 +03:00
. maskclear = ~ CRYPTO_ALG_TYPE_MASK ,
2023-06-15 13:28:48 +03:00
. maskset = CRYPTO_ALG_TYPE_AHASH_MASK ,
2015-06-16 20:30:55 +03:00
. type = CRYPTO_ALG_TYPE_AKCIPHER ,
. tfmsize = offsetof ( struct crypto_akcipher , base ) ,
} ;
2020-01-03 06:58:47 +03:00
int crypto_grab_akcipher ( struct crypto_akcipher_spawn * spawn ,
struct crypto_instance * inst ,
const char * name , u32 type , u32 mask )
2015-12-05 19:09:33 +03:00
{
spawn - > base . frontend = & crypto_akcipher_type ;
2020-01-03 06:58:48 +03:00
return crypto_grab_spawn ( & spawn - > base , inst , name , type , mask ) ;
2015-12-05 19:09:33 +03:00
}
EXPORT_SYMBOL_GPL ( crypto_grab_akcipher ) ;
2015-06-16 20:30:55 +03:00
struct crypto_akcipher * crypto_alloc_akcipher ( const char * alg_name , u32 type ,
u32 mask )
{
return crypto_alloc_tfm ( alg_name , & crypto_akcipher_type , type , mask ) ;
}
EXPORT_SYMBOL_GPL ( crypto_alloc_akcipher ) ;
2015-12-05 19:09:33 +03:00
static void akcipher_prepare_alg ( struct akcipher_alg * alg )
2015-06-16 20:30:55 +03:00
{
2023-02-16 13:35:13 +03:00
struct crypto_istat_akcipher * istat = akcipher_get_stat ( alg ) ;
2015-06-16 20:30:55 +03:00
struct crypto_alg * base = & alg - > base ;
base - > cra_type = & crypto_akcipher_type ;
base - > cra_flags & = ~ CRYPTO_ALG_TYPE_MASK ;
base - > cra_flags | = CRYPTO_ALG_TYPE_AKCIPHER ;
2023-02-16 13:35:13 +03:00
if ( IS_ENABLED ( CONFIG_CRYPTO_STATS ) )
memset ( istat , 0 , sizeof ( * istat ) ) ;
2015-12-05 19:09:33 +03:00
}
2019-04-11 18:51:13 +03:00
static int akcipher_default_op ( struct akcipher_request * req )
{
return - ENOSYS ;
}
2022-08-31 21:37:06 +03:00
static int akcipher_default_set_key ( struct crypto_akcipher * tfm ,
const void * key , unsigned int keylen )
{
return - ENOSYS ;
}
2015-12-05 19:09:33 +03:00
int crypto_register_akcipher ( struct akcipher_alg * alg )
{
struct crypto_alg * base = & alg - > base ;
2019-04-11 18:51:13 +03:00
if ( ! alg - > sign )
alg - > sign = akcipher_default_op ;
if ( ! alg - > verify )
alg - > verify = akcipher_default_op ;
if ( ! alg - > encrypt )
alg - > encrypt = akcipher_default_op ;
if ( ! alg - > decrypt )
alg - > decrypt = akcipher_default_op ;
2022-08-31 21:37:06 +03:00
if ( ! alg - > set_priv_key )
alg - > set_priv_key = akcipher_default_set_key ;
2019-04-11 18:51:13 +03:00
2015-12-05 19:09:33 +03:00
akcipher_prepare_alg ( alg ) ;
2015-06-16 20:30:55 +03:00
return crypto_register_alg ( base ) ;
}
EXPORT_SYMBOL_GPL ( crypto_register_akcipher ) ;
void crypto_unregister_akcipher ( struct akcipher_alg * alg )
{
crypto_unregister_alg ( & alg - > base ) ;
}
EXPORT_SYMBOL_GPL ( crypto_unregister_akcipher ) ;
2015-12-05 19:09:33 +03:00
int akcipher_register_instance ( struct crypto_template * tmpl ,
struct akcipher_instance * inst )
{
2020-01-03 07:04:40 +03:00
if ( WARN_ON ( ! inst - > free ) )
return - EINVAL ;
2015-12-05 19:09:33 +03:00
akcipher_prepare_alg ( & inst - > alg ) ;
return crypto_register_instance ( tmpl , akcipher_crypto_instance ( inst ) ) ;
}
EXPORT_SYMBOL_GPL ( akcipher_register_instance ) ;
2023-06-15 13:28:48 +03:00
int crypto_akcipher_sync_prep ( struct crypto_akcipher_sync_data * data )
2023-06-15 13:28:46 +03:00
{
unsigned int reqsize = crypto_akcipher_reqsize ( data - > tfm ) ;
struct akcipher_request * req ;
struct scatterlist * sg ;
2023-06-26 13:33:44 +03:00
unsigned int mlen ;
2023-06-15 13:28:46 +03:00
unsigned int len ;
u8 * buf ;
2023-06-26 13:33:44 +03:00
if ( data - > dst )
mlen = max ( data - > slen , data - > dlen ) ;
else
mlen = data - > slen + data - > dlen ;
2023-06-15 13:28:46 +03:00
len = sizeof ( * req ) + reqsize + mlen ;
if ( len < mlen )
return - EOVERFLOW ;
req = kzalloc ( len , GFP_KERNEL ) ;
if ( ! req )
return - ENOMEM ;
data - > req = req ;
2023-06-26 13:20:25 +03:00
akcipher_request_set_tfm ( req , data - > tfm ) ;
2023-06-15 13:28:46 +03:00
buf = ( u8 * ) ( req + 1 ) + reqsize ;
data - > buf = buf ;
memcpy ( buf , data - > src , data - > slen ) ;
2023-06-26 13:33:44 +03:00
sg = & data - > sg ;
2023-06-15 13:28:46 +03:00
sg_init_one ( sg , buf , mlen ) ;
2023-06-26 13:33:44 +03:00
akcipher_request_set_crypt ( req , sg , data - > dst ? sg : NULL ,
data - > slen , data - > dlen ) ;
2023-06-15 13:28:46 +03:00
crypto_init_wait ( & data - > cwait ) ;
akcipher_request_set_callback ( req , CRYPTO_TFM_REQ_MAY_SLEEP ,
crypto_req_done , & data - > cwait ) ;
return 0 ;
}
2023-06-15 13:28:48 +03:00
EXPORT_SYMBOL_GPL ( crypto_akcipher_sync_prep ) ;
2023-06-15 13:28:46 +03:00
2023-06-15 13:28:48 +03:00
int crypto_akcipher_sync_post ( struct crypto_akcipher_sync_data * data , int err )
2023-06-15 13:28:46 +03:00
{
err = crypto_wait_req ( err , & data - > cwait ) ;
2023-06-27 12:59:32 +03:00
if ( data - > dst )
memcpy ( data - > dst , data - > buf , data - > dlen ) ;
2023-06-15 13:28:46 +03:00
data - > dlen = data - > req - > dst_len ;
kfree_sensitive ( data - > req ) ;
return err ;
}
2023-06-15 13:28:48 +03:00
EXPORT_SYMBOL_GPL ( crypto_akcipher_sync_post ) ;
2023-06-15 13:28:46 +03:00
int crypto_akcipher_sync_encrypt ( struct crypto_akcipher * tfm ,
const void * src , unsigned int slen ,
void * dst , unsigned int dlen )
{
struct crypto_akcipher_sync_data data = {
. tfm = tfm ,
. src = src ,
. dst = dst ,
. slen = slen ,
. dlen = dlen ,
} ;
return crypto_akcipher_sync_prep ( & data ) ? :
crypto_akcipher_sync_post ( & data ,
crypto_akcipher_encrypt ( data . req ) ) ;
}
EXPORT_SYMBOL_GPL ( crypto_akcipher_sync_encrypt ) ;
int crypto_akcipher_sync_decrypt ( struct crypto_akcipher * tfm ,
const void * src , unsigned int slen ,
void * dst , unsigned int dlen )
{
struct crypto_akcipher_sync_data data = {
. tfm = tfm ,
. src = src ,
. dst = dst ,
. slen = slen ,
. dlen = dlen ,
} ;
return crypto_akcipher_sync_prep ( & data ) ? :
crypto_akcipher_sync_post ( & data ,
crypto_akcipher_decrypt ( data . req ) ) ? :
data . dlen ;
}
EXPORT_SYMBOL_GPL ( crypto_akcipher_sync_decrypt ) ;
2023-06-15 13:28:48 +03:00
static void crypto_exit_akcipher_ops_sig ( struct crypto_tfm * tfm )
{
struct crypto_akcipher * * ctx = crypto_tfm_ctx ( tfm ) ;
crypto_free_akcipher ( * ctx ) ;
}
int crypto_init_akcipher_ops_sig ( struct crypto_tfm * tfm )
{
struct crypto_akcipher * * ctx = crypto_tfm_ctx ( tfm ) ;
struct crypto_alg * calg = tfm - > __crt_alg ;
struct crypto_akcipher * akcipher ;
if ( ! crypto_mod_get ( calg ) )
return - EAGAIN ;
akcipher = crypto_create_tfm ( calg , & crypto_akcipher_type ) ;
if ( IS_ERR ( akcipher ) ) {
crypto_mod_put ( calg ) ;
return PTR_ERR ( akcipher ) ;
}
* ctx = akcipher ;
tfm - > exit = crypto_exit_akcipher_ops_sig ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( crypto_init_akcipher_ops_sig ) ;
2015-06-16 20:30:55 +03:00
MODULE_LICENSE ( " GPL " ) ;
2015-06-23 20:18:53 +03:00
MODULE_DESCRIPTION ( " Generic public key cipher type " ) ;