dcdc436ecf262ed72e3a5a03043aa719873be205
[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 #define PGM "pkbench"
38
39
40 static int verbose;
41 static int debug;
42
43
44 typedef struct context
45 {
46   gcry_sexp_t key_secret;
47   gcry_sexp_t key_public;
48   gcry_sexp_t data;
49   gcry_sexp_t data_encrypted;
50   gcry_sexp_t data_signed;
51 } *context_t;
52
53 typedef int (*work_t) (context_t context, unsigned int final);
54
55 static void
56 benchmark (work_t worker, context_t context)
57 {
58   clock_t timer_start, timer_stop;
59   unsigned int loop = 10;
60   unsigned int i = 0;
61   struct tms timer;
62   int ret = 0;
63
64 #ifdef HAVE_W32_SYSTEM
65   timer_start = clock ();
66 #else
67   times (&timer);
68   timer_start = timer.tms_utime;
69 #endif
70   for (i = 0; i < loop; i++)
71     {
72       ret = (*worker) (context, (i + 1) == loop);
73       if (! ret)
74         break;
75     }
76 #ifdef HAVE_W32_SYSTEM
77   timer_stop = clock ();
78 #else
79   times (&timer);
80   timer_stop = timer.tms_utime;
81 #endif
82
83   if (ret)
84     printf ("%.0f ms\n",
85             (((double) ((timer_stop - timer_start) / loop)) / CLOCKS_PER_SEC)
86             * 10000000);
87   else
88     printf ("[skipped]\n");
89 }
90
91 static int
92 work_encrypt (context_t context, unsigned int final)
93 {
94   gcry_error_t err = GPG_ERR_NO_ERROR;
95   gcry_sexp_t data_encrypted = NULL;
96   int ret = 1;
97
98   err = gcry_pk_encrypt (&data_encrypted,
99                          context->data, context->key_public);
100   if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
101     {
102       err = GPG_ERR_NO_ERROR;
103       ret = 0;
104     }
105   else
106     {
107       assert (! err);
108
109       if (final)
110         context->data_encrypted = data_encrypted;
111       else
112         gcry_sexp_release (data_encrypted);
113     }
114
115   return ret;
116 }
117
118 static int
119 work_decrypt (context_t context, unsigned int final)
120 {
121   gcry_error_t err = GPG_ERR_NO_ERROR;
122   int ret = 1;
123
124   if (! context->data_encrypted)
125     ret = 0;
126   else
127     {
128       gcry_sexp_t data_decrypted = NULL;
129       
130       err = gcry_pk_decrypt (&data_decrypted,
131                              context->data_encrypted,
132                              context->key_secret);
133       assert (! err);
134       if (final)
135         {
136           gcry_sexp_release (context->data_encrypted);
137           context->data_encrypted = NULL;
138         }
139       gcry_sexp_release (data_decrypted);
140     }
141
142   return ret;
143 }
144
145 static int
146 work_sign (context_t context, unsigned int final)
147 {
148   gcry_error_t err = GPG_ERR_NO_ERROR;
149   gcry_sexp_t data_signed = NULL;
150   int ret = 1;
151
152   err = gcry_pk_sign (&data_signed,
153                       context->data, context->key_secret);
154   if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
155     {
156       err = GPG_ERR_NO_ERROR;
157       ret = 0;
158     }
159   else
160     {
161       assert (! err);
162
163       if (final)
164         context->data_signed = data_signed;
165       else
166         gcry_sexp_release (data_signed);
167     }
168
169   return ret;
170 }
171
172 static int
173 work_verify (context_t context, unsigned int final)
174 {
175   gcry_error_t err = GPG_ERR_NO_ERROR;
176   int ret = 1;
177
178   if (! context->data_signed)
179     ret = 0;
180   else
181     {
182       err = gcry_pk_verify (context->data_signed,
183                             context->data,
184                             context->key_public);
185       assert (! err);
186       if (final)
187         {
188           gcry_sexp_release (context->data_signed);
189           context->data_signed = NULL;
190         }
191     }
192
193   return ret;
194 }
195
196 static void
197 process_key_pair (context_t context)
198 {
199   struct
200   {
201     work_t worker;
202     const char *identifier;
203   } worker_functions[] = { { work_encrypt, "encrypt" },
204                            { work_decrypt, "decrypt" },
205                            { work_sign,    "sign"    },
206                            { work_verify,  "verify"  } };
207   unsigned int i = 0;
208
209   for (i = 0; i < (sizeof (worker_functions) / sizeof (*worker_functions)); i++)
210     {
211       printf ("%s: ", worker_functions[i].identifier);
212       benchmark (worker_functions[i].worker, context);
213     }
214 }
215
216 static void
217 context_init (context_t context, gcry_sexp_t key_secret, gcry_sexp_t key_public)
218 {
219   gcry_error_t err = GPG_ERR_NO_ERROR;
220   unsigned int key_size = 0;
221   gcry_mpi_t data = NULL;
222   gcry_sexp_t data_sexp = NULL;
223
224   key_size = gcry_pk_get_nbits (key_secret);
225   assert (key_size);
226
227   data = gcry_mpi_new (key_size);
228   assert (data);
229
230   gcry_mpi_randomize (data, key_size, GCRY_STRONG_RANDOM);
231   gcry_mpi_clear_bit (data, key_size - 1);
232   err = gcry_sexp_build (&data_sexp, NULL,
233                          "(data (flags raw) (value %m))",
234                          data);
235   assert (! err);
236   gcry_mpi_release (data);
237
238   context->key_secret = key_secret;
239   context->key_public = key_public;
240   context->data = data_sexp;
241   context->data_encrypted = NULL;
242   context->data_signed = NULL;
243 }
244
245 static void
246 context_destroy (context_t context)
247 {
248   gcry_sexp_release (context->key_secret);
249   gcry_sexp_release (context->key_public);
250   gcry_sexp_release (context->data);
251 }
252
253 static void
254 process_key_pair_file (const char *key_pair_file)
255 {
256   gcry_error_t err = GPG_ERR_NO_ERROR;
257   void *key_pair_buffer = NULL;
258   gcry_sexp_t key_pair_sexp = NULL;
259   gcry_sexp_t key_secret_sexp = NULL;
260   gcry_sexp_t key_public_sexp = NULL;
261   struct context context = { NULL };
262   struct stat statbuf;
263   int key_pair_fd = -1;
264   int ret = 0;
265
266   ret = stat (key_pair_file, &statbuf);
267   assert (! ret);
268
269   key_pair_fd = open (key_pair_file, O_RDONLY);
270   assert (key_pair_fd != -1);
271
272   key_pair_buffer = mmap (NULL, statbuf.st_size, PROT_READ,
273                           MAP_PRIVATE, key_pair_fd, 0);
274   assert (key_pair_buffer != MAP_FAILED);
275
276   err = gcry_sexp_sscan (&key_pair_sexp, NULL,
277                          key_pair_buffer, statbuf.st_size);
278   assert (! err);
279
280   key_secret_sexp = gcry_sexp_find_token (key_pair_sexp, "private-key", 0);
281   assert (key_secret_sexp);
282   key_public_sexp = gcry_sexp_find_token (key_pair_sexp, "public-key", 0);
283   assert (key_public_sexp);
284
285   gcry_sexp_release (key_pair_sexp);
286   ret = munmap (key_pair_buffer, statbuf.st_size);
287   assert (! ret);
288   ret = close (key_pair_fd);
289   assert (! ret);
290
291   context_init (&context, key_secret_sexp, key_public_sexp);
292
293   printf ("Key file: %s\n", key_pair_file);
294   process_key_pair (&context);
295   printf ("\n");
296
297   context_destroy (&context);
298 }
299
300
301 static void
302 generate_key (const char *algorithm, const char *key_size)
303 {
304   gcry_error_t err = GPG_ERR_NO_ERROR;
305   size_t key_pair_buffer_size = 0;
306   char *key_pair_buffer = NULL;
307   gcry_sexp_t key_spec = NULL;
308   gcry_sexp_t key_pair = NULL;
309
310   err = gcry_sexp_build (&key_spec, NULL,
311                          "(genkey (%s (nbits %s)))",
312                          algorithm, key_size);
313   assert (! err);
314
315   err = gcry_pk_genkey (&key_pair, key_spec);
316   assert (! err);
317
318   key_pair_buffer_size = gcry_sexp_sprint (key_pair, GCRYSEXP_FMT_ADVANCED,
319                                            NULL, 0);
320   key_pair_buffer = malloc (key_pair_buffer_size);
321   assert (key_pair_buffer);
322
323   gcry_sexp_sprint (key_pair, GCRYSEXP_FMT_ADVANCED,
324                     key_pair_buffer, key_pair_buffer_size);
325
326   printf ("%.*s", key_pair_buffer_size, key_pair_buffer);
327 }
328
329
330
331 int
332 main (int argc, char **argv)
333 {
334   int last_argc = -1;
335   int genkey_mode = 0;
336
337   if (argc)
338     { argc--; argv++; }
339
340   gcry_control (GCRYCTL_DISABLE_SECMEM);
341   if (!gcry_check_version (GCRYPT_VERSION))
342     {
343       fprintf (stderr, PGM ": version mismatch\n");
344       exit (1);
345     }
346
347   while (argc && last_argc != argc )
348     {
349       last_argc = argc;
350       if (!strcmp (*argv, "--"))
351         {
352           argc--; argv++;
353           break;
354         }
355       else if (!strcmp (*argv, "--help"))
356         {
357           puts ("Usage: " PGM " [OPTIONS] [FILES]\n"
358                 "Various public key tests:\n\n"
359                 "  Default is to process all given key files\n\n"
360                 "  --genkey ALGONAME SIZE  Generate a public key\n"
361                 "\n"
362                 "  --verbose    enable extra informational output\n"
363                 "  --debug      enable additional debug output\n"
364                 "  --help       display this help and exit\n\n");
365           exit (0);
366         }
367       else if (!strcmp (*argv, "--verbose"))
368         {
369           verbose = 1;
370           argc--; argv++;
371         }
372       else if (!strcmp (*argv, "--debug"))
373         {
374           verbose = debug = 1;
375           argc--; argv++;
376         }
377       else if (!strcmp (*argv, "--genkey"))
378         {
379           genkey_mode = 1;
380           argc--; argv++;
381         }
382     }          
383
384   if (genkey_mode)
385     {
386       /* No valuable keys are create, so we can speed up our RNG. */
387       gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
388       if (debug)
389         gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
390     }
391   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
392
393   
394   if (genkey_mode && argc == 2)
395     {
396       generate_key (argv[0], argv[1]);
397     }
398   else if (!genkey_mode && argc)
399     {
400       int i;
401       
402       for (i = 0; i < argc; i++)
403         process_key_pair_file (argv[i]);
404     }
405   else
406     {
407       fprintf (stderr, "usage: " PGM
408                " [OPTIONS] [FILES] (try --help for more information)\n");
409       exit (1);
410     }
411   
412   return 0;
413 }