diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2017-05-10 03:48:23 +0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-06-07 12:07:46 +0200 |
commit | 4472887cbd1373d7781bea9d8935f2d4968dd580 (patch) | |
tree | ada6fb0eabc15708d082126a3ab7c4339d4515a6 /crypto | |
parent | 63399974effb65d755a94edd10f33cd74e5a1b77 (diff) | |
download | linux-stable-4472887cbd1373d7781bea9d8935f2d4968dd580.tar.gz linux-stable-4472887cbd1373d7781bea9d8935f2d4968dd580.tar.bz2 linux-stable-4472887cbd1373d7781bea9d8935f2d4968dd580.zip |
crypto: skcipher - Add missing API setkey checks
commit 9933e113c2e87a9f46a40fde8dafbf801dca1ab9 upstream.
The API setkey checks for key sizes and alignment went AWOL during the
skcipher conversion. This patch restores them.
Fixes: 4e6c3df4d729 ("crypto: skcipher - Add low-level skcipher...")
Reported-by: Baozeng <sploving1@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/skcipher.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/crypto/skcipher.c b/crypto/skcipher.c index f7d0018dcaee..93110d70c1d3 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -221,6 +221,44 @@ static int crypto_init_skcipher_ops_ablkcipher(struct crypto_tfm *tfm) return 0; } +static int skcipher_setkey_unaligned(struct crypto_skcipher *tfm, + const u8 *key, unsigned int keylen) +{ + unsigned long alignmask = crypto_skcipher_alignmask(tfm); + struct skcipher_alg *cipher = crypto_skcipher_alg(tfm); + u8 *buffer, *alignbuffer; + unsigned long absize; + int ret; + + absize = keylen + alignmask; + buffer = kmalloc(absize, GFP_ATOMIC); + if (!buffer) + return -ENOMEM; + + alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); + memcpy(alignbuffer, key, keylen); + ret = cipher->setkey(tfm, alignbuffer, keylen); + kzfree(buffer); + return ret; +} + +static int skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, + unsigned int keylen) +{ + struct skcipher_alg *cipher = crypto_skcipher_alg(tfm); + unsigned long alignmask = crypto_skcipher_alignmask(tfm); + + if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) { + crypto_skcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + if ((unsigned long)key & alignmask) + return skcipher_setkey_unaligned(tfm, key, keylen); + + return cipher->setkey(tfm, key, keylen); +} + static void crypto_skcipher_exit_tfm(struct crypto_tfm *tfm) { struct crypto_skcipher *skcipher = __crypto_skcipher_cast(tfm); @@ -241,7 +279,7 @@ static int crypto_skcipher_init_tfm(struct crypto_tfm *tfm) tfm->__crt_alg->cra_type == &crypto_givcipher_type) return crypto_init_skcipher_ops_ablkcipher(tfm); - skcipher->setkey = alg->setkey; + skcipher->setkey = skcipher_setkey; skcipher->encrypt = alg->encrypt; skcipher->decrypt = alg->decrypt; skcipher->ivsize = alg->ivsize; |