0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <crypto/internal/ecc.h>
0010 #include <crypto/internal/kpp.h>
0011 #include <crypto/kpp.h>
0012 #include <crypto/ecdh.h>
0013 #include <linux/scatterlist.h>
0014
0015 struct ecdh_ctx {
0016 unsigned int curve_id;
0017 unsigned int ndigits;
0018 u64 private_key[ECC_MAX_DIGITS];
0019 };
0020
0021 static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm)
0022 {
0023 return kpp_tfm_ctx(tfm);
0024 }
0025
0026 static int ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
0027 unsigned int len)
0028 {
0029 struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0030 struct ecdh params;
0031
0032 if (crypto_ecdh_decode_key(buf, len, ¶ms) < 0 ||
0033 params.key_size > sizeof(u64) * ctx->ndigits)
0034 return -EINVAL;
0035
0036 if (!params.key || !params.key_size)
0037 return ecc_gen_privkey(ctx->curve_id, ctx->ndigits,
0038 ctx->private_key);
0039
0040 memcpy(ctx->private_key, params.key, params.key_size);
0041
0042 if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits,
0043 ctx->private_key, params.key_size) < 0) {
0044 memzero_explicit(ctx->private_key, params.key_size);
0045 return -EINVAL;
0046 }
0047 return 0;
0048 }
0049
0050 static int ecdh_compute_value(struct kpp_request *req)
0051 {
0052 struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
0053 struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0054 u64 *public_key;
0055 u64 *shared_secret = NULL;
0056 void *buf;
0057 size_t copied, nbytes, public_key_sz;
0058 int ret = -ENOMEM;
0059
0060 nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
0061
0062 public_key_sz = 2 * nbytes;
0063
0064 public_key = kmalloc(public_key_sz, GFP_KERNEL);
0065 if (!public_key)
0066 return -ENOMEM;
0067
0068 if (req->src) {
0069 shared_secret = kmalloc(nbytes, GFP_KERNEL);
0070 if (!shared_secret)
0071 goto free_pubkey;
0072
0073
0074 ret = -EINVAL;
0075
0076
0077 if (public_key_sz != req->src_len)
0078 goto free_all;
0079
0080 copied = sg_copy_to_buffer(req->src,
0081 sg_nents_for_len(req->src,
0082 public_key_sz),
0083 public_key, public_key_sz);
0084 if (copied != public_key_sz)
0085 goto free_all;
0086
0087 ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits,
0088 ctx->private_key, public_key,
0089 shared_secret);
0090
0091 buf = shared_secret;
0092 } else {
0093 ret = ecc_make_pub_key(ctx->curve_id, ctx->ndigits,
0094 ctx->private_key, public_key);
0095 buf = public_key;
0096 nbytes = public_key_sz;
0097 }
0098
0099 if (ret < 0)
0100 goto free_all;
0101
0102
0103 nbytes = min_t(size_t, nbytes, req->dst_len);
0104 copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,
0105 nbytes),
0106 buf, nbytes);
0107 if (copied != nbytes)
0108 ret = -EINVAL;
0109
0110
0111 free_all:
0112 kfree_sensitive(shared_secret);
0113 free_pubkey:
0114 kfree(public_key);
0115 return ret;
0116 }
0117
0118 static unsigned int ecdh_max_size(struct crypto_kpp *tfm)
0119 {
0120 struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0121
0122
0123 return ctx->ndigits << (ECC_DIGITS_TO_BYTES_SHIFT + 1);
0124 }
0125
0126 static int ecdh_nist_p192_init_tfm(struct crypto_kpp *tfm)
0127 {
0128 struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0129
0130 ctx->curve_id = ECC_CURVE_NIST_P192;
0131 ctx->ndigits = ECC_CURVE_NIST_P192_DIGITS;
0132
0133 return 0;
0134 }
0135
0136 static struct kpp_alg ecdh_nist_p192 = {
0137 .set_secret = ecdh_set_secret,
0138 .generate_public_key = ecdh_compute_value,
0139 .compute_shared_secret = ecdh_compute_value,
0140 .max_size = ecdh_max_size,
0141 .init = ecdh_nist_p192_init_tfm,
0142 .base = {
0143 .cra_name = "ecdh-nist-p192",
0144 .cra_driver_name = "ecdh-nist-p192-generic",
0145 .cra_priority = 100,
0146 .cra_module = THIS_MODULE,
0147 .cra_ctxsize = sizeof(struct ecdh_ctx),
0148 },
0149 };
0150
0151 static int ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm)
0152 {
0153 struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0154
0155 ctx->curve_id = ECC_CURVE_NIST_P256;
0156 ctx->ndigits = ECC_CURVE_NIST_P256_DIGITS;
0157
0158 return 0;
0159 }
0160
0161 static struct kpp_alg ecdh_nist_p256 = {
0162 .set_secret = ecdh_set_secret,
0163 .generate_public_key = ecdh_compute_value,
0164 .compute_shared_secret = ecdh_compute_value,
0165 .max_size = ecdh_max_size,
0166 .init = ecdh_nist_p256_init_tfm,
0167 .base = {
0168 .cra_name = "ecdh-nist-p256",
0169 .cra_driver_name = "ecdh-nist-p256-generic",
0170 .cra_priority = 100,
0171 .cra_module = THIS_MODULE,
0172 .cra_ctxsize = sizeof(struct ecdh_ctx),
0173 },
0174 };
0175
0176 static int ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm)
0177 {
0178 struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0179
0180 ctx->curve_id = ECC_CURVE_NIST_P384;
0181 ctx->ndigits = ECC_CURVE_NIST_P384_DIGITS;
0182
0183 return 0;
0184 }
0185
0186 static struct kpp_alg ecdh_nist_p384 = {
0187 .set_secret = ecdh_set_secret,
0188 .generate_public_key = ecdh_compute_value,
0189 .compute_shared_secret = ecdh_compute_value,
0190 .max_size = ecdh_max_size,
0191 .init = ecdh_nist_p384_init_tfm,
0192 .base = {
0193 .cra_name = "ecdh-nist-p384",
0194 .cra_driver_name = "ecdh-nist-p384-generic",
0195 .cra_priority = 100,
0196 .cra_module = THIS_MODULE,
0197 .cra_ctxsize = sizeof(struct ecdh_ctx),
0198 },
0199 };
0200
0201 static bool ecdh_nist_p192_registered;
0202
0203 static int ecdh_init(void)
0204 {
0205 int ret;
0206
0207
0208 ret = crypto_register_kpp(&ecdh_nist_p192);
0209 ecdh_nist_p192_registered = ret == 0;
0210
0211 ret = crypto_register_kpp(&ecdh_nist_p256);
0212 if (ret)
0213 goto nist_p256_error;
0214
0215 ret = crypto_register_kpp(&ecdh_nist_p384);
0216 if (ret)
0217 goto nist_p384_error;
0218
0219 return 0;
0220
0221 nist_p384_error:
0222 crypto_unregister_kpp(&ecdh_nist_p256);
0223
0224 nist_p256_error:
0225 if (ecdh_nist_p192_registered)
0226 crypto_unregister_kpp(&ecdh_nist_p192);
0227 return ret;
0228 }
0229
0230 static void ecdh_exit(void)
0231 {
0232 if (ecdh_nist_p192_registered)
0233 crypto_unregister_kpp(&ecdh_nist_p192);
0234 crypto_unregister_kpp(&ecdh_nist_p256);
0235 crypto_unregister_kpp(&ecdh_nist_p384);
0236 }
0237
0238 subsys_initcall(ecdh_init);
0239 module_exit(ecdh_exit);
0240 MODULE_ALIAS_CRYPTO("ecdh");
0241 MODULE_LICENSE("GPL");
0242 MODULE_DESCRIPTION("ECDH generic algorithm");