Branch data Line data Source code
1 : : /*
2 : : * gnome-keyring
3 : : *
4 : : * Copyright (C) 2009 Stefan Walter
5 : : *
6 : : * This program is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU Lesser General Public License as
8 : : * published by the Free Software Foundation; either version 2.1 of
9 : : * the License, or (at your option) any later version.
10 : : *
11 : : * This program is distributed in the hope that it will be useful, but
12 : : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received copies of the GNU General Public License and
17 : : * the GNU Lesser General Public License along with this program. If
18 : : * not, see http://www.gnu.org/licenses/.
19 : : *
20 : : * Author: Stef Walter <stefw@thewalter.net>
21 : : */
22 : :
23 : : #include "config.h"
24 : :
25 : : #include "egg-dh.h"
26 : :
27 : : #include <gcrypt.h>
28 : : #include "egg-secure-memory.h"
29 : :
30 : : /* Enabling this is a complete security compromise */
31 : : #define DEBUG_DH_SECRET 0
32 : :
33 : 52 : EGG_SECURE_DECLARE (dh);
34 : :
35 : : struct egg_dh_params {
36 : : gcry_mpi_t prime;
37 : : gcry_mpi_t base;
38 : : };
39 : :
40 : : struct egg_dh_pubkey {
41 : : gcry_mpi_t inner;
42 : : };
43 : :
44 : : struct egg_dh_privkey {
45 : : gcry_mpi_t inner;
46 : : };
47 : :
48 : : egg_dh_params *
49 : 57 : egg_dh_default_params (const gchar *name)
50 : : {
51 : : const egg_dh_group *group;
52 : : gcry_error_t gcry;
53 : 57 : gcry_mpi_t prime = NULL, base = NULL;
54 : 57 : egg_dh_params *params = NULL;
55 : :
56 [ - + ]: 57 : g_return_val_if_fail (name, NULL);
57 : :
58 [ + + ]: 120 : for (group = egg_dh_groups; group->name; ++group)
59 [ + + ]: 119 : if (g_str_equal (group->name, name))
60 : 56 : break;
61 [ + + ]: 57 : if (!group->name)
62 : 1 : return NULL;
63 : :
64 : 56 : gcry = gcry_mpi_scan (&prime, GCRYMPI_FMT_USG,
65 : 56 : group->prime, group->n_prime, NULL);
66 [ - + ]: 56 : g_return_val_if_fail (gcry == 0, NULL);
67 [ - + ]: 56 : g_return_val_if_fail (gcry_mpi_get_nbits (prime) == group->bits, NULL);
68 : :
69 : 56 : gcry = gcry_mpi_scan (&base, GCRYMPI_FMT_USG,
70 : 56 : group->base, group->n_base, NULL);
71 [ - + ]: 56 : g_return_val_if_fail (gcry == 0, NULL);
72 : :
73 : 56 : params = g_new (struct egg_dh_params, 1);
74 [ - + ]: 56 : if (!params)
75 : 0 : goto error;
76 : :
77 : 56 : params->prime = g_steal_pointer (&prime);
78 : 56 : params->base = g_steal_pointer (&base);
79 : :
80 : 56 : error:
81 : 56 : gcry_mpi_release (prime);
82 : 56 : gcry_mpi_release (base);
83 : 56 : return params;
84 : : }
85 : :
86 : : gboolean
87 : 56 : egg_dh_gen_pair (egg_dh_params *params, guint bits,
88 : : egg_dh_pubkey **pub, egg_dh_privkey **priv)
89 : : {
90 : : guint pbits;
91 : 56 : gcry_mpi_t pub_inner = NULL, priv_inner = NULL;
92 : :
93 [ - + ]: 56 : g_return_val_if_fail (params, FALSE);
94 [ - + ]: 56 : g_return_val_if_fail (pub, FALSE);
95 [ - + ]: 56 : g_return_val_if_fail (priv, FALSE);
96 : :
97 : 56 : *pub = NULL;
98 : 56 : *priv = NULL;
99 : :
100 : 56 : pbits = gcry_mpi_get_nbits (params->prime);
101 [ - + ]: 56 : g_return_val_if_fail (pbits > 1, FALSE);
102 : :
103 [ + - ]: 56 : if (bits == 0) {
104 : 56 : bits = pbits;
105 [ # # ]: 0 : } else if (bits > pbits) {
106 : 0 : g_return_val_if_reached (FALSE);
107 : : }
108 : :
109 : : /*
110 : : * Generate a strong random number of bits, and not zero.
111 : : * gcry_mpi_randomize bumps up to the next byte. Since we
112 : : * need to have a value less than half of prime, we make sure
113 : : * we bump down.
114 : : */
115 : 56 : priv_inner = gcry_mpi_snew (bits);
116 [ - + ]: 56 : g_return_val_if_fail (priv_inner, FALSE);
117 [ + + ]: 112 : while (gcry_mpi_cmp_ui (priv_inner, 0) == 0)
118 : 56 : gcry_mpi_randomize (priv_inner, bits, GCRY_STRONG_RANDOM);
119 : :
120 : : /* Secret key value must be less than half of p */
121 [ - + ]: 56 : if (gcry_mpi_get_nbits (priv_inner) > bits)
122 : 0 : gcry_mpi_clear_highbit (priv_inner, bits);
123 [ + + ]: 56 : if (gcry_mpi_get_nbits (priv_inner) > pbits - 1)
124 : 26 : gcry_mpi_clear_highbit (priv_inner, pbits - 1);
125 [ - + ]: 56 : g_assert (gcry_mpi_cmp (params->prime, priv_inner) > 0);
126 : :
127 : 56 : pub_inner = gcry_mpi_new (gcry_mpi_get_nbits (priv_inner));
128 [ - + ]: 56 : if (!pub_inner)
129 : 0 : goto error;
130 : 56 : gcry_mpi_powm (pub_inner, params->base, priv_inner, params->prime);
131 : :
132 : 56 : *priv = g_new0 (struct egg_dh_privkey, 1);
133 [ - + ]: 56 : if (!*priv)
134 : 0 : goto error;
135 : 56 : (*priv)->inner = g_steal_pointer (&priv_inner);
136 : :
137 : 56 : *pub = g_new0 (struct egg_dh_pubkey, 1);
138 [ - + ]: 56 : if (!*pub)
139 : 0 : goto error;
140 : 56 : (*pub)->inner = g_steal_pointer (&pub_inner);
141 : :
142 : 56 : return TRUE;
143 : 0 : error:
144 : 0 : egg_dh_privkey_free (*priv);
145 : 0 : egg_dh_pubkey_free (*pub);
146 : :
147 : 0 : gcry_mpi_release (priv_inner);
148 : 0 : gcry_mpi_release (pub_inner);
149 : :
150 : 0 : g_return_val_if_reached (FALSE);
151 : : }
152 : :
153 : : GBytes *
154 : 52 : egg_dh_gen_secret (egg_dh_pubkey *peer, egg_dh_privkey *priv,
155 : : egg_dh_params *params)
156 : : {
157 : : gcry_error_t gcry;
158 : : guchar *value;
159 : : gsize n_prime;
160 : : gsize n_value;
161 : : gcry_mpi_t k;
162 : : gint bits;
163 : :
164 [ - + ]: 52 : g_return_val_if_fail (peer, NULL);
165 [ - + ]: 52 : g_return_val_if_fail (priv, NULL);
166 [ - + ]: 52 : g_return_val_if_fail (params, NULL);
167 : :
168 : 52 : bits = gcry_mpi_get_nbits (params->prime);
169 [ - + ]: 52 : g_return_val_if_fail (bits >= 0, NULL);
170 : :
171 : 52 : k = gcry_mpi_snew (bits);
172 [ - + ]: 52 : g_return_val_if_fail (k, NULL);
173 : 52 : gcry_mpi_powm (k, peer->inner, priv->inner, params->prime);
174 : :
175 : : /* Write out the secret */
176 : 52 : gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n_prime, params->prime);
177 [ - + ]: 52 : g_return_val_if_fail (gcry == 0, NULL);
178 : :
179 : 52 : value = egg_secure_alloc (n_prime);
180 [ - + ]: 52 : if (!value)
181 : 0 : return NULL;
182 : :
183 : 52 : gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value, n_prime, &n_value, k);
184 [ - + ]: 52 : g_return_val_if_fail (gcry == 0, NULL);
185 : :
186 : : /* Pad the secret with zero bytes to match length of prime in bytes. */
187 [ - + ]: 52 : if (n_value < n_prime) {
188 : 0 : memmove (value + (n_prime - n_value), value, n_value);
189 : 0 : memset (value, 0, (n_prime - n_value));
190 : : }
191 : :
192 : : #if DEBUG_DH_SECRET
193 : : g_printerr ("DH SECRET: ");
194 : : gcry_mpi_dump (k);
195 : : #endif
196 : 52 : gcry_mpi_release (k);
197 : :
198 : : #if DEBUG_DH_SECRET
199 : : gcry_mpi_scan (&k, GCRYMPI_FMT_USG, value, n_prime, NULL);
200 : : g_printerr ("RAW SECRET: ");
201 : : gcry_mpi_dump (k);
202 : : gcry_mpi_release (k);
203 : : #endif
204 : :
205 : 52 : return g_bytes_new_with_free_func (value, n_prime,
206 : : (GDestroyNotify)egg_secure_free,
207 : : value);
208 : : }
209 : :
210 : : void
211 : 46 : egg_dh_params_free (egg_dh_params *params)
212 : : {
213 [ - + ]: 46 : if (!params)
214 : 0 : return;
215 : 46 : gcry_mpi_release (params->prime);
216 : 46 : gcry_mpi_release (params->base);
217 : 46 : g_free (params);
218 : : }
219 : :
220 : : void
221 : 98 : egg_dh_pubkey_free (egg_dh_pubkey *pubkey)
222 : : {
223 [ - + ]: 98 : if (!pubkey)
224 : 0 : return;
225 [ + - ]: 98 : if (pubkey->inner)
226 : 98 : gcry_mpi_release (pubkey->inner);
227 : 98 : g_free (pubkey);
228 : : }
229 : :
230 : : void
231 : 46 : egg_dh_privkey_free (egg_dh_privkey *privkey)
232 : : {
233 [ - + ]: 46 : if (!privkey)
234 : 0 : return;
235 [ + - ]: 46 : if (privkey->inner)
236 : 46 : gcry_mpi_release (privkey->inner);
237 : 46 : g_free (privkey);
238 : : }
239 : :
240 : : GBytes *
241 : 56 : egg_dh_pubkey_export (const egg_dh_pubkey *pubkey)
242 : : {
243 : : gcry_error_t gcry;
244 : : unsigned char *buffer;
245 : : size_t n_buffer;
246 : :
247 : 56 : gcry = gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &n_buffer,
248 : 56 : pubkey->inner);
249 [ - + ]: 56 : g_return_val_if_fail (gcry == 0, NULL);
250 : :
251 : 56 : return g_bytes_new_with_free_func (buffer, n_buffer,
252 : : gcry_free, buffer);
253 : : }
254 : :
255 : : egg_dh_pubkey *
256 : 52 : egg_dh_pubkey_new_from_bytes (const egg_dh_params *params,
257 : : GBytes *bytes)
258 : : {
259 : : gcry_error_t gcry;
260 : : gcry_mpi_t inner;
261 : : egg_dh_pubkey *pub;
262 : :
263 : 52 : gcry = gcry_mpi_scan (&inner, GCRYMPI_FMT_USG,
264 : : g_bytes_get_data (bytes, NULL),
265 : : g_bytes_get_size (bytes),
266 : : NULL);
267 [ - + ]: 52 : if (gcry != 0)
268 : 0 : return NULL;
269 : :
270 : 52 : pub = g_new (struct egg_dh_pubkey, 1);
271 [ - + ]: 52 : if (!pub) {
272 : 0 : gcry_mpi_release (inner);
273 : 0 : return NULL;
274 : : }
275 : :
276 : 52 : pub->inner = inner;
277 : 52 : return pub;
278 : : }
|