Teach the generic xts() template to consume cryptlen larger than one data unit when the caller has configured a non-zero data_unit_size on the tfm. Each data unit is processed with its own IV, derived from the caller-supplied IV by treating it as a 128-bit little-endian counter and adding the data-unit index. This matches the sector-indexed XTS used by dm-crypt's plain64 IV mode and by typical inline-encryption hardware.
The single-data-unit body is unchanged and is now reached via a thin xts_crypt_multi() dispatcher that skips straight to the body when data_unit_size is zero (the legacy default), so existing users see no extra cost. Advertise CRYPTO_ALG_SKCIPHER_MULTI_DATA_UNIT in cra_flags only when the inner cipher is synchronous. An async inner cipher would require a per-DU completion chain which is out of scope for the slow software template; consumers that need multi-DU on async hardware will use one of the arch-specific drivers added later in this series. Signed-off-by: Leonid Ravich <[email protected]> --- crypto/xts.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/crypto/xts.c b/crypto/xts.c index 3da8f5e053d6..2b7233311dad 100644 --- a/crypto/xts.c +++ b/crypto/xts.c @@ -258,7 +258,7 @@ static int xts_init_crypt(struct skcipher_request *req, return 0; } -static int xts_encrypt(struct skcipher_request *req) +static int xts_encrypt_one(struct skcipher_request *req) { struct xts_request_ctx *rctx = skcipher_request_ctx(req); struct skcipher_request *subreq = &rctx->subreq; @@ -275,7 +275,7 @@ static int xts_encrypt(struct skcipher_request *req) return xts_cts_final(req, crypto_skcipher_encrypt); } -static int xts_decrypt(struct skcipher_request *req) +static int xts_decrypt_one(struct skcipher_request *req) { struct xts_request_ctx *rctx = skcipher_request_ctx(req); struct skcipher_request *subreq = &rctx->subreq; @@ -292,6 +292,16 @@ static int xts_decrypt(struct skcipher_request *req) return xts_cts_final(req, crypto_skcipher_decrypt); } +static int xts_encrypt(struct skcipher_request *req) +{ + return skcipher_walk_data_units(req, xts_encrypt_one); +} + +static int xts_decrypt(struct skcipher_request *req) +{ + return skcipher_walk_data_units(req, xts_decrypt_one); +} + static int xts_init_tfm(struct crypto_skcipher *tfm) { struct skcipher_instance *inst = skcipher_alg_instance(tfm); @@ -427,6 +437,17 @@ static int xts_create(struct crypto_template *tmpl, struct rtattr **tb) inst->alg.base.cra_alignmask = alg->base.cra_alignmask | (__alignof__(u64) - 1); + /* + * Advertise multi-data-unit support only when the inner cipher is + * synchronous. The dispatcher in skcipher_walk_data_units() calls + * the single-DU body in a loop and assumes synchronous completion; + * supporting async would require a per-DU callback chain, which + * the slow software template does not need. + */ + if (!(alg->base.cra_flags & CRYPTO_ALG_ASYNC)) + inst->alg.base.cra_flags |= + CRYPTO_ALG_SKCIPHER_MULTI_DATA_UNIT; + inst->alg.ivsize = XTS_BLOCK_SIZE; inst->alg.min_keysize = alg->min_keysize * 2; inst->alg.max_keysize = alg->max_keysize * 2; -- 2.47.3
