diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-24 08:46:03 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-24 08:46:03 -0700 |
| commit | cf9610f9116d55c5a66ef9f1faecacabd93a9322 (patch) | |
| tree | 757a3d280760c654767631cab5ad8af2d86d1848 /crypto/ecdh.c | |
| download | linux-stable-cf9610f9116d55c5a66ef9f1faecacabd93a9322.tar.gz linux-stable-cf9610f9116d55c5a66ef9f1faecacabd93a9322.zip | |
Merge tag 'pinctrl-v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrlgrafted
Pull pin control updates from Linus Walleij:
"Core changes:
- Use the non-blocking mux_state_try_select() in the generic MUX pin
control back-end
- Free pin maps on pinctrl_generic_to_map() failure in the core
helpers
New hardware pin control:
- Qualcomm Maili TLMM SoC, PMG1110 PMIC, and Eliza LPASS LPI TLMM SoC
(this is for the low power audio, LPASS = Low Power Audio SubSystem
portions)
- Upboard support on top of the Intel pin controller
- Apple T6030 and T6031 support (just compatible strings)
- Samsung Exynos 8855 SoC
- Mediatek MT6858 SoC
- Rockchip RK3308B and RV1106 SoCs
- Airoha EN7523 and AN7563 SoCs
Improvements:
- Qualcomm TLMM GPIOs are unconditionally marked as wakeup capable
- Qualcomm improvements on top of the Qualcomm PDC (power domain
controller) irqchip improvements from tglx:s tree
- Qualcomm IPQ806x and IPQ9650 non-urgent pin grop fixups
- The NPCM8xx driver has been put into shape fixing many pin and
group definitions
- Some non-urgent Tegra 264 pin assignments are fixed up
- Some non-urgent fixups to Airoha AN7581 and AN7583 registers and
pin assignments, missing features etc"
* tag 'pinctrl-v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (130 commits)
dt-bindings: pinctrl: Convert TI DA850 pupd to DT schema
pinctrl: meson: sync some modify from A4
pinctrl: meson: a4: Add input enable pin configuration
pinctrl: realtek: rtd1625: remove unused group name spdif_sel
pinctrl: realtek: rtd1625: fix base_bit for VE4 GPIO 13
dt-bindings: pinctrl: microchip,pic32mzda-pinctrl: Convert to DT schema
Revert "Merge branch 'ib-rsk7204' into devel"
pinctrl: rockchip: Add RV1106 pinctrl support
dt-bindings: pinctrl: rockchip: Add RV1106 compatible
pinctrl: rockchip: Decode drive strength in the get function
pinctrl: fix PINCTRL_GENERIC_MUX not always being selectable
pinctrl: airoha: add support of an7563 SoC
dt-bindings: pinctrl: airoha: add support of an7563 pin controller
pinctrl: airoha: try to find chip scu node by phandle first
pinctrl: airoha: add support of en7523 SoC
dt-bindings: pinctrl: airoha: add support of en7523 pin controller
pinctrl: airoha: an7583: add support for olt pinmux
pinctrl: airoha: an7583: add support for pon_alt pinmux
pinctrl: airoha: an7583: add support for npu_uart pinmux
dt-bindings: pinctrl: airoha: an7583: add missed features
...
Diffstat (limited to 'crypto/ecdh.c')
| -rw-r--r-- | crypto/ecdh.c | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/crypto/ecdh.c b/crypto/ecdh.c new file mode 100644 index 000000000..9f0b93b31 --- /dev/null +++ b/crypto/ecdh.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* ECDH key-agreement protocol + * + * Copyright (c) 2016, Intel Corporation + * Authors: Salvator Benedetto <salvatore.benedetto@intel.com> + */ + +#include <linux/module.h> +#include <crypto/internal/ecc.h> +#include <crypto/internal/kpp.h> +#include <crypto/kpp.h> +#include <crypto/ecdh.h> +#include <linux/scatterlist.h> + +struct ecdh_ctx { + unsigned int curve_id; + unsigned int ndigits; + u64 private_key[ECC_MAX_DIGITS]; +}; + +static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm) +{ + return kpp_tfm_ctx(tfm); +} + +static int ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, + unsigned int len) +{ + struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); + struct ecdh params; + int ret = 0; + + if (crypto_ecdh_decode_key(buf, len, ¶ms) < 0 || + params.key_size > sizeof(u64) * ctx->ndigits) + return -EINVAL; + + memset(ctx->private_key, 0, sizeof(ctx->private_key)); + + if (!params.key || !params.key_size) + return ecc_gen_privkey(ctx->curve_id, ctx->ndigits, + ctx->private_key); + + ecc_digits_from_bytes(params.key, params.key_size, + ctx->private_key, ctx->ndigits); + + if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits, + ctx->private_key, params.key_size) < 0) { + memzero_explicit(ctx->private_key, params.key_size); + ret = -EINVAL; + } + + return ret; +} + +static int ecdh_compute_value(struct kpp_request *req) +{ + struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); + struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); + u64 *public_key; + u64 *shared_secret = NULL; + void *buf; + size_t copied, nbytes, public_key_sz; + int ret = -ENOMEM; + + nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT; + /* Public part is a point thus it has both coordinates */ + public_key_sz = 2 * nbytes; + + public_key = kmalloc(public_key_sz, GFP_KERNEL); + if (!public_key) + return -ENOMEM; + + if (req->src) { + shared_secret = kmalloc(nbytes, GFP_KERNEL); + if (!shared_secret) + goto free_pubkey; + + /* from here on it's invalid parameters */ + ret = -EINVAL; + + /* must have exactly two points to be on the curve */ + if (public_key_sz != req->src_len) + goto free_all; + + copied = sg_copy_to_buffer(req->src, + sg_nents_for_len(req->src, + public_key_sz), + public_key, public_key_sz); + if (copied != public_key_sz) + goto free_all; + + ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits, + ctx->private_key, public_key, + shared_secret); + + buf = shared_secret; + } else { + ret = ecc_make_pub_key(ctx->curve_id, ctx->ndigits, + ctx->private_key, public_key); + buf = public_key; + nbytes = public_key_sz; + } + + if (ret < 0) + goto free_all; + + /* might want less than we've got */ + nbytes = min_t(size_t, nbytes, req->dst_len); + copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, + nbytes), + buf, nbytes); + if (copied != nbytes) + ret = -EINVAL; + + /* fall through */ +free_all: + kfree_sensitive(shared_secret); +free_pubkey: + kfree(public_key); + return ret; +} + +static unsigned int ecdh_max_size(struct crypto_kpp *tfm) +{ + struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); + + /* Public key is made of two coordinates, add one to the left shift */ + return ctx->ndigits << (ECC_DIGITS_TO_BYTES_SHIFT + 1); +} + +static int ecdh_nist_p192_init_tfm(struct crypto_kpp *tfm) +{ + struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); + + ctx->curve_id = ECC_CURVE_NIST_P192; + ctx->ndigits = ECC_CURVE_NIST_P192_DIGITS; + + return 0; +} + +static struct kpp_alg ecdh_nist_p192 = { + .set_secret = ecdh_set_secret, + .generate_public_key = ecdh_compute_value, + .compute_shared_secret = ecdh_compute_value, + .max_size = ecdh_max_size, + .init = ecdh_nist_p192_init_tfm, + .base = { + .cra_name = "ecdh-nist-p192", + .cra_driver_name = "ecdh-nist-p192-generic", + .cra_priority = 100, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct ecdh_ctx), + }, +}; + +static int ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm) +{ + struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); + + ctx->curve_id = ECC_CURVE_NIST_P256; + ctx->ndigits = ECC_CURVE_NIST_P256_DIGITS; + + return 0; +} + +static struct kpp_alg ecdh_nist_p256 = { + .set_secret = ecdh_set_secret, + .generate_public_key = ecdh_compute_value, + .compute_shared_secret = ecdh_compute_value, + .max_size = ecdh_max_size, + .init = ecdh_nist_p256_init_tfm, + .base = { + .cra_name = "ecdh-nist-p256", + .cra_driver_name = "ecdh-nist-p256-generic", + .cra_priority = 100, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct ecdh_ctx), + }, +}; + +static int ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm) +{ + struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); + + ctx->curve_id = ECC_CURVE_NIST_P384; + ctx->ndigits = ECC_CURVE_NIST_P384_DIGITS; + + return 0; +} + +static struct kpp_alg ecdh_nist_p384 = { + .set_secret = ecdh_set_secret, + .generate_public_key = ecdh_compute_value, + .compute_shared_secret = ecdh_compute_value, + .max_size = ecdh_max_size, + .init = ecdh_nist_p384_init_tfm, + .base = { + .cra_name = "ecdh-nist-p384", + .cra_driver_name = "ecdh-nist-p384-generic", + .cra_priority = 100, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct ecdh_ctx), + }, +}; + +static bool ecdh_nist_p192_registered; + +static int __init ecdh_init(void) +{ + int ret; + + /* NIST p192 will fail to register in FIPS mode */ + ret = crypto_register_kpp(&ecdh_nist_p192); + ecdh_nist_p192_registered = ret == 0; + + ret = crypto_register_kpp(&ecdh_nist_p256); + if (ret) + goto nist_p256_error; + + ret = crypto_register_kpp(&ecdh_nist_p384); + if (ret) + goto nist_p384_error; + + return 0; + +nist_p384_error: + crypto_unregister_kpp(&ecdh_nist_p256); + +nist_p256_error: + if (ecdh_nist_p192_registered) + crypto_unregister_kpp(&ecdh_nist_p192); + return ret; +} + +static void __exit ecdh_exit(void) +{ + if (ecdh_nist_p192_registered) + crypto_unregister_kpp(&ecdh_nist_p192); + crypto_unregister_kpp(&ecdh_nist_p256); + crypto_unregister_kpp(&ecdh_nist_p384); +} + +module_init(ecdh_init); +module_exit(ecdh_exit); +MODULE_ALIAS_CRYPTO("ecdh"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ECDH generic algorithm"); |
