Skip to content
88 changes: 32 additions & 56 deletions drivers/crypto/qce/aead.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
#include <crypto/gcm.h>
#include <crypto/authenc.h>
#include <crypto/internal/aead.h>
#include <crypto/internal/des.h>
#include <crypto/sha1.h>
#include <crypto/sha2.h>
#include <crypto/scatterwalk.h>
#include "aead.h"
Expand Down Expand Up @@ -500,7 +498,8 @@ static int qce_aead_crypt(struct aead_request *req, int encrypt)
struct qce_aead_reqctx *rctx = aead_request_ctx_dma(req);
struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
struct qce_alg_template *tmpl = to_aead_tmpl(tfm);
unsigned int blocksize = crypto_aead_blocksize(tfm);
unsigned int blocksize = crypto_aead_blocksize(tfm), authsize;
struct scatterlist __sg[2], *msg_sg;

rctx->flags = tmpl->alg_flags;
rctx->flags |= encrypt ? QCE_ENCRYPT : QCE_DECRYPT;
Expand All @@ -516,6 +515,35 @@ static int qce_aead_crypt(struct aead_request *req, int encrypt)
ctx->need_fallback = true;
}

/*
* CCM uses AES-CTR internally and the CE stalls on a partial final
* block, so a payload that is not a multiple of the block size has to
* be handled by the fallback.
*/
if (IS_CCM(rctx->flags) && !IS_ALIGNED(rctx->cryptlen, AES_BLOCK_SIZE))
ctx->need_fallback = true;

/*
* The CE reliably processes CCM only when the message payload is a
* single contiguous buffer. The associated data is linearized into a
* bounce buffer before being handed to the engine, but a fragmented
* payload makes the engine stall waiting for input, so route those
* requests to the fallback.
*/
if (IS_CCM(rctx->flags) && rctx->cryptlen) {
authsize = ctx->authsize;

msg_sg = scatterwalk_ffwd(__sg, req->src, req->assoclen);
if (sg_nents_for_len(msg_sg, rctx->cryptlen +
(encrypt ? 0 : authsize)) > 1)
ctx->need_fallback = true;

msg_sg = scatterwalk_ffwd(__sg, req->dst, req->assoclen);
if (sg_nents_for_len(msg_sg, rctx->cryptlen +
(encrypt ? authsize : 0)) > 1)
ctx->need_fallback = true;
}

/* If fallback is needed, schedule and exit */
if (ctx->need_fallback) {
/* Reset need_fallback in case the same ctx is used for another transaction */
Expand Down Expand Up @@ -592,7 +620,6 @@ static int qce_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int
struct qce_aead_ctx *ctx = crypto_aead_ctx(tfm);
struct crypto_authenc_keys authenc_keys;
unsigned long flags = to_aead_tmpl(tfm)->alg_flags;
u32 _key[6];
int err;

err = crypto_authenc_extractkeys(&authenc_keys, key, keylen);
Expand All @@ -603,26 +630,7 @@ static int qce_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int
authenc_keys.authkeylen > QCE_MAX_KEY_SIZE)
return -EINVAL;

if (IS_DES(flags)) {
err = verify_aead_des_key(tfm, authenc_keys.enckey, authenc_keys.enckeylen);
if (err)
return err;
} else if (IS_3DES(flags)) {
err = verify_aead_des3_key(tfm, authenc_keys.enckey, authenc_keys.enckeylen);
if (err)
return err;
/*
* The crypto engine does not support any two keys
* being the same for triple des algorithms. The
* verify_skcipher_des3_key does not check for all the
* below conditions. Schedule fallback in this case.
*/
memcpy(_key, authenc_keys.enckey, DES3_EDE_KEY_SIZE);
if (!((_key[0] ^ _key[2]) | (_key[1] ^ _key[3])) ||
!((_key[2] ^ _key[4]) | (_key[3] ^ _key[5])) ||
!((_key[0] ^ _key[4]) | (_key[1] ^ _key[5])))
ctx->need_fallback = true;
} else if (IS_AES(flags)) {
if (IS_AES(flags)) {
/* No random key sizes */
if (authenc_keys.enckeylen != AES_KEYSIZE_128 &&
authenc_keys.enckeylen != AES_KEYSIZE_192 &&
Expand Down Expand Up @@ -693,38 +701,6 @@ struct qce_aead_def {
};

static const struct qce_aead_def aead_def[] = {
{
.flags = QCE_ALG_DES | QCE_MODE_CBC | QCE_HASH_SHA1_HMAC,
.name = "authenc(hmac(sha1),cbc(des))",
.drv_name = "authenc-hmac-sha1-cbc-des-qce",
.blocksize = DES_BLOCK_SIZE,
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
},
{
.flags = QCE_ALG_3DES | QCE_MODE_CBC | QCE_HASH_SHA1_HMAC,
.name = "authenc(hmac(sha1),cbc(des3_ede))",
.drv_name = "authenc-hmac-sha1-cbc-3des-qce",
.blocksize = DES3_EDE_BLOCK_SIZE,
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
},
{
.flags = QCE_ALG_DES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC,
.name = "authenc(hmac(sha256),cbc(des))",
.drv_name = "authenc-hmac-sha256-cbc-des-qce",
.blocksize = DES_BLOCK_SIZE,
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
},
{
.flags = QCE_ALG_3DES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC,
.name = "authenc(hmac(sha256),cbc(des3_ede))",
.drv_name = "authenc-hmac-sha256-cbc-3des-qce",
.blocksize = DES3_EDE_BLOCK_SIZE,
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
},
{
.flags = QCE_ALG_AES | QCE_MODE_CBC | QCE_HASH_SHA256_HMAC,
.name = "authenc(hmac(sha256),cbc(aes))",
Expand Down
1 change: 1 addition & 0 deletions drivers/crypto/qce/cipher.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
struct qce_cipher_ctx {
u8 enc_key[QCE_MAX_KEY_SIZE];
unsigned int enc_keylen;
bool use_fallback;
struct crypto_skcipher *fallback;
};

Expand Down
55 changes: 12 additions & 43 deletions drivers/crypto/qce/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include <linux/interrupt.h>
#include <linux/types.h>
#include <crypto/scatterwalk.h>
#include <crypto/sha1.h>
#include <crypto/sha2.h>

#include "cipher.h"
Expand Down Expand Up @@ -119,18 +118,16 @@ static u32 qce_auth_cfg(unsigned long flags, u32 key_size, u32 auth_size)
cfg |= AUTH_KEY_SZ_AES256 << AUTH_KEY_SIZE_SHIFT;
}

if (IS_SHA1(flags) || IS_SHA1_HMAC(flags))
cfg |= AUTH_SIZE_SHA1 << AUTH_SIZE_SHIFT;
else if (IS_SHA256(flags) || IS_SHA256_HMAC(flags))
if (IS_SHA256(flags) || IS_SHA256_HMAC(flags))
cfg |= AUTH_SIZE_SHA256 << AUTH_SIZE_SHIFT;
else if (IS_CMAC(flags))
cfg |= AUTH_SIZE_ENUM_16_BYTES << AUTH_SIZE_SHIFT;
else if (IS_CCM(flags))
cfg |= (auth_size - 1) << AUTH_SIZE_SHIFT;

if (IS_SHA1(flags) || IS_SHA256(flags))
if (IS_SHA256(flags))
cfg |= AUTH_MODE_HASH << AUTH_MODE_SHIFT;
else if (IS_SHA1_HMAC(flags) || IS_SHA256_HMAC(flags))
else if (IS_SHA256_HMAC(flags))
cfg |= AUTH_MODE_HMAC << AUTH_MODE_SHIFT;
else if (IS_CCM(flags))
cfg |= AUTH_MODE_CCM << AUTH_MODE_SHIFT;
Expand Down Expand Up @@ -195,7 +192,7 @@ static int qce_setup_regs_ahash(struct crypto_async_request *async_req)
else
qce_cpu_to_be32p_array(auth, rctx->digest, digestsize);

iv_words = (IS_SHA1(rctx->flags) || IS_SHA1_HMAC(rctx->flags)) ? 5 : 8;
iv_words = 8;
qce_write_array(qce, REG_AUTH_IV0, (u32 *)auth, iv_words);

if (rctx->first_blk)
Expand Down Expand Up @@ -245,19 +242,8 @@ static u32 qce_encr_cfg(unsigned long flags, u32 aes_key_size)

if (IS_AES(flags))
cfg |= ENCR_ALG_AES << ENCR_ALG_SHIFT;
else if (IS_DES(flags) || IS_3DES(flags))
cfg |= ENCR_ALG_DES << ENCR_ALG_SHIFT;

if (IS_DES(flags))
cfg |= ENCR_KEY_SZ_DES << ENCR_KEY_SZ_SHIFT;

if (IS_3DES(flags))
cfg |= ENCR_KEY_SZ_3DES << ENCR_KEY_SZ_SHIFT;

switch (flags & QCE_MODE_MASK) {
case QCE_MODE_ECB:
cfg |= ENCR_MODE_ECB << ENCR_MODE_SHIFT;
break;
case QCE_MODE_CBC:
cfg |= ENCR_MODE_CBC << ENCR_MODE_SHIFT;
break;
Expand Down Expand Up @@ -342,13 +328,7 @@ static int qce_setup_regs_skcipher(struct crypto_async_request *async_req)

encr_cfg = qce_encr_cfg(flags, keylen);

if (IS_DES(flags)) {
enciv_words = 2;
enckey_words = 2;
} else if (IS_3DES(flags)) {
enciv_words = 2;
enckey_words = 6;
} else if (IS_AES(flags)) {
if (IS_AES(flags)) {
if (IS_XTS(flags))
qce_xtskey(qce, ctx->enc_key, ctx->enc_keylen,
rctx->cryptlen);
Expand All @@ -359,14 +339,12 @@ static int qce_setup_regs_skcipher(struct crypto_async_request *async_req)

qce_write_array(qce, REG_ENCR_KEY0, (u32 *)enckey, enckey_words);

if (!IS_ECB(flags)) {
if (IS_XTS(flags))
qce_xts_swapiv(enciv, rctx->iv, ivsize);
else
qce_cpu_to_be32p_array(enciv, rctx->iv, ivsize);
if (IS_XTS(flags))
qce_xts_swapiv(enciv, rctx->iv, ivsize);
else
qce_cpu_to_be32p_array(enciv, rctx->iv, ivsize);

qce_write_array(qce, REG_CNTR0_IV0, (u32 *)enciv, enciv_words);
}
qce_write_array(qce, REG_CNTR0_IV0, (u32 *)enciv, enciv_words);

if (IS_ENCRYPT(flags))
encr_cfg |= BIT(ENCODE_SHIFT);
Expand All @@ -393,10 +371,6 @@ static int qce_setup_regs_skcipher(struct crypto_async_request *async_req)
#endif

#ifdef CONFIG_CRYPTO_DEV_QCE_AEAD
static const u32 std_iv_sha1[SHA256_DIGEST_SIZE / sizeof(u32)] = {
SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4, 0, 0, 0
};

static const u32 std_iv_sha256[SHA256_DIGEST_SIZE / sizeof(u32)] = {
SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3,
SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7
Expand Down Expand Up @@ -473,13 +447,8 @@ static int qce_setup_regs_aead(struct crypto_async_request *async_req)
/* Write initial authentication IV only for HMAC algorithms */
if (IS_SHA_HMAC(rctx->flags)) {
/* Write default authentication iv */
if (IS_SHA1_HMAC(rctx->flags)) {
auth_ivsize = SHA1_DIGEST_SIZE;
memcpy(authiv, std_iv_sha1, auth_ivsize);
} else if (IS_SHA256_HMAC(rctx->flags)) {
auth_ivsize = SHA256_DIGEST_SIZE;
memcpy(authiv, std_iv_sha256, auth_ivsize);
}
auth_ivsize = SHA256_DIGEST_SIZE;
memcpy(authiv, std_iv_sha256, auth_ivsize);
authiv_words = auth_ivsize / sizeof(u32);
qce_write_array(qce, REG_AUTH_IV0, (u32 *)authiv, authiv_words);
} else if (IS_CCM(rctx->flags)) {
Expand Down
16 changes: 3 additions & 13 deletions drivers/crypto/qce/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

/* IV length in bytes */
#define QCE_AES_IV_LENGTH AES_BLOCK_SIZE
/* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
/* max of AES_BLOCK_SIZE */
#define QCE_MAX_IV_SIZE AES_BLOCK_SIZE

/* maximum nonce bytes */
Expand All @@ -33,14 +33,10 @@
#define QCE_MAX_ALIGN_SIZE 64

/* cipher algorithms */
#define QCE_ALG_DES BIT(0)
#define QCE_ALG_3DES BIT(1)
#define QCE_ALG_AES BIT(2)

/* hash and hmac algorithms */
#define QCE_HASH_SHA1 BIT(3)
#define QCE_HASH_SHA256 BIT(4)
#define QCE_HASH_SHA1_HMAC BIT(5)
#define QCE_HASH_SHA256_HMAC BIT(6)
#define QCE_HASH_AES_CMAC BIT(7)

Expand All @@ -58,21 +54,15 @@
#define QCE_ENCRYPT BIT(30)
#define QCE_DECRYPT BIT(31)

#define IS_DES(flags) (flags & QCE_ALG_DES)
#define IS_3DES(flags) (flags & QCE_ALG_3DES)
#define IS_AES(flags) (flags & QCE_ALG_AES)

#define IS_SHA1(flags) (flags & QCE_HASH_SHA1)
#define IS_SHA256(flags) (flags & QCE_HASH_SHA256)
#define IS_SHA1_HMAC(flags) (flags & QCE_HASH_SHA1_HMAC)
#define IS_SHA256_HMAC(flags) (flags & QCE_HASH_SHA256_HMAC)
#define IS_CMAC(flags) (flags & QCE_HASH_AES_CMAC)
#define IS_SHA(flags) (IS_SHA1(flags) || IS_SHA256(flags))
#define IS_SHA_HMAC(flags) \
(IS_SHA1_HMAC(flags) || IS_SHA256_HMAC(flags))
#define IS_SHA(flags) IS_SHA256(flags)
#define IS_SHA_HMAC(flags) IS_SHA256_HMAC(flags)

#define IS_CBC(mode) (mode & QCE_MODE_CBC)
#define IS_ECB(mode) (mode & QCE_MODE_ECB)
#define IS_CTR(mode) (mode & QCE_MODE_CTR)
#define IS_XTS(mode) (mode & QCE_MODE_XTS)
#define IS_CCM(mode) (mode & QCE_MODE_CCM)
Expand Down
4 changes: 0 additions & 4 deletions drivers/crypto/qce/regs-v5.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,6 @@

#define AUTH_SIZE_SHIFT 9
#define AUTH_SIZE_MASK GENMASK(13, 9)
#define AUTH_SIZE_SHA1 0
#define AUTH_SIZE_SHA256 1
#define AUTH_SIZE_ENUM_1_BYTES 0
#define AUTH_SIZE_ENUM_2_BYTES 1
Expand Down Expand Up @@ -284,15 +283,12 @@

#define ENCR_KEY_SZ_SHIFT 3
#define ENCR_KEY_SZ_MASK GENMASK(5, 3)
#define ENCR_KEY_SZ_DES 0
#define ENCR_KEY_SZ_3DES 1
#define ENCR_KEY_SZ_AES128 0
#define ENCR_KEY_SZ_AES256 2

#define ENCR_ALG_SHIFT 0
#define ENCR_ALG_MASK GENMASK(2, 0)
#define ENCR_ALG_NONE 0
#define ENCR_ALG_DES 1
#define ENCR_ALG_AES 2
#define ENCR_ALG_KASUMI 4
#define ENCR_ALG_SNOW_3G 5
Expand Down
Loading