lsh_keygen.c 5.43 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
2
/* lsh_keygen.c
 *
Niels Möller's avatar
Niels Möller committed
3
 * Generic key-generation program. Writes a spki-packaged private key
Niels Möller's avatar
Niels Möller committed
4
5
6
 * on stdout. You would usually pipe this to some other program to
 * extract the public key, encrypt the private key, and save the
 * results in two separate files.
Niels Möller's avatar
Niels Möller committed
7
 *
Niels Möller's avatar
Niels Möller committed
8
 * $Id$ */
Niels Möller's avatar
Niels Möller committed
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 Niels Mller
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
J.H.M. Dassen's avatar
J.H.M. Dassen committed
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Niels Möller's avatar
Niels Möller committed
27
28
 */

Niels Möller's avatar
Niels Möller committed
29
#include "dsa_keygen.h"
Niels Möller's avatar
Niels Möller committed
30

Niels Möller's avatar
Niels Möller committed
31
#include "blocking_write.h"
Niels Möller's avatar
Niels Möller committed
32
33
34
35
#include "crypto.h"
#include "format.h"
#include "publickey_crypto.h"
#include "randomness.h"
Niels Möller's avatar
Niels Möller committed
36
37
#include "sexp.h"
#include "werror.h"
38
#include "xalloc.h"
Niels Möller's avatar
Niels Möller committed
39

40
#include "lsh_argp.h"
Niels Möller's avatar
Niels Möller committed
41
42

#include <stdio.h>
Niels Möller's avatar
Niels Möller committed
43
#include <stdlib.h>
Niels Möller's avatar
Niels Möller committed
44

45
#if HAVE_UNISTD_H
Niels Möller's avatar
Niels Möller committed
46
#include <unistd.h>
47
#endif
Niels Möller's avatar
Niels Möller committed
48

49
50
51
52
53
54
55
56
57
58
59
60
61
#include "lsh_keygen.c.x"

/* Option parsing */

/* GABA:
   (class
     (name lsh_keygen_options)
     (vars
       (style . sexp_argp_state)
       ; (algorithm . int)
       (level . int)))
*/

Niels Möller's avatar
Niels Möller committed
62
static struct lsh_keygen_options *
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
make_lsh_keygen_options(void)
{
  NEW(lsh_keygen_options, self);
  self->style = SEXP_TRANSPORT;
  self->level = 8;

  return self;
}

static const struct argp_option
main_options[] =
{
  /* Name, key, arg-name, flags, doc, group */
  { "algorithm", 'a', "Algorithm", 0, "Default is to generate dsa keys", 0 },
  { "nist-level", 'l', "Security level", 0, "Level 0 uses 512-bit primes, "
    "level 8 uses 1024 bit primes. Default is 8.", 0 },
  { NULL, 0, NULL, 0, NULL, 0 }
};

static const struct argp_child
main_argp_children[] =
{
  { &sexp_output_argp, 0, NULL, 0 },
  { &werror_argp, 0, "", 0 },
  { NULL, 0, NULL, 0}
};

static error_t
main_argp_parser(int key, char *arg UNUSED, struct argp_state *state)
{
  CAST(lsh_keygen_options, self, state->input);

  switch(key)
    {
    default:
      return ARGP_ERR_UNKNOWN;
    case ARGP_KEY_INIT:
      state->child_inputs[0] = &self->style;
      state->child_inputs[1] = NULL;
      break;
    case ARGP_KEY_ARG:
      argp_error(state, "Spurious arguments.");
      break;
    case 'l':
	{
	  char *end;
	  long l = strtol(optarg, &end, 0);
	      
	  if (!*arg || *end)
	    {
	      argp_error(state, "Invalid security level.");
	      break;
	    }
	  if ( (l<0) || (l > 8))
	    {
	      argp_error(state, "Security level should be in the range 0-8.");
	      break;
	    }
	  self->level = l;
	  break;
	}

    case 'a':
      if (strcmp(arg, "dsa"))
	argp_error(state, "Sorry, doesn't support any algorithm but dsa.");

      break;
      
    }
  return 0;
}

static const struct argp
main_argp =
{ main_options, main_argp_parser, 
  "[-l LEVEL] [-a dsa]",
  ( "Generates a new private key for the given algorithm and security level.\v"
    "You will usually want to pipe the new key into a program like lsh_writekey, "
    "to split it into its private and public parts, and optionally encrypt "
    "the private information."),
  main_argp_children,
144
  NULL, NULL
145
146
};

Niels Möller's avatar
Niels Möller committed
147

Niels Möller's avatar
Niels Möller committed
148
149
150
151
152
153
154
155
156
157
158
159
static void
do_lsh_keygen_handler(struct exception_handler *s UNUSED,
		      const struct exception *e)
{
  werror("lsh_keygen: %z\n", e->msg);

  exit(EXIT_FAILURE);
}

static struct exception_handler handler =
STATIC_EXCEPTION_HANDLER(do_lsh_keygen_handler, NULL);

Niels Möller's avatar
Niels Möller committed
160
161
int main(int argc, char **argv)
{
162
163
  struct lsh_keygen_options * options
    = make_lsh_keygen_options();
164
  
Niels Möller's avatar
Niels Möller committed
165
  struct dsa_public public;
Niels Möller's avatar
Niels Möller committed
166
167
168
169
  mpz_t x;
  
  mpz_t t;
  struct randomness *r;
170

171
172
  argp_parse(&main_argp, argc, argv, 0, NULL, options);
  
Niels Möller's avatar
Niels Möller committed
173
174
175
176
177
178
179
180
181
  mpz_init(public.p);
  mpz_init(public.q);
  mpz_init(public.g);
  mpz_init(public.y);

  mpz_init(x);
  
  mpz_init(t);

Niels Möller's avatar
Niels Möller committed
182
  r = make_poor_random(&sha1_algorithm, NULL);
183
  dsa_nist_gen(public.p, public.q, r, options->level);
Niels Möller's avatar
Niels Möller committed
184

185
186
  debug("%xn\n"
	"%xn\n", public.p, public.q);
Niels Möller's avatar
Niels Möller committed
187
188

  /* Sanity check. */
Niels Möller's avatar
Niels Möller committed
189
  if (!mpz_probab_prime_p(public.p, 10))
Niels Möller's avatar
Niels Möller committed
190
    {
191
      werror("p not a prime!\n");
Niels Möller's avatar
Niels Möller committed
192
193
194
      return 1;
    }

Niels Möller's avatar
Niels Möller committed
195
  if (!mpz_probab_prime_p(public.q, 10))
Niels Möller's avatar
Niels Möller committed
196
    {
197
      werror("q not a prime!\n");
Niels Möller's avatar
Niels Möller committed
198
199
200
      return 1;
    }

Niels Möller's avatar
Niels Möller committed
201
  mpz_fdiv_r(t, public.p, public.q);
Niels Möller's avatar
Niels Möller committed
202
203
  if (mpz_cmp_ui(t, 1))
    {
204
      fatal("q doesn't divide p-1 !\n");
Niels Möller's avatar
Niels Möller committed
205
206
207
      return 1;
    }

Niels Möller's avatar
Niels Möller committed
208
  dsa_find_generator(public.g, r, public.p, public.q);
Niels Möller's avatar
Niels Möller committed
209
210

  r = make_reasonably_random();
Niels Möller's avatar
Niels Möller committed
211
  mpz_set(t, public.q);
Niels Möller's avatar
Niels Möller committed
212
213
214
215
216
  mpz_sub_ui(t, t, 2);
  bignum_random(x, r, t);

  mpz_add_ui(x, x, 1);

Niels Möller's avatar
Niels Möller committed
217
  mpz_powm(public.y, public.g, x, public.p);
Niels Möller's avatar
Niels Möller committed
218
  
Niels Möller's avatar
Niels Möller committed
219
220
  {
    /* Now, output a private key spki structure. */
221
    struct abstract_write *output = make_blocking_write(STDOUT_FILENO, 0, &handler);
Niels Möller's avatar
Niels Möller committed
222
223
224
    
    struct lsh_string *key = sexp_format
      (sexp_l(2, sexp_z("private-key"),
Niels Möller's avatar
Niels Möller committed
225
	      sexp_l(6, sexp_z("dsa"),
Niels Möller's avatar
Niels Möller committed
226
227
228
229
230
		     sexp_l(2, sexp_z("p"), sexp_un(public.p), -1),
		     sexp_l(2, sexp_z("q"), sexp_un(public.q), -1),
		     sexp_l(2, sexp_z("g"), sexp_un(public.g), -1),
		     sexp_l(2, sexp_z("y"), sexp_un(public.y), -1),
		     sexp_l(2, sexp_z("x"), sexp_un(x), -1), -1), -1),
231
       options->style, 0);
Niels Möller's avatar
Niels Möller committed
232

233
    A_WRITE(output, key);
Niels Möller's avatar
Niels Möller committed
234
235

    return EXIT_SUCCESS;
Niels Möller's avatar
Niels Möller committed
236
  }
Niels Möller's avatar
Niels Möller committed
237
238
239
}