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