summaryrefslogtreecommitdiff
path: root/tests/rsacvt.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2009-02-11 11:53:54 +0000
committerWerner Koch <wk@gnupg.org>2009-02-11 11:53:54 +0000
commit3e4b80a1ce8d789e004cedcf1e8a5e7681afb511 (patch)
treec32f7362842ba888631e272862ac54862bcf8db8 /tests/rsacvt.c
parent214ea62a185b7868f90a72d03ada9e36a85560d8 (diff)
downloadlibgcrypt-3e4b80a1ce8d789e004cedcf1e8a5e7681afb511.tar.gz
Add a new helper tool
Diffstat (limited to 'tests/rsacvt.c')
-rw-r--r--tests/rsacvt.c407
1 files changed, 407 insertions, 0 deletions
diff --git a/tests/rsacvt.c b/tests/rsacvt.c
new file mode 100644
index 00000000..78dad70f
--- /dev/null
+++ b/tests/rsacvt.c
@@ -0,0 +1,407 @@
+/* rsacvt.c - A debug tool to convert RSA formats.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This file is part of Libgcrypt.
+
+ Libgcrypt is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ Libgcrypt is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Input data format:
+
+=======
+# A hash denotes a comment line
+e861b700e17e8afe68[...]f1
+f7a7ca5367c661f8e6[...]61
+10001
+
+# After an empty line another input block may follow.
+7861b700e17e8afe68[...]f3
+e7a7ca5367c661f8e6[...]71
+3
+=========
+
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <ctype.h>
+#ifdef HAVE_W32_SYSTEM
+# include <fcntl.h> /* We need setmode(). */
+#else
+# include <signal.h>
+#endif
+#include <assert.h>
+#include <unistd.h>
+
+#ifdef _GCRYPT_IN_LIBGCRYPT
+# include "../src/gcrypt.h"
+#else
+# include <gcrypt.h>
+# define PACKAGE_BUGREPORT "devnull@example.org"
+# define PACKAGE_VERSION "[build on " __DATE__ " " __TIME__ "]"
+#endif
+
+
+#define PGM "rsacvt"
+
+#define my_isascii(c) (!((c) & 0x80))
+#define digitp(p) (*(p) >= '0' && *(p) <= '9')
+#define hexdigitp(a) (digitp (a) \
+ || (*(a) >= 'A' && *(a) <= 'F') \
+ || (*(a) >= 'a' && *(a) <= 'f'))
+#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
+ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
+#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+#define DIMof(type,member) DIM(((type *)0)->member)
+
+
+/* Verbose mode flag. */
+static int verbose;
+
+/* Prefix output with labels. */
+static int with_labels;
+
+/* Do not suppress leading zeroes. */
+static int keep_lz;
+
+
+/* Print a error message and exit the process with an error code. */
+static void
+die (const char *format, ...)
+{
+ va_list arg_ptr;
+
+ va_start (arg_ptr, format);
+ fputs (PGM ": ", stderr);
+ vfprintf (stderr, format, arg_ptr);
+ va_end (arg_ptr);
+ exit (1);
+}
+
+
+static char *
+read_textline (FILE *fp)
+{
+ char line[4096];
+ char *p;
+ int any = 0;
+
+ /* Read line but skip over initial empty lines. */
+ do
+ {
+ do
+ {
+ if (!fgets (line, sizeof line, fp))
+ {
+ if (feof (fp))
+ return NULL;
+ die ("error reading input line: %s\n", strerror (errno));
+ }
+ p = strchr (line, '\n');
+ if (p)
+ *p = 0;
+ p = line + (*line? (strlen (line)-1):0);
+ for ( ;p > line; p--)
+ if (my_isascii (*p) && isspace (*p))
+ *p = 0;
+ }
+ while (!any && !*line);
+ any = 1;
+ }
+ while (*line == '#'); /* Always skip comment lines. */
+ if (verbose > 1)
+ fprintf (stderr, PGM ": received line: %s\n", line);
+ return gcry_xstrdup (line);
+}
+
+
+static gcry_mpi_t
+read_hexmpi_line (FILE *fp, int *got_eof)
+{
+ gpg_error_t err;
+ gcry_mpi_t a;
+ char *line;
+
+ *got_eof = 0;
+ line = read_textline (fp);
+ if (!line)
+ {
+ *got_eof = 1;
+ return NULL;
+ }
+ err = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, line, 0, NULL);
+ gcry_free (line);
+ if (err)
+ a = NULL;
+ return a;
+}
+
+
+static int
+skip_to_empty_line (FILE *fp)
+{
+ char line[256];
+ char *p;
+
+ do
+ {
+ if (!fgets (line, sizeof line, fp))
+ {
+ if (feof (fp))
+ return -1;
+ die ("error reading input line: %s\n", strerror (errno));
+ }
+ p = strchr (line, '\n');
+ if (p)
+ *p =0;
+ }
+ while (*line);
+ return 0;
+}
+
+
+/* Print an MPI on a line. */
+static void
+print_mpi_line (const char *label, gcry_mpi_t a)
+{
+ unsigned char *buf, *p;
+ gcry_error_t err;
+ int writerr = 0;
+
+ if (with_labels && label)
+ printf ("%s = ", label);
+
+ err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buf, NULL, a);
+ if (err)
+ die ("gcry_mpi_aprint failed: %s\n", gpg_strerror (err));
+
+ p = buf;
+ if (!keep_lz && p[0] == '0' && p[1] == '0' && p[2])
+ p += 2;
+
+ printf ("%s\n", p);
+ if (ferror (stdout))
+ writerr++;
+ if (!writerr && fflush (stdout) == EOF)
+ writerr++;
+ if (writerr)
+ die ("writing output failed: %s\n", strerror (errno));
+ gcry_free (buf);
+}
+
+
+/* Compute and print missing RSA parameters. */
+static void
+compute_missing (gcry_mpi_t rsa_p, gcry_mpi_t rsa_q, gcry_mpi_t rsa_e)
+{
+ gcry_mpi_t rsa_n, rsa_d, rsa_pm1, rsa_qm1, rsa_u;
+ gcry_mpi_t phi, tmp_g, tmp_f;
+
+ rsa_n = gcry_mpi_new (0);
+ rsa_d = gcry_mpi_new (0);
+ rsa_pm1 = gcry_mpi_new (0);
+ rsa_qm1 = gcry_mpi_new (0);
+ rsa_u = gcry_mpi_new (0);
+
+ phi = gcry_mpi_new (0);
+ tmp_f = gcry_mpi_new (0);
+ tmp_g = gcry_mpi_new (0);
+
+ /* Check that p < q; if not swap p and q. */
+ if (gcry_mpi_cmp (rsa_p, rsa_q) > 0)
+ {
+ fprintf (stderr, PGM ": swapping p and q\n");
+ gcry_mpi_swap (rsa_p, rsa_q);
+ }
+
+ gcry_mpi_mul (rsa_n, rsa_p, rsa_q);
+
+
+ /* Compute the Euler totient: phi = (p-1)(q-1) */
+ gcry_mpi_sub_ui (rsa_pm1, rsa_p, 1);
+ gcry_mpi_sub_ui (rsa_qm1, rsa_q, 1);
+ gcry_mpi_mul (phi, rsa_pm1, rsa_qm1);
+
+ if (!gcry_mpi_gcd (tmp_g, rsa_e, phi))
+ die ("parameter 'e' does match 'p' and 'q'\n");
+
+ /* Compute: f = lcm(p-1,q-1) = phi / gcd(p-1,q-1) */
+ gcry_mpi_gcd (tmp_g, rsa_pm1, rsa_qm1);
+ gcry_mpi_div (tmp_f, NULL, phi, tmp_g, -1);
+
+ /* Compute the secret key: d = e^{-1} mod lcm(p-1,q-1) */
+ gcry_mpi_invm (rsa_d, rsa_e, tmp_f);
+
+ /* Compute the CRT helpers: d mod (p-1), d mod (q-1) */
+ gcry_mpi_mod (rsa_pm1, rsa_d, rsa_pm1);
+ gcry_mpi_mod (rsa_qm1, rsa_d, rsa_pm1);
+
+ /* Compute the CRT value: u = p^{-1} mod q */
+ gcry_mpi_invm (rsa_u, rsa_p, rsa_q);
+
+ gcry_mpi_release (phi);
+ gcry_mpi_release (tmp_f);
+ gcry_mpi_release (tmp_g);
+
+ /* Print everything. */
+ print_mpi_line ("n", rsa_n);
+ print_mpi_line ("e", rsa_e);
+ print_mpi_line ("d", rsa_d);
+ print_mpi_line ("p", rsa_p);
+ print_mpi_line ("q", rsa_q);
+ print_mpi_line ("dmp1", rsa_pm1);
+ print_mpi_line ("dmq1", rsa_qm1);
+ print_mpi_line ("u", rsa_u);
+
+ gcry_mpi_release (rsa_n);
+ gcry_mpi_release (rsa_d);
+ gcry_mpi_release (rsa_pm1);
+ gcry_mpi_release (rsa_qm1);
+ gcry_mpi_release (rsa_u);
+}
+
+
+
+static void
+usage (int show_help)
+{
+ if (!show_help)
+ {
+ fputs ("usage: " PGM
+ " [OPTION] [FILE] (try --help for more information)\n", stderr);
+ exit (2);
+ }
+ fputs
+ ("Usage: " PGM " [OPTIONS] [FILE]\n"
+ "Take RSA parameters p, n, e and compute missing parameters.\n"
+ "OPTIONS:\n"
+ " --version Print version information\n"
+ " --verbose Print additional information\n"
+ " --labels Prefix output with labels\n"
+ " --keep-lz Keep all leading zeroes in the output\n"
+ " --help Print this text\n"
+ "With no FILE, or if FILE is -, read standard input.\n"
+ "Report bugs to " PACKAGE_BUGREPORT ".\n" , stdout);
+ exit (0);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ int last_argc = -1;
+ FILE *input;
+ gcry_mpi_t rsa_p, rsa_q, rsa_e;
+ int got_eof;
+ int any = 0;
+
+ if (argc)
+ { argc--; argv++; }
+
+ while (argc && last_argc != argc )
+ {
+ last_argc = argc;
+ if (!strcmp (*argv, "--"))
+ {
+ argc--; argv++;
+ break;
+ }
+ else if (!strcmp (*argv, "--help"))
+ {
+ usage (1);
+ }
+ else if (!strcmp (*argv, "--version"))
+ {
+ fputs (PGM " (Libgcrypt) " PACKAGE_VERSION "\n", stdout);
+ printf ("libgcrypt %s\n", gcry_check_version (NULL));
+ exit (0);
+ }
+ else if (!strcmp (*argv, "--verbose"))
+ {
+ verbose++;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--labels"))
+ {
+ with_labels = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--keep-lz"))
+ {
+ keep_lz = 1;
+ argc--; argv++;
+ }
+ }
+
+ if (argc > 1)
+ usage (0);
+
+#if !defined (HAVE_W32_SYSTEM) && !defined (_WIN32)
+ signal (SIGPIPE, SIG_IGN);
+#endif
+
+ if (argc == 1 && strcmp (argv[0], "-"))
+ {
+ input = fopen (argv[0], "r");
+ if (!input)
+ die ("can't open `%s': %s\n", argv[0], strerror (errno));
+ }
+ else
+ input = stdin;
+
+ gcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose);
+ if (!gcry_check_version ("1.4.0"))
+ die ("Libgcrypt is not sufficient enough\n");
+ gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+
+ do
+ {
+ rsa_p = read_hexmpi_line (input, &got_eof);
+ if (!rsa_p && got_eof)
+ break;
+ if (!rsa_p)
+ die ("RSA parameter 'p' missing or not properly hex encoded\n");
+ rsa_q = read_hexmpi_line (input, &got_eof);
+ if (!rsa_q)
+ die ("RSA parameter 'q' missing or not properly hex encoded\n");
+ rsa_e = read_hexmpi_line (input, &got_eof);
+ if (!rsa_e)
+ die ("RSA parameter 'e' missing or not properly hex encoded\n");
+ got_eof = skip_to_empty_line (input);
+
+ if (any)
+ putchar ('\n');
+
+ compute_missing (rsa_p, rsa_q, rsa_e);
+
+ gcry_mpi_release (rsa_p);
+ gcry_mpi_release (rsa_q);
+ gcry_mpi_release (rsa_e);
+
+ any = 1;
+ }
+ while (!got_eof);
+
+ return 0;
+}
+