linux/crypto/ecdh.c
<<
>>
Prefs
   1/* ECDH key-agreement protocol
   2 *
   3 * Copyright (c) 2016, Intel Corporation
   4 * Authors: Salvator Benedetto <salvatore.benedetto@intel.com>
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public Licence
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the Licence, or (at your option) any later version.
  10 */
  11
  12#include <linux/module.h>
  13#include <crypto/internal/kpp.h>
  14#include <crypto/kpp.h>
  15#include <crypto/ecdh.h>
  16#include <linux/scatterlist.h>
  17#include "ecc.h"
  18
  19struct ecdh_ctx {
  20        unsigned int curve_id;
  21        unsigned int ndigits;
  22        u64 private_key[ECC_MAX_DIGITS];
  23        u64 public_key[2 * ECC_MAX_DIGITS];
  24        u64 shared_secret[ECC_MAX_DIGITS];
  25};
  26
  27static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm)
  28{
  29        return kpp_tfm_ctx(tfm);
  30}
  31
  32static unsigned int ecdh_supported_curve(unsigned int curve_id)
  33{
  34        switch (curve_id) {
  35        case ECC_CURVE_NIST_P192: return 3;
  36        case ECC_CURVE_NIST_P256: return 4;
  37        default: return 0;
  38        }
  39}
  40
  41static int ecdh_set_secret(struct crypto_kpp *tfm, void *buf, unsigned int len)
  42{
  43        struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
  44        struct ecdh params;
  45        unsigned int ndigits;
  46
  47        if (crypto_ecdh_decode_key(buf, len, &params) < 0)
  48                return -EINVAL;
  49
  50        ndigits = ecdh_supported_curve(params.curve_id);
  51        if (!ndigits)
  52                return -EINVAL;
  53
  54        ctx->curve_id = params.curve_id;
  55        ctx->ndigits = ndigits;
  56
  57        if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits,
  58                             (const u8 *)params.key, params.key_size) < 0)
  59                return -EINVAL;
  60
  61        memcpy(ctx->private_key, params.key, params.key_size);
  62
  63        return 0;
  64}
  65
  66static int ecdh_compute_value(struct kpp_request *req)
  67{
  68        int ret = 0;
  69        struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
  70        struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
  71        size_t copied, nbytes;
  72        void *buf;
  73
  74        nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
  75
  76        if (req->src) {
  77                copied = sg_copy_to_buffer(req->src, 1, ctx->public_key,
  78                                           2 * nbytes);
  79                if (copied != 2 * nbytes)
  80                        return -EINVAL;
  81
  82                ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits,
  83                                         (const u8 *)ctx->private_key, nbytes,
  84                                         (const u8 *)ctx->public_key, 2 * nbytes,
  85                                         (u8 *)ctx->shared_secret, nbytes);
  86
  87                buf = ctx->shared_secret;
  88        } else {
  89                ret = ecdh_make_pub_key(ctx->curve_id, ctx->ndigits,
  90                                        (const u8 *)ctx->private_key, nbytes,
  91                                        (u8 *)ctx->public_key,
  92                                        sizeof(ctx->public_key));
  93                buf = ctx->public_key;
  94                /* Public part is a point thus it has both coordinates */
  95                nbytes *= 2;
  96        }
  97
  98        if (ret < 0)
  99                return ret;
 100
 101        copied = sg_copy_from_buffer(req->dst, 1, buf, nbytes);
 102        if (copied != nbytes)
 103                return -EINVAL;
 104
 105        return ret;
 106}
 107
 108static int ecdh_max_size(struct crypto_kpp *tfm)
 109{
 110        struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
 111        int nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
 112
 113        /* Public key is made of two coordinates */
 114        return 2 * nbytes;
 115}
 116
 117static void no_exit_tfm(struct crypto_kpp *tfm)
 118{
 119        return;
 120}
 121
 122static struct kpp_alg ecdh = {
 123        .set_secret = ecdh_set_secret,
 124        .generate_public_key = ecdh_compute_value,
 125        .compute_shared_secret = ecdh_compute_value,
 126        .max_size = ecdh_max_size,
 127        .exit = no_exit_tfm,
 128        .base = {
 129                .cra_name = "ecdh",
 130                .cra_driver_name = "ecdh-generic",
 131                .cra_priority = 100,
 132                .cra_module = THIS_MODULE,
 133                .cra_ctxsize = sizeof(struct ecdh_ctx),
 134        },
 135};
 136
 137static int ecdh_init(void)
 138{
 139        return crypto_register_kpp(&ecdh);
 140}
 141
 142static void ecdh_exit(void)
 143{
 144        crypto_unregister_kpp(&ecdh);
 145}
 146
 147module_init(ecdh_init);
 148module_exit(ecdh_exit);
 149MODULE_ALIAS_CRYPTO("ecdh");
 150MODULE_LICENSE("GPL");
 151MODULE_DESCRIPTION("ECDH generic algorithm");
 152