ChangeLog:
[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 #include <sys/times.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <time.h>
34
35 typedef struct context
36 {
37   gcry_sexp_t key_secret;
38   gcry_sexp_t key_public;
39   gcry_sexp_t data;
40   gcry_sexp_t data_encrypted;
41   gcry_sexp_t data_signed;
42 } *context_t;
43
44 typedef int (*work_t) (context_t context, unsigned int final);
45
46 static void
47 benchmark (work_t worker, context_t context)
48 {
49   clock_t timer_start, timer_stop;
50   unsigned int loop = 10;
51   unsigned int i = 0;
52   struct tms timer;
53   int ret = 0;
54
55   times (&timer);
56   timer_start = timer.tms_utime;
57   for (i = 0; i < loop; i++)
58     {
59       ret = (*worker) (context, (i + 1) == loop);
60       if (! ret)
61         break;
62     }
63   times (&timer);
64   timer_stop = timer.tms_utime;
65
66   if (ret)
67     printf ("%.0f ms\n",
68             (((double) ((timer_stop - timer_start) / loop)) / CLOCKS_PER_SEC)
69             * 10000000);
70   else
71     printf ("[skipped]\n");
72 }
73
74 static int
75 work_encrypt (context_t context, unsigned int final)
76 {
77   gcry_error_t err = GPG_ERR_NO_ERROR;
78   gcry_sexp_t data_encrypted = NULL;
79   int ret = 1;
80
81   err = gcry_pk_encrypt (&data_encrypted,
82                          context->data, context->key_public);
83   if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
84     {
85       err = GPG_ERR_NO_ERROR;
86       ret = 0;
87     }
88   else
89     {
90       assert (! err);
91
92       if (final)
93         context->data_encrypted = data_encrypted;
94       else
95         gcry_sexp_release (data_encrypted);
96     }
97
98   return ret;
99 }
100
101 static int
102 work_decrypt (context_t context, unsigned int final)
103 {
104   gcry_error_t err = GPG_ERR_NO_ERROR;
105   int ret = 1;
106
107   if (! context->data_encrypted)
108     ret = 0;
109   else
110     {
111       gcry_sexp_t data_decrypted = NULL;
112       
113       err = gcry_pk_decrypt (&data_decrypted,
114                              context->data_encrypted,
115                              context->key_secret);
116       assert (! err);
117       if (final)
118         {
119           gcry_sexp_release (context->data_encrypted);
120           context->data_encrypted = NULL;
121         }
122       gcry_sexp_release (data_decrypted);
123     }
124
125   return ret;
126 }
127
128 static int
129 work_sign (context_t context, unsigned int final)
130 {
131   gcry_error_t err = GPG_ERR_NO_ERROR;
132   gcry_sexp_t data_signed = NULL;
133   int ret = 1;
134
135   err = gcry_pk_sign (&data_signed,
136                       context->data, context->key_secret);
137   if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
138     {
139       err = GPG_ERR_NO_ERROR;
140       ret = 0;
141     }
142   else
143     {
144       assert (! err);
145
146       if (final)
147         context->data_signed = data_signed;
148       else
149         gcry_sexp_release (data_signed);
150     }
151
152   return ret;
153 }
154
155 static int
156 work_verify (context_t context, unsigned int final)
157 {
158   gcry_error_t err = GPG_ERR_NO_ERROR;
159   int ret = 1;
160
161   if (! context->data_signed)
162     ret = 0;
163   else
164     {
165       err = gcry_pk_verify (context->data_signed,
166                             context->data,
167                             context->key_public);
168       assert (! err);
169       if (final)
170         {
171           gcry_sexp_release (context->data_signed);
172           context->data_signed = NULL;
173         }
174     }
175
176   return ret;
177 }
178
179 static void
180 process_key_pair (context_t context)
181 {
182   struct
183   {
184     work_t worker;
185     const char *identifier;
186   } worker_functions[] = { { work_encrypt, "encrypt" },
187                            { work_decrypt, "decrypt" },
188                            { work_sign,    "sign"    },
189                            { work_verify,  "verify"  } };
190   unsigned int i = 0;
191
192   for (i = 0; i < (sizeof (worker_functions) / sizeof (*worker_functions)); i++)
193     {
194       printf ("%s: ", worker_functions[i].identifier);
195       benchmark (worker_functions[i].worker, context);
196     }
197 }
198
199 static void
200 context_init (context_t context, gcry_sexp_t key_secret, gcry_sexp_t key_public)
201 {
202   gcry_error_t err = GPG_ERR_NO_ERROR;
203   unsigned int key_size = 0;
204   gcry_mpi_t data = NULL;
205   gcry_sexp_t data_sexp = NULL;
206
207   key_size = gcry_pk_get_nbits (key_secret);
208   assert (key_size);
209
210   data = gcry_mpi_new (key_size);
211   assert (data);
212
213   gcry_mpi_randomize (data, key_size, GCRY_STRONG_RANDOM);
214   gcry_mpi_clear_bit (data, key_size - 1);
215   err = gcry_sexp_build (&data_sexp, NULL,
216                          "(data (flags raw) (value %m))",
217                          data);
218   assert (! err);
219   gcry_mpi_release (data);
220
221   context->key_secret = key_secret;
222   context->key_public = key_public;
223   context->data = data_sexp;
224   context->data_encrypted = NULL;
225   context->data_signed = NULL;
226 }
227
228 static void
229 context_destroy (context_t context)
230 {
231   gcry_sexp_release (context->key_secret);
232   gcry_sexp_release (context->key_public);
233   gcry_sexp_release (context->data);
234 }
235
236 static void
237 process_key_pair_file (const char *key_pair_file)
238 {
239   gcry_error_t err = GPG_ERR_NO_ERROR;
240   void *key_pair_buffer = NULL;
241   gcry_sexp_t key_pair_sexp = NULL;
242   gcry_sexp_t key_secret_sexp = NULL;
243   gcry_sexp_t key_public_sexp = NULL;
244   struct context context = { NULL };
245   struct stat statbuf;
246   int key_pair_fd = -1;
247   int ret = 0;
248
249   ret = stat (key_pair_file, &statbuf);
250   assert (! ret);
251
252   key_pair_fd = open (key_pair_file, O_RDONLY);
253   assert (key_pair_fd != -1);
254
255   key_pair_buffer = mmap (NULL, statbuf.st_size, PROT_READ,
256                           MAP_PRIVATE, key_pair_fd, 0);
257   assert (key_pair_buffer != MAP_FAILED);
258
259   err = gcry_sexp_sscan (&key_pair_sexp, NULL,
260                          key_pair_buffer, statbuf.st_size);
261   assert (! err);
262
263   key_secret_sexp = gcry_sexp_find_token (key_pair_sexp, "private-key", 0);
264   assert (key_secret_sexp);
265   key_public_sexp = gcry_sexp_find_token (key_pair_sexp, "public-key", 0);
266   assert (key_public_sexp);
267
268   gcry_sexp_release (key_pair_sexp);
269   ret = munmap (key_pair_buffer, statbuf.st_size);
270   assert (! ret);
271   ret = close (key_pair_fd);
272   assert (! ret);
273
274   context_init (&context, key_secret_sexp, key_public_sexp);
275
276   printf ("Key file: %s\n", key_pair_file);
277   process_key_pair (&context);
278   printf ("\n");
279
280   context_destroy (&context);
281 }
282
283 static const char *program_name = NULL;
284
285 static void
286 print_usage (int err)
287 {
288   fprintf (err ? stderr : stdout,
289            "Usage: %s [--help ] [ --genkey <algorithm>,<size> ] <key files ...>\n\n",
290            program_name);
291   exit (err);
292 }
293
294 static void
295 generate_key (const char *algorithm, const char *key_size)
296 {
297   gcry_error_t err = GPG_ERR_NO_ERROR;
298   size_t key_pair_buffer_size = 0;
299   char *key_pair_buffer = NULL;
300   gcry_sexp_t key_spec = NULL;
301   gcry_sexp_t key_pair = NULL;
302
303   err = gcry_sexp_build (&key_spec, NULL,
304                          "(genkey (%s (nbits %s)))",
305                          algorithm, key_size);
306   assert (! err);
307
308   err = gcry_pk_genkey (&key_pair, key_spec);
309   assert (! err);
310
311   key_pair_buffer_size = gcry_sexp_sprint (key_pair, GCRYSEXP_FMT_ADVANCED,
312                                            NULL, 0);
313   key_pair_buffer = malloc (key_pair_buffer_size);
314   assert (key_pair_buffer);
315
316   gcry_sexp_sprint (key_pair, GCRYSEXP_FMT_ADVANCED,
317                     key_pair_buffer, key_pair_buffer_size);
318
319   printf ("%.*s", key_pair_buffer_size, key_pair_buffer);
320 }
321
322 int
323 main (int argc, char **argv)
324 {
325   program_name = argc ? argv[0] : "";
326
327   gcry_control (GCRYCTL_DISABLE_SECMEM);
328   
329   if (argv[1] && ((! strcmp (argv[1], "--help"))
330                   || (! strcmp (argv[1], "-h"))))
331     print_usage (0);
332   else if (argv[1] && ((! strcmp (argv[1], "--genkey"))
333                        || (! strcmp (argv[1], "-g"))))
334     {
335       char *algorithm = NULL;
336       char *key_size = NULL;
337
338       if (argv[2])
339         {
340           algorithm = argv[2];
341           key_size = strchr (algorithm, ',');
342           if (key_size)
343             {
344               *key_size = 0;
345               key_size++;
346             }
347         }
348
349       if (algorithm && key_size)
350         generate_key (algorithm, key_size);
351       else
352         print_usage (EXIT_FAILURE);
353     }
354   else
355     {
356       unsigned int i = 0;
357
358       for (i = 1; (i < argc); i++)
359         process_key_pair_file (argv[i]);
360     }
361
362   return EXIT_SUCCESS;
363 }