lsh_keygen.c 6.7 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
62
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
144
145
146
147
#include "lsh_keygen.c.x"

/* Option parsing */

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

struct lsh_keygen_options *
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,
  NULL
};

#if 0
Niels Möller's avatar
Niels Möller committed
148
149
150
151
static void usage(void) NORETURN;

static void usage(void)
{
152
  werror("Usage: lsh_keygen [-o style] [-l nist-level] [-a dsa] [-q] [-d] [-v]\n");
Niels Möller's avatar
Niels Möller committed
153
154
  exit(1);
}
155
#endif
Niels Möller's avatar
Niels Möller committed
156

Niels Möller's avatar
Niels Möller committed
157
158
159
160
161
162
163
164
165
166
167
168
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
169
170
int main(int argc, char **argv)
{
171
172
  struct lsh_keygen_options * options
    = make_lsh_keygen_options();
173
  
Niels Möller's avatar
Niels Möller committed
174
  struct dsa_public public;
Niels Möller's avatar
Niels Möller committed
175
176
177
178
  mpz_t x;
  
  mpz_t t;
  struct randomness *r;
179

180
181
182
  argp_parse(&main_argp, argc, argv, 0, NULL, options);
  
#if 0
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  while((option = getopt(argc, argv, "a:dl:o:qv")) != -1)
    switch(option)
      {
      case 'l':
	{
	  char *end;

	  l = strtol(optarg, &end, 0);
	      
	  if (!*optarg || *end)
	    usage();

	  if ( (l<0) || (l > 8))
	    {
197
	      werror("lsh_keygen: nist-level should be in the range 0-8.\n");
198
199
200
201
202
	      usage();
	    }
	  break;
	}
      case 'a':
Niels Möller's avatar
Niels Möller committed
203
	if (strcmp(optarg, "dsa"))
204
	  {
205
	    werror("lsh_keygen: Sorry, doesn't support any algorithm but dsa.\n");
206
207
208
209
210
211
212
213
214
215
216
217
218
219
	    usage();
	  }
	break;
      case 'o':
	if (!strcmp(optarg, "transport"))
	  style = SEXP_TRANSPORT;
	else if (!strcmp(optarg, "canonical"))
	  style = SEXP_CANONICAL;
	else if (!strcmp(optarg, "advanced"))
	  style = SEXP_ADVANCED;
	else if (!strcmp(optarg, "international"))
	  style = SEXP_INTERNATIONAL;
	else
	  {
220
	    werror("lsh_keygen: Style must be one of\n"
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
		   "  'transport', 'canonical', 'advanced' or 'international'\n");
	    usage();
	  }
	break;
      case 'q':
	quiet_flag = 1;
	break;
      case 'd':
	debug_flag = 1;
	break;
      case 'v':
	verbose_flag = 1;
	break;
      default:
	usage();
      }
Niels Möller's avatar
Niels Möller committed
237
  
238
  if (argc != optind)
Niels Möller's avatar
Niels Möller committed
239
    usage();
240
#endif
Niels Möller's avatar
Niels Möller committed
241
242
243
244
245
246
247
248
249
250
251
  
  mpz_init(public.p);
  mpz_init(public.q);
  mpz_init(public.g);
  mpz_init(public.y);

  mpz_init(x);
  
  mpz_init(t);

  r = make_poor_random(&sha_algorithm, NULL);
252
  dsa_nist_gen(public.p, public.q, r, options->level);
Niels Möller's avatar
Niels Möller committed
253

254
255
  debug("%xn\n"
	"%xn\n", public.p, public.q);
Niels Möller's avatar
Niels Möller committed
256
257

  /* Sanity check. */
Niels Möller's avatar
Niels Möller committed
258
  if (!mpz_probab_prime_p(public.p, 10))
Niels Möller's avatar
Niels Möller committed
259
    {
260
      werror("p not a prime!\n");
Niels Möller's avatar
Niels Möller committed
261
262
263
      return 1;
    }

Niels Möller's avatar
Niels Möller committed
264
  if (!mpz_probab_prime_p(public.q, 10))
Niels Möller's avatar
Niels Möller committed
265
    {
266
      werror("q not a prime!\n");
Niels Möller's avatar
Niels Möller committed
267
268
269
      return 1;
    }

Niels Möller's avatar
Niels Möller committed
270
  mpz_fdiv_r(t, public.p, public.q);
Niels Möller's avatar
Niels Möller committed
271
272
  if (mpz_cmp_ui(t, 1))
    {
273
      fatal("q doesn't divide p-1 !\n");
Niels Möller's avatar
Niels Möller committed
274
275
276
      return 1;
    }

Niels Möller's avatar
Niels Möller committed
277
  dsa_find_generator(public.g, r, public.p, public.q);
Niels Möller's avatar
Niels Möller committed
278
279

  r = make_reasonably_random();
Niels Möller's avatar
Niels Möller committed
280
  mpz_set(t, public.q);
Niels Möller's avatar
Niels Möller committed
281
282
283
284
285
  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
286
  mpz_powm(public.y, public.g, x, public.p);
Niels Möller's avatar
Niels Möller committed
287
  
Niels Möller's avatar
Niels Möller committed
288
289
  {
    /* Now, output a private key spki structure. */
290
    struct abstract_write *output = make_blocking_write(STDOUT_FILENO, 0, &handler);
Niels Möller's avatar
Niels Möller committed
291
292
293
    
    struct lsh_string *key = sexp_format
      (sexp_l(2, sexp_z("private-key"),
Niels Möller's avatar
Niels Möller committed
294
	      sexp_l(6, sexp_z("dsa"),
Niels Möller's avatar
Niels Möller committed
295
296
297
298
299
		     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),
300
       options->style, 0);
Niels Möller's avatar
Niels Möller committed
301

302
    A_WRITE(output, key);
Niels Möller's avatar
Niels Möller committed
303
304

    return EXIT_SUCCESS;
Niels Möller's avatar
Niels Möller committed
305
  }
Niels Möller's avatar
Niels Möller committed
306
307
308
}