Tweaks for W32
[libgcrypt.git] / tests / pkbench.c
1 /* pkbench.c - Pubkey menchmarking
2  *      Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt 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  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 #include <gcrypt.h>
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <sys/mman.h>
29 #include <sys/stat.h>
30 #ifndef HAVE_W32_SYSTEM
31 #include <sys/times.h>
32 #endif HAVE_W32_SYSTEM
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <time.h>
36
37 typedef struct context
38 {
39   gcry_sexp_t key_secret;
40   gcry_sexp_t key_public;
41   gcry_sexp_t data;
42   gcry_sexp_t data_encrypted;
43   gcry_sexp_t data_signed;
44 } *context_t;
45
46 typedef int (*work_t) (context_t context, unsigned int final);
47
48 static void
49 benchmark (work_t worker, context_t context)
50 {
51   clock_t timer_start, timer_stop;
52   unsigned int loop = 10;
53   unsigned int i = 0;
54   struct tms timer;
55   int ret = 0;
56
57 #ifdef HAVE_W32_SYSTEM
58   timer_start = clock ();
59 #else
60   times (&timer);
61   timer_start = timer.tms_utime;
62 #endif
63   for (i = 0; i < loop; i++)
64     {
65       ret = (*worker) (context, (i + 1) == loop);
66       if (! ret)
67         break;
68     }
69 #ifdef HAVE_W32_SYSTEM
70   timer_stop = clock ();
71 #else
72   times (&timer);
73   timer_stop = timer.tms_utime;
74 #endif
75
76   if (ret)
77     printf ("%.0f ms\n",
78             (((double) ((timer_stop - timer_start) / loop)) / CLOCKS_PER_SEC)
79             * 10000000);
80   else
81     printf ("[skipped]\n");
82 }
83
84 static int
85 work_encrypt (context_t context, unsigned int final)
86 {
87   gcry_error_t err = GPG_ERR_NO_ERROR;
88   gcry_sexp_t data_encrypted = NULL;
89   int ret = 1;
90
91   err = gcry_pk_encrypt (&data_encrypted,
92                          context->data, context->key_public);
93   if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
94     {
95       err = GPG_ERR_NO_ERROR;
96       ret = 0;
97     }
98   else
99     {
100       assert (! err);
101
102       if (final)
103         context->data_encrypted = data_encrypted;
104       else
105         gcry_sexp_release (data_encrypted);
106     }
107
108   return ret;
109 }
110
111 static int
112 work_decrypt (context_t context, unsigned int final)
113 {
114   gcry_error_t err = GPG_ERR_NO_ERROR;
115   int ret = 1;
116
117   if (! context->data_encrypted)
118     ret = 0;
119   else
120     {
121       gcry_sexp_t data_decrypted = NULL;
122       
123       err = gcry_pk_decrypt (&data_decrypted,
124                              context->data_encrypted,
125                              context->key_secret);
126       assert (! err);
127       if (final)
128         {
129           gcry_sexp_release (context->data_encrypted);
130           context->data_encrypted = NULL;
131         }
132       gcry_sexp_release (data_decrypted);
133     }
134
135   return ret;
136 }
137
138 static int
139 work_sign (context_t context, unsigned int final)
140 {
141   gcry_error_t err = GPG_ERR_NO_ERROR;
142   gcry_sexp_t data_signed = NULL;
143   int ret = 1;
144
145   err = gcry_pk_sign (&data_signed,
146                       context->data, context->key_secret);
147   if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
148     {
149       err = GPG_ERR_NO_ERROR;
150       ret = 0;
151     }
152   else
153     {
154       assert (! err);
155
156       if (final)
157         context->data_signed = data_signed;
158       else
159         gcry_sexp_release (data_signed);
160     }
161
162   return ret;
163 }
164
165 static int
166 work_verify (context_t context, unsigned int final)
167 {
168   gcry_error_t err = GPG_ERR_NO_ERROR;
169   int ret = 1;
170
171   if (! context->data_signed)
172     ret = 0;
173   else
174     {
175       err = gcry_pk_verify (context->data_signed,
176                             context->data,
177                             context->key_public);
178       assert (! err);
179       if (final)
180         {
181           gcry_sexp_release (context->data_signed);
182           context->data_signed = NULL;
183         }
184     }
185
186   return ret;
187 }
188
189 static void
190 process_key_pair (context_t context)
191 {
192   struct
193   {
194     work_t worker;
195     const char *identifier;
196   } worker_functions[] = { { work_encrypt, "encrypt" },
197                            { work_decrypt, "decrypt" },
198                            { work_sign,    "sign"    },
199                            { work_verify,  "verify"  } };
200   unsigned int i = 0;
201
202   for (i = 0; i < (sizeof (worker_functions) / sizeof (*worker_functions)); i++)
203     {
204       printf ("%s: ", worker_functions[i].identifier);
205       benchmark (worker_functions[i].worker, context);
206     }
207 }
208
209 static void
210 context_init (context_t context, gcry_sexp_t key_secret, gcry_sexp_t key_public)
211 {
212   gcry_error_t err = GPG_ERR_NO_ERROR;
213   unsigned int key_size = 0;
214   gcry_mpi_t data = NULL;
215   gcry_sexp_t data_sexp = NULL;
216
217   key_size = gcry_pk_get_nbits (key_secret);
218   assert (key_size);
219
220   data = gcry_mpi_new (key_size);
221   assert (data);
222
223   gcry_mpi_randomize (data, key_size, GCRY_STRONG_RANDOM);
224   gcry_mpi_clear_bit (data, key_size - 1);
225   err = gcry_sexp_build (&data_sexp, NULL,
226                          "(data (flags raw) (value %m))",
227                          data);
228   assert (! err);
229   gcry_mpi_release (data);
230
231   context->key_secret = key_secret;
232   context->key_public = key_public;
233   context->data = data_sexp;
234   context->data_encrypted = NULL;
235   context->data_signed = NULL;
236 }
237
238 static void
239 context_destroy (context_t context)
240 {
241   gcry_sexp_release (context->key_secret);
242   gcry_sexp_release (context->key_public);
243   gcry_sexp_release (context->data);
244 }
245
246 static void
247 process_key_pair_file (const char *key_pair_file)
248 {
249   gcry_error_t err = GPG_ERR_NO_ERROR;
250   void *key_pair_buffer = NULL;
251   gcry_sexp_t key_pair_sexp = NULL;
252   gcry_sexp_t key_secret_sexp = NULL;
253   gcry_sexp_t key_public_sexp = NULL;
254   struct context context = { NULL };
255   struct stat statbuf;
256   int key_pair_fd = -1;
257   int ret = 0;
258
259   ret = stat (key_pair_file, &statbuf);
260   assert (! ret);
261
262   key_pair_fd = open (key_pair_file, O_RDONLY);
263   assert (key_pair_fd != -1);
264
265   key_pair_buffer = mmap (NULL, statbuf.st_size, PROT_READ,
266                           MAP_PRIVATE, key_pair_fd, 0);
267   assert (key_pair_buffer != MAP_FAILED);
268
269   err = gcry_sexp_sscan (&key_pair_sexp, NULL,
270                          key_pair_buffer, statbuf.st_size);
271   assert (! err);
272
273   key_secret_sexp = gcry_sexp_find_token (key_pair_sexp, "private-key", 0);
274   assert (key_secret_sexp);
275   key_public_sexp = gcry_sexp_find_token (key_pair_sexp, "public-key", 0);
276   assert (key_public_sexp);
277
278   gcry_sexp_release (key_pair_sexp);
279   ret = munmap (key_pair_buffer, statbuf.st_size);
280   assert (! ret);
281   ret = close (key_pair_fd);
282   assert (! ret);
283
284   context_init (&context, key_secret_sexp, key_public_sexp);
285
286   printf ("Key file: %s\n", key_pair_file);
287   process_key_pair (&context);
288   printf ("\n");
289
290   context_destroy (&context);
291 }
292
293 static const char *program_name = NULL;
294
295 static void
296 print_usage (int err)
297 {
298   fprintf (err ? stderr : stdout,
299            "Usage: %s [--help ] [ --genkey <algorithm>,<size> ] <key files ...>\n\n",
300            program_name);
301   exit (err);
302 }
303
304 static void
305 generate_key (const char *algorithm, const char *key_size)
306 {
307   gcry_error_t err = GPG_ERR_NO_ERROR;
308   size_t key_pair_buffer_size = 0;
309   char *key_pair_buffer = NULL;
310   gcry_sexp_t key_spec = NULL;
311   gcry_sexp_t key_pair = NULL;
312
313   err = gcry_sexp_build (&key_spec, NULL,
314                          "(genkey (%s (nbits %s)))",
315                          algorithm, key_size);
316   assert (! err);
317
318   err = gcry_pk_genkey (&key_pair, key_spec);
319   assert (! err);
320
321   key_pair_buffer_size = gcry_sexp_sprint (key_pair, GCRYSEXP_FMT_ADVANCED,
322                                            NULL, 0);
323   key_pair_buffer = malloc (key_pair_buffer_size);
324   assert (key_pair_buffer);
325
326   gcry_sexp_sprint (key_pair, GCRYSEXP_FMT_ADVANCED,
327                     key_pair_buffer, key_pair_buffer_size);
328
329   printf ("%.*s", key_pair_buffer_size, key_pair_buffer);
330 }
331
332 int
333 main (int argc, char **argv)
334 {
335   program_name = argc ? argv[0] : "";
336
337   gcry_control (GCRYCTL_DISABLE_SECMEM);
338   
339   if (argv[1] && ((! strcmp (argv[1], "--help"))
340                   || (! strcmp (argv[1], "-h"))))
341     print_usage (0);
342   else if (argv[1] && ((! strcmp (argv[1], "--genkey"))
343                        || (! strcmp (argv[1], "-g"))))
344     {
345       char *algorithm = NULL;
346       char *key_size = NULL;
347
348       /* No valuable keys are create, so we can speed up our RNG. */
349       gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
350
351       if (argv[2])
352         {
353           algorithm = argv[2];
354           key_size = strchr (algorithm, ',');
355           if (key_size)
356             {
357               *key_size = 0;
358               key_size++;
359             }
360         }
361
362       if (algorithm && key_size)
363         generate_key (algorithm, key_size);
364       else
365         print_usage (EXIT_FAILURE);
366     }
367   else
368     {
369       unsigned int i = 0;
370
371       for (i = 1; (i < argc); i++)
372         process_key_pair_file (argv[i]);
373     }
374
375   return EXIT_SUCCESS;
376 }