Skip to content

Commit 662ea18

Browse files
committed
crypto: skcipher - Make use of internal state
This patch adds code to the skcipher/lskcipher API to make use of the internal state if present. In particular, the skcipher lskcipher wrapper will allocate a buffer for the IV/state and feed that to the underlying lskcipher algorithm. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
1 parent 0ae4dcc commit 662ea18

File tree

3 files changed

+139
-8
lines changed

3 files changed

+139
-8
lines changed

crypto/lskcipher.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ static int crypto_lskcipher_crypt_unaligned(
9090
u8 *iv, int (*crypt)(struct crypto_lskcipher *tfm, const u8 *src,
9191
u8 *dst, unsigned len, u8 *iv, u32 flags))
9292
{
93+
unsigned statesize = crypto_lskcipher_statesize(tfm);
9394
unsigned ivsize = crypto_lskcipher_ivsize(tfm);
9495
unsigned bs = crypto_lskcipher_blocksize(tfm);
9596
unsigned cs = crypto_lskcipher_chunksize(tfm);
@@ -104,7 +105,7 @@ static int crypto_lskcipher_crypt_unaligned(
104105
if (!tiv)
105106
return -ENOMEM;
106107

107-
memcpy(tiv, iv, ivsize);
108+
memcpy(tiv, iv, ivsize + statesize);
108109

109110
p = kmalloc(PAGE_SIZE, GFP_ATOMIC);
110111
err = -ENOMEM;
@@ -132,7 +133,7 @@ static int crypto_lskcipher_crypt_unaligned(
132133
err = len ? -EINVAL : 0;
133134

134135
out:
135-
memcpy(iv, tiv, ivsize);
136+
memcpy(iv, tiv, ivsize + statesize);
136137
kfree_sensitive(p);
137138
kfree_sensitive(tiv);
138139
return err;
@@ -197,25 +198,45 @@ EXPORT_SYMBOL_GPL(crypto_lskcipher_decrypt);
197198
static int crypto_lskcipher_crypt_sg(struct skcipher_request *req,
198199
int (*crypt)(struct crypto_lskcipher *tfm,
199200
const u8 *src, u8 *dst,
200-
unsigned len, u8 *iv,
201+
unsigned len, u8 *ivs,
201202
u32 flags))
202203
{
203204
struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
204205
struct crypto_lskcipher **ctx = crypto_skcipher_ctx(skcipher);
206+
u8 *ivs = skcipher_request_ctx(req);
205207
struct crypto_lskcipher *tfm = *ctx;
206208
struct skcipher_walk walk;
209+
unsigned ivsize;
210+
u32 flags;
207211
int err;
208212

213+
ivsize = crypto_lskcipher_ivsize(tfm);
214+
ivs = PTR_ALIGN(ivs, crypto_skcipher_alignmask(skcipher) + 1);
215+
216+
flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
217+
218+
if (req->base.flags & CRYPTO_SKCIPHER_REQ_CONT)
219+
flags |= CRYPTO_LSKCIPHER_FLAG_CONT;
220+
else
221+
memcpy(ivs, req->iv, ivsize);
222+
223+
if (!(req->base.flags & CRYPTO_SKCIPHER_REQ_NOTFINAL))
224+
flags |= CRYPTO_LSKCIPHER_FLAG_FINAL;
225+
209226
err = skcipher_walk_virt(&walk, req, false);
210227

211228
while (walk.nbytes) {
212229
err = crypt(tfm, walk.src.virt.addr, walk.dst.virt.addr,
213-
walk.nbytes, walk.iv,
214-
walk.nbytes == walk.total ?
215-
CRYPTO_LSKCIPHER_FLAG_FINAL : 0);
230+
walk.nbytes, ivs,
231+
flags & ~(walk.nbytes == walk.total ?
232+
0 : CRYPTO_LSKCIPHER_FLAG_FINAL));
216233
err = skcipher_walk_done(&walk, err);
234+
flags |= CRYPTO_LSKCIPHER_FLAG_CONT;
217235
}
218236

237+
if (flags & CRYPTO_LSKCIPHER_FLAG_FINAL)
238+
memcpy(req->iv, ivs, ivsize);
239+
219240
return err;
220241
}
221242

@@ -278,6 +299,7 @@ static void __maybe_unused crypto_lskcipher_show(
278299
seq_printf(m, "max keysize : %u\n", skcipher->co.max_keysize);
279300
seq_printf(m, "ivsize : %u\n", skcipher->co.ivsize);
280301
seq_printf(m, "chunksize : %u\n", skcipher->co.chunksize);
302+
seq_printf(m, "statesize : %u\n", skcipher->co.statesize);
281303
}
282304

283305
static int __maybe_unused crypto_lskcipher_report(

crypto/skcipher.c

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,64 @@ int crypto_skcipher_decrypt(struct skcipher_request *req)
698698
}
699699
EXPORT_SYMBOL_GPL(crypto_skcipher_decrypt);
700700

701+
static int crypto_lskcipher_export(struct skcipher_request *req, void *out)
702+
{
703+
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
704+
u8 *ivs = skcipher_request_ctx(req);
705+
706+
ivs = PTR_ALIGN(ivs, crypto_skcipher_alignmask(tfm) + 1);
707+
708+
memcpy(out, ivs + crypto_skcipher_ivsize(tfm),
709+
crypto_skcipher_statesize(tfm));
710+
711+
return 0;
712+
}
713+
714+
static int crypto_lskcipher_import(struct skcipher_request *req, const void *in)
715+
{
716+
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
717+
u8 *ivs = skcipher_request_ctx(req);
718+
719+
ivs = PTR_ALIGN(ivs, crypto_skcipher_alignmask(tfm) + 1);
720+
721+
memcpy(ivs + crypto_skcipher_ivsize(tfm), in,
722+
crypto_skcipher_statesize(tfm));
723+
724+
return 0;
725+
}
726+
727+
static int skcipher_noexport(struct skcipher_request *req, void *out)
728+
{
729+
return 0;
730+
}
731+
732+
static int skcipher_noimport(struct skcipher_request *req, const void *in)
733+
{
734+
return 0;
735+
}
736+
737+
int crypto_skcipher_export(struct skcipher_request *req, void *out)
738+
{
739+
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
740+
struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
741+
742+
if (alg->co.base.cra_type != &crypto_skcipher_type)
743+
return crypto_lskcipher_export(req, out);
744+
return alg->export(req, out);
745+
}
746+
EXPORT_SYMBOL_GPL(crypto_skcipher_export);
747+
748+
int crypto_skcipher_import(struct skcipher_request *req, const void *in)
749+
{
750+
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
751+
struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
752+
753+
if (alg->co.base.cra_type != &crypto_skcipher_type)
754+
return crypto_lskcipher_import(req, in);
755+
return alg->import(req, in);
756+
}
757+
EXPORT_SYMBOL_GPL(crypto_skcipher_import);
758+
701759
static void crypto_skcipher_exit_tfm(struct crypto_tfm *tfm)
702760
{
703761
struct crypto_skcipher *skcipher = __crypto_skcipher_cast(tfm);
@@ -713,8 +771,17 @@ static int crypto_skcipher_init_tfm(struct crypto_tfm *tfm)
713771

714772
skcipher_set_needkey(skcipher);
715773

716-
if (tfm->__crt_alg->cra_type != &crypto_skcipher_type)
774+
if (tfm->__crt_alg->cra_type != &crypto_skcipher_type) {
775+
unsigned am = crypto_skcipher_alignmask(skcipher);
776+
unsigned reqsize;
777+
778+
reqsize = am & ~(crypto_tfm_ctx_alignment() - 1);
779+
reqsize += crypto_skcipher_ivsize(skcipher);
780+
reqsize += crypto_skcipher_statesize(skcipher);
781+
crypto_skcipher_set_reqsize(skcipher, reqsize);
782+
717783
return crypto_init_lskcipher_ops_sg(tfm);
784+
}
718785

719786
if (alg->exit)
720787
skcipher->base.exit = crypto_skcipher_exit_tfm;
@@ -756,6 +823,7 @@ static void crypto_skcipher_show(struct seq_file *m, struct crypto_alg *alg)
756823
seq_printf(m, "ivsize : %u\n", skcipher->ivsize);
757824
seq_printf(m, "chunksize : %u\n", skcipher->chunksize);
758825
seq_printf(m, "walksize : %u\n", skcipher->walksize);
826+
seq_printf(m, "statesize : %u\n", skcipher->statesize);
759827
}
760828

761829
static int __maybe_unused crypto_skcipher_report(
@@ -870,7 +938,9 @@ int skcipher_prepare_alg_common(struct skcipher_alg_common *alg)
870938
struct crypto_istat_cipher *istat = skcipher_get_stat_common(alg);
871939
struct crypto_alg *base = &alg->base;
872940

873-
if (alg->ivsize > PAGE_SIZE / 8 || alg->chunksize > PAGE_SIZE / 8)
941+
if (alg->ivsize > PAGE_SIZE / 8 || alg->chunksize > PAGE_SIZE / 8 ||
942+
alg->statesize > PAGE_SIZE / 2 ||
943+
(alg->ivsize + alg->statesize) > PAGE_SIZE / 2)
874944
return -EINVAL;
875945

876946
if (!alg->chunksize)
@@ -899,6 +969,12 @@ static int skcipher_prepare_alg(struct skcipher_alg *alg)
899969
if (!alg->walksize)
900970
alg->walksize = alg->chunksize;
901971

972+
if (!alg->statesize) {
973+
alg->import = skcipher_noimport;
974+
alg->export = skcipher_noexport;
975+
} else if (!(alg->import && alg->export))
976+
return -EINVAL;
977+
902978
base->cra_type = &crypto_skcipher_type;
903979
base->cra_flags |= CRYPTO_ALG_TYPE_SKCIPHER;
904980

include/crypto/skcipher.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,39 @@ int crypto_skcipher_encrypt(struct skcipher_request *req);
746746
*/
747747
int crypto_skcipher_decrypt(struct skcipher_request *req);
748748

749+
/**
750+
* crypto_skcipher_export() - export partial state
751+
* @req: reference to the skcipher_request handle that holds all information
752+
* needed to perform the operation
753+
* @out: output buffer of sufficient size that can hold the state
754+
*
755+
* Export partial state of the transformation. This function dumps the
756+
* entire state of the ongoing transformation into a provided block of
757+
* data so it can be @import 'ed back later on. This is useful in case
758+
* you want to save partial result of the transformation after
759+
* processing certain amount of data and reload this partial result
760+
* multiple times later on for multiple re-use. No data processing
761+
* happens at this point.
762+
*
763+
* Return: 0 if the cipher operation was successful; < 0 if an error occurred
764+
*/
765+
int crypto_skcipher_export(struct skcipher_request *req, void *out);
766+
767+
/**
768+
* crypto_skcipher_import() - import partial state
769+
* @req: reference to the skcipher_request handle that holds all information
770+
* needed to perform the operation
771+
* @in: buffer holding the state
772+
*
773+
* Import partial state of the transformation. This function loads the
774+
* entire state of the ongoing transformation from a provided block of
775+
* data so the transformation can continue from this point onward. No
776+
* data processing happens at this point.
777+
*
778+
* Return: 0 if the cipher operation was successful; < 0 if an error occurred
779+
*/
780+
int crypto_skcipher_import(struct skcipher_request *req, const void *in);
781+
749782
/**
750783
* crypto_lskcipher_encrypt() - encrypt plaintext
751784
* @tfm: lskcipher handle

0 commit comments

Comments
 (0)