Blame view

crypto/ecdh.c 4.11 KB
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
1
2
3
4
5
6
  /* ECDH key-agreement protocol
   *
   * Copyright (c) 2016, Intel Corporation
   * Authors: Salvator Benedetto <salvatore.benedetto@intel.com>
   *
   * This program is free software; you can redistribute it and/or
c0ca1215d   Tudor-Dan Ambarus   crypto: kpp, (ec)...
7
   * modify it under the terms of the GNU General Public License
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
8
   * as published by the Free Software Foundation; either version
c0ca1215d   Tudor-Dan Ambarus   crypto: kpp, (ec)...
9
   * 2 of the License, or (at your option) any later version.
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
10
11
12
13
14
15
16
17
18
19
20
21
22
   */
  
  #include <linux/module.h>
  #include <crypto/internal/kpp.h>
  #include <crypto/kpp.h>
  #include <crypto/ecdh.h>
  #include <linux/scatterlist.h>
  #include "ecc.h"
  
  struct ecdh_ctx {
  	unsigned int curve_id;
  	unsigned int ndigits;
  	u64 private_key[ECC_MAX_DIGITS];
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
23
24
25
26
27
28
29
30
31
32
  };
  
  static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm)
  {
  	return kpp_tfm_ctx(tfm);
  }
  
  static unsigned int ecdh_supported_curve(unsigned int curve_id)
  {
  	switch (curve_id) {
d5c3b1789   Kees Cook   crypto: ecc - Act...
33
34
  	case ECC_CURVE_NIST_P192: return ECC_CURVE_NIST_P192_DIGITS;
  	case ECC_CURVE_NIST_P256: return ECC_CURVE_NIST_P256_DIGITS;
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
35
36
37
  	default: return 0;
  	}
  }
5527dfb6d   Eric Biggers   crypto: kpp - con...
38
39
  static int ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
  			   unsigned int len)
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  {
  	struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
  	struct ecdh params;
  	unsigned int ndigits;
  
  	if (crypto_ecdh_decode_key(buf, len, &params) < 0)
  		return -EINVAL;
  
  	ndigits = ecdh_supported_curve(params.curve_id);
  	if (!ndigits)
  		return -EINVAL;
  
  	ctx->curve_id = params.curve_id;
  	ctx->ndigits = ndigits;
6755fd269   Tudor-Dan Ambarus   crypto: ecdh - ad...
54
55
56
  	if (!params.key || !params.key_size)
  		return ecc_gen_privkey(ctx->curve_id, ctx->ndigits,
  				       ctx->private_key);
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
57
  	if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits,
ad2695971   Tudor-Dan Ambarus   crypto: ecc - rem...
58
  			     (const u64 *)params.key, params.key_size) < 0)
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
59
60
61
62
63
64
65
66
67
  		return -EINVAL;
  
  	memcpy(ctx->private_key, params.key, params.key_size);
  
  	return 0;
  }
  
  static int ecdh_compute_value(struct kpp_request *req)
  {
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
68
69
  	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
  	struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
952035bae   Tudor-Dan Ambarus   crypto: ecdh - fi...
70
71
  	u64 *public_key;
  	u64 *shared_secret = NULL;
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
72
  	void *buf;
952035bae   Tudor-Dan Ambarus   crypto: ecdh - fi...
73
74
  	size_t copied, nbytes, public_key_sz;
  	int ret = -ENOMEM;
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
75
76
  
  	nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
952035bae   Tudor-Dan Ambarus   crypto: ecdh - fi...
77
78
79
80
81
82
  	/* 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;
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
83
84
  
  	if (req->src) {
952035bae   Tudor-Dan Ambarus   crypto: ecdh - fi...
85
86
87
  		shared_secret = kmalloc(nbytes, GFP_KERNEL);
  		if (!shared_secret)
  			goto free_pubkey;
95ec01ba1   James Bottomley   crypto: ecdh - fi...
88
89
90
91
92
93
94
95
96
97
98
99
  		/* 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)
952035bae   Tudor-Dan Ambarus   crypto: ecdh - fi...
100
  			goto free_all;
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
101

8f44df154   Stephen Rothwell   crypto: ecdh - ma...
102
  		ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits,
952035bae   Tudor-Dan Ambarus   crypto: ecdh - fi...
103
104
  						ctx->private_key, public_key,
  						shared_secret);
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
105

952035bae   Tudor-Dan Ambarus   crypto: ecdh - fi...
106
  		buf = shared_secret;
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
107
  	} else {
7380c56d2   Tudor-Dan Ambarus   crypto: ecc - ren...
108
  		ret = ecc_make_pub_key(ctx->curve_id, ctx->ndigits,
952035bae   Tudor-Dan Ambarus   crypto: ecdh - fi...
109
110
111
  				       ctx->private_key, public_key);
  		buf = public_key;
  		nbytes = public_key_sz;
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
112
113
114
  	}
  
  	if (ret < 0)
952035bae   Tudor-Dan Ambarus   crypto: ecdh - fi...
115
  		goto free_all;
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
116

95ec01ba1   James Bottomley   crypto: ecdh - fi...
117
118
119
120
121
  	/* 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);
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
122
  	if (copied != nbytes)
952035bae   Tudor-Dan Ambarus   crypto: ecdh - fi...
123
  		ret = -EINVAL;
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
124

952035bae   Tudor-Dan Ambarus   crypto: ecdh - fi...
125
126
127
128
129
  	/* fall through */
  free_all:
  	kzfree(shared_secret);
  free_pubkey:
  	kfree(public_key);
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
130
131
  	return ret;
  }
d0efb48b8   Tudor-Dan Ambarus   crypto: ecdh - co...
132
  static unsigned int ecdh_max_size(struct crypto_kpp *tfm)
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
133
134
  {
  	struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
135

d0efb48b8   Tudor-Dan Ambarus   crypto: ecdh - co...
136
137
  	/* Public key is made of two coordinates, add one to the left shift */
  	return ctx->ndigits << (ECC_DIGITS_TO_BYTES_SHIFT + 1);
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
138
  }
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
139
140
141
142
143
  static struct kpp_alg ecdh = {
  	.set_secret = ecdh_set_secret,
  	.generate_public_key = ecdh_compute_value,
  	.compute_shared_secret = ecdh_compute_value,
  	.max_size = ecdh_max_size,
3c4b23901   Salvatore Benedetto   crypto: ecdh - Ad...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  	.base = {
  		.cra_name = "ecdh",
  		.cra_driver_name = "ecdh-generic",
  		.cra_priority = 100,
  		.cra_module = THIS_MODULE,
  		.cra_ctxsize = sizeof(struct ecdh_ctx),
  	},
  };
  
  static int ecdh_init(void)
  {
  	return crypto_register_kpp(&ecdh);
  }
  
  static void ecdh_exit(void)
  {
  	crypto_unregister_kpp(&ecdh);
  }
  
  module_init(ecdh_init);
  module_exit(ecdh_exit);
  MODULE_ALIAS_CRYPTO("ecdh");
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("ECDH generic algorithm");