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 .
*
* Copyright ( c ) 2007 Herbert Xu < herbert @ gondor . apana . org . au >
*
* 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-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>
2009-10-07 17:09:06 +04:00
# include <linux/sched.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>
# include <net/netlink.h>
2007-08-30 11:36:14 +04:00
2007-12-12 14:23:36 +03:00
# include "internal.h"
2015-05-27 09:37:30 +03:00
struct compat_request_ctx {
struct scatterlist src [ 2 ] ;
struct scatterlist dst [ 2 ] ;
struct scatterlist ivbuf [ 2 ] ;
struct scatterlist * ivsg ;
struct aead_givcrypt_request subreq ;
} ;
2015-05-11 12:48:12 +03:00
static int aead_null_givencrypt ( struct aead_givcrypt_request * req ) ;
static int aead_null_givdecrypt ( struct aead_givcrypt_request * req ) ;
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-05-21 10:11:08 +03:00
ret = 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 ) ;
2015-05-11 12:48:12 +03:00
tfm = tfm - > child ;
2007-08-30 11:36:14 +04:00
if ( ( unsigned long ) key & alignmask )
return setkey_unaligned ( tfm , key , keylen ) ;
2015-05-21 10:11:08 +03:00
return tfm - > setkey ( tfm , key , keylen ) ;
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-05-21 10:11:08 +03:00
if ( tfm - > setauthsize ) {
err = tfm - > setauthsize ( tfm - > child , authsize ) ;
2007-12-02 10:49:21 +03:00
if ( err )
return err ;
}
2015-05-11 12:48:12 +03:00
tfm - > child - > authsize = authsize ;
tfm - > authsize = authsize ;
2007-12-02 10:49:21 +03:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( crypto_aead_setauthsize ) ;
2015-05-21 10:11:01 +03:00
struct aead_old_request {
struct scatterlist srcbuf [ 2 ] ;
struct scatterlist dstbuf [ 2 ] ;
struct aead_request subreq ;
} ;
unsigned int crypto_aead_reqsize ( struct crypto_aead * tfm )
{
return tfm - > reqsize + sizeof ( struct aead_old_request ) ;
}
EXPORT_SYMBOL_GPL ( crypto_aead_reqsize ) ;
static int old_crypt ( struct aead_request * req ,
int ( * crypt ) ( struct aead_request * req ) )
{
struct aead_old_request * nreq = aead_request_ctx ( req ) ;
struct crypto_aead * aead = crypto_aead_reqtfm ( req ) ;
struct scatterlist * src , * dst ;
if ( req - > old )
return crypt ( req ) ;
2015-05-23 10:41:57 +03:00
src = scatterwalk_ffwd ( nreq - > srcbuf , req - > src , req - > assoclen ) ;
2015-05-27 09:37:29 +03:00
dst = req - > src = = req - > dst ?
src : scatterwalk_ffwd ( nreq - > dstbuf , req - > dst , req - > assoclen ) ;
2015-05-21 10:11:01 +03:00
aead_request_set_tfm ( & nreq - > subreq , aead ) ;
aead_request_set_callback ( & nreq - > subreq , aead_request_flags ( req ) ,
req - > base . complete , req - > base . data ) ;
aead_request_set_crypt ( & nreq - > subreq , src , dst , req - > cryptlen ,
req - > iv ) ;
aead_request_set_assoc ( & nreq - > subreq , req - > src , req - > assoclen ) ;
return crypt ( & nreq - > subreq ) ;
}
static int old_encrypt ( struct aead_request * req )
{
struct crypto_aead * aead = crypto_aead_reqtfm ( req ) ;
2015-05-21 10:11:02 +03:00
struct old_aead_alg * alg = crypto_old_aead_alg ( aead ) ;
2015-05-21 10:11:01 +03:00
return old_crypt ( req , alg - > encrypt ) ;
}
static int old_decrypt ( struct aead_request * req )
{
struct crypto_aead * aead = crypto_aead_reqtfm ( req ) ;
2015-05-21 10:11:02 +03:00
struct old_aead_alg * alg = crypto_old_aead_alg ( aead ) ;
2015-05-21 10:11:01 +03:00
return old_crypt ( req , alg - > decrypt ) ;
}
2007-12-12 14:27:25 +03:00
static int no_givcrypt ( struct aead_givcrypt_request * req )
2007-12-10 11:18:01 +03:00
{
return - ENOSYS ;
}
2015-05-21 10:11:08 +03:00
static int crypto_old_aead_init_tfm ( struct crypto_tfm * tfm )
2007-08-30 11:36:14 +04:00
{
2015-05-21 10:11:02 +03:00
struct old_aead_alg * alg = & tfm - > __crt_alg - > cra_aead ;
2015-05-11 12:48:12 +03:00
struct crypto_aead * crt = __crypto_aead_cast ( tfm ) ;
2007-08-30 11:36:14 +04:00
2007-12-02 10:49:21 +03:00
if ( max ( alg - > maxauthsize , alg - > ivsize ) > PAGE_SIZE / 8 )
2007-08-30 11:36:14 +04:00
return - EINVAL ;
2015-05-21 10:11:08 +03:00
crt - > setkey = alg - > setkey ;
crt - > setauthsize = alg - > setauthsize ;
2015-05-21 10:11:01 +03:00
crt - > encrypt = old_encrypt ;
crt - > decrypt = old_decrypt ;
2015-05-11 12:48:12 +03:00
if ( alg - > ivsize ) {
crt - > givencrypt = alg - > givencrypt ? : no_givcrypt ;
crt - > givdecrypt = alg - > givdecrypt ? : no_givcrypt ;
} else {
crt - > givencrypt = aead_null_givencrypt ;
crt - > givdecrypt = aead_null_givdecrypt ;
}
crt - > child = __crypto_aead_cast ( tfm ) ;
2007-12-02 10:49:21 +03:00
crt - > authsize = alg - > maxauthsize ;
2007-08-30 11:36:14 +04:00
return 0 ;
}
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 ) ;
if ( crypto_old_aead_alg ( aead ) - > encrypt )
return crypto_old_aead_init_tfm ( tfm ) ;
aead - > setkey = alg - > setkey ;
aead - > setauthsize = alg - > setauthsize ;
aead - > encrypt = alg - > encrypt ;
aead - > decrypt = alg - > decrypt ;
aead - > child = __crypto_aead_cast ( tfm ) ;
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 ;
}
2011-11-03 16:46:07 +04:00
# ifdef CONFIG_NET
2015-05-21 10:11:08 +03:00
static int crypto_old_aead_report ( struct sk_buff * skb , struct crypto_alg * alg )
2011-09-27 09:44:27 +04:00
{
struct crypto_report_aead raead ;
2015-05-21 10:11:02 +03:00
struct old_aead_alg * aead = & alg - > cra_aead ;
2011-09-27 09:44:27 +04:00
2013-02-05 21:19:13 +04:00
strncpy ( raead . type , " aead " , sizeof ( raead . type ) ) ;
strncpy ( raead . geniv , aead - > geniv ? : " <built-in> " , sizeof ( raead . geniv ) ) ;
2011-09-27 09:44:27 +04:00
raead . blocksize = alg - > cra_blocksize ;
raead . maxauthsize = aead - > maxauthsize ;
raead . ivsize = aead - > ivsize ;
2012-04-02 04:19:05 +04:00
if ( nla_put ( skb , CRYPTOCFGA_REPORT_AEAD ,
sizeof ( struct crypto_report_aead ) , & raead ) )
goto nla_put_failure ;
2011-09-27 09:44:27 +04:00
return 0 ;
nla_put_failure :
return - EMSGSIZE ;
}
2011-11-03 16:46:07 +04:00
# else
2015-05-21 10:11:08 +03:00
static int crypto_old_aead_report ( struct sk_buff * skb , struct crypto_alg * alg )
2011-11-03 16:46:07 +04:00
{
return - ENOSYS ;
}
# endif
2011-09-27 09:44:27 +04:00
2015-05-21 10:11:08 +03:00
static void crypto_old_aead_show ( struct seq_file * m , struct crypto_alg * alg )
2007-08-30 11:36:14 +04:00
__attribute__ ( ( unused ) ) ;
2015-05-21 10:11:08 +03:00
static void crypto_old_aead_show ( struct seq_file * m , struct crypto_alg * alg )
2007-08-30 11:36:14 +04:00
{
2015-05-21 10:11:02 +03:00
struct old_aead_alg * aead = & alg - > cra_aead ;
2007-08-30 11:36:14 +04:00
seq_printf ( m , " type : aead \n " ) ;
2007-12-14 17:29:37 +03:00
seq_printf ( m , " async : %s \n " , alg - > cra_flags & CRYPTO_ALG_ASYNC ?
" yes " : " no " ) ;
2007-08-30 11:36:14 +04:00
seq_printf ( m , " blocksize : %u \n " , alg - > cra_blocksize ) ;
seq_printf ( m , " ivsize : %u \n " , aead - > ivsize ) ;
2007-12-02 10:49:21 +03:00
seq_printf ( m , " maxauthsize : %u \n " , aead - > maxauthsize ) ;
2007-12-12 14:23:36 +03:00
seq_printf ( m , " geniv : %s \n " , aead - > geniv ? : " <built-in> " ) ;
2007-08-30 11:36:14 +04:00
}
const struct crypto_type crypto_aead_type = {
2015-05-11 12:48:12 +03:00
. extsize = crypto_alg_extsize ,
. init_tfm = crypto_aead_init_tfm ,
2007-08-30 11:36:14 +04:00
# ifdef CONFIG_PROC_FS
2015-05-21 10:11:08 +03:00
. show = crypto_old_aead_show ,
2007-08-30 11:36:14 +04:00
# endif
2015-05-21 10:11:08 +03:00
. report = crypto_old_aead_report ,
2015-05-11 12:48:12 +03:00
. lookup = crypto_lookup_aead ,
. maskclear = ~ ( CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV ) ,
. maskset = CRYPTO_ALG_TYPE_MASK ,
. type = CRYPTO_ALG_TYPE_AEAD ,
. tfmsize = offsetof ( struct crypto_aead , base ) ,
2007-08-30 11:36:14 +04:00
} ;
EXPORT_SYMBOL_GPL ( crypto_aead_type ) ;
2015-05-21 10:11:08 +03:00
# 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 )
__attribute__ ( ( unused ) ) ;
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 " ) ;
}
static const struct crypto_type crypto_new_aead_type = {
. extsize = crypto_alg_extsize ,
. init_tfm = crypto_aead_init_tfm ,
# 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 ) ,
} ;
2007-12-12 14:23:36 +03:00
static int aead_null_givencrypt ( struct aead_givcrypt_request * req )
{
return crypto_aead_encrypt ( & req - > areq ) ;
}
static int aead_null_givdecrypt ( struct aead_givcrypt_request * req )
{
return crypto_aead_decrypt ( & req - > areq ) ;
}
2011-11-03 16:46:07 +04:00
# ifdef CONFIG_NET
2011-09-27 09:45:44 +04:00
static int crypto_nivaead_report ( struct sk_buff * skb , struct crypto_alg * alg )
{
struct crypto_report_aead raead ;
2015-05-21 10:11:02 +03:00
struct old_aead_alg * aead = & alg - > cra_aead ;
2011-09-27 09:45:44 +04:00
2013-02-05 21:19:13 +04:00
strncpy ( raead . type , " nivaead " , sizeof ( raead . type ) ) ;
strncpy ( raead . geniv , aead - > geniv , sizeof ( raead . geniv ) ) ;
2011-09-27 09:45:44 +04:00
raead . blocksize = alg - > cra_blocksize ;
raead . maxauthsize = aead - > maxauthsize ;
raead . ivsize = aead - > ivsize ;
2012-04-02 04:19:05 +04:00
if ( nla_put ( skb , CRYPTOCFGA_REPORT_AEAD ,
sizeof ( struct crypto_report_aead ) , & raead ) )
goto nla_put_failure ;
2011-09-27 09:45:44 +04:00
return 0 ;
nla_put_failure :
return - EMSGSIZE ;
}
2011-11-03 16:46:07 +04:00
# else
static int crypto_nivaead_report ( struct sk_buff * skb , struct crypto_alg * alg )
{
return - ENOSYS ;
}
# endif
2011-09-27 09:45:44 +04:00
2007-12-12 14:23:36 +03:00
static void crypto_nivaead_show ( struct seq_file * m , struct crypto_alg * alg )
__attribute__ ( ( unused ) ) ;
static void crypto_nivaead_show ( struct seq_file * m , struct crypto_alg * alg )
{
2015-05-21 10:11:02 +03:00
struct old_aead_alg * aead = & alg - > cra_aead ;
2007-12-12 14:23:36 +03:00
seq_printf ( m , " type : nivaead \n " ) ;
2007-12-14 17:29:37 +03:00
seq_printf ( m , " async : %s \n " , alg - > cra_flags & CRYPTO_ALG_ASYNC ?
" yes " : " no " ) ;
2007-12-12 14:23:36 +03:00
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 : %s \n " , aead - > geniv ) ;
}
const struct crypto_type crypto_nivaead_type = {
2015-05-11 12:48:12 +03:00
. extsize = crypto_alg_extsize ,
. init_tfm = crypto_aead_init_tfm ,
2007-12-12 14:23:36 +03:00
# ifdef CONFIG_PROC_FS
. show = crypto_nivaead_show ,
# endif
2011-09-27 09:45:44 +04:00
. report = crypto_nivaead_report ,
2015-05-11 12:48:12 +03:00
. maskclear = ~ ( CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV ) ,
. maskset = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV ,
. type = CRYPTO_ALG_TYPE_AEAD ,
. tfmsize = offsetof ( struct crypto_aead , base ) ,
2007-12-12 14:23:36 +03:00
} ;
EXPORT_SYMBOL_GPL ( crypto_nivaead_type ) ;
static int crypto_grab_nivaead ( struct crypto_aead_spawn * spawn ,
const char * name , u32 type , u32 mask )
{
2015-05-11 12:48:12 +03:00
spawn - > base . frontend = & crypto_nivaead_type ;
return crypto_grab_spawn ( & spawn - > base , name , type , mask ) ;
2007-12-12 14:23:36 +03:00
}
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 ) ;
}
static void compat_encrypt_complete2 ( struct aead_request * req , int err )
{
struct compat_request_ctx * rctx = aead_request_ctx ( req ) ;
struct aead_givcrypt_request * subreq = & rctx - > subreq ;
struct crypto_aead * geniv ;
if ( err = = - EINPROGRESS )
return ;
if ( err )
goto out ;
geniv = crypto_aead_reqtfm ( req ) ;
scatterwalk_map_and_copy ( subreq - > giv , rctx - > ivsg , 0 ,
crypto_aead_ivsize ( geniv ) , 1 ) ;
out :
kzfree ( subreq - > giv ) ;
}
static void compat_encrypt_complete ( struct crypto_async_request * base , int err )
{
struct aead_request * req = base - > data ;
compat_encrypt_complete2 ( req , err ) ;
aead_request_complete ( req , err ) ;
}
static int compat_encrypt ( struct aead_request * req )
{
struct crypto_aead * geniv = crypto_aead_reqtfm ( req ) ;
struct aead_geniv_ctx * ctx = crypto_aead_ctx ( geniv ) ;
struct compat_request_ctx * rctx = aead_request_ctx ( req ) ;
struct aead_givcrypt_request * subreq = & rctx - > subreq ;
unsigned int ivsize = crypto_aead_ivsize ( geniv ) ;
struct scatterlist * src , * dst ;
crypto_completion_t compl ;
void * data ;
u8 * info ;
__be64 seq ;
int err ;
if ( req - > cryptlen < ivsize )
return - EINVAL ;
compl = req - > base . complete ;
data = req - > base . data ;
rctx - > ivsg = scatterwalk_ffwd ( rctx - > ivbuf , req - > dst , req - > assoclen ) ;
info = PageHighMem ( sg_page ( rctx - > ivsg ) ) ? NULL : sg_virt ( rctx - > ivsg ) ;
if ( ! info ) {
info = kmalloc ( ivsize , req - > base . flags &
CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
GFP_ATOMIC ) ;
if ( ! info )
return - ENOMEM ;
compl = compat_encrypt_complete ;
data = req ;
}
memcpy ( & seq , req - > iv + ivsize - sizeof ( seq ) , sizeof ( seq ) ) ;
src = scatterwalk_ffwd ( rctx - > src , req - > src , req - > assoclen + ivsize ) ;
dst = req - > src = = req - > dst ?
src : scatterwalk_ffwd ( rctx - > dst , rctx - > ivsg , ivsize ) ;
aead_givcrypt_set_tfm ( subreq , ctx - > child ) ;
aead_givcrypt_set_callback ( subreq , req - > base . flags ,
req - > base . complete , req - > base . data ) ;
aead_givcrypt_set_crypt ( subreq , src , dst ,
req - > cryptlen - ivsize , req - > iv ) ;
aead_givcrypt_set_assoc ( subreq , req - > src , req - > assoclen ) ;
aead_givcrypt_set_giv ( subreq , info , be64_to_cpu ( seq ) ) ;
err = crypto_aead_givencrypt ( subreq ) ;
if ( unlikely ( PageHighMem ( sg_page ( rctx - > ivsg ) ) ) )
compat_encrypt_complete2 ( req , err ) ;
return err ;
}
static int compat_decrypt ( struct aead_request * req )
{
struct crypto_aead * geniv = crypto_aead_reqtfm ( req ) ;
struct aead_geniv_ctx * ctx = crypto_aead_ctx ( geniv ) ;
struct compat_request_ctx * rctx = aead_request_ctx ( req ) ;
struct aead_request * subreq = & rctx - > subreq . areq ;
unsigned int ivsize = crypto_aead_ivsize ( geniv ) ;
struct scatterlist * src , * dst ;
crypto_completion_t compl ;
void * data ;
if ( req - > cryptlen < ivsize )
return - EINVAL ;
aead_request_set_tfm ( subreq , ctx - > child ) ;
compl = req - > base . complete ;
data = req - > base . data ;
src = scatterwalk_ffwd ( rctx - > src , req - > src , req - > assoclen + ivsize ) ;
dst = req - > src = = req - > dst ?
src : scatterwalk_ffwd ( rctx - > dst , req - > dst ,
req - > assoclen + ivsize ) ;
aead_request_set_callback ( subreq , req - > base . flags , compl , data ) ;
aead_request_set_crypt ( subreq , src , dst ,
req - > cryptlen - ivsize , req - > iv ) ;
aead_request_set_assoc ( subreq , req - > src , req - > assoclen ) ;
scatterwalk_map_and_copy ( req - > iv , req - > src , req - > assoclen , ivsize , 0 ) ;
return crypto_aead_decrypt ( subreq ) ;
}
static int compat_encrypt_first ( struct aead_request * req )
{
struct crypto_aead * geniv = crypto_aead_reqtfm ( req ) ;
struct aead_geniv_ctx * ctx = crypto_aead_ctx ( geniv ) ;
int err = 0 ;
spin_lock_bh ( & ctx - > lock ) ;
if ( geniv - > encrypt ! = compat_encrypt_first )
goto unlock ;
geniv - > encrypt = compat_encrypt ;
unlock :
spin_unlock_bh ( & ctx - > lock ) ;
if ( err )
return err ;
return compat_encrypt ( req ) ;
}
static int aead_geniv_init_compat ( struct crypto_tfm * tfm )
{
struct crypto_aead * geniv = __crypto_aead_cast ( tfm ) ;
struct aead_geniv_ctx * ctx = crypto_aead_ctx ( geniv ) ;
int err ;
spin_lock_init ( & ctx - > lock ) ;
crypto_aead_set_reqsize ( geniv , sizeof ( struct compat_request_ctx ) ) ;
err = aead_geniv_init ( tfm ) ;
ctx - > child = geniv - > child ;
geniv - > child = geniv ;
return err ;
}
static void aead_geniv_exit_compat ( struct crypto_tfm * tfm )
{
struct crypto_aead * geniv = __crypto_aead_cast ( tfm ) ;
struct aead_geniv_ctx * ctx = crypto_aead_ctx ( geniv ) ;
crypto_free_aead ( ctx - > child ) ;
}
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
if ( ( algt - > type ^ ( CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV ) ) &
algt - > mask )
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-05-27 09:37:30 +03:00
err = ( algt - > mask & CRYPTO_ALG_GENIV ) ?
crypto_grab_nivaead ( spawn , name , type , mask ) :
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 ;
/*
* This is only true if we ' re constructing an algorithm with its
* default IV generator . For the default generator we elide the
* template name and double - check the IV generator .
*/
if ( algt - > mask & CRYPTO_ALG_GENIV ) {
2015-05-21 10:11:13 +03:00
if ( ! alg - > base . cra_aead . encrypt )
goto err_drop_alg ;
if ( strcmp ( tmpl - > name , alg - > base . cra_aead . geniv ) )
2007-12-12 14:23:36 +03:00
goto err_drop_alg ;
2015-05-21 10:11:13 +03:00
memcpy ( inst - > alg . base . cra_name , alg - > base . cra_name ,
2007-12-12 14:23:36 +03:00
CRYPTO_MAX_ALG_NAME ) ;
2015-05-21 10:11:13 +03:00
memcpy ( inst - > alg . base . cra_driver_name ,
alg - > base . cra_driver_name , CRYPTO_MAX_ALG_NAME ) ;
inst - > alg . base . cra_flags = CRYPTO_ALG_TYPE_AEAD |
CRYPTO_ALG_GENIV ;
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_type = & crypto_aead_type ;
inst - > alg . base . cra_aead . ivsize = ivsize ;
inst - > alg . base . cra_aead . maxauthsize = maxauthsize ;
inst - > alg . base . cra_aead . setkey = alg - > base . cra_aead . setkey ;
inst - > alg . base . cra_aead . setauthsize =
alg - > base . cra_aead . setauthsize ;
inst - > alg . base . cra_aead . encrypt = alg - > base . cra_aead . encrypt ;
inst - > alg . base . cra_aead . decrypt = alg - > base . cra_aead . decrypt ;
goto out ;
2007-12-12 14:23:36 +03:00
}
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-05-23 10:41:53 +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
2015-05-27 09:37:30 +03:00
inst - > alg . encrypt = compat_encrypt_first ;
inst - > alg . decrypt = compat_decrypt ;
inst - > alg . base . cra_init = aead_geniv_init_compat ;
inst - > alg . base . cra_exit = aead_geniv_exit_compat ;
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 ) ;
int aead_geniv_init ( struct crypto_tfm * tfm )
{
struct crypto_instance * inst = ( void * ) tfm - > __crt_alg ;
2015-05-11 12:48:12 +03:00
struct crypto_aead * child ;
2007-12-12 14:23:36 +03:00
struct crypto_aead * aead ;
2015-05-11 12:48:12 +03:00
aead = __crypto_aead_cast ( tfm ) ;
2007-12-12 14:23:36 +03:00
2015-05-11 12:48:12 +03:00
child = crypto_spawn_aead ( crypto_instance_ctx ( inst ) ) ;
if ( IS_ERR ( child ) )
return PTR_ERR ( child ) ;
aead - > child = child ;
aead - > reqsize + = crypto_aead_reqsize ( child ) ;
2007-12-12 14:23:36 +03:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( aead_geniv_init ) ;
void aead_geniv_exit ( struct crypto_tfm * tfm )
{
2015-05-11 12:48:12 +03:00
crypto_free_aead ( __crypto_aead_cast ( tfm ) - > child ) ;
2007-12-12 14:23:36 +03:00
}
EXPORT_SYMBOL_GPL ( aead_geniv_exit ) ;
2007-12-12 14:24:27 +03:00
static int crypto_nivaead_default ( struct crypto_alg * alg , u32 type , u32 mask )
{
struct rtattr * tb [ 3 ] ;
struct {
struct rtattr attr ;
struct crypto_attr_type data ;
} ptype ;
struct {
struct rtattr attr ;
struct crypto_attr_alg data ;
} palg ;
struct crypto_template * tmpl ;
struct crypto_instance * inst ;
struct crypto_alg * larval ;
const char * geniv ;
int err ;
larval = crypto_larval_lookup ( alg - > cra_driver_name ,
CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV ,
CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV ) ;
err = PTR_ERR ( larval ) ;
if ( IS_ERR ( larval ) )
goto out ;
err = - EAGAIN ;
if ( ! crypto_is_larval ( larval ) )
goto drop_larval ;
ptype . attr . rta_len = sizeof ( ptype ) ;
ptype . attr . rta_type = CRYPTOA_TYPE ;
ptype . data . type = type | CRYPTO_ALG_GENIV ;
/* GENIV tells the template that we're making a default geniv. */
ptype . data . mask = mask | CRYPTO_ALG_GENIV ;
tb [ 0 ] = & ptype . attr ;
palg . attr . rta_len = sizeof ( palg ) ;
palg . attr . rta_type = CRYPTOA_ALG ;
/* Must use the exact name to locate ourselves. */
memcpy ( palg . data . name , alg - > cra_driver_name , CRYPTO_MAX_ALG_NAME ) ;
tb [ 1 ] = & palg . attr ;
tb [ 2 ] = NULL ;
geniv = alg - > cra_aead . geniv ;
tmpl = crypto_lookup_template ( geniv ) ;
err = - ENOENT ;
if ( ! tmpl )
goto kill_larval ;
2015-05-23 10:41:49 +03:00
if ( tmpl - > create ) {
err = tmpl - > create ( tmpl , tb ) ;
if ( err )
goto put_tmpl ;
goto ok ;
}
2007-12-12 14:24:27 +03:00
inst = tmpl - > alloc ( tb ) ;
err = PTR_ERR ( inst ) ;
if ( IS_ERR ( inst ) )
goto put_tmpl ;
2014-12-05 08:24:44 +03:00
err = crypto_register_instance ( tmpl , inst ) ;
if ( err ) {
2007-12-12 14:24:27 +03:00
tmpl - > free ( inst ) ;
goto put_tmpl ;
}
2015-05-23 10:41:49 +03:00
ok :
2007-12-12 14:24:27 +03:00
/* Redo the lookup to use the instance we just registered. */
err = - EAGAIN ;
put_tmpl :
crypto_tmpl_put ( tmpl ) ;
kill_larval :
crypto_larval_kill ( larval ) ;
drop_larval :
crypto_mod_put ( larval ) ;
out :
crypto_mod_put ( alg ) ;
return err ;
}
2012-03-29 11:03:47 +04:00
struct crypto_alg * crypto_lookup_aead ( const char * name , u32 type , u32 mask )
2007-12-12 14:24:27 +03:00
{
struct crypto_alg * alg ;
alg = crypto_alg_mod_lookup ( name , type , mask ) ;
if ( IS_ERR ( alg ) )
return alg ;
if ( alg - > cra_type = = & crypto_aead_type )
return alg ;
if ( ! alg - > cra_aead . ivsize )
return alg ;
2009-02-18 15:41:47 +03:00
crypto_mod_put ( alg ) ;
alg = crypto_alg_mod_lookup ( name , type | CRYPTO_ALG_TESTED ,
mask & ~ CRYPTO_ALG_TESTED ) ;
if ( IS_ERR ( alg ) )
return alg ;
if ( alg - > cra_type = = & crypto_aead_type ) {
2015-04-23 11:37:46 +03:00
if ( ~ alg - > cra_flags & ( type ^ ~ mask ) & CRYPTO_ALG_TESTED ) {
2009-02-18 15:41:47 +03:00
crypto_mod_put ( alg ) ;
alg = ERR_PTR ( - ENOENT ) ;
}
return alg ;
}
BUG_ON ( ! alg - > cra_aead . ivsize ) ;
2007-12-12 14:24:27 +03:00
return ERR_PTR ( crypto_nivaead_default ( alg , type , mask ) ) ;
}
2012-03-29 11:03:47 +04:00
EXPORT_SYMBOL_GPL ( crypto_lookup_aead ) ;
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 ;
if ( max ( alg - > maxauthsize , alg - > ivsize ) > PAGE_SIZE / 8 )
return - EINVAL ;
base - > cra_type = & crypto_new_aead_type ;
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 ) ;
int crypto_unregister_aead ( struct aead_alg * alg )
{
return crypto_unregister_alg ( & alg - > base ) ;
}
EXPORT_SYMBOL_GPL ( crypto_unregister_aead ) ;
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) " ) ;