Re: [RFC] [crypto] S390-AES add fallback driver.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <sebastian@xxxxxxxxxxxxx>
> ---
> 
> 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 (jang@xxxxxxxxxx)
> + *		Sebastian Siewior (sebastian@xxxxxxxxxxxxx> 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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux