2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2006-09-21 05:44:08 +04:00
/*
* CBC : Cipher Block Chaining mode
*
2016-11-22 15:08:42 +03:00
* Copyright ( c ) 2006 - 2016 Herbert Xu < herbert @ gondor . apana . org . au >
2006-09-21 05:44:08 +04:00
*/
2016-11-22 15:08:39 +03:00
# include <crypto/internal/skcipher.h>
2006-09-21 05:44:08 +04:00
# include <linux/err.h>
# include <linux/init.h>
# include <linux/kernel.h>
2007-11-20 12:36:00 +03:00
# include <linux/log2.h>
2006-09-21 05:44:08 +04:00
# include <linux/module.h>
2023-09-14 11:28:28 +03:00
static int crypto_cbc_encrypt_segment ( struct crypto_lskcipher * tfm ,
const u8 * src , u8 * dst , unsigned nbytes ,
u8 * iv )
2016-11-22 15:08:39 +03:00
{
2023-09-14 11:28:28 +03:00
unsigned int bsize = crypto_lskcipher_blocksize ( tfm ) ;
2020-09-01 14:49:11 +03:00
2023-09-14 11:28:28 +03:00
for ( ; nbytes > = bsize ; src + = bsize , dst + = bsize , nbytes - = bsize ) {
2020-09-01 14:49:11 +03:00
crypto_xor ( iv , src , bsize ) ;
2023-09-14 11:28:28 +03:00
crypto_lskcipher_encrypt ( tfm , iv , dst , bsize , NULL ) ;
2020-09-01 14:49:11 +03:00
memcpy ( iv , dst , bsize ) ;
2023-09-14 11:28:28 +03:00
}
2020-09-01 14:49:11 +03:00
return nbytes ;
}
2023-09-14 11:28:28 +03:00
static int crypto_cbc_encrypt_inplace ( struct crypto_lskcipher * tfm ,
u8 * src , unsigned nbytes , u8 * oiv )
2020-09-01 14:49:11 +03:00
{
2023-09-14 11:28:28 +03:00
unsigned int bsize = crypto_lskcipher_blocksize ( tfm ) ;
u8 * iv = oiv ;
if ( nbytes < bsize )
goto out ;
2020-09-01 14:49:11 +03:00
do {
crypto_xor ( src , iv , bsize ) ;
2023-09-14 11:28:28 +03:00
crypto_lskcipher_encrypt ( tfm , src , src , bsize , NULL ) ;
2020-09-01 14:49:11 +03:00
iv = src ;
src + = bsize ;
} while ( ( nbytes - = bsize ) > = bsize ) ;
2023-09-14 11:28:28 +03:00
memcpy ( oiv , iv , bsize ) ;
2020-09-01 14:49:11 +03:00
2023-09-14 11:28:28 +03:00
out :
2020-09-01 14:49:11 +03:00
return nbytes ;
2016-11-22 15:08:39 +03:00
}
2023-09-14 11:28:28 +03:00
static int crypto_cbc_encrypt ( struct crypto_lskcipher * tfm , const u8 * src ,
u8 * dst , unsigned len , u8 * iv , bool final )
2006-09-21 05:44:08 +04:00
{
2023-09-14 11:28:28 +03:00
struct crypto_lskcipher * * ctx = crypto_lskcipher_ctx ( tfm ) ;
struct crypto_lskcipher * cipher = * ctx ;
int rem ;
2020-09-01 14:49:11 +03:00
2023-09-14 11:28:28 +03:00
if ( src = = dst )
rem = crypto_cbc_encrypt_inplace ( cipher , dst , len , iv ) ;
else
rem = crypto_cbc_encrypt_segment ( cipher , src , dst , len , iv ) ;
2020-09-01 14:49:11 +03:00
2023-09-14 11:28:28 +03:00
return rem & & final ? - EINVAL : rem ;
2020-09-01 14:49:11 +03:00
}
2023-09-14 11:28:28 +03:00
static int crypto_cbc_decrypt_segment ( struct crypto_lskcipher * tfm ,
const u8 * src , u8 * dst , unsigned nbytes ,
u8 * oiv )
2020-09-01 14:49:11 +03:00
{
2023-09-14 11:28:28 +03:00
unsigned int bsize = crypto_lskcipher_blocksize ( tfm ) ;
const u8 * iv = oiv ;
if ( nbytes < bsize )
goto out ;
2020-09-01 14:49:11 +03:00
do {
2023-09-14 11:28:28 +03:00
crypto_lskcipher_decrypt ( tfm , src , dst , bsize , NULL ) ;
2020-09-01 14:49:11 +03:00
crypto_xor ( dst , iv , bsize ) ;
iv = src ;
src + = bsize ;
dst + = bsize ;
} while ( ( nbytes - = bsize ) > = bsize ) ;
2023-09-14 11:28:28 +03:00
memcpy ( oiv , iv , bsize ) ;
2020-09-01 14:49:11 +03:00
2023-09-14 11:28:28 +03:00
out :
2020-09-01 14:49:11 +03:00
return nbytes ;
2016-11-22 15:08:39 +03:00
}
2023-09-14 11:28:28 +03:00
static int crypto_cbc_decrypt_inplace ( struct crypto_lskcipher * tfm ,
u8 * src , unsigned nbytes , u8 * iv )
2016-11-22 15:08:39 +03:00
{
2023-09-14 11:28:28 +03:00
unsigned int bsize = crypto_lskcipher_blocksize ( tfm ) ;
2020-09-01 14:49:11 +03:00
u8 last_iv [ MAX_CIPHER_BLOCKSIZE ] ;
2023-09-14 11:28:28 +03:00
if ( nbytes < bsize )
goto out ;
2020-09-01 14:49:11 +03:00
/* Start of the last block. */
src + = nbytes - ( nbytes & ( bsize - 1 ) ) - bsize ;
memcpy ( last_iv , src , bsize ) ;
for ( ; ; ) {
2023-09-14 11:28:28 +03:00
crypto_lskcipher_decrypt ( tfm , src , src , bsize , NULL ) ;
2020-09-01 14:49:11 +03:00
if ( ( nbytes - = bsize ) < bsize )
break ;
crypto_xor ( src , src - bsize , bsize ) ;
src - = bsize ;
}
2023-09-14 11:28:28 +03:00
crypto_xor ( src , iv , bsize ) ;
memcpy ( iv , last_iv , bsize ) ;
2020-09-01 14:49:11 +03:00
2023-09-14 11:28:28 +03:00
out :
2020-09-01 14:49:11 +03:00
return nbytes ;
2016-11-22 15:08:39 +03:00
}
2023-09-14 11:28:28 +03:00
static int crypto_cbc_decrypt ( struct crypto_lskcipher * tfm , const u8 * src ,
u8 * dst , unsigned len , u8 * iv , bool final )
2016-11-22 15:08:39 +03:00
{
2023-09-14 11:28:28 +03:00
struct crypto_lskcipher * * ctx = crypto_lskcipher_ctx ( tfm ) ;
struct crypto_lskcipher * cipher = * ctx ;
int rem ;
2006-09-21 05:44:08 +04:00
2023-09-14 11:28:28 +03:00
if ( src = = dst )
rem = crypto_cbc_decrypt_inplace ( cipher , dst , len , iv ) ;
else
rem = crypto_cbc_decrypt_segment ( cipher , src , dst , len , iv ) ;
2006-09-21 05:44:08 +04:00
2023-09-14 11:28:28 +03:00
return rem & & final ? - EINVAL : rem ;
2006-09-21 05:44:08 +04:00
}
2016-11-22 15:08:39 +03:00
static int crypto_cbc_create ( struct crypto_template * tmpl , struct rtattr * * tb )
{
2023-09-14 11:28:28 +03:00
struct lskcipher_instance * inst ;
2007-01-01 10:37:02 +03:00
int err ;
2023-09-14 11:28:28 +03:00
inst = lskcipher_alloc_instance_simple ( tmpl , tb ) ;
2019-01-04 07:16:15 +03:00
if ( IS_ERR ( inst ) )
return PTR_ERR ( inst ) ;
2007-11-20 12:36:00 +03:00
2016-11-22 15:08:39 +03:00
err = - EINVAL ;
2023-09-14 11:28:28 +03:00
if ( ! is_power_of_2 ( inst - > alg . co . base . cra_blocksize ) )
2019-01-04 07:16:15 +03:00
goto out_free_inst ;
2006-09-21 05:44:08 +04:00
2016-11-22 15:08:39 +03:00
inst - > alg . encrypt = crypto_cbc_encrypt ;
inst - > alg . decrypt = crypto_cbc_decrypt ;
2006-09-21 05:44:08 +04:00
2023-09-14 11:28:28 +03:00
err = lskcipher_register_instance ( tmpl , inst ) ;
2019-12-20 08:29:40 +03:00
if ( err ) {
2019-01-04 07:16:15 +03:00
out_free_inst :
2019-12-20 08:29:40 +03:00
inst - > free ( inst ) ;
}
2019-01-04 07:16:15 +03:00
return err ;
2006-09-21 05:44:08 +04:00
}
static struct crypto_template crypto_cbc_tmpl = {
. name = " cbc " ,
2016-11-22 15:08:39 +03:00
. create = crypto_cbc_create ,
2006-09-21 05:44:08 +04:00
. module = THIS_MODULE ,
} ;
static int __init crypto_cbc_module_init ( void )
{
return crypto_register_template ( & crypto_cbc_tmpl ) ;
}
static void __exit crypto_cbc_module_exit ( void )
{
crypto_unregister_template ( & crypto_cbc_tmpl ) ;
}
2019-04-12 07:57:42 +03:00
subsys_initcall ( crypto_cbc_module_init ) ;
2006-09-21 05:44:08 +04:00
module_exit ( crypto_cbc_module_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
2019-01-04 07:16:15 +03:00
MODULE_DESCRIPTION ( " CBC block cipher mode of operation " ) ;
2014-11-25 03:32:38 +03:00
MODULE_ALIAS_CRYPTO ( " cbc " ) ;