2007-08-30 11:36:14 +04:00
/*
* AEAD : Authenticated Encryption with Associated Data
2010-02-16 15:24:07 +03:00
*
2007-08-30 11:36:14 +04:00
* This file provides API support for AEAD algorithms .
*
2015-08-14 10:30:41 +03:00
* Copyright ( c ) 2007 - 2015 Herbert Xu < herbert @ gondor . apana . org . au >
2007-08-30 11:36:14 +04:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the Free
2010-02-16 15:24:07 +03:00
* Software Foundation ; either version 2 of the License , or ( at your option )
2007-08-30 11:36:14 +04:00
* any later version .
*
*/
2015-05-27 09:37:30 +03:00
# include <crypto/internal/geniv.h>
2015-08-13 12:28:58 +03:00
# include <crypto/internal/rng.h>
# include <crypto/null.h>
2015-05-21 10:11:01 +03:00
# include <crypto/scatterwalk.h>
2007-12-12 14:23:36 +03:00
# include <linux/err.h>
2007-08-30 11:36:14 +04:00
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
2007-12-12 14:24:27 +03:00
# include <linux/rtnetlink.h>
2007-08-30 11:36:14 +04:00
# include <linux/slab.h>
# include <linux/seq_file.h>
2011-09-27 09:44:27 +04:00
# include <linux/cryptouser.h>
2016-12-31 18:56:23 +03:00
# include <linux/compiler.h>
2011-09-27 09:44:27 +04:00
# include <net/netlink.h>
2007-08-30 11:36:14 +04:00
2007-12-12 14:23:36 +03:00
# include "internal.h"
2007-08-30 11:36:14 +04:00
static int setkey_unaligned ( struct crypto_aead * tfm , const u8 * key ,
unsigned int keylen )
{
unsigned long alignmask = crypto_aead_alignmask ( tfm ) ;
int ret ;
u8 * buffer , * alignbuffer ;
unsigned long absize ;
absize = keylen + alignmask ;
buffer = kmalloc ( absize , GFP_ATOMIC ) ;
if ( ! buffer )
return - ENOMEM ;
alignbuffer = ( u8 * ) ALIGN ( ( unsigned long ) buffer , alignmask + 1 ) ;
memcpy ( alignbuffer , key , keylen ) ;
2015-08-14 10:30:41 +03:00
ret = crypto_aead_alg ( tfm ) - > setkey ( tfm , alignbuffer , keylen ) ;
2007-08-30 11:36:14 +04:00
memset ( alignbuffer , 0 , keylen ) ;
kfree ( buffer ) ;
return ret ;
}
2015-05-11 12:48:12 +03:00
int crypto_aead_setkey ( struct crypto_aead * tfm ,
const u8 * key , unsigned int keylen )
2007-08-30 11:36:14 +04:00
{
unsigned long alignmask = crypto_aead_alignmask ( tfm ) ;
2018-01-03 22:16:30 +03:00
int err ;
2007-08-30 11:36:14 +04:00
if ( ( unsigned long ) key & alignmask )
2018-01-03 22:16:30 +03:00
err = setkey_unaligned ( tfm , key , keylen ) ;
else
err = crypto_aead_alg ( tfm ) - > setkey ( tfm , key , keylen ) ;
if ( err )
return err ;
2007-08-30 11:36:14 +04:00
2018-01-03 22:16:30 +03:00
crypto_aead_clear_flags ( tfm , CRYPTO_TFM_NEED_KEY ) ;
return 0 ;
2007-08-30 11:36:14 +04:00
}
2015-05-11 12:48:12 +03:00
EXPORT_SYMBOL_GPL ( crypto_aead_setkey ) ;
2007-08-30 11:36:14 +04:00
2007-12-02 10:49:21 +03:00
int crypto_aead_setauthsize ( struct crypto_aead * tfm , unsigned int authsize )
{
int err ;
2015-05-22 11:30:48 +03:00
if ( authsize > crypto_aead_maxauthsize ( tfm ) )
2007-12-02 10:49:21 +03:00
return - EINVAL ;
2015-08-14 10:30:41 +03:00
if ( crypto_aead_alg ( tfm ) - > setauthsize ) {
err = crypto_aead_alg ( tfm ) - > setauthsize ( tfm , authsize ) ;
2007-12-02 10:49:21 +03:00
if ( err )
return err ;
}
2015-05-11 12:48:12 +03:00
tfm - > authsize = authsize ;
2007-12-02 10:49:21 +03:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( crypto_aead_setauthsize ) ;
2015-05-28 17:07:53 +03:00
static void crypto_aead_exit_tfm ( struct crypto_tfm * tfm )
{
struct crypto_aead * aead = __crypto_aead_cast ( tfm ) ;
struct aead_alg * alg = crypto_aead_alg ( aead ) ;
alg - > exit ( aead ) ;
}
2015-05-21 10:11:08 +03:00
static int crypto_aead_init_tfm ( struct crypto_tfm * tfm )
{
struct crypto_aead * aead = __crypto_aead_cast ( tfm ) ;
struct aead_alg * alg = crypto_aead_alg ( aead ) ;
2018-01-03 22:16:30 +03:00
crypto_aead_set_flags ( aead , CRYPTO_TFM_NEED_KEY ) ;
2015-05-21 10:11:08 +03:00
aead - > authsize = alg - > maxauthsize ;
2015-05-28 17:07:53 +03:00
if ( alg - > exit )
aead - > base . exit = crypto_aead_exit_tfm ;
if ( alg - > init )
return alg - > init ( aead ) ;
2015-05-21 10:11:08 +03:00
return 0 ;
}
# ifdef CONFIG_NET
static int crypto_aead_report ( struct sk_buff * skb , struct crypto_alg * alg )
{
struct crypto_report_aead raead ;
struct aead_alg * aead = container_of ( alg , struct aead_alg , base ) ;
strncpy ( raead . type , " aead " , sizeof ( raead . type ) ) ;
strncpy ( raead . geniv , " <none> " , sizeof ( raead . geniv ) ) ;
raead . blocksize = alg - > cra_blocksize ;
raead . maxauthsize = aead - > maxauthsize ;
raead . ivsize = aead - > ivsize ;
if ( nla_put ( skb , CRYPTOCFGA_REPORT_AEAD ,
sizeof ( struct crypto_report_aead ) , & raead ) )
goto nla_put_failure ;
return 0 ;
nla_put_failure :
return - EMSGSIZE ;
}
# else
static int crypto_aead_report ( struct sk_buff * skb , struct crypto_alg * alg )
{
return - ENOSYS ;
}
# endif
static void crypto_aead_show ( struct seq_file * m , struct crypto_alg * alg )
2016-12-31 18:56:23 +03:00
__maybe_unused ;
2015-05-21 10:11:08 +03:00
static void crypto_aead_show ( struct seq_file * m , struct crypto_alg * alg )
{
struct aead_alg * aead = container_of ( alg , struct aead_alg , base ) ;
seq_printf ( m , " type : aead \n " ) ;
seq_printf ( m , " async : %s \n " , alg - > cra_flags & CRYPTO_ALG_ASYNC ?
" yes " : " no " ) ;
seq_printf ( m , " blocksize : %u \n " , alg - > cra_blocksize ) ;
seq_printf ( m , " ivsize : %u \n " , aead - > ivsize ) ;
seq_printf ( m , " maxauthsize : %u \n " , aead - > maxauthsize ) ;
seq_printf ( m , " geniv : <none> \n " ) ;
}
2015-07-09 02:17:17 +03:00
static void crypto_aead_free_instance ( struct crypto_instance * inst )
{
struct aead_instance * aead = aead_instance ( inst ) ;
if ( ! aead - > free ) {
inst - > tmpl - > free ( inst ) ;
return ;
}
aead - > free ( aead ) ;
}
2015-08-14 10:30:41 +03:00
static const struct crypto_type crypto_aead_type = {
2015-05-21 10:11:08 +03:00
. extsize = crypto_alg_extsize ,
. init_tfm = crypto_aead_init_tfm ,
2015-07-09 02:17:17 +03:00
. free = crypto_aead_free_instance ,
2015-05-21 10:11:08 +03:00
# ifdef CONFIG_PROC_FS
. show = crypto_aead_show ,
# endif
. report = crypto_aead_report ,
. maskclear = ~ CRYPTO_ALG_TYPE_MASK ,
. maskset = CRYPTO_ALG_TYPE_MASK ,
. type = CRYPTO_ALG_TYPE_AEAD ,
. tfmsize = offsetof ( struct crypto_aead , base ) ,
} ;
2015-05-27 09:37:30 +03:00
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 ) ;
}
2015-05-21 10:11:13 +03:00
struct aead_instance * aead_geniv_alloc ( struct crypto_template * tmpl ,
struct rtattr * * tb , u32 type , u32 mask )
2007-12-12 14:23:36 +03:00
{
const char * name ;
struct crypto_aead_spawn * spawn ;
struct crypto_attr_type * algt ;
2015-05-21 10:11:13 +03:00
struct aead_instance * inst ;
struct aead_alg * alg ;
unsigned int ivsize ;
unsigned int maxauthsize ;
2007-12-12 14:23:36 +03:00
int err ;
algt = crypto_get_attr_type ( tb ) ;
if ( IS_ERR ( algt ) )
2013-01-22 15:29:26 +04:00
return ERR_CAST ( algt ) ;
2007-12-12 14:23:36 +03:00
2015-08-13 12:29:06 +03:00
if ( ( algt - > type ^ CRYPTO_ALG_TYPE_AEAD ) & algt - > mask )
2007-12-12 14:23:36 +03:00
return ERR_PTR ( - EINVAL ) ;
name = crypto_attr_alg_name ( tb [ 1 ] ) ;
if ( IS_ERR ( name ) )
2013-01-22 15:29:26 +04:00
return ERR_CAST ( name ) ;
2007-12-12 14:23:36 +03:00
inst = kzalloc ( sizeof ( * inst ) + sizeof ( * spawn ) , GFP_KERNEL ) ;
if ( ! inst )
return ERR_PTR ( - ENOMEM ) ;
2015-05-21 10:11:13 +03:00
spawn = aead_instance_ctx ( inst ) ;
2007-12-12 14:23:36 +03:00
/* Ignore async algorithms if necessary. */
mask | = crypto_requires_sync ( algt - > type , algt - > mask ) ;
2015-05-21 10:11:13 +03:00
crypto_set_aead_spawn ( spawn , aead_crypto_instance ( inst ) ) ;
2015-08-14 10:30:41 +03:00
err = crypto_grab_aead ( spawn , name , type , mask ) ;
2007-12-12 14:23:36 +03:00
if ( err )
goto err_free_inst ;
2015-05-21 10:11:13 +03:00
alg = crypto_spawn_aead_alg ( spawn ) ;
2015-05-22 11:30:48 +03:00
ivsize = crypto_aead_alg_ivsize ( alg ) ;
maxauthsize = crypto_aead_alg_maxauthsize ( alg ) ;
2007-12-12 14:23:36 +03:00
err = - EINVAL ;
2015-05-27 09:37:30 +03:00
if ( ivsize < sizeof ( u64 ) )
2007-12-12 14:23:36 +03:00
goto err_drop_alg ;
2015-05-21 10:11:13 +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 )
goto err_drop_alg ;
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 )
goto err_drop_alg ;
2007-12-12 14:23:36 +03:00
2015-08-13 12:29:06 +03:00
inst - > alg . base . cra_flags = alg - > base . cra_flags & CRYPTO_ALG_ASYNC ;
2015-05-21 10:11:13 +03:00
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 ;
2015-05-27 09:37:30 +03:00
inst - > alg . base . cra_ctxsize = sizeof ( struct aead_geniv_ctx ) ;
inst - > alg . setkey = aead_geniv_setkey ;
inst - > alg . setauthsize = aead_geniv_setauthsize ;
2007-12-12 14:23:36 +03:00
2015-05-21 10:11:13 +03:00
inst - > alg . ivsize = ivsize ;
inst - > alg . maxauthsize = maxauthsize ;
2007-12-12 14:23:36 +03:00
out :
return inst ;
err_drop_alg :
crypto_drop_aead ( spawn ) ;
err_free_inst :
kfree ( inst ) ;
inst = ERR_PTR ( err ) ;
goto out ;
}
EXPORT_SYMBOL_GPL ( aead_geniv_alloc ) ;
2015-05-21 10:11:13 +03:00
void aead_geniv_free ( struct aead_instance * inst )
2007-12-12 14:23:36 +03:00
{
2015-05-21 10:11:13 +03:00
crypto_drop_aead ( aead_instance_ctx ( inst ) ) ;
2007-12-12 14:23:36 +03:00
kfree ( inst ) ;
}
EXPORT_SYMBOL_GPL ( aead_geniv_free ) ;
2015-08-13 12:28:58 +03:00
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 ;
2017-12-07 21:56:34 +03:00
ctx - > sknull = crypto_get_default_null_skcipher ( ) ;
2016-07-12 08:17:42 +03:00
err = PTR_ERR ( ctx - > sknull ) ;
if ( IS_ERR ( ctx - > sknull ) )
goto out ;
2015-08-13 12:28:58 +03:00
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 :
2017-12-07 21:56:34 +03:00
crypto_put_default_null_skcipher ( ) ;
2015-08-13 12:28:58 +03:00
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 ) ;
2017-12-07 21:56:34 +03:00
crypto_put_default_null_skcipher ( ) ;
2015-08-13 12:28:58 +03:00
}
EXPORT_SYMBOL_GPL ( aead_exit_geniv ) ;
2007-12-12 14:24:27 +03:00
int crypto_grab_aead ( struct crypto_aead_spawn * spawn , const char * name ,
u32 type , u32 mask )
{
2015-05-11 12:48:12 +03:00
spawn - > base . frontend = & crypto_aead_type ;
return crypto_grab_spawn ( & spawn - > base , name , type , mask ) ;
2007-12-12 14:24:27 +03:00
}
EXPORT_SYMBOL_GPL ( crypto_grab_aead ) ;
struct crypto_aead * crypto_alloc_aead ( const char * alg_name , u32 type , u32 mask )
{
2015-05-11 12:48:12 +03:00
return crypto_alloc_tfm ( alg_name , & crypto_aead_type , type , mask ) ;
2007-12-12 14:24:27 +03:00
}
EXPORT_SYMBOL_GPL ( crypto_alloc_aead ) ;
2015-05-21 10:11:08 +03:00
static int aead_prepare_alg ( struct aead_alg * alg )
{
struct crypto_alg * base = & alg - > base ;
2016-07-12 08:17:33 +03:00
if ( max3 ( alg - > maxauthsize , alg - > ivsize , alg - > chunksize ) >
PAGE_SIZE / 8 )
2015-05-21 10:11:08 +03:00
return - EINVAL ;
2016-07-12 08:17:33 +03:00
if ( ! alg - > chunksize )
alg - > chunksize = base - > cra_blocksize ;
2015-08-14 10:30:41 +03:00
base - > cra_type = & crypto_aead_type ;
2015-05-21 10:11:08 +03:00
base - > cra_flags & = ~ CRYPTO_ALG_TYPE_MASK ;
base - > cra_flags | = CRYPTO_ALG_TYPE_AEAD ;
return 0 ;
}
int crypto_register_aead ( struct aead_alg * alg )
{
struct crypto_alg * base = & alg - > base ;
int err ;
err = aead_prepare_alg ( alg ) ;
if ( err )
return err ;
return crypto_register_alg ( base ) ;
}
EXPORT_SYMBOL_GPL ( crypto_register_aead ) ;
2015-05-28 17:07:57 +03:00
void crypto_unregister_aead ( struct aead_alg * alg )
2015-05-21 10:11:08 +03:00
{
2015-05-28 17:07:57 +03:00
crypto_unregister_alg ( & alg - > base ) ;
2015-05-21 10:11:08 +03:00
}
EXPORT_SYMBOL_GPL ( crypto_unregister_aead ) ;
2015-05-28 17:07:59 +03:00
int crypto_register_aeads ( struct aead_alg * algs , int count )
{
int i , ret ;
for ( i = 0 ; i < count ; i + + ) {
ret = crypto_register_aead ( & algs [ i ] ) ;
if ( ret )
goto err ;
}
return 0 ;
err :
for ( - - i ; i > = 0 ; - - i )
crypto_unregister_aead ( & algs [ i ] ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( crypto_register_aeads ) ;
void crypto_unregister_aeads ( struct aead_alg * algs , int count )
{
int i ;
for ( i = count - 1 ; i > = 0 ; - - i )
crypto_unregister_aead ( & algs [ i ] ) ;
}
EXPORT_SYMBOL_GPL ( crypto_unregister_aeads ) ;
2015-05-21 10:11:08 +03:00
int aead_register_instance ( struct crypto_template * tmpl ,
struct aead_instance * inst )
{
int err ;
err = aead_prepare_alg ( & inst - > alg ) ;
if ( err )
return err ;
return crypto_register_instance ( tmpl , aead_crypto_instance ( inst ) ) ;
}
EXPORT_SYMBOL_GPL ( aead_register_instance ) ;
2007-08-30 11:36:14 +04:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Authenticated Encryption with Associated Data (AEAD) " ) ;