2019-06-01 11:08:56 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2021-03-20 23:25:25 +03:00
/*
2016-07-18 18:26:26 +03:00
* AES XTS routines supporting VMX In - core instructions on Power 8
*
* Copyright ( C ) 2015 International Business Machines Inc .
*
* Author : Leonidas S . Barbosa < leosilva @ linux . vnet . ibm . com >
*/
2019-04-13 08:33:12 +03:00
# include <asm/simd.h>
2016-07-18 18:26:26 +03:00
# include <asm/switch_to.h>
# include <crypto/aes.h>
2019-04-13 08:33:12 +03:00
# include <crypto/internal/simd.h>
2019-05-20 19:44:48 +03:00
# include <crypto/internal/skcipher.h>
2016-07-18 18:26:26 +03:00
# include <crypto/xts.h>
# include "aesp8-ppc.h"
struct p8_aes_xts_ctx {
2019-05-20 19:44:48 +03:00
struct crypto_skcipher * fallback ;
2016-07-18 18:26:26 +03:00
struct aes_key enc_key ;
struct aes_key dec_key ;
struct aes_key tweak_key ;
} ;
2019-05-20 19:44:48 +03:00
static int p8_aes_xts_init ( struct crypto_skcipher * tfm )
2016-07-18 18:26:26 +03:00
{
2019-05-20 19:44:48 +03:00
struct p8_aes_xts_ctx * ctx = crypto_skcipher_ctx ( tfm ) ;
struct crypto_skcipher * fallback ;
2016-07-18 18:26:26 +03:00
2019-05-20 19:44:48 +03:00
fallback = crypto_alloc_skcipher ( " xts(aes) " , 0 ,
CRYPTO_ALG_NEED_FALLBACK |
CRYPTO_ALG_ASYNC ) ;
2016-07-18 18:26:26 +03:00
if ( IS_ERR ( fallback ) ) {
2019-05-20 19:44:48 +03:00
pr_err ( " Failed to allocate xts(aes) fallback: %ld \n " ,
PTR_ERR ( fallback ) ) ;
2016-07-18 18:26:26 +03:00
return PTR_ERR ( fallback ) ;
}
2019-05-20 19:44:48 +03:00
crypto_skcipher_set_reqsize ( tfm , sizeof ( struct skcipher_request ) +
crypto_skcipher_reqsize ( fallback ) ) ;
2016-07-18 18:26:26 +03:00
ctx - > fallback = fallback ;
return 0 ;
}
2019-05-20 19:44:48 +03:00
static void p8_aes_xts_exit ( struct crypto_skcipher * tfm )
2016-07-18 18:26:26 +03:00
{
2019-05-20 19:44:48 +03:00
struct p8_aes_xts_ctx * ctx = crypto_skcipher_ctx ( tfm ) ;
2016-07-18 18:26:26 +03:00
2019-05-20 19:44:48 +03:00
crypto_free_skcipher ( ctx - > fallback ) ;
2016-07-18 18:26:26 +03:00
}
2019-05-20 19:44:48 +03:00
static int p8_aes_xts_setkey ( struct crypto_skcipher * tfm , const u8 * key ,
2016-07-18 18:26:26 +03:00
unsigned int keylen )
{
2019-05-20 19:44:48 +03:00
struct p8_aes_xts_ctx * ctx = crypto_skcipher_ctx ( tfm ) ;
2016-07-18 18:26:26 +03:00
int ret ;
2019-05-20 19:44:48 +03:00
ret = xts_verify_key ( tfm , key , keylen ) ;
2016-07-18 18:26:26 +03:00
if ( ret )
return ret ;
preempt_disable ( ) ;
pagefault_disable ( ) ;
enable_kernel_vsx ( ) ;
ret = aes_p8_set_encrypt_key ( key + keylen / 2 , ( keylen / 2 ) * 8 , & ctx - > tweak_key ) ;
2019-04-10 09:46:35 +03:00
ret | = aes_p8_set_encrypt_key ( key , ( keylen / 2 ) * 8 , & ctx - > enc_key ) ;
ret | = aes_p8_set_decrypt_key ( key , ( keylen / 2 ) * 8 , & ctx - > dec_key ) ;
2016-07-18 18:26:26 +03:00
disable_kernel_vsx ( ) ;
pagefault_enable ( ) ;
preempt_enable ( ) ;
2019-05-20 19:44:48 +03:00
ret | = crypto_skcipher_setkey ( ctx - > fallback , key , keylen ) ;
2019-04-10 09:46:35 +03:00
return ret ? - EINVAL : 0 ;
2016-07-18 18:26:26 +03:00
}
2019-05-20 19:44:48 +03:00
static int p8_aes_xts_crypt ( struct skcipher_request * req , int enc )
2016-07-18 18:26:26 +03:00
{
2019-05-20 19:44:48 +03:00
struct crypto_skcipher * tfm = crypto_skcipher_reqtfm ( req ) ;
const struct p8_aes_xts_ctx * ctx = crypto_skcipher_ctx ( tfm ) ;
struct skcipher_walk walk ;
unsigned int nbytes ;
2016-07-18 18:26:26 +03:00
u8 tweak [ AES_BLOCK_SIZE ] ;
2019-05-20 19:44:48 +03:00
int ret ;
2016-07-18 18:26:26 +03:00
2020-01-08 08:06:46 +03:00
if ( req - > cryptlen < AES_BLOCK_SIZE )
return - EINVAL ;
2019-08-16 17:06:24 +03:00
if ( ! crypto_simd_usable ( ) | | ( req - > cryptlen % XTS_BLOCK_SIZE ) ! = 0 ) {
2019-05-20 19:44:48 +03:00
struct skcipher_request * subreq = skcipher_request_ctx ( req ) ;
* subreq = * req ;
skcipher_request_set_tfm ( subreq , ctx - > fallback ) ;
return enc ? crypto_skcipher_encrypt ( subreq ) :
crypto_skcipher_decrypt ( subreq ) ;
}
ret = skcipher_walk_virt ( & walk , req , false ) ;
if ( ret )
return ret ;
preempt_disable ( ) ;
pagefault_disable ( ) ;
enable_kernel_vsx ( ) ;
2018-08-22 09:26:31 +03:00
2019-05-20 19:44:48 +03:00
aes_p8_encrypt ( walk . iv , tweak , & ctx - > tweak_key ) ;
disable_kernel_vsx ( ) ;
pagefault_enable ( ) ;
preempt_enable ( ) ;
2018-08-22 09:26:31 +03:00
2019-05-20 19:44:48 +03:00
while ( ( nbytes = walk . nbytes ) ! = 0 ) {
2016-07-18 18:26:26 +03:00
preempt_disable ( ) ;
pagefault_disable ( ) ;
enable_kernel_vsx ( ) ;
2019-05-20 19:44:48 +03:00
if ( enc )
aes_p8_xts_encrypt ( walk . src . virt . addr ,
walk . dst . virt . addr ,
round_down ( nbytes , AES_BLOCK_SIZE ) ,
& ctx - > enc_key , NULL , tweak ) ;
else
aes_p8_xts_decrypt ( walk . src . virt . addr ,
walk . dst . virt . addr ,
round_down ( nbytes , AES_BLOCK_SIZE ) ,
& ctx - > dec_key , NULL , tweak ) ;
2018-08-22 09:26:31 +03:00
disable_kernel_vsx ( ) ;
pagefault_enable ( ) ;
preempt_enable ( ) ;
2019-05-20 19:44:48 +03:00
ret = skcipher_walk_done ( & walk , nbytes % AES_BLOCK_SIZE ) ;
2016-07-18 18:26:26 +03:00
}
return ret ;
}
2019-05-20 19:44:48 +03:00
static int p8_aes_xts_encrypt ( struct skcipher_request * req )
2016-07-18 18:26:26 +03:00
{
2019-05-20 19:44:48 +03:00
return p8_aes_xts_crypt ( req , 1 ) ;
2016-07-18 18:26:26 +03:00
}
2019-05-20 19:44:48 +03:00
static int p8_aes_xts_decrypt ( struct skcipher_request * req )
2016-07-18 18:26:26 +03:00
{
2019-05-20 19:44:48 +03:00
return p8_aes_xts_crypt ( req , 0 ) ;
2016-07-18 18:26:26 +03:00
}
2019-05-20 19:44:48 +03:00
struct skcipher_alg p8_aes_xts_alg = {
. base . cra_name = " xts(aes) " ,
. base . cra_driver_name = " p8_aes_xts " ,
. base . cra_module = THIS_MODULE ,
. base . cra_priority = 2000 ,
. base . cra_flags = CRYPTO_ALG_NEED_FALLBACK ,
. base . cra_blocksize = AES_BLOCK_SIZE ,
. base . cra_ctxsize = sizeof ( struct p8_aes_xts_ctx ) ,
. setkey = p8_aes_xts_setkey ,
. encrypt = p8_aes_xts_encrypt ,
. decrypt = p8_aes_xts_decrypt ,
. init = p8_aes_xts_init ,
. exit = p8_aes_xts_exit ,
. min_keysize = 2 * AES_MIN_KEY_SIZE ,
. max_keysize = 2 * AES_MAX_KEY_SIZE ,
. ivsize = AES_BLOCK_SIZE ,
2016-07-18 18:26:26 +03:00
} ;