Use more odd chuck sizes for check_one_md
[libgcrypt.git] / tests / rsacvt.c
1 /* rsacvt.c  -  A debug tool to convert RSA formats.
2    Copyright (C) 2009 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* Input data format:
21
22 =======
23 # A hash denotes a comment line
24 e861b700e17e8afe68[...]f1
25 f7a7ca5367c661f8e6[...]61
26 10001
27
28 # After an empty line another input block may follow.
29 7861b700e17e8afe68[...]f3
30 e7a7ca5367c661f8e6[...]71
31 3
32 =========
33
34 */
35
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <stdarg.h>
44 #include <errno.h>
45 #include <ctype.h>
46 #ifdef HAVE_W32_SYSTEM
47 # include <fcntl.h> /* We need setmode().  */
48 #else
49 # include <signal.h>
50 #endif
51 #include <assert.h>
52 #include <unistd.h>
53
54 #ifdef _GCRYPT_IN_LIBGCRYPT
55 # include "../src/gcrypt-int.h"
56 #else
57 # include <gcrypt.h>
58 # define PACKAGE_BUGREPORT "devnull@example.org"
59 # define PACKAGE_VERSION "[build on " __DATE__ " " __TIME__ "]"
60 #endif
61
62
63 #define PGM "rsacvt"
64
65 #define my_isascii(c) (!((c) & 0x80))
66 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
67 #define hexdigitp(a) (digitp (a)                     \
68                       || (*(a) >= 'A' && *(a) <= 'F')  \
69                       || (*(a) >= 'a' && *(a) <= 'f'))
70 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
71                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
72 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
73 #define DIM(v)               (sizeof(v)/sizeof((v)[0]))
74 #define DIMof(type,member)   DIM(((type *)0)->member)
75
76
77 /* Verbose mode flag.  */
78 static int verbose;
79
80 /* Prefix output with labels.  */
81 static int with_labels;
82
83 /* Do not suppress leading zeroes.  */
84 static int keep_lz;
85
86 /* Create parameters as specified by OpenPGP (rfc4880).  That is we
87    don't store dmp1 and dmp1 but d and make sure that p is less than  q.  */
88 static int openpgp_mode;
89
90
91 /* Print a error message and exit the process with an error code.  */
92 static void
93 die (const char *format, ...)
94 {
95   va_list arg_ptr;
96
97   va_start (arg_ptr, format);
98   fputs (PGM ": ", stderr);
99   vfprintf (stderr, format, arg_ptr);
100   va_end (arg_ptr);
101   exit (1);
102 }
103
104
105 static char *
106 read_textline (FILE *fp)
107 {
108   char line[4096];
109   char *p;
110   int any = 0;
111
112   /* Read line but skip over initial empty lines.  */
113   do
114     {
115       do
116         {
117           if (!fgets (line, sizeof line, fp))
118             {
119               if (feof (fp))
120                 return NULL;
121               die ("error reading input line: %s\n", strerror (errno));
122             }
123           p = strchr (line, '\n');
124           if (p)
125             *p = 0;
126           p = line + (*line? (strlen (line)-1):0);
127           for ( ;p > line; p--)
128             if (my_isascii (*p) && isspace (*p))
129               *p = 0;
130         }
131       while (!any && !*line);
132       any = 1;
133     }
134   while (*line == '#');  /* Always skip comment lines.  */
135   if (verbose > 1)
136     fprintf (stderr, PGM ": received line: %s\n", line);
137   return gcry_xstrdup (line);
138 }
139
140
141 static gcry_mpi_t
142 read_hexmpi_line (FILE *fp, int *got_eof)
143 {
144   gpg_error_t err;
145   gcry_mpi_t a;
146   char *line;
147
148   *got_eof = 0;
149   line = read_textline (fp);
150   if (!line)
151     {
152       *got_eof = 1;
153       return NULL;
154     }
155   err = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, line, 0, NULL);
156   gcry_free (line);
157   if (err)
158     a = NULL;
159   return a;
160 }
161
162
163 static int
164 skip_to_empty_line (FILE *fp)
165 {
166   char line[256];
167   char *p;
168
169   do
170     {
171       if (!fgets (line, sizeof line, fp))
172         {
173           if (feof (fp))
174             return -1;
175           die ("error reading input line: %s\n", strerror (errno));
176         }
177       p = strchr (line, '\n');
178       if (p)
179         *p =0;
180     }
181   while (*line);
182   return 0;
183 }
184
185
186 /* Print an MPI on a line.  */
187 static void
188 print_mpi_line (const char *label, gcry_mpi_t a)
189 {
190   unsigned char *buf, *p;
191   gcry_error_t err;
192   int writerr = 0;
193
194   if (with_labels && label)
195     printf ("%s = ", label);
196
197   err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buf, NULL, a);
198   if (err)
199     die ("gcry_mpi_aprint failed: %s\n", gpg_strerror (err));
200
201   p = buf;
202   if (!keep_lz && p[0] == '0' && p[1] == '0' && p[2])
203     p += 2;
204
205   printf ("%s\n", p);
206   if (ferror (stdout))
207     writerr++;
208   if (!writerr && fflush (stdout) == EOF)
209     writerr++;
210   if (writerr)
211     die ("writing output failed: %s\n", strerror (errno));
212   gcry_free (buf);
213 }
214
215
216 /* Compute and print missing RSA parameters.  */
217 static void
218 compute_missing (gcry_mpi_t rsa_p, gcry_mpi_t rsa_q, gcry_mpi_t rsa_e)
219 {
220   gcry_mpi_t rsa_n, rsa_d, rsa_pm1, rsa_qm1, rsa_u;
221   gcry_mpi_t phi, tmp_g, tmp_f;
222
223   rsa_n = gcry_mpi_new (0);
224   rsa_d = gcry_mpi_new (0);
225   rsa_pm1 = gcry_mpi_new (0);
226   rsa_qm1 = gcry_mpi_new (0);
227   rsa_u = gcry_mpi_new (0);
228
229   phi = gcry_mpi_new (0);
230   tmp_f = gcry_mpi_new (0);
231   tmp_g = gcry_mpi_new (0);
232
233   /* Check that p < q; if not swap p and q.  */
234   if (openpgp_mode && gcry_mpi_cmp (rsa_p, rsa_q) > 0)
235     {
236       fprintf (stderr, PGM ": swapping p and q\n");
237       gcry_mpi_swap (rsa_p, rsa_q);
238     }
239
240   gcry_mpi_mul (rsa_n, rsa_p, rsa_q);
241
242
243   /* Compute the Euler totient:  phi = (p-1)(q-1)  */
244   gcry_mpi_sub_ui (rsa_pm1, rsa_p, 1);
245   gcry_mpi_sub_ui (rsa_qm1, rsa_q, 1);
246   gcry_mpi_mul (phi, rsa_pm1, rsa_qm1);
247
248   if (!gcry_mpi_gcd (tmp_g, rsa_e, phi))
249     die ("parameter 'e' does match 'p' and 'q'\n");
250
251   /* Compute: f = lcm(p-1,q-1) = phi / gcd(p-1,q-1) */
252   gcry_mpi_gcd (tmp_g, rsa_pm1, rsa_qm1);
253   gcry_mpi_div (tmp_f, NULL, phi, tmp_g, -1);
254
255   /* Compute the secret key:  d = e^{-1} mod lcm(p-1,q-1) */
256   gcry_mpi_invm (rsa_d, rsa_e, tmp_f);
257
258   /* Compute the CRT helpers: d mod (p-1), d mod (q-1)   */
259   gcry_mpi_mod (rsa_pm1, rsa_d, rsa_pm1);
260   gcry_mpi_mod (rsa_qm1, rsa_d, rsa_qm1);
261
262   /* Compute the CRT value:   OpenPGP:    u = p^{-1} mod q
263                              Standard: iqmp = q^{-1} mod p */
264   if (openpgp_mode)
265     gcry_mpi_invm (rsa_u, rsa_p, rsa_q);
266   else
267     gcry_mpi_invm (rsa_u, rsa_q, rsa_p);
268
269   gcry_mpi_release (phi);
270   gcry_mpi_release (tmp_f);
271   gcry_mpi_release (tmp_g);
272
273   /* Print everything.  */
274   print_mpi_line ("n", rsa_n);
275   print_mpi_line ("e", rsa_e);
276   if (openpgp_mode)
277     print_mpi_line ("d", rsa_d);
278   print_mpi_line ("p", rsa_p);
279   print_mpi_line ("q", rsa_q);
280   if (openpgp_mode)
281     print_mpi_line ("u", rsa_u);
282   else
283     {
284       print_mpi_line ("dmp1", rsa_pm1);
285       print_mpi_line ("dmq1", rsa_qm1);
286       print_mpi_line ("iqmp", rsa_u);
287     }
288
289   gcry_mpi_release (rsa_n);
290   gcry_mpi_release (rsa_d);
291   gcry_mpi_release (rsa_pm1);
292   gcry_mpi_release (rsa_qm1);
293   gcry_mpi_release (rsa_u);
294 }
295
296
297 \f
298 static void
299 usage (int show_help)
300 {
301   if (!show_help)
302     {
303       fputs ("usage: " PGM
304              " [OPTION] [FILE] (try --help for more information)\n", stderr);
305       exit (2);
306     }
307   fputs
308     ("Usage: " PGM " [OPTIONS] [FILE]\n"
309      "Take RSA parameters p, n, e and compute missing parameters.\n"
310      "OPTIONS:\n"
311      "  --openpgp        Compute as specified by RFC4880\n"
312      "  --labels         Prefix output with labels\n"
313      "  --keep-lz        Keep all leading zeroes in the output\n"
314      "  --verbose        Print additional information\n"
315      "  --version        Print version information\n"
316      "  --help           Print this text\n"
317      "With no FILE, or if FILE is -, read standard input.\n"
318      "Report bugs to " PACKAGE_BUGREPORT ".\n" , stdout);
319   exit (0);
320 }
321
322
323 int
324 main (int argc, char **argv)
325 {
326   int last_argc = -1;
327   FILE *input;
328   gcry_mpi_t  rsa_p, rsa_q, rsa_e;
329   int got_eof;
330   int any = 0;
331
332   if (argc)
333     { argc--; argv++; }
334
335   while (argc && last_argc != argc )
336     {
337       last_argc = argc;
338       if (!strcmp (*argv, "--"))
339         {
340           argc--; argv++;
341           break;
342         }
343       else if (!strcmp (*argv, "--help"))
344         {
345           usage (1);
346         }
347       else if (!strcmp (*argv, "--version"))
348         {
349           fputs (PGM " (Libgcrypt) " PACKAGE_VERSION "\n", stdout);
350           printf ("libgcrypt %s\n", gcry_check_version (NULL));
351           exit (0);
352         }
353       else if (!strcmp (*argv, "--verbose"))
354         {
355           verbose++;
356           argc--; argv++;
357         }
358       else if (!strcmp (*argv, "--labels"))
359         {
360           with_labels = 1;
361           argc--; argv++;
362         }
363       else if (!strcmp (*argv, "--keep-lz"))
364         {
365           keep_lz = 1;
366           argc--; argv++;
367         }
368       else if (!strcmp (*argv, "--openpgp"))
369         {
370           openpgp_mode = 1;
371           argc--; argv++;
372         }
373     }
374
375   if (argc > 1)
376     usage (0);
377
378 #if !defined (HAVE_W32_SYSTEM) && !defined (_WIN32)
379   signal (SIGPIPE, SIG_IGN);
380 #endif
381
382   if (argc == 1 && strcmp (argv[0], "-"))
383     {
384       input = fopen (argv[0], "r");
385       if (!input)
386         die ("can't open `%s': %s\n", argv[0], strerror (errno));
387     }
388   else
389     input = stdin;
390
391   gcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose);
392   if (!gcry_check_version ("1.4.0"))
393     die ("Libgcrypt is not sufficient enough\n");
394   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
395   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
396
397   do
398     {
399       rsa_p = read_hexmpi_line (input, &got_eof);
400       if (!rsa_p && got_eof)
401         break;
402       if (!rsa_p)
403         die ("RSA parameter 'p' missing or not properly hex encoded\n");
404       rsa_q = read_hexmpi_line (input, &got_eof);
405       if (!rsa_q)
406         die ("RSA parameter 'q' missing or not properly hex encoded\n");
407       rsa_e = read_hexmpi_line (input, &got_eof);
408       if (!rsa_e)
409         die ("RSA parameter 'e' missing or not properly hex encoded\n");
410       got_eof = skip_to_empty_line (input);
411
412       if (any)
413         putchar ('\n');
414
415       compute_missing (rsa_p, rsa_q, rsa_e);
416
417       gcry_mpi_release (rsa_p);
418       gcry_mpi_release (rsa_q);
419       gcry_mpi_release (rsa_e);
420
421       any = 1;
422     }
423   while (!got_eof);
424
425   return 0;
426 }