2019-11-08 13:41:58 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* geniv : Shared IV generator code
*
* This file provides common code to IV generators such as seqiv .
*
* Copyright ( c ) 2007 - 2019 Herbert Xu < herbert @ gondor . apana . org . au >
*/
# include <crypto/internal/geniv.h>
# include <crypto/internal/rng.h>
# include <crypto/null.h>
# include <linux/err.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/rtnetlink.h>
# include <linux/slab.h>
static int aead_geniv_setkey ( struct crypto_aead * tfm ,
const u8 * key , unsigned int keylen )
{
struct aead_geniv_ctx * ctx = crypto_aead_ctx ( tfm ) ;
return crypto_aead_setkey ( ctx - > child , key , keylen ) ;
}
static int aead_geniv_setauthsize ( struct crypto_aead * tfm ,
unsigned int authsize )
{
struct aead_geniv_ctx * ctx = crypto_aead_ctx ( tfm ) ;
return crypto_aead_setauthsize ( ctx - > child , authsize ) ;
}
2020-01-03 07:04:36 +03:00
static void aead_geniv_free ( struct aead_instance * inst )
{
crypto_drop_aead ( aead_instance_ctx ( inst ) ) ;
kfree ( inst ) ;
}
2019-11-08 13:41:58 +03:00
struct aead_instance * aead_geniv_alloc ( struct crypto_template * tmpl ,
struct rtattr * * tb , u32 type , u32 mask )
{
struct crypto_aead_spawn * spawn ;
struct crypto_attr_type * algt ;
struct aead_instance * inst ;
struct aead_alg * alg ;
unsigned int ivsize ;
unsigned int maxauthsize ;
int err ;
algt = crypto_get_attr_type ( tb ) ;
if ( IS_ERR ( algt ) )
return ERR_CAST ( algt ) ;
if ( ( algt - > type ^ CRYPTO_ALG_TYPE_AEAD ) & algt - > mask )
return ERR_PTR ( - EINVAL ) ;
inst = kzalloc ( sizeof ( * inst ) + sizeof ( * spawn ) , GFP_KERNEL ) ;
if ( ! inst )
return ERR_PTR ( - ENOMEM ) ;
spawn = aead_instance_ctx ( inst ) ;
/* Ignore async algorithms if necessary. */
mask | = crypto_requires_sync ( algt - > type , algt - > mask ) ;
2020-01-03 06:58:46 +03:00
err = crypto_grab_aead ( spawn , aead_crypto_instance ( inst ) ,
2020-02-26 07:59:20 +03:00
crypto_attr_alg_name ( tb [ 1 ] ) , type , mask ) ;
2019-11-08 13:41:58 +03:00
if ( err )
goto err_free_inst ;
alg = crypto_spawn_aead_alg ( spawn ) ;
ivsize = crypto_aead_alg_ivsize ( alg ) ;
maxauthsize = crypto_aead_alg_maxauthsize ( alg ) ;
err = - EINVAL ;
if ( ivsize < sizeof ( u64 ) )
2020-02-26 07:59:20 +03:00
goto err_free_inst ;
2019-11-08 13:41:58 +03:00
err = - ENAMETOOLONG ;
if ( snprintf ( inst - > alg . base . cra_name , CRYPTO_MAX_ALG_NAME ,
" %s(%s) " , tmpl - > name , alg - > base . cra_name ) > =
CRYPTO_MAX_ALG_NAME )
2020-02-26 07:59:20 +03:00
goto err_free_inst ;
2019-11-08 13:41:58 +03:00
if ( snprintf ( inst - > alg . base . cra_driver_name , CRYPTO_MAX_ALG_NAME ,
" %s(%s) " , tmpl - > name , alg - > base . cra_driver_name ) > =
CRYPTO_MAX_ALG_NAME )
2020-02-26 07:59:20 +03:00
goto err_free_inst ;
2019-11-08 13:41:58 +03:00
inst - > alg . base . cra_flags = alg - > base . cra_flags & CRYPTO_ALG_ASYNC ;
inst - > alg . base . cra_priority = alg - > base . cra_priority ;
inst - > alg . base . cra_blocksize = alg - > base . cra_blocksize ;
inst - > alg . base . cra_alignmask = alg - > base . cra_alignmask ;
inst - > alg . base . cra_ctxsize = sizeof ( struct aead_geniv_ctx ) ;
inst - > alg . setkey = aead_geniv_setkey ;
inst - > alg . setauthsize = aead_geniv_setauthsize ;
inst - > alg . ivsize = ivsize ;
inst - > alg . maxauthsize = maxauthsize ;
2020-01-03 07:04:36 +03:00
inst - > free = aead_geniv_free ;
2019-11-08 13:41:58 +03:00
out :
return inst ;
err_free_inst :
2020-02-26 07:59:20 +03:00
aead_geniv_free ( inst ) ;
2019-11-08 13:41:58 +03:00
inst = ERR_PTR ( err ) ;
goto out ;
}
EXPORT_SYMBOL_GPL ( aead_geniv_alloc ) ;
int aead_init_geniv ( struct crypto_aead * aead )
{
struct aead_geniv_ctx * ctx = crypto_aead_ctx ( aead ) ;
struct aead_instance * inst = aead_alg_instance ( aead ) ;
struct crypto_aead * child ;
int err ;
spin_lock_init ( & ctx - > lock ) ;
err = crypto_get_default_rng ( ) ;
if ( err )
goto out ;
err = crypto_rng_get_bytes ( crypto_default_rng , ctx - > salt ,
crypto_aead_ivsize ( aead ) ) ;
crypto_put_default_rng ( ) ;
if ( err )
goto out ;
ctx - > sknull = crypto_get_default_null_skcipher ( ) ;
err = PTR_ERR ( ctx - > sknull ) ;
if ( IS_ERR ( ctx - > sknull ) )
goto out ;
child = crypto_spawn_aead ( aead_instance_ctx ( inst ) ) ;
err = PTR_ERR ( child ) ;
if ( IS_ERR ( child ) )
goto drop_null ;
ctx - > child = child ;
crypto_aead_set_reqsize ( aead , crypto_aead_reqsize ( child ) +
sizeof ( struct aead_request ) ) ;
err = 0 ;
out :
return err ;
drop_null :
crypto_put_default_null_skcipher ( ) ;
goto out ;
}
EXPORT_SYMBOL_GPL ( aead_init_geniv ) ;
void aead_exit_geniv ( struct crypto_aead * tfm )
{
struct aead_geniv_ctx * ctx = crypto_aead_ctx ( tfm ) ;
crypto_free_aead ( ctx - > child ) ;
crypto_put_default_null_skcipher ( ) ;
}
EXPORT_SYMBOL_GPL ( aead_exit_geniv ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Shared IV generator code " ) ;