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