Lines Matching +full:has +full:- +full:ecc
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Intel Keem Bay OCS ECC Crypto Driver.
5 * Copyright (C) 2019-2021 Intel Corporation
13 #include <crypto/internal/ecc.h>
32 #define DRV_NAME "keembay-ocs-ecc"
52 /* ECC Instruction : for ECC_COMMAND */
76 * struct ocs_ecc_dev - ECC device context
78 * @dev: OCS ECC device
79 * @base_reg: IO base address of OCS ECC
94 * struct ocs_ecc_ctx - Transformation context.
95 * @ecc_dev: The ECC driver associated with this context.
111 /* Global variable holding the list of OCS ECC devices (only one expected). */
117 /* Get OCS ECC tfm context from kpp_request. */
130 * Wait for ECC idle i.e when an operation (other than write operations)
137 return readl_poll_timeout((dev->base_reg + HW_OFFS_OCS_ECC_STATUS), in ocs_ecc_wait_idle()
146 ecc_dev->base_reg + HW_OFFS_OCS_ECC_COMMAND); in ocs_ecc_cmd_start()
149 /* Direct write of u32 buffer to ECC engine with associated instruction. */
156 iowrite32(op_size | inst, dev->base_reg + HW_OFFS_OCS_ECC_COMMAND); in ocs_ecc_write_cmd_and_data()
159 memcpy_toio(dev->base_reg + HW_OFFS_OCS_ECC_DATA_IN, data_in, in ocs_ecc_write_cmd_and_data()
163 /* Start OCS ECC operation and wait for its completion. */
167 reinit_completion(&ecc_dev->irq_done); in ocs_ecc_trigger_op()
169 iowrite32(ECC_ENABLE_INTR, ecc_dev->base_reg + HW_OFFS_OCS_ECC_IER); in ocs_ecc_trigger_op()
170 iowrite32(op_size | inst, ecc_dev->base_reg + HW_OFFS_OCS_ECC_COMMAND); in ocs_ecc_trigger_op()
172 return wait_for_completion_interruptible(&ecc_dev->irq_done); in ocs_ecc_trigger_op()
176 * ocs_ecc_read_cx_out() - Read the CX data output buffer.
177 * @dev: The OCS ECC device to read from.
185 memcpy_fromio(cx_out, dev->base_reg + HW_OFFS_OCS_ECC_CX_DATA_OUT, in ocs_ecc_read_cx_out()
190 * ocs_ecc_read_cy_out() - Read the CX data output buffer.
191 * @dev: The OCS ECC device to read from.
199 memcpy_fromio(cy_out, dev->base_reg + HW_OFFS_OCS_ECC_CY_DATA_OUT, in ocs_ecc_read_cy_out()
205 if (tctx->ecc_dev) in kmb_ocs_ecc_find_dev()
206 return tctx->ecc_dev; in kmb_ocs_ecc_find_dev()
211 tctx->ecc_dev = list_first_entry(&ocs_ecc.dev_list, struct ocs_ecc_dev, in kmb_ocs_ecc_find_dev()
216 return tctx->ecc_dev; in kmb_ocs_ecc_find_dev()
219 /* Do point multiplication using OCS ECC HW. */
227 u32 op_size = (curve->g.ndigits > ECC_CURVE_NIST_P256_DIGITS) ? in kmb_ecc_point_mult()
229 size_t nbytes = digits_to_bytes(curve->g.ndigits); in kmb_ecc_point_mult()
252 point->x, nbytes); in kmb_ecc_point_mult()
256 point->y, nbytes); in kmb_ecc_point_mult()
263 * side-channel-resistance value. in kmb_ecc_point_mult()
275 curve->p, nbytes); in kmb_ecc_point_mult()
279 curve->a, nbytes); in kmb_ecc_point_mult()
287 ocs_ecc_read_cx_out(ecc_dev, result->x, nbytes); in kmb_ecc_point_mult()
288 ocs_ecc_read_cy_out(ecc_dev, result->y, nbytes); in kmb_ecc_point_mult()
294 * kmb_ecc_do_scalar_op() - Perform Scalar operation using OCS ECC HW.
295 * @ecc_dev: The OCS ECC device to use.
301 * @inst: The operation to perform (as an OCS ECC instruction).
333 curve->p, nbytes); in kmb_ecc_do_scalar_op()
335 /* Give instruction A.B or A+B to ECC engine. */ in kmb_ecc_do_scalar_op()
343 return -EINVAL; in kmb_ecc_do_scalar_op()
348 /* SP800-56A section 5.6.2.3.4 partial verification: ephemeral keys only */
358 if (WARN_ON(pk->ndigits != curve->g.ndigits)) in kmb_ocs_ecc_is_pubkey_valid_partial()
359 return -EINVAL; in kmb_ocs_ecc_is_pubkey_valid_partial()
363 return -EINVAL; in kmb_ocs_ecc_is_pubkey_valid_partial()
365 /* Check 2: Verify key is in the range [0, p-1]. */ in kmb_ocs_ecc_is_pubkey_valid_partial()
366 if (vli_cmp(curve->p, pk->x, pk->ndigits) != 1) in kmb_ocs_ecc_is_pubkey_valid_partial()
367 return -EINVAL; in kmb_ocs_ecc_is_pubkey_valid_partial()
369 if (vli_cmp(curve->p, pk->y, pk->ndigits) != 1) in kmb_ocs_ecc_is_pubkey_valid_partial()
370 return -EINVAL; in kmb_ocs_ecc_is_pubkey_valid_partial()
375 /* Compute y^2 -> store in yy */ in kmb_ocs_ecc_is_pubkey_valid_partial()
376 rc = kmb_ecc_do_scalar_op(ecc_dev, yy, pk->y, pk->y, curve, pk->ndigits, in kmb_ocs_ecc_is_pubkey_valid_partial()
385 rc = kmb_ecc_do_scalar_op(ecc_dev, xxx, pk->x, w, curve, pk->ndigits, in kmb_ocs_ecc_is_pubkey_valid_partial()
390 /* Do a*x -> store in w. */ in kmb_ocs_ecc_is_pubkey_valid_partial()
391 rc = kmb_ecc_do_scalar_op(ecc_dev, w, curve->a, pk->x, curve, in kmb_ocs_ecc_is_pubkey_valid_partial()
392 pk->ndigits, in kmb_ocs_ecc_is_pubkey_valid_partial()
398 rc = kmb_ecc_do_scalar_op(ecc_dev, w, w, curve->b, curve, in kmb_ocs_ecc_is_pubkey_valid_partial()
399 pk->ndigits, in kmb_ocs_ecc_is_pubkey_valid_partial()
404 /* x^3 + ax + b == x^3 + w -> store in w. */ in kmb_ocs_ecc_is_pubkey_valid_partial()
405 rc = kmb_ecc_do_scalar_op(ecc_dev, w, xxx, w, curve, pk->ndigits, in kmb_ocs_ecc_is_pubkey_valid_partial()
411 rc = vli_cmp(yy, w, pk->ndigits); in kmb_ocs_ecc_is_pubkey_valid_partial()
413 rc = -EINVAL; in kmb_ocs_ecc_is_pubkey_valid_partial()
423 /* SP800-56A section 5.6.2.3.3 full verification */
437 nQ = ecc_alloc_point(pk->ndigits); in kmb_ocs_ecc_is_pubkey_valid_full()
439 return -ENOMEM; in kmb_ocs_ecc_is_pubkey_valid_full()
441 rc = kmb_ecc_point_mult(ecc_dev, nQ, pk, curve->n, curve); in kmb_ocs_ecc_is_pubkey_valid_full()
446 rc = -EINVAL; in kmb_ocs_ecc_is_pubkey_valid_full()
457 size_t ndigits = curve->g.ndigits; in kmb_ecc_is_key_valid()
462 return -EINVAL; in kmb_ecc_is_key_valid()
465 return -EINVAL; in kmb_ecc_is_key_valid()
467 /* Make sure the private key is in the range [2, n-3]. */ in kmb_ecc_is_key_valid()
468 if (vli_cmp(one, private_key, ndigits) != -1) in kmb_ecc_is_key_valid()
469 return -EINVAL; in kmb_ecc_is_key_valid()
471 vli_sub(res, curve->n, one, ndigits); in kmb_ecc_is_key_valid()
474 return -EINVAL; in kmb_ecc_is_key_valid()
480 * ECC private keys are generated using the method of extra random bits,
481 * equivalent to that described in FIPS 186-4, Appendix B.4.1.
485 * 0 <= c mod(n-1) <= n-2 and implies that
486 * 1 <= d <= n-1
489 * [1, n-1].
493 size_t nbytes = digits_to_bytes(curve->g.ndigits); in kmb_ecc_gen_privkey()
498 nbits = vli_num_bits(curve->n, curve->g.ndigits); in kmb_ecc_gen_privkey()
500 /* Check that N is included in Table 1 of FIPS 186-4, section 6.1.1 */ in kmb_ecc_gen_privkey()
501 if (nbits < 160 || curve->g.ndigits > ARRAY_SIZE(priv)) in kmb_ecc_gen_privkey()
502 return -EINVAL; in kmb_ecc_gen_privkey()
505 * FIPS 186-4 recommends that the private key should be obtained from a in kmb_ecc_gen_privkey()
509 * The maximum security strength identified by NIST SP800-57pt1r4 for in kmb_ecc_gen_privkey()
510 * ECC is 256 (N >= 512). in kmb_ecc_gen_privkey()
516 return -EFAULT; in kmb_ecc_gen_privkey()
527 ecc_swap_digits(priv, privkey, curve->g.ndigits); in kmb_ecc_gen_privkey()
547 if (params.key_size > digits_to_bytes(tctx->curve->g.ndigits)) { in kmb_ocs_ecdh_set_secret()
548 rc = -EINVAL; in kmb_ocs_ecdh_set_secret()
552 /* Auto-generate private key is not provided. */ in kmb_ocs_ecdh_set_secret()
554 rc = kmb_ecc_gen_privkey(tctx->curve, tctx->private_key); in kmb_ocs_ecdh_set_secret()
558 rc = kmb_ecc_is_key_valid(tctx->curve, (const u64 *)params.key, in kmb_ocs_ecdh_set_secret()
563 ecc_swap_digits((const u64 *)params.key, tctx->private_key, in kmb_ocs_ecdh_set_secret()
564 tctx->curve->g.ndigits); in kmb_ocs_ecdh_set_secret()
569 tctx->curve = NULL; in kmb_ocs_ecdh_set_secret()
578 struct ocs_ecc_dev *ecc_dev = tctx->ecc_dev; in kmb_ecc_do_shared_secret()
579 const struct ecc_curve *curve = tctx->curve; in kmb_ecc_do_shared_secret()
586 nbytes = digits_to_bytes(curve->g.ndigits); in kmb_ecc_do_shared_secret()
588 /* Public key is a point, thus it has two coordinates */ in kmb_ecc_do_shared_secret()
592 copied = sg_copy_to_buffer(req->src, in kmb_ecc_do_shared_secret()
593 sg_nents_for_len(req->src, pubk_len), in kmb_ecc_do_shared_secret()
596 return -EINVAL; in kmb_ecc_do_shared_secret()
599 pk = ecc_alloc_point(curve->g.ndigits); in kmb_ecc_do_shared_secret()
601 return -ENOMEM; in kmb_ecc_do_shared_secret()
603 ecc_swap_digits(pubk_buf, pk->x, curve->g.ndigits); in kmb_ecc_do_shared_secret()
604 ecc_swap_digits(&pubk_buf[curve->g.ndigits], pk->y, curve->g.ndigits); in kmb_ecc_do_shared_secret()
609 * Check 2: Verify key is in the range [1, p-1]. in kmb_ecc_do_shared_secret()
617 result = ecc_alloc_point(pk->ndigits); in kmb_ecc_do_shared_secret()
619 rc = -ENOMEM; in kmb_ecc_do_shared_secret()
624 rc = kmb_ecc_point_mult(ecc_dev, result, pk, tctx->private_key, curve); in kmb_ecc_do_shared_secret()
629 rc = -EFAULT; in kmb_ecc_do_shared_secret()
634 ecc_swap_digits(result->x, shared_secret, result->ndigits); in kmb_ecc_do_shared_secret()
637 nbytes = min_t(size_t, nbytes, req->dst_len); in kmb_ecc_do_shared_secret()
639 copied = sg_copy_from_buffer(req->dst, in kmb_ecc_do_shared_secret()
640 sg_nents_for_len(req->dst, nbytes), in kmb_ecc_do_shared_secret()
644 rc = -EINVAL; in kmb_ecc_do_shared_secret()
661 const struct ecc_curve *curve = tctx->curve; in kmb_ecc_do_public_key()
668 /* Public key is a point, so it has double the digits. */ in kmb_ecc_do_public_key()
669 pubk_len = 2 * digits_to_bytes(curve->g.ndigits); in kmb_ecc_do_public_key()
671 pk = ecc_alloc_point(curve->g.ndigits); in kmb_ecc_do_public_key()
673 return -ENOMEM; in kmb_ecc_do_public_key()
676 rc = kmb_ecc_point_mult(tctx->ecc_dev, pk, &curve->g, tctx->private_key, in kmb_ecc_do_public_key()
681 /* SP800-56A rev 3 5.6.2.1.3 key check */ in kmb_ecc_do_public_key()
682 if (kmb_ocs_ecc_is_pubkey_valid_full(tctx->ecc_dev, curve, pk)) { in kmb_ecc_do_public_key()
683 rc = -EAGAIN; in kmb_ecc_do_public_key()
688 ecc_swap_digits(pk->x, pubk_buf, pk->ndigits); in kmb_ecc_do_public_key()
689 ecc_swap_digits(pk->y, &pubk_buf[pk->ndigits], pk->ndigits); in kmb_ecc_do_public_key()
691 /* Copy public key to req->dst. */ in kmb_ecc_do_public_key()
692 copied = sg_copy_from_buffer(req->dst, in kmb_ecc_do_public_key()
693 sg_nents_for_len(req->dst, pubk_len), in kmb_ecc_do_public_key()
697 rc = -EINVAL; in kmb_ecc_do_public_key()
710 struct ocs_ecc_dev *ecc_dev = tctx->ecc_dev; in kmb_ocs_ecc_do_one_request()
713 if (req->src) in kmb_ocs_ecc_do_one_request()
718 crypto_finalize_kpp_request(ecc_dev->engine, req, rc); in kmb_ocs_ecc_do_one_request()
726 const struct ecc_curve *curve = tctx->curve; in kmb_ocs_ecdh_generate_public_key()
728 /* Ensure kmb_ocs_ecdh_set_secret() has been successfully called. */ in kmb_ocs_ecdh_generate_public_key()
729 if (!tctx->curve) in kmb_ocs_ecdh_generate_public_key()
730 return -EINVAL; in kmb_ocs_ecdh_generate_public_key()
733 if (!req->dst) in kmb_ocs_ecdh_generate_public_key()
734 return -EINVAL; in kmb_ocs_ecdh_generate_public_key()
737 if (req->dst_len < (2 * digits_to_bytes(curve->g.ndigits))) in kmb_ocs_ecdh_generate_public_key()
738 return -EINVAL; in kmb_ocs_ecdh_generate_public_key()
741 if (req->src) in kmb_ocs_ecdh_generate_public_key()
742 return -EINVAL; in kmb_ocs_ecdh_generate_public_key()
744 return crypto_transfer_kpp_request_to_engine(tctx->ecc_dev->engine, in kmb_ocs_ecdh_generate_public_key()
751 const struct ecc_curve *curve = tctx->curve; in kmb_ocs_ecdh_compute_shared_secret()
753 /* Ensure kmb_ocs_ecdh_set_secret() has been successfully called. */ in kmb_ocs_ecdh_compute_shared_secret()
754 if (!tctx->curve) in kmb_ocs_ecdh_compute_shared_secret()
755 return -EINVAL; in kmb_ocs_ecdh_compute_shared_secret()
758 if (!req->dst) in kmb_ocs_ecdh_compute_shared_secret()
759 return -EINVAL; in kmb_ocs_ecdh_compute_shared_secret()
762 if (!req->src) in kmb_ocs_ecdh_compute_shared_secret()
763 return -EINVAL; in kmb_ocs_ecdh_compute_shared_secret()
766 * req->src is expected to the (other-side) public key, so its length in kmb_ocs_ecdh_compute_shared_secret()
769 if (req->src_len != 2 * digits_to_bytes(curve->g.ndigits)) in kmb_ocs_ecdh_compute_shared_secret()
770 return -EINVAL; in kmb_ocs_ecdh_compute_shared_secret()
772 return crypto_transfer_kpp_request_to_engine(tctx->ecc_dev->engine, in kmb_ocs_ecdh_compute_shared_secret()
780 tctx->ecc_dev = kmb_ocs_ecc_find_dev(tctx); in kmb_ecc_tctx_init()
782 if (IS_ERR(tctx->ecc_dev)) { in kmb_ecc_tctx_init()
784 PTR_ERR(tctx->ecc_dev)); in kmb_ecc_tctx_init()
785 return PTR_ERR(tctx->ecc_dev); in kmb_ecc_tctx_init()
788 tctx->curve = ecc_get_curve(curve_id); in kmb_ecc_tctx_init()
789 if (!tctx->curve) in kmb_ecc_tctx_init()
790 return -EOPNOTSUPP; in kmb_ecc_tctx_init()
813 memzero_explicit(tctx->private_key, sizeof(*tctx->private_key)); in kmb_ocs_ecdh_exit_tfm()
821 return digits_to_bytes(tctx->curve->g.ndigits) * 2; in kmb_ocs_ecdh_max_size()
832 .cra_name = "ecdh-nist-p256",
833 .cra_driver_name = "ecdh-nist-p256-keembay-ocs",
849 .cra_name = "ecdh-nist-p384",
850 .cra_driver_name = "ecdh-nist-p384-keembay-ocs",
867 status = ioread32(ecc_dev->base_reg + HW_OFFS_OCS_ECC_ISR); in ocs_ecc_irq_handler()
868 iowrite32(status, ecc_dev->base_reg + HW_OFFS_OCS_ECC_ISR); in ocs_ecc_irq_handler()
873 complete(&ecc_dev->irq_done); in ocs_ecc_irq_handler()
880 struct device *dev = &pdev->dev; in kmb_ocs_ecc_probe()
886 return -ENOMEM; in kmb_ocs_ecc_probe()
888 ecc_dev->dev = dev; in kmb_ocs_ecc_probe()
892 INIT_LIST_HEAD(&ecc_dev->list); in kmb_ocs_ecc_probe()
893 init_completion(&ecc_dev->irq_done); in kmb_ocs_ecc_probe()
896 ecc_dev->base_reg = devm_platform_ioremap_resource(pdev, 0); in kmb_ocs_ecc_probe()
897 if (IS_ERR(ecc_dev->base_reg)) { in kmb_ocs_ecc_probe()
899 rc = PTR_ERR(ecc_dev->base_reg); in kmb_ocs_ecc_probe()
904 ecc_dev->irq = platform_get_irq(pdev, 0); in kmb_ocs_ecc_probe()
905 if (ecc_dev->irq < 0) { in kmb_ocs_ecc_probe()
906 rc = ecc_dev->irq; in kmb_ocs_ecc_probe()
910 rc = devm_request_threaded_irq(dev, ecc_dev->irq, ocs_ecc_irq_handler, in kmb_ocs_ecc_probe()
911 NULL, 0, "keembay-ocs-ecc", ecc_dev); in kmb_ocs_ecc_probe()
917 /* Add device to the list of OCS ECC devices. */ in kmb_ocs_ecc_probe()
919 list_add_tail(&ecc_dev->list, &ocs_ecc.dev_list); in kmb_ocs_ecc_probe()
923 ecc_dev->engine = crypto_engine_alloc_init(dev, 1); in kmb_ocs_ecc_probe()
924 if (!ecc_dev->engine) { in kmb_ocs_ecc_probe()
926 rc = -ENOMEM; in kmb_ocs_ecc_probe()
930 rc = crypto_engine_start(ecc_dev->engine); in kmb_ocs_ecc_probe()
957 crypto_engine_exit(ecc_dev->engine); in kmb_ocs_ecc_probe()
961 list_del(&ecc_dev->list); in kmb_ocs_ecc_probe()
977 list_del(&ecc_dev->list); in kmb_ocs_ecc_remove()
980 crypto_engine_exit(ecc_dev->engine); in kmb_ocs_ecc_remove()
986 .compatible = "intel,keembay-ocs-ecc",
1003 MODULE_DESCRIPTION("Intel Keem Bay OCS ECC Driver");
1004 MODULE_ALIAS_CRYPTO("ecdh-nist-p256");
1005 MODULE_ALIAS_CRYPTO("ecdh-nist-p384");
1006 MODULE_ALIAS_CRYPTO("ecdh-nist-p256-keembay-ocs");
1007 MODULE_ALIAS_CRYPTO("ecdh-nist-p384-keembay-ocs");