| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include "rk_crypto_skcipher_utils.h" |
| |
| struct rk_crypto_algt *rk_cipher_get_algt(struct crypto_skcipher *tfm) |
| { |
| <------>struct skcipher_alg *alg = crypto_skcipher_alg(tfm); |
| |
| <------>return container_of(alg, struct rk_crypto_algt, alg.crypto); |
| } |
| |
| struct rk_crypto_algt *rk_aead_get_algt(struct crypto_aead *tfm) |
| { |
| <------>struct aead_alg *alg = crypto_aead_alg(tfm); |
| |
| <------>return container_of(alg, struct rk_crypto_algt, alg.aead); |
| } |
| |
| struct rk_cipher_ctx *rk_cipher_ctx_cast(struct rk_crypto_dev *rk_dev) |
| { |
| <------>struct rk_cipher_ctx *ctx = crypto_tfm_ctx(rk_dev->async_req->tfm); |
| |
| <------>return ctx; |
| } |
| |
| struct rk_alg_ctx *rk_cipher_alg_ctx(struct rk_crypto_dev *rk_dev) |
| { |
| <------>return &(rk_cipher_ctx_cast(rk_dev)->algs_ctx); |
| } |
| |
| static bool is_no_multi_blocksize(uint32_t mode) |
| { |
| <------>return (mode == CIPHER_MODE_CFB || |
| <------><------>mode == CIPHER_MODE_OFB || |
| <------><------>mode == CIPHER_MODE_CTR || |
| <------><------>mode == CIPHER_MODE_XTS || |
| <------><------>mode == CIPHER_MODE_GCM) ? true : false; |
| } |
| |
| int rk_cipher_fallback(struct skcipher_request *req, struct rk_cipher_ctx *ctx, bool encrypt) |
| { |
| <------>int ret; |
| |
| <------>CRYPTO_MSG("use fallback tfm"); |
| |
| <------>if (!ctx->fallback_tfm) { |
| <------><------>ret = -ENODEV; |
| <------><------>CRYPTO_MSG("fallback_tfm is empty!\n"); |
| <------><------>goto exit; |
| <------>} |
| |
| <------>if (!ctx->fallback_key_inited) { |
| <------><------>ret = crypto_skcipher_setkey(ctx->fallback_tfm, |
| <------><------><------><------><------> ctx->key, ctx->keylen); |
| <------><------>if (ret) { |
| <------><------><------>CRYPTO_MSG("fallback crypto_skcipher_setkey err = %d\n", |
| <------><------><------><------> ret); |
| <------><------><------>goto exit; |
| <------><------>} |
| |
| <------><------>ctx->fallback_key_inited = true; |
| <------>} |
| |
| <------>skcipher_request_set_tfm(&ctx->fallback_req, ctx->fallback_tfm); |
| <------>skcipher_request_set_callback(&ctx->fallback_req, |
| <------><------><------><------> req->base.flags, |
| <------><------><------><------> req->base.complete, |
| <------><------><------><------> req->base.data); |
| |
| <------>skcipher_request_set_crypt(&ctx->fallback_req, req->src, |
| <------><------><------><------> req->dst, req->cryptlen, req->iv); |
| |
| <------>ret = encrypt ? crypto_skcipher_encrypt(&ctx->fallback_req) : |
| <------><------><------>crypto_skcipher_decrypt(&ctx->fallback_req); |
| |
| exit: |
| <------>return ret; |
| } |
| |
| |
| static void rk_ctr128_inc(uint8_t *counter) |
| { |
| <------>u32 n = 16; |
| <------>u8 c; |
| |
| <------>do { |
| <------><------>--n; |
| <------><------>c = counter[n]; |
| <------><------>++c; |
| <------><------>counter[n] = c; |
| <------><------>if (c) |
| <------><------><------>return; |
| <------>} while (n); |
| } |
| |
| static void rk_ctr128_calc(uint8_t *counter, uint32_t data_len) |
| { |
| <------>u32 i; |
| <------>u32 chunksize = AES_BLOCK_SIZE; |
| |
| <------>for (i = 0; i < DIV_ROUND_UP(data_len, chunksize); i++) |
| <------><------>rk_ctr128_inc(counter); |
| } |
| |
| static uint32_t rk_get_new_iv(struct rk_cipher_ctx *ctx, u32 mode, bool is_enc, uint8_t *iv) |
| { |
| <------>struct scatterlist *sg_dst; |
| <------>struct rk_alg_ctx *alg_ctx = &ctx->algs_ctx; |
| <------>uint32_t ivsize = alg_ctx->chunk_size; |
| |
| <------>if (!iv) |
| <------><------>return 0; |
| |
| <------>sg_dst = alg_ctx->aligned ? alg_ctx->sg_dst : &alg_ctx->sg_tmp; |
| |
| <------>CRYPTO_TRACE("aligned = %u, count = %u, ivsize = %u, is_enc = %d\n", |
| <------><------> alg_ctx->aligned, alg_ctx->count, ivsize, is_enc); |
| |
| <------>switch (mode) { |
| <------>case CIPHER_MODE_CTR: |
| <------><------>rk_ctr128_calc(iv, alg_ctx->count); |
| <------><------>break; |
| <------>case CIPHER_MODE_CBC: |
| <------>case CIPHER_MODE_CFB: |
| <------><------>if (is_enc) |
| <------><------><------>sg_pcopy_to_buffer(sg_dst, alg_ctx->map_nents, |
| <------><------><------><------><------> iv, ivsize, alg_ctx->count - ivsize); |
| <------><------>else |
| <------><------><------>memcpy(iv, ctx->lastc, ivsize); |
| <------><------>break; |
| <------>case CIPHER_MODE_OFB: |
| <------><------>sg_pcopy_to_buffer(sg_dst, alg_ctx->map_nents, |
| <------><------><------><------> iv, ivsize, alg_ctx->count - ivsize); |
| <------><------>crypto_xor(iv, ctx->lastc, ivsize); |
| <------><------>break; |
| <------>default: |
| <------><------>return 0; |
| <------>} |
| |
| <------>return ivsize; |
| } |
| |
| static void rk_iv_copyback(struct rk_crypto_dev *rk_dev) |
| { |
| <------>uint32_t iv_size; |
| <------>struct skcipher_request *req = skcipher_request_cast(rk_dev->async_req); |
| <------>struct rk_cipher_ctx *ctx = rk_cipher_ctx_cast(rk_dev); |
| <------>struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); |
| <------>struct rk_crypto_algt *algt = rk_cipher_get_algt(cipher); |
| |
| <------>iv_size = rk_get_new_iv(ctx, algt->mode, ctx->is_enc, ctx->iv); |
| |
| <------>if (iv_size && req->iv) |
| <------><------>memcpy(req->iv, ctx->iv, iv_size); |
| } |
| |
| static void rk_update_iv(struct rk_crypto_dev *rk_dev) |
| { |
| <------>uint32_t iv_size; |
| <------>struct rk_cipher_ctx *ctx = rk_cipher_ctx_cast(rk_dev); |
| <------>struct rk_alg_ctx *algs_ctx = &ctx->algs_ctx; |
| <------>struct skcipher_request *req = skcipher_request_cast(rk_dev->async_req); |
| <------>struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); |
| <------>struct rk_crypto_algt *algt = rk_cipher_get_algt(cipher); |
| |
| <------>iv_size = rk_get_new_iv(ctx, algt->mode, ctx->is_enc, ctx->iv); |
| |
| <------>if (iv_size) |
| <------><------>algs_ctx->ops.hw_write_iv(rk_dev, ctx->iv, iv_size); |
| } |
| |
| static int rk_set_data_start(struct rk_crypto_dev *rk_dev) |
| { |
| <------>int err; |
| <------>struct rk_alg_ctx *alg_ctx = rk_cipher_alg_ctx(rk_dev); |
| |
| <------>err = rk_dev->load_data(rk_dev, alg_ctx->sg_src, alg_ctx->sg_dst); |
| <------>if (!err) { |
| <------><------>u32 ivsize = alg_ctx->chunk_size; |
| <------><------>struct scatterlist *src_sg; |
| <------><------>struct rk_cipher_ctx *ctx = rk_cipher_ctx_cast(rk_dev); |
| |
| <------><------>memset(ctx->lastc, 0x00, sizeof(ctx->lastc)); |
| |
| <------><------>src_sg = alg_ctx->aligned ? alg_ctx->sg_src : &alg_ctx->sg_tmp; |
| |
| <------><------>ivsize = alg_ctx->count > ivsize ? ivsize : alg_ctx->count; |
| |
| <------><------>sg_pcopy_to_buffer(src_sg, alg_ctx->map_nents, |
| <------><------><------><------> ctx->lastc, ivsize, alg_ctx->count - ivsize); |
| |
| <------><------>alg_ctx->ops.hw_dma_start(rk_dev, true); |
| <------>} |
| |
| <------>return err; |
| } |
| |
| int rk_cipher_setkey(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen) |
| { |
| <------>struct rk_crypto_algt *algt = rk_cipher_get_algt(cipher); |
| <------>struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(cipher); |
| <------>uint32_t key_factor; |
| <------>int ret = -EINVAL; |
| |
| <------>CRYPTO_MSG("algo = %x, mode = %x, key_len = %d\n", |
| <------><------> algt->algo, algt->mode, keylen); |
| |
| <------> |
| <------>key_factor = algt->mode == CIPHER_MODE_XTS ? 2 : 1; |
| |
| <------>switch (algt->algo) { |
| <------>case CIPHER_ALGO_DES: |
| <------><------>ret = verify_skcipher_des_key(cipher, key); |
| <------><------>if (ret) |
| <------><------><------>goto exit; |
| <------><------>break; |
| <------>case CIPHER_ALGO_DES3_EDE: |
| <------><------>ret = verify_skcipher_des3_key(cipher, key); |
| <------><------>if (ret) |
| <------><------><------>goto exit; |
| <------><------>break; |
| <------>case CIPHER_ALGO_AES: |
| <------><------>if (keylen != (AES_KEYSIZE_128 * key_factor) && |
| <------><------> keylen != (AES_KEYSIZE_192 * key_factor) && |
| <------><------> keylen != (AES_KEYSIZE_256 * key_factor)) |
| <------><------><------>goto exit; |
| <------><------>break; |
| <------>case CIPHER_ALGO_SM4: |
| <------><------>if (keylen != (SM4_KEY_SIZE * key_factor)) |
| <------><------><------>goto exit; |
| <------><------>break; |
| <------>default: |
| <------><------>ret = -EINVAL; |
| <------><------>goto exit; |
| <------>} |
| |
| <------>memcpy(ctx->key, key, keylen); |
| <------>ctx->keylen = keylen; |
| <------>ctx->fallback_key_inited = false; |
| |
| <------>ret = 0; |
| exit: |
| <------>return ret; |
| } |
| |
| int rk_ablk_rx(struct rk_crypto_dev *rk_dev) |
| { |
| <------>int err = 0; |
| <------>struct rk_cipher_ctx *ctx = rk_cipher_ctx_cast(rk_dev); |
| <------>struct rk_alg_ctx *alg_ctx = rk_cipher_alg_ctx(rk_dev); |
| |
| <------>CRYPTO_TRACE("left_bytes = %u\n", alg_ctx->left_bytes); |
| |
| <------>err = rk_dev->unload_data(rk_dev); |
| <------>if (err) |
| <------><------>goto out_rx; |
| |
| <------>if (alg_ctx->left_bytes) { |
| <------><------>rk_update_iv(rk_dev); |
| <------><------>if (alg_ctx->aligned) { |
| <------><------><------>if (sg_is_last(alg_ctx->sg_src)) { |
| <------><------><------><------>dev_err(rk_dev->dev, "[%s:%d] Lack of data\n", |
| <------><------><------><------><------>__func__, __LINE__); |
| <------><------><------><------>err = -ENOMEM; |
| <------><------><------><------>goto out_rx; |
| <------><------><------>} |
| <------><------><------>alg_ctx->sg_src = sg_next(alg_ctx->sg_src); |
| <------><------><------>alg_ctx->sg_dst = sg_next(alg_ctx->sg_dst); |
| <------><------>} |
| <------><------>err = rk_set_data_start(rk_dev); |
| <------>} else { |
| <------><------>if (alg_ctx->is_aead) { |
| <------><------><------>u8 hard_tag[RK_MAX_TAG_SIZE]; |
| <------><------><------>u8 user_tag[RK_MAX_TAG_SIZE]; |
| <------><------><------>struct aead_request *req = |
| <------><------><------><------>aead_request_cast(rk_dev->async_req); |
| <------><------><------>struct crypto_aead *tfm = crypto_aead_reqtfm(req); |
| |
| <------><------><------>unsigned int authsize = crypto_aead_authsize(tfm); |
| |
| <------><------><------>CRYPTO_TRACE("cryptlen = %u, assoclen = %u, aead authsize = %u", |
| <------><------><------><------> alg_ctx->total, alg_ctx->assoclen, authsize); |
| |
| <------><------><------>err = alg_ctx->ops.hw_get_result(rk_dev, hard_tag, authsize); |
| <------><------><------>if (err) |
| <------><------><------><------>goto out_rx; |
| |
| <------><------><------>CRYPTO_DUMPHEX("hard_tag", hard_tag, authsize); |
| <------><------><------>if (!ctx->is_enc) { |
| <------><------><------><------>if (!sg_pcopy_to_buffer(alg_ctx->req_src, |
| <------><------><------><------><------><------><------>sg_nents(alg_ctx->req_src), |
| <------><------><------><------><------><------><------>user_tag, authsize, |
| <------><------><------><------><------><------><------>alg_ctx->total + |
| <------><------><------><------><------><------><------>alg_ctx->assoclen)) { |
| <------><------><------><------><------>err = -EINVAL; |
| <------><------><------><------><------>goto out_rx; |
| <------><------><------><------>} |
| |
| <------><------><------><------>CRYPTO_DUMPHEX("user_tag", user_tag, authsize); |
| <------><------><------><------>err = crypto_memneq(user_tag, hard_tag, authsize) ? -EBADMSG : 0; |
| <------><------><------>} else { |
| <------><------><------><------>if (!sg_pcopy_from_buffer(alg_ctx->req_dst, |
| <------><------><------><------><------><------><------> sg_nents(alg_ctx->req_dst), |
| <------><------><------><------><------><------><------> hard_tag, authsize, |
| <------><------><------><------><------><------><------> alg_ctx->total + |
| <------><------><------><------><------><------><------> alg_ctx->assoclen)) { |
| <------><------><------><------><------>err = -EINVAL; |
| <------><------><------><------><------>goto out_rx; |
| <------><------><------><------>} |
| <------><------><------>} |
| <------><------>} else { |
| <------><------><------>rk_iv_copyback(rk_dev); |
| <------><------>} |
| <------>} |
| out_rx: |
| <------>return err; |
| } |
| |
| int rk_ablk_start(struct rk_crypto_dev *rk_dev) |
| { |
| <------>struct skcipher_request *req = |
| <------><------>skcipher_request_cast(rk_dev->async_req); |
| <------>struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); |
| <------>struct rk_crypto_algt *algt = rk_cipher_get_algt(tfm); |
| <------>struct rk_alg_ctx *alg_ctx = rk_cipher_alg_ctx(rk_dev); |
| <------>unsigned long flags; |
| <------>int err = 0; |
| |
| <------>alg_ctx->left_bytes = req->cryptlen; |
| <------>alg_ctx->total = req->cryptlen; |
| <------>alg_ctx->sg_src = req->src; |
| <------>alg_ctx->req_src = req->src; |
| <------>alg_ctx->src_nents = sg_nents_for_len(req->src, req->cryptlen); |
| <------>alg_ctx->sg_dst = req->dst; |
| <------>alg_ctx->req_dst = req->dst; |
| <------>alg_ctx->dst_nents = sg_nents_for_len(req->dst, req->cryptlen); |
| |
| <------>CRYPTO_TRACE("total = %u", alg_ctx->total); |
| |
| <------>spin_lock_irqsave(&rk_dev->lock, flags); |
| <------>alg_ctx->ops.hw_init(rk_dev, algt->algo, algt->mode); |
| <------>err = rk_set_data_start(rk_dev); |
| <------>spin_unlock_irqrestore(&rk_dev->lock, flags); |
| <------>return err; |
| } |
| |
| int rk_skcipher_handle_req(struct rk_crypto_dev *rk_dev, struct skcipher_request *req) |
| { |
| <------>struct rk_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm); |
| <------>struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); |
| <------>struct rk_crypto_algt *algt = rk_cipher_get_algt(cipher); |
| |
| <------>if (!IS_ALIGNED(req->cryptlen, ctx->algs_ctx.chunk_size) && |
| <------> !is_no_multi_blocksize(algt->mode)) |
| <------><------>return -EINVAL; |
| <------>else |
| <------><------>return rk_dev->enqueue(rk_dev, &req->base); |
| } |
| |
| int rk_aead_fallback(struct aead_request *req, struct rk_cipher_ctx *ctx, bool encrypt) |
| { |
| <------>int ret; |
| <------>struct aead_request *subreq = aead_request_ctx(req); |
| |
| <------>if (!ctx->fallback_aead) { |
| <------><------>CRYPTO_TRACE("fallback_tfm is empty"); |
| <------><------>return -EINVAL; |
| <------>} |
| |
| <------>CRYPTO_MSG("use fallback tfm"); |
| |
| <------>if (!ctx->fallback_key_inited) { |
| <------><------>ret = crypto_aead_setkey(ctx->fallback_aead, ctx->key, ctx->keylen); |
| <------><------>if (ret) { |
| <------><------><------>CRYPTO_MSG("fallback crypto_skcipher_setkey err = %d\n", ret); |
| <------><------><------>goto exit; |
| <------><------>} |
| |
| <------><------>ctx->fallback_key_inited = true; |
| <------>} |
| |
| <------>aead_request_set_tfm(subreq, ctx->fallback_aead); |
| <------>aead_request_set_callback(subreq, req->base.flags, req->base.complete, req->base.data); |
| <------>aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, req->iv); |
| <------>aead_request_set_ad(subreq, req->assoclen); |
| |
| <------>ret = encrypt ? crypto_aead_encrypt(subreq) : crypto_aead_decrypt(subreq); |
| |
| exit: |
| <------>return ret; |
| } |
| |
| int rk_aead_setkey(struct crypto_aead *cipher, const u8 *key, unsigned int keylen) |
| { |
| <------>struct crypto_tfm *tfm = crypto_aead_tfm(cipher); |
| <------>struct rk_crypto_algt *algt = rk_aead_get_algt(cipher); |
| <------>struct rk_cipher_ctx *ctx = crypto_tfm_ctx(tfm); |
| <------>int ret = -EINVAL; |
| |
| <------>CRYPTO_MSG("algo = %x, mode = %x, key_len = %d\n", algt->algo, algt->mode, keylen); |
| |
| <------>switch (algt->algo) { |
| <------>case CIPHER_ALGO_AES: |
| <------><------>if (keylen != AES_KEYSIZE_128 && |
| <------><------> keylen != AES_KEYSIZE_192 && |
| <------><------> keylen != AES_KEYSIZE_256) |
| <------><------><------>goto error; |
| |
| <------><------>break; |
| <------>case CIPHER_ALGO_SM4: |
| <------><------>if (keylen != SM4_KEY_SIZE) |
| <------><------><------>goto error; |
| |
| <------><------>break; |
| <------>default: |
| <------><------>CRYPTO_TRACE(); |
| <------><------>goto error; |
| <------>} |
| |
| <------>memcpy(ctx->key, key, keylen); |
| <------>ctx->keylen = keylen; |
| <------>ctx->fallback_key_inited = false; |
| |
| <------>return 0; |
| |
| error: |
| <------>return ret; |
| } |
| |
| int rk_aead_start(struct rk_crypto_dev *rk_dev) |
| { |
| <------>struct aead_request *req = aead_request_cast(rk_dev->async_req); |
| <------>struct crypto_aead *tfm = crypto_aead_reqtfm(req); |
| <------>struct rk_cipher_ctx *ctx = crypto_aead_ctx(tfm); |
| <------>struct rk_crypto_algt *algt = rk_aead_get_algt(tfm); |
| <------>struct rk_alg_ctx *alg_ctx = rk_cipher_alg_ctx(rk_dev); |
| <------>unsigned int total = 0, authsize; |
| <------>unsigned long flags; |
| <------>int err = 0; |
| |
| <------>total = req->cryptlen + req->assoclen; |
| |
| <------>authsize = ctx->is_enc ? 0 : crypto_aead_authsize(tfm); |
| |
| <------>alg_ctx->total = req->cryptlen - authsize; |
| <------>alg_ctx->assoclen = req->assoclen; |
| <------>alg_ctx->sg_src = req->src; |
| <------>alg_ctx->req_src = req->src; |
| <------>alg_ctx->src_nents = sg_nents_for_len(req->src, total); |
| <------>alg_ctx->sg_dst = req->dst; |
| <------>alg_ctx->req_dst = req->dst; |
| <------>alg_ctx->dst_nents = sg_nents_for_len(req->dst, total - authsize); |
| <------>alg_ctx->left_bytes = alg_ctx->total; |
| |
| <------>CRYPTO_TRACE("src_nents = %zu, dst_nents = %zu", alg_ctx->src_nents, alg_ctx->dst_nents); |
| <------>CRYPTO_TRACE("is_enc = %d, authsize = %u, cryptlen = %u, total = %u, assoclen = %u", |
| <------><------> ctx->is_enc, authsize, req->cryptlen, alg_ctx->total, alg_ctx->assoclen); |
| |
| <------>spin_lock_irqsave(&rk_dev->lock, flags); |
| <------>alg_ctx->ops.hw_init(rk_dev, algt->algo, algt->mode); |
| <------>err = rk_set_data_start(rk_dev); |
| <------>spin_unlock_irqrestore(&rk_dev->lock, flags); |
| <------>return err; |
| } |
| |
| int rk_aead_gcm_setauthsize(struct crypto_aead *tfm, unsigned int authsize) |
| { |
| <------>return crypto_gcm_check_authsize(authsize); |
| } |
| |
| int rk_aead_handle_req(struct rk_crypto_dev *rk_dev, struct aead_request *req) |
| { |
| <------>return rk_dev->enqueue(rk_dev, &req->base); |
| } |
| |