On Sun, 2007-11-11 at 22:10 +0100, Sebastian Siewior wrote:
> Some CPUs support only 128 bit keys in HW. This patch adds SW fallback
> support for the other keys which may be required. The generic algorithm
> (and the block mode) must be availble in case of a fallback.
> 
> Signed-off-by: Sebastian Siewior <[EMAIL PROTECTED]>
> ---
> 
> Jan, please I didn't have the time to compile test. My compiler nagged
> only about the header file so it could work :)

Sebastian, thanks for working on this! Do you know if I need other
posted patches that are not yet in cryptodev-2.6 for this to work?

I'm asking becuase I'm getting the following crash using tcrypt (aes
192-bit key, ecb-mode) :(

Call Trace:
(Ý<0000000002ee5680>¨ 0x2ee5680)
 Ý<00000001008292ae>¨ crypto_ecb_setkey+0x52/0x74 Ýecb¨
 Ý<000000010082316e>¨ setkey_fallback_blk+0x5e/0x98 Ýaes_s390¨
 Ý<0000000100886d76>¨ test_cipher+0x2da/0x8f0 Ýtcrypt¨
 Ý<000000010080570e>¨ init+0x70e/0x1808 Ýtcrypt¨
 Ý<00000000000674f4>¨ sys_init_module+0x148/0x1e64
 Ý<00000000000222f8>¨ sysc_noemu+0x10/0x16
 Ý<000002000011ff6e>¨ 0x2000011ff6e

>From my limited understanding of the internals of crypto API I think
this is because crypto_ecb_setkey() calls crypto_cipher_setkey() instead
of crypto_blkcipher_setkey() and the layout of struct blkcipher_tfm
has the *iv where cipher_tfm has the setkey(). And oops, since the *iv
is zero we have a null pointer call. But maybe I'm just missing another patch...

thanks, Jan


> diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
> index 812511b..393a450 100644
> --- a/arch/s390/crypto/aes_s390.c
> +++ b/arch/s390/crypto/aes_s390.c
> @@ -6,6 +6,7 @@
>   * s390 Version:
>   *   Copyright IBM Corp. 2005,2007
>   *   Author(s): Jan Glauber ([EMAIL PROTECTED])
> + *           Sebastian Siewior ([EMAIL PROTECTED]> SW-Fallback
>   *
>   * Derived from "crypto/aes_generic.c"
>   *
> @@ -18,6 +19,7 @@
> 
>  #include <crypto/aes.h>
>  #include <crypto/algapi.h>
> +#include <linux/err.h>
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include "crypt_s390.h"
> @@ -34,45 +36,89 @@ struct s390_aes_ctx {
>       long enc;
>       long dec;
>       int key_len;
> +     union {
> +             struct crypto_blkcipher *blk;
> +             struct crypto_cipher *cip;
> +     } fallback;
>  };
> 
> -static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
> -                    unsigned int key_len)
> +/*
> + * Check if the key_len is supported by the HW.
> + * Returns 0 if it is, a positive number if it is not and software fallback 
> is
> + * required or a negative number in case the key size is not valid
> + */
> +static int need_fallback(unsigned int key_len)
>  {
> -     struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
> -     u32 *flags = &tfm->crt_flags;
> -
>       switch (key_len) {
>       case 16:
>               if (!(keylen_flag & AES_KEYLEN_128))
> -                     goto fail;
> +                     return 1;
>               break;
>       case 24:
>               if (!(keylen_flag & AES_KEYLEN_192))
> -                     goto fail;
> -
> +                     return 1;
>               break;
>       case 32:
>               if (!(keylen_flag & AES_KEYLEN_256))
> -                     goto fail;
> +                     return 1;
>               break;
>       default:
> -             goto fail;
> +             return -1;
>               break;
>       }
> +     return 0;
> +}
> +
> +static int setkey_fallback_cip(struct crypto_tfm *tfm, const u8 *in_key,
> +             unsigned int key_len)
> +{
> +     struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
> +     int ret;
> +
> +     sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
> +     sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags &
> +                     CRYPTO_TFM_REQ_MASK);
> +
> +     ret = crypto_cipher_setkey(sctx->fallback.cip, in_key, key_len);
> +     if (ret) {
> +             tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
> +             tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags &
> +                             CRYPTO_TFM_RES_MASK);
> +     }
> +     return ret;
> +}
> +
> +static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
> +                    unsigned int key_len)
> +{
> +     struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
> +     u32 *flags = &tfm->crt_flags;
> +     int ret;
> +
> +     ret = need_fallback(key_len);
> +     if (ret < 0) {
> +             *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
> +             return -EINVAL;
> +     }
> 
>       sctx->key_len = key_len;
> -     memcpy(sctx->key, in_key, key_len);
> -     return 0;
> -fail:
> -     *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
> -     return -EINVAL;
> +     if (!ret) {
> +             memcpy(sctx->key, in_key, key_len);
> +             return 0;
> +     }
> +
> +     return setkey_fallback_cip(tfm, in_key, key_len);
>  }
> 
>  static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
>  {
>       const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
> 
> +     if (unlikely(need_fallback(sctx->key_len))) {
> +             crypto_cipher_encrypt_one(sctx->fallback.cip, out, in);
> +             return;
> +     }
> +
>       switch (sctx->key_len) {
>       case 16:
>               crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in,
> @@ -93,6 +139,11 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, 
> const u8 *in)
>  {
>       const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
> 
> +     if (unlikely(need_fallback(sctx->key_len))) {
> +             crypto_cipher_decrypt_one(sctx->fallback.cip, out, in);
> +             return;
> +     }
> +
>       switch (sctx->key_len) {
>       case 16:
>               crypt_s390_km(KM_AES_128_DECRYPT, &sctx->key, out, in,
> @@ -109,7 +160,6 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, 
> const u8 *in)
>       }
>  }
> 
> -
>  static struct crypto_alg aes_alg = {
>       .cra_name               =       "aes",
>       .cra_driver_name        =       "aes-s390",
> @@ -131,10 +181,71 @@ static struct crypto_alg aes_alg = {
>       }
>  };
> 
> +static int setkey_fallback_blk(struct crypto_tfm *tfm, const u8 *key,
> +             unsigned int len)
> +{
> +     struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
> +     unsigned int ret;
> +
> +     /*
> +      * The requested key size is not supported by HW, do a fallback
> +      */
> +     sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
> +     sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags &
> +                     CRYPTO_TFM_REQ_MASK);
> +
> +     ret = crypto_blkcipher_setkey(sctx->fallback.blk, key, len);
> +     if (ret) {
> +             tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
> +             tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags &
> +                             CRYPTO_TFM_RES_MASK);
> +     }
> +     return ret;
> +}
> +
> +static int fallback_blk_dec(struct blkcipher_desc *desc,
> +             struct scatterlist *dst, struct scatterlist *src,
> +             unsigned int nbytes)
> +{
> +     unsigned int ret;
> +     struct crypto_blkcipher *tfm;
> +     struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
> +
> +     tfm = desc->tfm;
> +     desc->tfm = sctx->fallback.blk;
> +
> +     ret = crypto_blkcipher_decrypt(desc, dst, src, nbytes);
> +
> +     desc->tfm = tfm;
> +     return ret;
> +}
> +
> +static int fallback_blk_enc(struct blkcipher_desc *desc,
> +             struct scatterlist *dst, struct scatterlist *src,
> +             unsigned int nbytes)
> +{
> +     unsigned int ret;
> +     struct crypto_blkcipher *tfm;
> +     struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
> +
> +     tfm = desc->tfm;
> +     desc->tfm = sctx->fallback.blk;
> +
> +     ret = crypto_blkcipher_encrypt(desc, dst, src, nbytes);
> +
> +     desc->tfm = tfm;
> +     return ret;
> +}
> +
>  static int ecb_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
>                          unsigned int key_len)
>  {
>       struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
> +     int ret;
> +
> +     ret = need_fallback(key_len);
> +     if (ret > 0)
> +             return setkey_fallback_blk(tfm, in_key, key_len);
> 
>       switch (key_len) {
>       case 16:
> @@ -183,6 +294,9 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc,
>       struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
>       struct blkcipher_walk walk;
> 
> +     if (unlikely(need_fallback(sctx->key_len)))
> +             return fallback_blk_enc(desc, dst, src, nbytes);
> +
>       blkcipher_walk_init(&walk, dst, src, nbytes);
>       return ecb_aes_crypt(desc, sctx->enc, sctx->key, &walk);
>  }
> @@ -194,10 +308,37 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc,
>       struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
>       struct blkcipher_walk walk;
> 
> +     if (unlikely(need_fallback(sctx->key_len)))
> +             return fallback_blk_dec(desc, dst, src, nbytes);
> +
>       blkcipher_walk_init(&walk, dst, src, nbytes);
>       return ecb_aes_crypt(desc, sctx->dec, sctx->key, &walk);
>  }
> 
> +static int fallback_init_blk(struct crypto_tfm *tfm)
> +{
> +     const char *name = tfm->__crt_alg->cra_name;
> +     struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
> +
> +     sctx->fallback.blk = crypto_alloc_blkcipher(name, 0,
> +                     CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
> +
> +     if (IS_ERR(sctx->fallback.blk)) {
> +             printk(KERN_ERR "Error allocating fallback algo %s\n", name);
> +             return PTR_ERR(sctx->fallback.blk);
> +     }
> +
> +     return 0;
> +}
> +
> +static void fallback_exit_blk(struct crypto_tfm *tfm)
> +{
> +     struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
> +
> +     crypto_free_blkcipher(sctx->fallback.blk);
> +     sctx->fallback.blk = NULL;
> +}
> +
>  static struct crypto_alg ecb_aes_alg = {
>       .cra_name               =       "ecb(aes)",
>       .cra_driver_name        =       "ecb-aes-s390",
> @@ -209,6 +350,8 @@ static struct crypto_alg ecb_aes_alg = {
>       .cra_type               =       &crypto_blkcipher_type,
>       .cra_module             =       THIS_MODULE,
>       .cra_list               =       LIST_HEAD_INIT(ecb_aes_alg.cra_list),
> +     .cra_init               =       fallback_init_blk,
> +     .cra_exit               =       fallback_exit_blk,
>       .cra_u                  =       {
>               .blkcipher = {
>                       .min_keysize            =       AES_MIN_KEY_SIZE,
> @@ -224,6 +367,11 @@ static int cbc_aes_set_key(struct crypto_tfm *tfm, const 
> u8 *in_key,
>                          unsigned int key_len)
>  {
>       struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
> +     int ret;
> +
> +     ret = need_fallback(key_len);
> +     if (ret > 0)
> +             return setkey_fallback_blk(tfm, in_key, key_len);
> 
>       switch (key_len) {
>       case 16:
> @@ -278,6 +426,9 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
>       struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
>       struct blkcipher_walk walk;
> 
> +     if (unlikely(need_fallback(sctx->key_len)))
> +             return fallback_blk_enc(desc, dst, src, nbytes);
> +
>       blkcipher_walk_init(&walk, dst, src, nbytes);
>       return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk);
>  }
> @@ -289,6 +440,9 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
>       struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
>       struct blkcipher_walk walk;
> 
> +     if (unlikely(need_fallback(sctx->key_len)))
> +             return fallback_blk_dec(desc, dst, src, nbytes);
> +
>       blkcipher_walk_init(&walk, dst, src, nbytes);
>       return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk);
>  }
> @@ -304,6 +458,8 @@ static struct crypto_alg cbc_aes_alg = {
>       .cra_type               =       &crypto_blkcipher_type,
>       .cra_module             =       THIS_MODULE,
>       .cra_list               =       LIST_HEAD_INIT(cbc_aes_alg.cra_list),
> +     .cra_init               =       fallback_init_blk,
> +     .cra_exit               =       fallback_exit_blk,
>       .cra_u                  =       {
>               .blkcipher = {
>                       .min_keysize            =       AES_MIN_KEY_SIZE,
> @@ -331,14 +487,10 @@ static int __init aes_init(void)
>               return -EOPNOTSUPP;
> 
>       /* z9 109 and z9 BC/EC only support 128 bit key length */
> -     if (keylen_flag == AES_KEYLEN_128) {
> -             aes_alg.cra_u.cipher.cia_max_keysize = AES_MIN_KEY_SIZE;
> -             ecb_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE;
> -             cbc_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE;
> +     if (keylen_flag == AES_KEYLEN_128)
>               printk(KERN_INFO
>                      "aes_s390: hardware acceleration only available for"
>                      "128 bit keys\n");
> -     }
> 
>       ret = crypto_register_alg(&aes_alg);
>       if (ret)
> @@ -377,4 +529,3 @@ MODULE_ALIAS("aes");
> 
>  MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
>  MODULE_LICENSE("GPL");
> -

-
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to