2005-04-17 02:20:36 +04:00
/*
* Cryptographic API .
*
* Cipher operations .
*
* Copyright ( c ) 2002 James Morris < jmorris @ intercode . com . au >
2005-07-07 00:51:31 +04:00
* Copyright ( c ) 2005 Herbert Xu < herbert @ gondor . apana . org . au >
2005-04-17 02:20:36 +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:31:37 +03:00
* Software Foundation ; either version 2 of the License , or ( at your option )
2005-04-17 02:20:36 +04:00
* any later version .
*
*/
2007-01-27 02:05:15 +03:00
2018-04-09 16:54:47 +03:00
# include <crypto/algapi.h>
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/crypto.h>
# include <linux/errno.h>
2007-08-23 12:23:01 +04:00
# include <linux/slab.h>
2005-04-17 02:20:36 +04:00
# include <linux/string.h>
# include "internal.h"
2007-08-23 12:23:01 +04:00
static int setkey_unaligned ( struct crypto_tfm * tfm , const u8 * key ,
unsigned int keylen )
2007-05-19 13:51:21 +04:00
{
struct cipher_alg * cia = & tfm - > __crt_alg - > cra_cipher ;
unsigned long alignmask = crypto_tfm_alg_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 ) ;
ret = cia - > cia_setkey ( tfm , alignbuffer , keylen ) ;
2007-08-03 16:33:47 +04:00
memset ( alignbuffer , 0 , keylen ) ;
2007-05-19 13:51:21 +04:00
kfree ( buffer ) ;
return ret ;
}
2005-04-17 02:20:36 +04:00
static int setkey ( struct crypto_tfm * tfm , const u8 * key , unsigned int keylen )
{
struct cipher_alg * cia = & tfm - > __crt_alg - > cra_cipher ;
2007-05-19 13:51:21 +04:00
unsigned long alignmask = crypto_tfm_alg_alignmask ( tfm ) ;
2006-08-13 08:16:39 +04:00
tfm - > crt_flags & = ~ CRYPTO_TFM_RES_MASK ;
2005-04-17 02:20:36 +04:00
if ( keylen < cia - > cia_min_keysize | | keylen > cia - > cia_max_keysize ) {
tfm - > crt_flags | = CRYPTO_TFM_RES_BAD_KEY_LEN ;
return - EINVAL ;
2007-05-19 13:51:21 +04:00
}
if ( ( unsigned long ) key & alignmask )
return setkey_unaligned ( tfm , key , keylen ) ;
return cia - > cia_setkey ( tfm , key , keylen ) ;
2005-04-17 02:20:36 +04:00
}
2006-08-13 14:58:18 +04:00
static void cipher_crypt_unaligned ( void ( * fn ) ( struct crypto_tfm * , u8 * ,
const u8 * ) ,
struct crypto_tfm * tfm ,
u8 * dst , const u8 * src )
{
unsigned long alignmask = crypto_tfm_alg_alignmask ( tfm ) ;
unsigned int size = crypto_tfm_alg_blocksize ( tfm ) ;
2018-04-09 16:54:47 +03:00
u8 buffer [ MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK ] ;
2006-08-13 14:58:18 +04:00
u8 * tmp = ( u8 * ) ALIGN ( ( unsigned long ) buffer , alignmask + 1 ) ;
memcpy ( tmp , src , size ) ;
fn ( tfm , tmp , tmp ) ;
memcpy ( dst , tmp , size ) ;
}
static void cipher_encrypt_unaligned ( struct crypto_tfm * tfm ,
u8 * dst , const u8 * src )
{
unsigned long alignmask = crypto_tfm_alg_alignmask ( tfm ) ;
struct cipher_alg * cipher = & tfm - > __crt_alg - > cra_cipher ;
if ( unlikely ( ( ( unsigned long ) dst | ( unsigned long ) src ) & alignmask ) ) {
cipher_crypt_unaligned ( cipher - > cia_encrypt , tfm , dst , src ) ;
return ;
}
cipher - > cia_encrypt ( tfm , dst , src ) ;
}
static void cipher_decrypt_unaligned ( struct crypto_tfm * tfm ,
u8 * dst , const u8 * src )
{
unsigned long alignmask = crypto_tfm_alg_alignmask ( tfm ) ;
struct cipher_alg * cipher = & tfm - > __crt_alg - > cra_cipher ;
if ( unlikely ( ( ( unsigned long ) dst | ( unsigned long ) src ) & alignmask ) ) {
cipher_crypt_unaligned ( cipher - > cia_decrypt , tfm , dst , src ) ;
return ;
}
cipher - > cia_decrypt ( tfm , dst , src ) ;
}
2005-04-17 02:20:36 +04:00
int crypto_init_cipher_ops ( struct crypto_tfm * tfm )
{
struct cipher_tfm * ops = & tfm - > crt_cipher ;
2006-08-13 14:58:18 +04:00
struct cipher_alg * cipher = & tfm - > __crt_alg - > cra_cipher ;
2005-04-17 02:20:36 +04:00
ops - > cit_setkey = setkey ;
2006-08-13 14:58:18 +04:00
ops - > cit_encrypt_one = crypto_tfm_alg_alignmask ( tfm ) ?
cipher_encrypt_unaligned : cipher - > cia_encrypt ;
ops - > cit_decrypt_one = crypto_tfm_alg_alignmask ( tfm ) ?
cipher_decrypt_unaligned : cipher - > cia_decrypt ;
2005-04-17 02:20:36 +04:00
2007-01-27 02:05:15 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}