162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#ifndef _CRYPTO_ECB_CBC_HELPER_H 462306a36Sopenharmony_ci#define _CRYPTO_ECB_CBC_HELPER_H 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 762306a36Sopenharmony_ci#include <asm/fpu/api.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* 1062306a36Sopenharmony_ci * Mode helpers to instantiate parameterized skcipher ECB/CBC modes without 1162306a36Sopenharmony_ci * having to rely on indirect calls and retpolines. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define ECB_WALK_START(req, bsize, fpu_blocks) do { \ 1562306a36Sopenharmony_ci void *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); \ 1662306a36Sopenharmony_ci const int __fpu_blocks = (fpu_blocks); \ 1762306a36Sopenharmony_ci const int __bsize = (bsize); \ 1862306a36Sopenharmony_ci struct skcipher_walk walk; \ 1962306a36Sopenharmony_ci int err = skcipher_walk_virt(&walk, (req), false); \ 2062306a36Sopenharmony_ci while (walk.nbytes > 0) { \ 2162306a36Sopenharmony_ci unsigned int nbytes = walk.nbytes; \ 2262306a36Sopenharmony_ci bool do_fpu = __fpu_blocks != -1 && \ 2362306a36Sopenharmony_ci nbytes >= __fpu_blocks * __bsize; \ 2462306a36Sopenharmony_ci const u8 *src = walk.src.virt.addr; \ 2562306a36Sopenharmony_ci u8 *dst = walk.dst.virt.addr; \ 2662306a36Sopenharmony_ci u8 __maybe_unused buf[(bsize)]; \ 2762306a36Sopenharmony_ci if (do_fpu) kernel_fpu_begin() 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define CBC_WALK_START(req, bsize, fpu_blocks) \ 3062306a36Sopenharmony_ci ECB_WALK_START(req, bsize, fpu_blocks) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define ECB_WALK_ADVANCE(blocks) do { \ 3362306a36Sopenharmony_ci dst += (blocks) * __bsize; \ 3462306a36Sopenharmony_ci src += (blocks) * __bsize; \ 3562306a36Sopenharmony_ci nbytes -= (blocks) * __bsize; \ 3662306a36Sopenharmony_ci} while (0) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define ECB_BLOCK(blocks, func) do { \ 3962306a36Sopenharmony_ci const int __blocks = (blocks); \ 4062306a36Sopenharmony_ci if (do_fpu && __blocks < __fpu_blocks) { \ 4162306a36Sopenharmony_ci kernel_fpu_end(); \ 4262306a36Sopenharmony_ci do_fpu = false; \ 4362306a36Sopenharmony_ci } \ 4462306a36Sopenharmony_ci while (nbytes >= __blocks * __bsize) { \ 4562306a36Sopenharmony_ci (func)(ctx, dst, src); \ 4662306a36Sopenharmony_ci ECB_WALK_ADVANCE(blocks); \ 4762306a36Sopenharmony_ci } \ 4862306a36Sopenharmony_ci} while (0) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define CBC_ENC_BLOCK(func) do { \ 5162306a36Sopenharmony_ci const u8 *__iv = walk.iv; \ 5262306a36Sopenharmony_ci while (nbytes >= __bsize) { \ 5362306a36Sopenharmony_ci crypto_xor_cpy(dst, src, __iv, __bsize); \ 5462306a36Sopenharmony_ci (func)(ctx, dst, dst); \ 5562306a36Sopenharmony_ci __iv = dst; \ 5662306a36Sopenharmony_ci ECB_WALK_ADVANCE(1); \ 5762306a36Sopenharmony_ci } \ 5862306a36Sopenharmony_ci memcpy(walk.iv, __iv, __bsize); \ 5962306a36Sopenharmony_ci} while (0) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define CBC_DEC_BLOCK(blocks, func) do { \ 6262306a36Sopenharmony_ci const int __blocks = (blocks); \ 6362306a36Sopenharmony_ci if (do_fpu && __blocks < __fpu_blocks) { \ 6462306a36Sopenharmony_ci kernel_fpu_end(); \ 6562306a36Sopenharmony_ci do_fpu = false; \ 6662306a36Sopenharmony_ci } \ 6762306a36Sopenharmony_ci while (nbytes >= __blocks * __bsize) { \ 6862306a36Sopenharmony_ci const u8 *__iv = src + ((blocks) - 1) * __bsize; \ 6962306a36Sopenharmony_ci if (dst == src) \ 7062306a36Sopenharmony_ci __iv = memcpy(buf, __iv, __bsize); \ 7162306a36Sopenharmony_ci (func)(ctx, dst, src); \ 7262306a36Sopenharmony_ci crypto_xor(dst, walk.iv, __bsize); \ 7362306a36Sopenharmony_ci memcpy(walk.iv, __iv, __bsize); \ 7462306a36Sopenharmony_ci ECB_WALK_ADVANCE(blocks); \ 7562306a36Sopenharmony_ci } \ 7662306a36Sopenharmony_ci} while (0) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define ECB_WALK_END() \ 7962306a36Sopenharmony_ci if (do_fpu) kernel_fpu_end(); \ 8062306a36Sopenharmony_ci err = skcipher_walk_done(&walk, nbytes); \ 8162306a36Sopenharmony_ci } \ 8262306a36Sopenharmony_ci return err; \ 8362306a36Sopenharmony_ci} while (0) 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#define CBC_WALK_END() ECB_WALK_END() 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#endif 88