2011-03-08 03:04:58 +03:00
/*
* authencesn . c - AEAD wrapper for IPsec with extended sequence numbers ,
* derived from authenc . c
*
* Copyright ( C ) 2010 secunet Security Networks AG
* Copyright ( C ) 2010 Steffen Klassert < steffen . klassert @ secunet . com >
2015-08-07 11:42:59 +03:00
* Copyright ( c ) 2015 Herbert Xu < herbert @ gondor . apana . org . au >
2011-03-08 03:04:58 +03: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
* Software Foundation ; either version 2 of the License , or ( at your option )
* any later version .
*
*/
2015-05-11 12:47:42 +03:00
# include <crypto/internal/aead.h>
2011-03-08 03:04:58 +03:00
# include <crypto/internal/hash.h>
# include <crypto/internal/skcipher.h>
# include <crypto/authenc.h>
2015-08-07 11:42:59 +03:00
# include <crypto/null.h>
2011-03-08 03:04:58 +03:00
# include <crypto/scatterwalk.h>
# include <linux/err.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/rtnetlink.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
struct authenc_esn_instance_ctx {
struct crypto_ahash_spawn auth ;
struct crypto_skcipher_spawn enc ;
} ;
struct crypto_authenc_esn_ctx {
unsigned int reqoff ;
struct crypto_ahash * auth ;
struct crypto_ablkcipher * enc ;
2015-08-07 11:42:59 +03:00
struct crypto_blkcipher * null ;
2011-03-08 03:04:58 +03:00
} ;
struct authenc_esn_request_ctx {
2015-08-07 11:42:59 +03:00
struct scatterlist src [ 2 ] ;
struct scatterlist dst [ 2 ] ;
2011-03-08 03:04:58 +03:00
char tail [ ] ;
} ;
static void authenc_esn_request_complete ( struct aead_request * req , int err )
{
if ( err ! = - EINPROGRESS )
aead_request_complete ( req , err ) ;
}
2015-08-07 11:42:59 +03:00
static int crypto_authenc_esn_setauthsize ( struct crypto_aead * authenc_esn ,
unsigned int authsize )
{
if ( authsize > 0 & & authsize < 4 )
return - EINVAL ;
return 0 ;
}
2011-03-08 03:04:58 +03:00
static int crypto_authenc_esn_setkey ( struct crypto_aead * authenc_esn , const u8 * key ,
unsigned int keylen )
{
struct crypto_authenc_esn_ctx * ctx = crypto_aead_ctx ( authenc_esn ) ;
struct crypto_ahash * auth = ctx - > auth ;
struct crypto_ablkcipher * enc = ctx - > enc ;
2013-10-15 15:49:31 +04:00
struct crypto_authenc_keys keys ;
2011-03-08 03:04:58 +03:00
int err = - EINVAL ;
2013-10-15 15:49:31 +04:00
if ( crypto_authenc_extractkeys ( & keys , key , keylen ) ! = 0 )
2011-03-08 03:04:58 +03:00
goto badkey ;
crypto_ahash_clear_flags ( auth , CRYPTO_TFM_REQ_MASK ) ;
crypto_ahash_set_flags ( auth , crypto_aead_get_flags ( authenc_esn ) &
CRYPTO_TFM_REQ_MASK ) ;
2013-10-15 15:49:31 +04:00
err = crypto_ahash_setkey ( auth , keys . authkey , keys . authkeylen ) ;
2011-03-08 03:04:58 +03:00
crypto_aead_set_flags ( authenc_esn , crypto_ahash_get_flags ( auth ) &
CRYPTO_TFM_RES_MASK ) ;
if ( err )
goto out ;
crypto_ablkcipher_clear_flags ( enc , CRYPTO_TFM_REQ_MASK ) ;
crypto_ablkcipher_set_flags ( enc , crypto_aead_get_flags ( authenc_esn ) &
CRYPTO_TFM_REQ_MASK ) ;
2013-10-15 15:49:31 +04:00
err = crypto_ablkcipher_setkey ( enc , keys . enckey , keys . enckeylen ) ;
2011-03-08 03:04:58 +03:00
crypto_aead_set_flags ( authenc_esn , crypto_ablkcipher_get_flags ( enc ) &
CRYPTO_TFM_RES_MASK ) ;
out :
return err ;
badkey :
crypto_aead_set_flags ( authenc_esn , CRYPTO_TFM_RES_BAD_KEY_LEN ) ;
goto out ;
}
2015-08-07 11:42:59 +03:00
static int crypto_authenc_esn_genicv_tail ( struct aead_request * req ,
unsigned int flags )
2011-03-08 03:04:58 +03:00
{
struct crypto_aead * authenc_esn = crypto_aead_reqtfm ( req ) ;
struct crypto_authenc_esn_ctx * ctx = crypto_aead_ctx ( authenc_esn ) ;
struct authenc_esn_request_ctx * areq_ctx = aead_request_ctx ( req ) ;
2015-08-07 11:42:59 +03:00
struct crypto_ahash * auth = ctx - > auth ;
u8 * hash = PTR_ALIGN ( ( u8 * ) areq_ctx - > tail ,
crypto_ahash_alignmask ( auth ) + 1 ) ;
unsigned int authsize = crypto_aead_authsize ( authenc_esn ) ;
unsigned int assoclen = req - > assoclen ;
unsigned int cryptlen = req - > cryptlen ;
struct scatterlist * dst = req - > dst ;
u32 tmp [ 2 ] ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
/* Move high-order bits of sequence number back. */
scatterwalk_map_and_copy ( tmp , dst , 4 , 4 , 0 ) ;
scatterwalk_map_and_copy ( tmp + 1 , dst , assoclen + cryptlen , 4 , 0 ) ;
scatterwalk_map_and_copy ( tmp , dst , 0 , 8 , 1 ) ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
scatterwalk_map_and_copy ( hash , dst , assoclen + cryptlen , authsize , 1 ) ;
return 0 ;
2011-03-08 03:04:58 +03:00
}
static void authenc_esn_geniv_ahash_done ( struct crypto_async_request * areq ,
int err )
{
struct aead_request * req = areq - > data ;
2015-08-07 11:42:59 +03:00
err = err ? : crypto_authenc_esn_genicv_tail ( req , 0 ) ;
2011-03-08 03:04:58 +03:00
aead_request_complete ( req , err ) ;
}
2015-08-07 11:42:59 +03:00
static int crypto_authenc_esn_genicv ( struct aead_request * req ,
unsigned int flags )
2011-03-08 03:04:58 +03:00
{
struct crypto_aead * authenc_esn = crypto_aead_reqtfm ( req ) ;
struct authenc_esn_request_ctx * areq_ctx = aead_request_ctx ( req ) ;
struct crypto_authenc_esn_ctx * ctx = crypto_aead_ctx ( authenc_esn ) ;
2015-08-07 11:42:59 +03:00
struct crypto_ahash * auth = ctx - > auth ;
u8 * hash = PTR_ALIGN ( ( u8 * ) areq_ctx - > tail ,
crypto_ahash_alignmask ( auth ) + 1 ) ;
2011-03-08 03:04:58 +03:00
struct ahash_request * ahreq = ( void * ) ( areq_ctx - > tail + ctx - > reqoff ) ;
2015-08-07 11:42:59 +03:00
unsigned int authsize = crypto_aead_authsize ( authenc_esn ) ;
unsigned int assoclen = req - > assoclen ;
2011-03-08 03:04:58 +03:00
unsigned int cryptlen = req - > cryptlen ;
2015-08-07 11:42:59 +03:00
struct scatterlist * dst = req - > dst ;
u32 tmp [ 2 ] ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
if ( ! authsize )
return 0 ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
/* Move high-order bits of sequence number to the end. */
scatterwalk_map_and_copy ( tmp , dst , 0 , 8 , 0 ) ;
scatterwalk_map_and_copy ( tmp , dst , 4 , 4 , 1 ) ;
scatterwalk_map_and_copy ( tmp + 1 , dst , assoclen + cryptlen , 4 , 1 ) ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
sg_init_table ( areq_ctx - > dst , 2 ) ;
dst = scatterwalk_ffwd ( areq_ctx - > dst , dst , 4 ) ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
ahash_request_set_tfm ( ahreq , auth ) ;
ahash_request_set_crypt ( ahreq , dst , hash , assoclen + cryptlen ) ;
ahash_request_set_callback ( ahreq , flags ,
authenc_esn_geniv_ahash_done , req ) ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
return crypto_ahash_digest ( ahreq ) ? :
crypto_authenc_esn_genicv_tail ( req , aead_request_flags ( req ) ) ;
2011-03-08 03:04:58 +03:00
}
2015-08-07 11:42:59 +03:00
static void crypto_authenc_esn_encrypt_done ( struct crypto_async_request * req ,
int err )
2011-03-08 03:04:58 +03:00
{
2015-08-07 11:42:59 +03:00
struct aead_request * areq = req - > data ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
if ( ! err )
err = crypto_authenc_esn_genicv ( areq , 0 ) ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
authenc_esn_request_complete ( areq , err ) ;
2011-03-08 03:04:58 +03:00
}
2015-08-07 11:42:59 +03:00
static int crypto_authenc_esn_copy ( struct aead_request * req , unsigned int len )
2011-03-08 03:04:58 +03:00
{
struct crypto_aead * authenc_esn = crypto_aead_reqtfm ( req ) ;
struct crypto_authenc_esn_ctx * ctx = crypto_aead_ctx ( authenc_esn ) ;
2015-08-07 11:42:59 +03:00
struct blkcipher_desc desc = {
. tfm = ctx - > null ,
} ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
return crypto_blkcipher_encrypt ( & desc , req - > dst , req - > src , len ) ;
2011-03-08 03:04:58 +03:00
}
2015-08-07 11:42:59 +03:00
static int crypto_authenc_esn_encrypt ( struct aead_request * req )
2011-03-08 03:04:58 +03:00
{
struct crypto_aead * authenc_esn = crypto_aead_reqtfm ( req ) ;
struct authenc_esn_request_ctx * areq_ctx = aead_request_ctx ( req ) ;
2015-08-07 11:42:59 +03:00
struct crypto_authenc_esn_ctx * ctx = crypto_aead_ctx ( authenc_esn ) ;
struct ablkcipher_request * abreq = ( void * ) ( areq_ctx - > tail
+ ctx - > reqoff ) ;
struct crypto_ablkcipher * enc = ctx - > enc ;
unsigned int assoclen = req - > assoclen ;
2011-03-08 03:04:58 +03:00
unsigned int cryptlen = req - > cryptlen ;
2015-08-07 11:42:59 +03:00
struct scatterlist * src , * dst ;
int err ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
sg_init_table ( areq_ctx - > src , 2 ) ;
src = scatterwalk_ffwd ( areq_ctx - > src , req - > src , assoclen ) ;
dst = src ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
if ( req - > src ! = req - > dst ) {
err = crypto_authenc_esn_copy ( req , assoclen ) ;
if ( err )
return err ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
sg_init_table ( areq_ctx - > dst , 2 ) ;
dst = scatterwalk_ffwd ( areq_ctx - > dst , req - > dst , assoclen ) ;
2011-03-08 03:04:58 +03:00
}
ablkcipher_request_set_tfm ( abreq , enc ) ;
ablkcipher_request_set_callback ( abreq , aead_request_flags ( req ) ,
crypto_authenc_esn_encrypt_done , req ) ;
2015-08-07 11:42:59 +03:00
ablkcipher_request_set_crypt ( abreq , src , dst , cryptlen , req - > iv ) ;
2011-03-08 03:04:58 +03:00
err = crypto_ablkcipher_encrypt ( abreq ) ;
if ( err )
return err ;
2015-08-07 11:42:59 +03:00
return crypto_authenc_esn_genicv ( req , aead_request_flags ( req ) ) ;
2011-03-08 03:04:58 +03:00
}
2015-08-07 11:42:59 +03:00
static int crypto_authenc_esn_decrypt_tail ( struct aead_request * req ,
unsigned int flags )
2011-03-08 03:04:58 +03:00
{
2015-08-07 11:42:59 +03:00
struct crypto_aead * authenc_esn = crypto_aead_reqtfm ( req ) ;
unsigned int authsize = crypto_aead_authsize ( authenc_esn ) ;
struct authenc_esn_request_ctx * areq_ctx = aead_request_ctx ( req ) ;
struct crypto_authenc_esn_ctx * ctx = crypto_aead_ctx ( authenc_esn ) ;
struct ablkcipher_request * abreq = ( void * ) ( areq_ctx - > tail
+ ctx - > reqoff ) ;
struct crypto_ahash * auth = ctx - > auth ;
u8 * ohash = PTR_ALIGN ( ( u8 * ) areq_ctx - > tail ,
crypto_ahash_alignmask ( auth ) + 1 ) ;
unsigned int cryptlen = req - > cryptlen - authsize ;
unsigned int assoclen = req - > assoclen ;
struct scatterlist * dst = req - > dst ;
u8 * ihash = ohash + crypto_ahash_digestsize ( auth ) ;
u32 tmp [ 2 ] ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
/* Move high-order bits of sequence number back. */
scatterwalk_map_and_copy ( tmp , dst , 4 , 4 , 0 ) ;
scatterwalk_map_and_copy ( tmp + 1 , dst , assoclen + cryptlen , 4 , 0 ) ;
scatterwalk_map_and_copy ( tmp , dst , 0 , 8 , 1 ) ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
if ( crypto_memneq ( ihash , ohash , authsize ) )
return - EBADMSG ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
sg_init_table ( areq_ctx - > dst , 2 ) ;
dst = scatterwalk_ffwd ( areq_ctx - > dst , dst , assoclen ) ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
ablkcipher_request_set_tfm ( abreq , ctx - > enc ) ;
ablkcipher_request_set_callback ( abreq , flags ,
req - > base . complete , req - > base . data ) ;
ablkcipher_request_set_crypt ( abreq , dst , dst , cryptlen , req - > iv ) ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
return crypto_ablkcipher_decrypt ( abreq ) ;
2011-03-08 03:04:58 +03:00
}
2015-08-07 11:42:59 +03:00
static void authenc_esn_verify_ahash_done ( struct crypto_async_request * areq ,
int err )
2011-03-08 03:04:58 +03:00
{
2015-08-07 11:42:59 +03:00
struct aead_request * req = areq - > data ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
err = err ? : crypto_authenc_esn_decrypt_tail ( req , 0 ) ;
aead_request_complete ( req , err ) ;
2011-03-08 03:04:58 +03:00
}
2015-08-07 11:42:59 +03:00
static int crypto_authenc_esn_decrypt ( struct aead_request * req )
2011-03-08 03:04:58 +03:00
{
struct crypto_aead * authenc_esn = crypto_aead_reqtfm ( req ) ;
struct authenc_esn_request_ctx * areq_ctx = aead_request_ctx ( req ) ;
2015-08-07 11:42:59 +03:00
struct crypto_authenc_esn_ctx * ctx = crypto_aead_ctx ( authenc_esn ) ;
struct ahash_request * ahreq = ( void * ) ( areq_ctx - > tail + ctx - > reqoff ) ;
unsigned int authsize = crypto_aead_authsize ( authenc_esn ) ;
struct crypto_ahash * auth = ctx - > auth ;
u8 * ohash = PTR_ALIGN ( ( u8 * ) areq_ctx - > tail ,
crypto_ahash_alignmask ( auth ) + 1 ) ;
unsigned int assoclen = req - > assoclen ;
unsigned int cryptlen = req - > cryptlen ;
u8 * ihash = ohash + crypto_ahash_digestsize ( auth ) ;
struct scatterlist * dst = req - > dst ;
u32 tmp [ 2 ] ;
int err ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
cryptlen - = authsize ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
if ( req - > src ! = dst ) {
err = crypto_authenc_esn_copy ( req , assoclen + cryptlen ) ;
if ( err )
return err ;
}
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
scatterwalk_map_and_copy ( ihash , req - > src , assoclen + cryptlen ,
authsize , 0 ) ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
if ( ! authsize )
goto tail ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
/* Move high-order bits of sequence number to the end. */
scatterwalk_map_and_copy ( tmp , dst , 0 , 8 , 0 ) ;
scatterwalk_map_and_copy ( tmp , dst , 4 , 4 , 1 ) ;
scatterwalk_map_and_copy ( tmp + 1 , dst , assoclen + cryptlen , 4 , 1 ) ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
sg_init_table ( areq_ctx - > dst , 2 ) ;
dst = scatterwalk_ffwd ( areq_ctx - > dst , dst , 4 ) ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
ahash_request_set_tfm ( ahreq , auth ) ;
ahash_request_set_crypt ( ahreq , dst , ohash , assoclen + cryptlen ) ;
ahash_request_set_callback ( ahreq , aead_request_flags ( req ) ,
authenc_esn_verify_ahash_done , req ) ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
err = crypto_ahash_digest ( ahreq ) ;
2011-03-08 03:04:58 +03:00
if ( err )
return err ;
2015-08-07 11:42:59 +03:00
tail :
return crypto_authenc_esn_decrypt_tail ( req , aead_request_flags ( req ) ) ;
2011-03-08 03:04:58 +03:00
}
2015-08-07 11:42:59 +03:00
static int crypto_authenc_esn_init_tfm ( struct crypto_aead * tfm )
2011-03-08 03:04:58 +03:00
{
2015-08-07 11:42:59 +03:00
struct aead_instance * inst = aead_alg_instance ( tfm ) ;
struct authenc_esn_instance_ctx * ictx = aead_instance_ctx ( inst ) ;
struct crypto_authenc_esn_ctx * ctx = crypto_aead_ctx ( tfm ) ;
2011-03-08 03:04:58 +03:00
struct crypto_ahash * auth ;
struct crypto_ablkcipher * enc ;
2015-08-07 11:42:59 +03:00
struct crypto_blkcipher * null ;
2011-03-08 03:04:58 +03:00
int err ;
auth = crypto_spawn_ahash ( & ictx - > auth ) ;
if ( IS_ERR ( auth ) )
return PTR_ERR ( auth ) ;
enc = crypto_spawn_skcipher ( & ictx - > enc ) ;
err = PTR_ERR ( enc ) ;
if ( IS_ERR ( enc ) )
goto err_free_ahash ;
2015-08-07 11:42:59 +03:00
null = crypto_get_default_null_skcipher ( ) ;
err = PTR_ERR ( null ) ;
if ( IS_ERR ( null ) )
goto err_free_skcipher ;
2011-03-08 03:04:58 +03:00
ctx - > auth = auth ;
ctx - > enc = enc ;
2015-08-07 11:42:59 +03:00
ctx - > null = null ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
ctx - > reqoff = ALIGN ( 2 * crypto_ahash_digestsize ( auth ) ,
crypto_ahash_alignmask ( auth ) + 1 ) ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
crypto_aead_set_reqsize (
tfm ,
2015-05-11 12:47:55 +03:00
sizeof ( struct authenc_esn_request_ctx ) +
ctx - > reqoff +
max_t ( unsigned int ,
crypto_ahash_reqsize ( auth ) +
sizeof ( struct ahash_request ) ,
sizeof ( struct skcipher_givcrypt_request ) +
crypto_ablkcipher_reqsize ( enc ) ) ) ;
2011-03-08 03:04:58 +03:00
return 0 ;
2015-08-07 11:42:59 +03:00
err_free_skcipher :
crypto_free_ablkcipher ( enc ) ;
2011-03-08 03:04:58 +03:00
err_free_ahash :
crypto_free_ahash ( auth ) ;
return err ;
}
2015-08-07 11:42:59 +03:00
static void crypto_authenc_esn_exit_tfm ( struct crypto_aead * tfm )
2011-03-08 03:04:58 +03:00
{
2015-08-07 11:42:59 +03:00
struct crypto_authenc_esn_ctx * ctx = crypto_aead_ctx ( tfm ) ;
2011-03-08 03:04:58 +03:00
crypto_free_ahash ( ctx - > auth ) ;
crypto_free_ablkcipher ( ctx - > enc ) ;
2015-08-07 11:42:59 +03:00
crypto_put_default_null_skcipher ( ) ;
}
static void crypto_authenc_esn_free ( struct aead_instance * inst )
{
struct authenc_esn_instance_ctx * ctx = aead_instance_ctx ( inst ) ;
crypto_drop_skcipher ( & ctx - > enc ) ;
crypto_drop_ahash ( & ctx - > auth ) ;
kfree ( inst ) ;
2011-03-08 03:04:58 +03:00
}
2015-08-07 11:42:59 +03:00
static int crypto_authenc_esn_create ( struct crypto_template * tmpl ,
struct rtattr * * tb )
2011-03-08 03:04:58 +03:00
{
struct crypto_attr_type * algt ;
2015-08-07 11:42:59 +03:00
struct aead_instance * inst ;
2011-03-08 03:04:58 +03:00
struct hash_alg_common * auth ;
struct crypto_alg * auth_base ;
struct crypto_alg * enc ;
struct authenc_esn_instance_ctx * ctx ;
const char * enc_name ;
int err ;
algt = crypto_get_attr_type ( tb ) ;
if ( IS_ERR ( algt ) )
2015-08-07 11:42:59 +03:00
return PTR_ERR ( algt ) ;
2011-03-08 03:04:58 +03:00
2015-08-13 12:29:06 +03:00
if ( ( algt - > type ^ CRYPTO_ALG_TYPE_AEAD ) & algt - > mask )
2015-08-07 11:42:59 +03:00
return - EINVAL ;
2011-03-08 03:04:58 +03:00
auth = ahash_attr_alg ( tb [ 1 ] , CRYPTO_ALG_TYPE_HASH ,
CRYPTO_ALG_TYPE_AHASH_MASK ) ;
if ( IS_ERR ( auth ) )
2015-08-07 11:42:59 +03:00
return PTR_ERR ( auth ) ;
2011-03-08 03:04:58 +03:00
auth_base = & auth - > base ;
enc_name = crypto_attr_alg_name ( tb [ 2 ] ) ;
err = PTR_ERR ( enc_name ) ;
if ( IS_ERR ( enc_name ) )
goto out_put_auth ;
inst = kzalloc ( sizeof ( * inst ) + sizeof ( * ctx ) , GFP_KERNEL ) ;
err = - ENOMEM ;
if ( ! inst )
goto out_put_auth ;
2015-08-07 11:42:59 +03:00
ctx = aead_instance_ctx ( inst ) ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
err = crypto_init_ahash_spawn ( & ctx - > auth , auth ,
aead_crypto_instance ( inst ) ) ;
2011-03-08 03:04:58 +03:00
if ( err )
goto err_free_inst ;
2015-08-07 11:42:59 +03:00
crypto_set_skcipher_spawn ( & ctx - > enc , aead_crypto_instance ( inst ) ) ;
2011-03-08 03:04:58 +03:00
err = crypto_grab_skcipher ( & ctx - > enc , enc_name , 0 ,
crypto_requires_sync ( algt - > type ,
algt - > mask ) ) ;
if ( err )
goto err_drop_auth ;
enc = crypto_skcipher_spawn_alg ( & ctx - > enc ) ;
err = - ENAMETOOLONG ;
2015-08-07 11:42:59 +03:00
if ( snprintf ( inst - > alg . base . cra_name , CRYPTO_MAX_ALG_NAME ,
" authencesn(%s,%s) " , auth_base - > cra_name ,
enc - > cra_name ) > = CRYPTO_MAX_ALG_NAME )
2011-03-08 03:04:58 +03:00
goto err_drop_enc ;
2015-08-07 11:42:59 +03:00
if ( snprintf ( inst - > alg . base . cra_driver_name , CRYPTO_MAX_ALG_NAME ,
2011-03-08 03:04:58 +03:00
" authencesn(%s,%s) " , auth_base - > cra_driver_name ,
enc - > cra_driver_name ) > = CRYPTO_MAX_ALG_NAME )
goto err_drop_enc ;
2015-08-07 11:42:59 +03:00
inst - > alg . base . cra_flags = enc - > cra_flags & CRYPTO_ALG_ASYNC ;
inst - > alg . base . cra_priority = enc - > cra_priority * 10 +
auth_base - > cra_priority ;
inst - > alg . base . cra_blocksize = enc - > cra_blocksize ;
inst - > alg . base . cra_alignmask = auth_base - > cra_alignmask |
enc - > cra_alignmask ;
inst - > alg . base . cra_ctxsize = sizeof ( struct crypto_authenc_esn_ctx ) ;
inst - > alg . ivsize = enc - > cra_ablkcipher . ivsize ;
inst - > alg . maxauthsize = auth - > digestsize ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
inst - > alg . init = crypto_authenc_esn_init_tfm ;
inst - > alg . exit = crypto_authenc_esn_exit_tfm ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
inst - > alg . setkey = crypto_authenc_esn_setkey ;
inst - > alg . setauthsize = crypto_authenc_esn_setauthsize ;
inst - > alg . encrypt = crypto_authenc_esn_encrypt ;
inst - > alg . decrypt = crypto_authenc_esn_decrypt ;
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
inst - > free = crypto_authenc_esn_free ,
2011-03-08 03:04:58 +03:00
2015-08-07 11:42:59 +03:00
err = aead_register_instance ( tmpl , inst ) ;
if ( err )
goto err_drop_enc ;
2011-03-08 03:04:58 +03:00
out :
crypto_mod_put ( auth_base ) ;
2015-08-07 11:42:59 +03:00
return err ;
2011-03-08 03:04:58 +03:00
err_drop_enc :
crypto_drop_skcipher ( & ctx - > enc ) ;
err_drop_auth :
crypto_drop_ahash ( & ctx - > auth ) ;
err_free_inst :
kfree ( inst ) ;
out_put_auth :
goto out ;
}
static struct crypto_template crypto_authenc_esn_tmpl = {
. name = " authencesn " ,
2015-08-07 11:42:59 +03:00
. create = crypto_authenc_esn_create ,
2011-03-08 03:04:58 +03:00
. module = THIS_MODULE ,
} ;
static int __init crypto_authenc_esn_module_init ( void )
{
return crypto_register_template ( & crypto_authenc_esn_tmpl ) ;
}
static void __exit crypto_authenc_esn_module_exit ( void )
{
crypto_unregister_template ( & crypto_authenc_esn_tmpl ) ;
}
module_init ( crypto_authenc_esn_module_init ) ;
module_exit ( crypto_authenc_esn_module_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Steffen Klassert <steffen.klassert@secunet.com> " ) ;
MODULE_DESCRIPTION ( " AEAD wrapper for IPsec with extended sequence numbers " ) ;
2014-11-25 03:32:38 +03:00
MODULE_ALIAS_CRYPTO ( " authencesn " ) ;