⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rsasigkey.c

📁 This a good VPN source
💻 C
字号:
/* * RSA signature key generation * Copyright (C) 1999, 2000, 2001  Henry Spencer. *  * 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.  See <http://www.fsf.org/copyleft/gpl.txt>. *  * 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. * * RCSID $Id: rsasigkey.c,v 1.27 2004/05/23 21:32:03 paul Exp $ */#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>#include <unistd.h>#include <stdio.h>#include <time.h>#include <limits.h>#include <errno.h>#include <string.h>#include <assert.h>#include <getopt.h>#include <openswan.h>#include <gmp.h>#ifndef DEVICE#define	DEVICE	"/dev/random"#endif#ifndef MAXBITS#define	MAXBITS	20000#endif/* the code in getoldkey() knows about this */#define	E	3		/* standard public exponent */char usage[] = "rsasigkey [--verbose] [--random device] nbits";char usage2[] = "rsasigkey [--verbose] --oldkey filename";struct option opts[] = {  {"verbose",	0,	NULL,	'v',},  {"random",	1,	NULL,	'r',},  {"rounds",	1,	NULL,	'p',},  {"oldkey",	1,	NULL,	'o',},  {"hostname",	1,	NULL,	'H',},  {"noopt",	0,	NULL,	'n',},  {"help",		0,	NULL,	'h',},  {"version",	0,	NULL,	'V',},  {0,		0,	NULL,	0,}};int verbose = 0;		/* narrate the action? */char *device = DEVICE;		/* where to get randomness */int nrounds = 30;		/* rounds of prime checking; 25 is good */mpz_t prime1;			/* old key's prime1 */mpz_t prime2;			/* old key's prime2 */char outputhostname[1024];	/* hostname for output */int do_lcm = 1;			/* use lcm(p-1, q-1), not (p-1)*(q-1) */char me[] = "ipsec rsasigkey";	/* for messages *//* forwards */int getoldkey(char *filename);void rsasigkey(int nbits, int useoldkey);void initprime(mpz_t var, int nbits, int eval);void initrandom(mpz_t var, int nbits);void getrandom(size_t nbytes, char *buf);char *bundle(int e, mpz_t n, size_t *sizep);char *conv(char *bits, size_t nbytes, int format);char *hexout(mpz_t var);void report(char *msg);/* - main - mostly argument parsing */int main(int argc, char *argv[]){	int opt;	extern int optind;	extern char *optarg;	int errflg = 0;	int i;	int nbits;	char *oldkeyfile = NULL;	while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF)		switch (opt) {		case 'v':	/* verbose description */			verbose = 1;			break;		case 'r':	/* nonstandard /dev/random */			device = optarg;			break;		case 'p':	/* number of prime-check rounds */			nrounds = atoi(optarg);			if (nrounds <= 0) {				fprintf(stderr, "%s: rounds must be > 0\n", me);				exit(2);			}			break;		case 'o':	/* reformat old key */			oldkeyfile = optarg;			break;		case 'H':	/* set hostname for output */			strcpy(outputhostname, optarg);			break;		case 'n':	/* don't optimize the private key */			do_lcm = 0;			break;		case 'h':	/* help */			printf("Usage:\t%s\n", usage);			printf("\tor\n");			printf("\t%s\n", usage2);			exit(0);			break;		case 'V':	/* version */			printf("%s %s\n", me, ipsec_version_code());			exit(0);			break;		case '?':		default:			errflg = 1;			break;		}	if (errflg || optind != ((oldkeyfile != NULL) ? argc : argc-1)) {		printf("Usage:\t%s\n", usage);		printf("\tor\n");		printf("\t%s\n", usage2);		exit(2);	}	if (outputhostname[0] == '\0') {		i = gethostname(outputhostname, sizeof(outputhostname));		if (i < 0) {			fprintf(stderr, "%s: gethostname failed (%s)\n",				me,				strerror(errno));			exit(1);		}	}	if (oldkeyfile == NULL) {		assert(argv[optind] != NULL);		nbits = atoi(argv[optind]);	} else		nbits = getoldkey(oldkeyfile);	if (nbits <= 0) {		fprintf(stderr, "%s: invalid bit count (%d)\n", me, nbits);		exit(1);	} else if (nbits > MAXBITS) {		fprintf(stderr, "%s: overlarge bit count (max %d)\n", me,								MAXBITS);		exit(1);	} else if (nbits % (CHAR_BIT*2) != 0) {	/* *2 for nbits/2-bit primes */		fprintf(stderr, "%s: bit count (%d) not multiple of %d\n", me,						nbits, (int)CHAR_BIT*2);		exit(1);	}	rsasigkey(nbits, (oldkeyfile == NULL) ? 0 : 1);	exit(0);}/* - getoldkey - fetch an old key's primes */int				/* nbits */getoldkey(filename)char *filename;{	FILE *f;	char line[MAXBITS/2];	char *p;	char *value;	static char pube[] = "PublicExponent:";	static char pubevalue[] = "0x03";	static char pr1[] = "Prime1:";	static char pr2[] = "Prime2:";#	define	STREQ(a, b)	(strcmp(a, b) == 0)	int sawpube = 0;	int sawpr1 = 0;	int sawpr2 = 0;	int nbits;	nbits = 0; 	if (STREQ(filename, "-"))		f = stdin;	else		f = fopen(filename, "r");	if (f == NULL) {		fprintf(stderr, "%s: unable to open file `%s' (%s)\n", me,						filename, strerror(errno));		exit(1);	}	if (verbose)		fprintf(stderr, "getting old key from %s...\n", filename);	while (fgets(line, sizeof(line), f) != NULL) {		p = line + strlen(line) - 1;		if (*p != '\n') {			fprintf(stderr, "%s: over-long line in file `%s'\n",							me, filename);			exit(1);		}		*p = '\0';		p = line + strspn(line, " \t");		/* p -> first word */		value = strpbrk(p, " \t");		/* value -> after it */		if (value != NULL) {			*value++ = '\0';			value += strspn(value, " \t");			/* value -> second word if any */		}		if (value == NULL || *value == '\0') {			/* wrong format */		} else if (STREQ(p, pube)) {			sawpube = 1;			if (!STREQ(value, pubevalue)) {				fprintf(stderr, "%s: wrong public exponent (`%s') in old key\n",					me, value);				exit(1);			}		} else if (STREQ(p, pr1)) {			if (sawpr1) {				fprintf(stderr, "%s: duplicate `%s' lines in `%s'\n",					me, pr1, filename);				exit(1);			}			sawpr1 = 1;			nbits = (strlen(value) - 2) * 4 * 2;			if (mpz_init_set_str(prime1, value, 0) < 0) {				fprintf(stderr, "%s: conversion error in reading old prime1\n",					me);				exit(1);			}		} else if (STREQ(p, pr2)) {			if (sawpr2) {				fprintf(stderr, "%s: duplicate `%s' lines in `%s'\n",					me, pr2, filename);				exit(1);			}			sawpr2 = 1;			if (mpz_init_set_str(prime2, value, 0) < 0) {				fprintf(stderr, "%s: conversion error in reading old prime2\n",					me);				exit(1);			}		}	}		if (f != stdin)		fclose(f);	if (!sawpube || !sawpr1 || !sawpr2) {		fprintf(stderr, "%s: old key missing or incomplete\n", me);		exit(1);	}	assert(sawpr1);		/* and thus nbits is known */	return(nbits);}/* - rsasigkey - generate an RSA signature key * e is fixed at 3, without discussion.  That would not be wise if these * keys were to be used for encryption, but for signatures there are some * real speed advantages. */voidrsasigkey(nbits, useoldkey)int nbits;int useoldkey;			/* take primes from old key? */{	mpz_t p;	mpz_t q;	mpz_t n;	mpz_t e;	mpz_t d;	mpz_t q1;			/* temporary */	mpz_t m;			/* internal modulus, (p-1)*(q-1) */	mpz_t t;			/* temporary */	mpz_t exp1;	mpz_t exp2;	mpz_t coeff;	char *bundp;	size_t bs;	int success;	time_t now = time((time_t *)NULL);	/* the easy stuff */	if (useoldkey) {		mpz_init_set(p, prime1);		mpz_init_set(q, prime2);	} else {		initprime(p, nbits/2, E);		initprime(q, nbits/2, E);	}	mpz_init(t);	if (mpz_cmp(p, q) < 0) {		report("swapping primes so p is the larger...");		mpz_set(t, p);		mpz_set(p, q);		mpz_set(q, t);	}	report("computing modulus...");	mpz_init(n);	mpz_mul(n, p, q);		/* n = p*q */	mpz_init_set_ui(e, E);	/* internal modulus */	report("computing lcm(p-1, q-1)...");	mpz_init_set(m, p);	mpz_sub_ui(m, m, 1);	mpz_init_set(q1, q);	mpz_sub_ui(q1, q1, 1);	mpz_gcd(t, m, q1);		/* t = gcd(p-1, q-1) */	mpz_mul(m, m, q1);		/* m = (p-1)*(q-1) */	if (do_lcm)		mpz_divexact(m, m, t);		/* m = lcm(p-1, q-1) */	mpz_gcd(t, m, e);	assert(mpz_cmp_ui(t, 1) == 0);	/* m and e relatively prime */	/* decryption key */	report("computing d...");	mpz_init(d);	success = mpz_invert(d, e, m);	assert(success);		/* e has an inverse mod m */	if (mpz_cmp_ui(d, 0) < 0)		mpz_add(d, d, m);	assert(mpz_cmp(d, m) < 0);	/* the speedup hacks */	report("computing exp1, exp1, coeff...");	mpz_init(exp1);	mpz_sub_ui(t, p, 1);	mpz_mod(exp1, d, t);		/* exp1 = d mod p-1 */	mpz_init(exp2);	mpz_sub_ui(t, q, 1);	mpz_mod(exp2, d, t);		/* exp2 = d mod q-1 */	mpz_init(coeff);	mpz_invert(coeff, q, p);	/* coeff = q^-1 mod p */	if (mpz_cmp_ui(coeff, 0) < 0)		mpz_add(coeff, coeff, p);	assert(mpz_cmp(coeff, p) < 0);	/* and the output */	/* note, getoldkey() knows about some of this */	report("output...\n");		/* deliberate extra newline */	printf("\t# RSA %d bits   %s   %s", nbits, outputhostname, ctime(&now));							/* ctime provides \n */	printf("\t# for signatures only, UNSAFE FOR ENCRYPTION\n");	bundp = bundle(E, n, &bs);	printf("\t#pubkey=%s\n", conv(bundp, bs, 's'));	/* RFC2537ish format */	printf("\tModulus: %s\n", hexout(n));	printf("\tPublicExponent: %s\n", hexout(e));	printf("\t# everything after this point is secret\n");	printf("\tPrivateExponent: %s\n", hexout(d));	printf("\tPrime1: %s\n", hexout(p));	printf("\tPrime2: %s\n", hexout(q));	printf("\tExponent1: %s\n", hexout(exp1));	printf("\tExponent2: %s\n", hexout(exp2));	printf("\tCoefficient: %s\n", hexout(coeff));}/* - initprime - initialize an mpz_t to a random prime of specified size * Efficiency tweak:  we reject candidates that are 1 higher than a multiple * of e, since they will make the internal modulus not relatively prime to e. */voidinitprime(var, nbits, eval)mpz_t var;int nbits;			/* known to be a multiple of CHAR_BIT */int eval;			/* value of e; 0 means don't bother w. tweak */{	unsigned long tries;	size_t len;#	define	OKAY(p)	(eval == 0 || mpz_fdiv_ui(p, eval) != 1)	initrandom(var, nbits);	assert(mpz_fdiv_ui(var, 2) == 1);	/* odd number */	report("looking for a prime starting there (can take a while)...");	tries = 1;	while (!( OKAY(var) && mpz_probab_prime_p(var, nrounds) )) {		mpz_add_ui(var, var, 2);		tries++;	}	len = mpz_sizeinbase(var, 2);	assert(len == (size_t)nbits || len == (size_t)(nbits+1));	if (len == (size_t)(nbits+1)) {		report("carry out occurred (!), retrying...");		mpz_clear(var);		initprime(var, nbits, eval);		return;	}	if (verbose)		fprintf(stderr, "found it after %lu tries.\n", tries);}/* - initrandom - initialize an mpz_t to a random number, specified bit count * Converting via hex is a bit weird, but it's the best route GMP gives us. * Note that highmost and lowmost bits are forced on -- highmost to give a * number of exactly the specified length, lowmost so it is an odd number. */voidinitrandom(var, nbits)mpz_t var;int nbits;			/* known to be a multiple of CHAR_BIT */{	size_t nbytes = (size_t)(nbits / CHAR_BIT);	static char bitbuf[MAXBITS/CHAR_BIT];	static char hexbuf[2 + MAXBITS/4 + 1];	size_t hsize = sizeof(hexbuf);	assert(nbytes <= sizeof(bitbuf));	getrandom(nbytes, bitbuf);	bitbuf[0] |= 01 << (CHAR_BIT-1);	/* force high bit on */	bitbuf[nbytes-1] |= 01;			/* force low bit on */	if (datatot(bitbuf, nbytes, 'x', hexbuf, hsize) > hsize) {		fprintf(stderr, "%s: can't-happen buffer overflow\n", me);		exit(1);	}	if (mpz_init_set_str(var, hexbuf, 0) < 0) {		fprintf(stderr, "%s: can't-happen hex conversion error\n", me);		exit(1);	}}/* - getrandom - get some random bytes from /dev/random (or wherever) */voidgetrandom(nbytes, buf)size_t nbytes;char *buf;			/* known to be big enough */{	size_t ndone;	int dev;	size_t got;	dev = open(device, 0);	if (dev < 0) {		fprintf(stderr, "%s: could not open %s (%s)\n", me,						device, strerror(errno));		exit(1);	}	ndone = 0;	if (verbose)		fprintf(stderr, "getting %d random bytes from %s...\n", (int) nbytes,							device);	while (ndone < nbytes) {		got = read(dev, buf + ndone, nbytes - ndone);		if (got < 0) {			fprintf(stderr, "%s: read error on %s (%s)\n", me,						device, strerror(errno));			exit(1);		}		if (got == 0) {			fprintf(stderr, "%s: eof on %s!?!\n", me, device);			exit(1);		}		ndone += got;	}	close(dev);}/* - hexout - prepare hex output, guaranteeing even number of digits * (The current FreeS/WAN conversion routines want an even digit count, * but mpz_get_str doesn't promise one.) */char *				/* pointer to static buffer (ick) */hexout(var)mpz_t var;{	static char hexbuf[3 + MAXBITS/4 + 1];	char *hexp;	mpz_get_str(hexbuf+3, 16, var);	if (strlen(hexbuf+3)%2 == 0)	/* even number of hex digits */		hexp = hexbuf+1;	else {				/* odd, must pad */		hexp = hexbuf;		hexp[2] = '0';	}	hexp[0] = '0';	hexp[1] = 'x';	return hexp;}/* - bundle - bundle e and n into an RFC2537-format lump * Note, calls hexout. */char *				/* pointer to static buffer (ick) */bundle(e, n, sizep)int e;mpz_t n;size_t *sizep;{	char *hexp = hexout(n);	static char bundbuf[2 + MAXBITS/8];	const char *er;	size_t size;	assert(e <= 255);	bundbuf[0] = 1;	bundbuf[1] = e;	er = ttodata(hexp, 0, 0, bundbuf+2, sizeof(bundbuf)-2, &size);	if (er != NULL) {		fprintf(stderr, "%s: can't-happen bundle convert error `%s'\n",								me, er);		exit(1);	}	if (size > sizeof(bundbuf)-2) {		fprintf(stderr, "%s: can't-happen bundle overflow (need %d)\n",								me, (int) size);		exit(1);	}	if (sizep != NULL)		*sizep = size + 2;	return bundbuf;}/* - conv - convert bits to output in specified format */char *				/* pointer to static buffer (ick) */conv(bits, nbytes, format)char *bits;size_t nbytes;int format;			/* datatot() code */{	static char convbuf[MAXBITS/4 + 50];	/* enough for hex */	size_t n;	n = datatot(bits, nbytes, format, convbuf, sizeof(convbuf));	if (n == 0) {		fprintf(stderr, "%s: can't-happen convert error\n", me);		exit(1);	}	if (n > sizeof(convbuf)) {		fprintf(stderr, "%s: can't-happen convert overflow (need %d)\n",								me, (int) n);		exit(1);	}	return convbuf;}/* - report - report progress, if indicated */voidreport(msg)char *msg;{	if (!verbose)		return;	fprintf(stderr, "%s\n", msg);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -