Tizen 2.0 Release
[external/libgnutls26.git] / lib / gcrypt / mpi.c
1 /*
2  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2010 Free
3  * Software Foundation, Inc.
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * The GnuTLS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA
23  *
24  */
25
26 /* Here lie everything that has to do with large numbers, libgcrypt and
27  * other stuff that didn't fit anywhere else.
28  */
29
30 #include <gnutls_int.h>
31 #include <gnutls_errors.h>
32 #include <gnutls_num.h>
33 #include <gnutls_mpi.h>
34 #include <gcrypt.h>
35
36 /* Functions that refer to the libgcrypt library.
37  */
38
39 static inline int
40 _format_conv (gnutls_bigint_format_t format)
41 {
42   if (format == GNUTLS_MPI_FORMAT_USG)
43     return GCRYMPI_FMT_USG;
44   else if (format == GNUTLS_MPI_FORMAT_STD)
45     return GCRYMPI_FMT_STD;
46   else
47     return GCRYMPI_FMT_PGP;
48 }
49
50 /* returns zero on success
51  */
52 static bigint_t
53 wrap_gcry_mpi_scan (const void *buffer, size_t nbytes,
54                     gnutls_bigint_format_t format)
55 {
56   gcry_mpi_t ret_mpi = NULL;
57   int ret;
58
59   ret = gcry_mpi_scan (&ret_mpi, _format_conv (format), buffer, nbytes, NULL);
60   if (ret != 0)
61     return NULL;
62
63   return ret_mpi;
64 }
65
66 static int
67 wrap_gcry_mpi_print (const bigint_t a, void *buffer, size_t * nbytes,
68                      gnutls_bigint_format_t format)
69 {
70   int ret;
71   size_t init_bytes = *nbytes;
72
73   format = _format_conv (format);
74
75   if (nbytes == NULL || a == NULL)
76     return GNUTLS_E_INVALID_REQUEST;
77
78   ret = gcry_mpi_print (format, buffer, *nbytes, nbytes, a);
79   if (!ret)
80     {
81       if (buffer == NULL || init_bytes < *nbytes)
82         {
83
84           /* in STD format we may want to include
85            * an extra byte for zero. Sometimes the gcry_
86            * function doesn't add it.
87            */
88           if (format == GNUTLS_MPI_FORMAT_STD)
89             (*nbytes)++;
90           return GNUTLS_E_SHORT_MEMORY_BUFFER;
91         }
92       return 0;
93     }
94
95   return GNUTLS_E_MPI_PRINT_FAILED;
96 }
97
98 static bigint_t
99 wrap_gcry_mpi_new (int nbits)
100 {
101   return gcry_mpi_new (nbits);
102 }
103
104 static int
105 wrap_gcry_mpi_cmp (const bigint_t u, const bigint_t v)
106 {
107   return gcry_mpi_cmp (u, v);
108 }
109
110 static int
111 wrap_gcry_mpi_cmp_ui (const bigint_t u, unsigned long v)
112 {
113   return gcry_mpi_cmp_ui (u, v);
114 }
115
116 static bigint_t
117 wrap_gcry_mpi_set (bigint_t w, const bigint_t u)
118 {
119   return gcry_mpi_set (w, u);
120 }
121
122 static bigint_t
123 wrap_gcry_mpi_set_ui (bigint_t w, unsigned long u)
124 {
125   return gcry_mpi_set_ui (w, u);
126 }
127
128 static unsigned int
129 wrap_gcry_mpi_get_nbits (bigint_t a)
130 {
131   return gcry_mpi_get_nbits (a);
132 }
133
134 static void
135 wrap_gcry_mpi_release (bigint_t a)
136 {
137   gcry_mpi_release (a);
138 }
139
140 #undef _gnutls_mpi_alloc_like
141 #define _gnutls_mpi_alloc_like(x) gcry_mpi_new(gcry_mpi_get_nbits(x))
142
143 static bigint_t
144 wrap_gcry_mpi_mod (const bigint_t a, const bigint_t b)
145 {
146   bigint_t r = _gnutls_mpi_alloc_like (b);
147
148   if (r == NULL)
149     return NULL;
150
151   gcry_mpi_mod (r, a, b);
152
153   return r;
154 }
155
156 static bigint_t
157 wrap_gcry_mpi_powm (bigint_t w, const bigint_t b, const bigint_t e,
158                     const bigint_t m)
159 {
160   if (w == NULL)
161     w = _gnutls_mpi_alloc_like (m);
162
163   if (w == NULL)
164     return NULL;
165
166   gcry_mpi_powm (w, b, e, m);
167
168   return w;
169 }
170
171 static bigint_t
172 wrap_gcry_mpi_addm (bigint_t w, const bigint_t a, const bigint_t b,
173                     const bigint_t m)
174 {
175   if (w == NULL)
176     w = _gnutls_mpi_alloc_like (m);
177
178   if (w == NULL)
179     return NULL;
180
181   gcry_mpi_addm (w, a, b, m);
182
183   return w;
184 }
185
186 static bigint_t
187 wrap_gcry_mpi_subm (bigint_t w, const bigint_t a, const bigint_t b,
188                     const bigint_t m)
189 {
190   if (w == NULL)
191     w = _gnutls_mpi_alloc_like (m);
192
193   if (w == NULL)
194     return NULL;
195
196   gcry_mpi_subm (w, a, b, m);
197
198   return w;
199 }
200
201 static bigint_t
202 wrap_gcry_mpi_mulm (bigint_t w, const bigint_t a, const bigint_t b,
203                     const bigint_t m)
204 {
205   if (w == NULL)
206     w = _gnutls_mpi_alloc_like (m);
207
208   if (w == NULL)
209     return NULL;
210
211   gcry_mpi_mulm (w, a, b, m);
212
213   return w;
214 }
215
216 static bigint_t
217 wrap_gcry_mpi_add (bigint_t w, const bigint_t a, const bigint_t b)
218 {
219   if (w == NULL)
220     w = _gnutls_mpi_alloc_like (b);
221
222   if (w == NULL)
223     return NULL;
224
225   gcry_mpi_add (w, a, b);
226
227   return w;
228 }
229
230 static bigint_t
231 wrap_gcry_mpi_sub (bigint_t w, const bigint_t a, const bigint_t b)
232 {
233   if (w == NULL)
234     w = _gnutls_mpi_alloc_like (b);
235
236   if (w == NULL)
237     return NULL;
238
239   gcry_mpi_sub (w, a, b);
240
241   return w;
242 }
243
244 static bigint_t
245 wrap_gcry_mpi_mul (bigint_t w, const bigint_t a, const bigint_t b)
246 {
247   if (w == NULL)
248     w = _gnutls_mpi_alloc_like (b);
249
250   if (w == NULL)
251     return NULL;
252
253   gcry_mpi_mul (w, a, b);
254
255   return w;
256 }
257
258 /* q = a / b */
259 static bigint_t
260 wrap_gcry_mpi_div (bigint_t q, const bigint_t a, const bigint_t b)
261 {
262   if (q == NULL)
263     q = _gnutls_mpi_alloc_like (a);
264
265   if (q == NULL)
266     return NULL;
267
268   gcry_mpi_div (q, NULL, a, b, 0);
269
270   return q;
271 }
272
273 static bigint_t
274 wrap_gcry_mpi_add_ui (bigint_t w, const bigint_t a, unsigned long b)
275 {
276   if (w == NULL)
277     w = _gnutls_mpi_alloc_like (a);
278
279   if (w == NULL)
280     return NULL;
281
282   gcry_mpi_add_ui (w, a, b);
283
284   return w;
285 }
286
287 static bigint_t
288 wrap_gcry_mpi_sub_ui (bigint_t w, const bigint_t a, unsigned long b)
289 {
290   if (w == NULL)
291     w = _gnutls_mpi_alloc_like (a);
292
293   if (w == NULL)
294     return NULL;
295
296   gcry_mpi_sub_ui (w, a, b);
297
298   return w;
299 }
300
301 static bigint_t
302 wrap_gcry_mpi_mul_ui (bigint_t w, const bigint_t a, unsigned long b)
303 {
304   if (w == NULL)
305     w = _gnutls_mpi_alloc_like (a);
306
307   if (w == NULL)
308     return NULL;
309
310   gcry_mpi_mul_ui (w, a, b);
311
312   return w;
313 }
314
315 static int
316 wrap_gcry_prime_check (bigint_t pp)
317 {
318   return gcry_prime_check (pp, 0);
319 }
320
321 static int
322 wrap_gcry_generate_group (gnutls_group_st * group, unsigned int bits)
323 {
324   gcry_mpi_t g = NULL, prime = NULL;
325   gcry_error_t err;
326   int times = 0, qbits;
327   gcry_mpi_t *factors = NULL;
328
329   /* Calculate the size of a prime factor of (prime-1)/2.
330    * This is an emulation of the values in "Selecting Cryptographic Key Sizes" paper.
331    */
332   if (bits < 256)
333     qbits = bits / 2;
334   else
335     {
336       qbits = (bits / 40) + 105;
337     }
338
339   if (qbits & 1)                /* better have an even number */
340     qbits++;
341
342   /* find a prime number of size bits.
343    */
344   do
345     {
346       if (times)
347         {
348           gcry_mpi_release (prime);
349           gcry_prime_release_factors (factors);
350         }
351
352       err = gcry_prime_generate (&prime, bits, qbits, &factors,
353                                  NULL, NULL, GCRY_STRONG_RANDOM,
354                                  GCRY_PRIME_FLAG_SPECIAL_FACTOR);
355       if (err != 0)
356         {
357           gnutls_assert ();
358           return GNUTLS_E_INTERNAL_ERROR;
359         }
360
361       err = gcry_prime_check (prime, 0);
362
363       times++;
364     }
365   while (err != 0 && times < 10);
366
367   if (err != 0)
368     {
369       gnutls_assert ();
370       gcry_mpi_release (prime);
371       gcry_prime_release_factors (factors);
372       return GNUTLS_E_INTERNAL_ERROR;
373     }
374
375   /* generate the group generator.
376    */
377   err = gcry_prime_group_generator (&g, prime, factors, NULL);
378   gcry_prime_release_factors (factors);
379   if (err != 0)
380     {
381       gnutls_assert ();
382       gcry_mpi_release (prime);
383       return GNUTLS_E_INTERNAL_ERROR;
384     }
385
386   group->g = g;
387   group->p = prime;
388
389   return 0;
390 }
391
392 int crypto_bigint_prio = INT_MAX;
393
394 gnutls_crypto_bigint_st _gnutls_mpi_ops = {
395   .bigint_new = wrap_gcry_mpi_new,
396   .bigint_cmp = wrap_gcry_mpi_cmp,
397   .bigint_cmp_ui = wrap_gcry_mpi_cmp_ui,
398   .bigint_mod = wrap_gcry_mpi_mod,
399   .bigint_set = wrap_gcry_mpi_set,
400   .bigint_set_ui = wrap_gcry_mpi_set_ui,
401   .bigint_get_nbits = wrap_gcry_mpi_get_nbits,
402   .bigint_powm = wrap_gcry_mpi_powm,
403   .bigint_addm = wrap_gcry_mpi_addm,
404   .bigint_subm = wrap_gcry_mpi_subm,
405   .bigint_add = wrap_gcry_mpi_add,
406   .bigint_sub = wrap_gcry_mpi_sub,
407   .bigint_add_ui = wrap_gcry_mpi_add_ui,
408   .bigint_sub_ui = wrap_gcry_mpi_sub_ui,
409   .bigint_mul = wrap_gcry_mpi_mul,
410   .bigint_mulm = wrap_gcry_mpi_mulm,
411   .bigint_mul_ui = wrap_gcry_mpi_mul_ui,
412   .bigint_div = wrap_gcry_mpi_div,
413   .bigint_prime_check = wrap_gcry_prime_check,
414   .bigint_release = wrap_gcry_mpi_release,
415   .bigint_print = wrap_gcry_mpi_print,
416   .bigint_scan = wrap_gcry_mpi_scan,
417   .bigint_generate_group = wrap_gcry_generate_group
418 };