Back to home page

LXR

 
 

    


0001 /* ECDH key-agreement protocol
0002  *
0003  * Copyright (c) 2016, Intel Corporation
0004  * Authors: Salvator Benedetto <salvatore.benedetto@intel.com>
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU General Public Licence
0008  * as published by the Free Software Foundation; either version
0009  * 2 of the Licence, or (at your option) any later version.
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <crypto/internal/kpp.h>
0014 #include <crypto/kpp.h>
0015 #include <crypto/ecdh.h>
0016 #include <linux/scatterlist.h>
0017 #include "ecc.h"
0018 
0019 struct ecdh_ctx {
0020     unsigned int curve_id;
0021     unsigned int ndigits;
0022     u64 private_key[ECC_MAX_DIGITS];
0023     u64 public_key[2 * ECC_MAX_DIGITS];
0024     u64 shared_secret[ECC_MAX_DIGITS];
0025 };
0026 
0027 static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm)
0028 {
0029     return kpp_tfm_ctx(tfm);
0030 }
0031 
0032 static unsigned int ecdh_supported_curve(unsigned int curve_id)
0033 {
0034     switch (curve_id) {
0035     case ECC_CURVE_NIST_P192: return 3;
0036     case ECC_CURVE_NIST_P256: return 4;
0037     default: return 0;
0038     }
0039 }
0040 
0041 static int ecdh_set_secret(struct crypto_kpp *tfm, void *buf, unsigned int len)
0042 {
0043     struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0044     struct ecdh params;
0045     unsigned int ndigits;
0046 
0047     if (crypto_ecdh_decode_key(buf, len, &params) < 0)
0048         return -EINVAL;
0049 
0050     ndigits = ecdh_supported_curve(params.curve_id);
0051     if (!ndigits)
0052         return -EINVAL;
0053 
0054     ctx->curve_id = params.curve_id;
0055     ctx->ndigits = ndigits;
0056 
0057     if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits,
0058                  (const u8 *)params.key, params.key_size) < 0)
0059         return -EINVAL;
0060 
0061     memcpy(ctx->private_key, params.key, params.key_size);
0062 
0063     return 0;
0064 }
0065 
0066 static int ecdh_compute_value(struct kpp_request *req)
0067 {
0068     int ret = 0;
0069     struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
0070     struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0071     size_t copied, nbytes;
0072     void *buf;
0073 
0074     nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
0075 
0076     if (req->src) {
0077         copied = sg_copy_to_buffer(req->src, 1, ctx->public_key,
0078                        2 * nbytes);
0079         if (copied != 2 * nbytes)
0080             return -EINVAL;
0081 
0082         ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits,
0083                      (const u8 *)ctx->private_key, nbytes,
0084                      (const u8 *)ctx->public_key, 2 * nbytes,
0085                      (u8 *)ctx->shared_secret, nbytes);
0086 
0087         buf = ctx->shared_secret;
0088     } else {
0089         ret = ecdh_make_pub_key(ctx->curve_id, ctx->ndigits,
0090                     (const u8 *)ctx->private_key, nbytes,
0091                     (u8 *)ctx->public_key,
0092                     sizeof(ctx->public_key));
0093         buf = ctx->public_key;
0094         /* Public part is a point thus it has both coordinates */
0095         nbytes *= 2;
0096     }
0097 
0098     if (ret < 0)
0099         return ret;
0100 
0101     copied = sg_copy_from_buffer(req->dst, 1, buf, nbytes);
0102     if (copied != nbytes)
0103         return -EINVAL;
0104 
0105     return ret;
0106 }
0107 
0108 static int ecdh_max_size(struct crypto_kpp *tfm)
0109 {
0110     struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0111     int nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
0112 
0113     /* Public key is made of two coordinates */
0114     return 2 * nbytes;
0115 }
0116 
0117 static void no_exit_tfm(struct crypto_kpp *tfm)
0118 {
0119     return;
0120 }
0121 
0122 static struct kpp_alg ecdh = {
0123     .set_secret = ecdh_set_secret,
0124     .generate_public_key = ecdh_compute_value,
0125     .compute_shared_secret = ecdh_compute_value,
0126     .max_size = ecdh_max_size,
0127     .exit = no_exit_tfm,
0128     .base = {
0129         .cra_name = "ecdh",
0130         .cra_driver_name = "ecdh-generic",
0131         .cra_priority = 100,
0132         .cra_module = THIS_MODULE,
0133         .cra_ctxsize = sizeof(struct ecdh_ctx),
0134     },
0135 };
0136 
0137 static int ecdh_init(void)
0138 {
0139     return crypto_register_kpp(&ecdh);
0140 }
0141 
0142 static void ecdh_exit(void)
0143 {
0144     crypto_unregister_kpp(&ecdh);
0145 }
0146 
0147 module_init(ecdh_init);
0148 module_exit(ecdh_exit);
0149 MODULE_ALIAS_CRYPTO("ecdh");
0150 MODULE_LICENSE("GPL");
0151 MODULE_DESCRIPTION("ECDH generic algorithm");