#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>
#else
# include <signal.h>
#endif
#include <assert.h>
#include <unistd.h>
#ifdef _GCRYPT_IN_LIBGCRYPT
# include "../src/gcrypt-int.h"
#else
# include <gcrypt.h>
# define PACKAGE_BUGREPORT "devnull@example.org"
# define PACKAGE_VERSION "[build on " __DATE__ " " __TIME__ "]"
#endif
#define PGM "rsacvt"
#include "t-common.h"
static int with_labels;
static int keep_lz;
static int openpgp_mode;
static char *
read_textline (FILE *fp)
{
char line[4096];
char *p;
int any = 0;
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 == '#');
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;
}
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);
}
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);
if (openpgp_mode && 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);
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");
gcry_mpi_gcd (tmp_g, rsa_pm1, rsa_qm1);
gcry_mpi_div (tmp_f, NULL, phi, tmp_g, -1);
gcry_mpi_invm (rsa_d, rsa_e, tmp_f);
gcry_mpi_mod (rsa_pm1, rsa_d, rsa_pm1);
gcry_mpi_mod (rsa_qm1, rsa_d, rsa_qm1);
if (openpgp_mode)
gcry_mpi_invm (rsa_u, rsa_p, rsa_q);
else
gcry_mpi_invm (rsa_u, rsa_q, rsa_p);
gcry_mpi_release (phi);
gcry_mpi_release (tmp_f);
gcry_mpi_release (tmp_g);
print_mpi_line ("n", rsa_n);
print_mpi_line ("e", rsa_e);
if (openpgp_mode)
print_mpi_line ("d", rsa_d);
print_mpi_line ("p", rsa_p);
print_mpi_line ("q", rsa_q);
if (openpgp_mode)
print_mpi_line ("u", rsa_u);
else
{
print_mpi_line ("dmp1", rsa_pm1);
print_mpi_line ("dmq1", rsa_qm1);
print_mpi_line ("iqmp", 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"
" --openpgp Compute as specified by RFC4880\n"
" --labels Prefix output with labels\n"
" --keep-lz Keep all leading zeroes in the output\n"
" --verbose Print additional information\n"
" --version Print version information\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++;
}
else if (!strcmp (*argv, "--openpgp"))
{
openpgp_mode = 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;
xgcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose);
if (!gcry_check_version ("1.4.0"))
die ("Libgcrypt is not sufficient enough\n");
xgcry_control (GCRYCTL_DISABLE_SECMEM, 0);
xgcry_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;
}