xref: /openbmc/linux/crypto/dh.c (revision 9ee0034b8f49aaaa7e7c2da8db1038915db99c19)
1  /*  Diffie-Hellman Key Agreement Method [RFC2631]
2   *
3   * Copyright (c) 2016, Intel Corporation
4   * Authors: Salvatore 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/dh.h>
16  #include <linux/mpi.h>
17  
18  struct dh_ctx {
19  	MPI p;
20  	MPI g;
21  	MPI xa;
22  };
23  
24  static inline void dh_clear_params(struct dh_ctx *ctx)
25  {
26  	mpi_free(ctx->p);
27  	mpi_free(ctx->g);
28  	ctx->p = NULL;
29  	ctx->g = NULL;
30  }
31  
32  static void dh_free_ctx(struct dh_ctx *ctx)
33  {
34  	dh_clear_params(ctx);
35  	mpi_free(ctx->xa);
36  	ctx->xa = NULL;
37  }
38  
39  /*
40   * If base is g we compute the public key
41   *	ya = g^xa mod p; [RFC2631 sec 2.1.1]
42   * else if base if the counterpart public key we compute the shared secret
43   *	ZZ = yb^xa mod p; [RFC2631 sec 2.1.1]
44   */
45  static int _compute_val(const struct dh_ctx *ctx, MPI base, MPI val)
46  {
47  	/* val = base^xa mod p */
48  	return mpi_powm(val, base, ctx->xa, ctx->p);
49  }
50  
51  static inline struct dh_ctx *dh_get_ctx(struct crypto_kpp *tfm)
52  {
53  	return kpp_tfm_ctx(tfm);
54  }
55  
56  static int dh_check_params_length(unsigned int p_len)
57  {
58  	return (p_len < 1536) ? -EINVAL : 0;
59  }
60  
61  static int dh_set_params(struct dh_ctx *ctx, struct dh *params)
62  {
63  	if (unlikely(!params->p || !params->g))
64  		return -EINVAL;
65  
66  	if (dh_check_params_length(params->p_size << 3))
67  		return -EINVAL;
68  
69  	ctx->p = mpi_read_raw_data(params->p, params->p_size);
70  	if (!ctx->p)
71  		return -EINVAL;
72  
73  	ctx->g = mpi_read_raw_data(params->g, params->g_size);
74  	if (!ctx->g) {
75  		mpi_free(ctx->p);
76  		return -EINVAL;
77  	}
78  
79  	return 0;
80  }
81  
82  static int dh_set_secret(struct crypto_kpp *tfm, void *buf, unsigned int len)
83  {
84  	struct dh_ctx *ctx = dh_get_ctx(tfm);
85  	struct dh params;
86  
87  	if (crypto_dh_decode_key(buf, len, &params) < 0)
88  		return -EINVAL;
89  
90  	if (dh_set_params(ctx, &params) < 0)
91  		return -EINVAL;
92  
93  	ctx->xa = mpi_read_raw_data(params.key, params.key_size);
94  	if (!ctx->xa) {
95  		dh_clear_params(ctx);
96  		return -EINVAL;
97  	}
98  
99  	return 0;
100  }
101  
102  static int dh_compute_value(struct kpp_request *req)
103  {
104  	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
105  	struct dh_ctx *ctx = dh_get_ctx(tfm);
106  	MPI base, val = mpi_alloc(0);
107  	int ret = 0;
108  	int sign;
109  
110  	if (!val)
111  		return -ENOMEM;
112  
113  	if (unlikely(!ctx->xa)) {
114  		ret = -EINVAL;
115  		goto err_free_val;
116  	}
117  
118  	if (req->src) {
119  		base = mpi_read_raw_from_sgl(req->src, req->src_len);
120  		if (!base) {
121  			ret = EINVAL;
122  			goto err_free_val;
123  		}
124  	} else {
125  		base = ctx->g;
126  	}
127  
128  	ret = _compute_val(ctx, base, val);
129  	if (ret)
130  		goto err_free_base;
131  
132  	ret = mpi_write_to_sgl(val, req->dst, req->dst_len, &sign);
133  	if (ret)
134  		goto err_free_base;
135  
136  	if (sign < 0)
137  		ret = -EBADMSG;
138  err_free_base:
139  	if (req->src)
140  		mpi_free(base);
141  err_free_val:
142  	mpi_free(val);
143  	return ret;
144  }
145  
146  static int dh_max_size(struct crypto_kpp *tfm)
147  {
148  	struct dh_ctx *ctx = dh_get_ctx(tfm);
149  
150  	return mpi_get_size(ctx->p);
151  }
152  
153  static void dh_exit_tfm(struct crypto_kpp *tfm)
154  {
155  	struct dh_ctx *ctx = dh_get_ctx(tfm);
156  
157  	dh_free_ctx(ctx);
158  }
159  
160  static struct kpp_alg dh = {
161  	.set_secret = dh_set_secret,
162  	.generate_public_key = dh_compute_value,
163  	.compute_shared_secret = dh_compute_value,
164  	.max_size = dh_max_size,
165  	.exit = dh_exit_tfm,
166  	.base = {
167  		.cra_name = "dh",
168  		.cra_driver_name = "dh-generic",
169  		.cra_priority = 100,
170  		.cra_module = THIS_MODULE,
171  		.cra_ctxsize = sizeof(struct dh_ctx),
172  	},
173  };
174  
175  static int dh_init(void)
176  {
177  	return crypto_register_kpp(&dh);
178  }
179  
180  static void dh_exit(void)
181  {
182  	crypto_unregister_kpp(&dh);
183  }
184  
185  module_init(dh_init);
186  module_exit(dh_exit);
187  MODULE_ALIAS_CRYPTO("dh");
188  MODULE_LICENSE("GPL");
189  MODULE_DESCRIPTION("DH generic algorithm");
190