📄 pgpkkeygen.c
字号:
/*
* pgpkKeyGen.c -- Routines to generate a key
*
* Copyright (C) 1997 Pretty Good Privacy, Inc. All rights reserved.
*
* 970514 BAT Created new file from MHW's routine from pgpk.c
* Broken up into smaller functions
* And a PGP file without a single goto, now! Who'd have thunk
* it?
*
* $Id: pgpkKeyGen.c,v 1.1.2.8.2.2 1997/07/09 02:13:51 mhw Exp $
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h> /* for sbrk() */
#endif
#ifdef UNIX
#include <sys/stat.h> /* for umask() */
#endif
#include "pgpDebug.h"
#include "pgpEnv.h"
#include "pgpMem.h"
#include "pgpKeyDB.h"
#include "pgpOutput.h"
#include "pgpkUI.h"
#include "pgpkInit.h"
#include "pgpkExit.h"
#include "pgpOpt.h"
#include "pgpUserIO.h"
#include "pgpRndPool.h"
#include "pgpkKeyGen.h"
#include "pass.h"
#include "url.h"
#include "keyserver.h"
#define MIN_KEY_SIZE 768
static int
keygenProgress (void *arg, int c);
static int
KeyGenGetPassphrase(Boolean GotArgs,
char *passphrase,
size_t passphraselen,
void *ui_arg);
static int
KeyGenGetValidity(Boolean GotArgs, int *validity);
static int
KeyGenGetName(Boolean GotArgs, char *namebuf, int *namelen);
static int
KeyGenGetKeySize(Boolean GotArgs, byte pkalg, int *keybits, int *subkeybits);
static int
KeyGenGetKeyType(Boolean GotArgs, byte *pkalg, byte *subkalg);
static int
ParseKeyGenArgs(int argc,
char *argv[],
byte *pkalg,
byte *subkalg,
int *keybits,
int *subkeybits,
int *namelen,
char *namebuf,
int *validity,
char *passphrase,
int passphraselen,
char **keyserver);
static int KeyGenSendKey(Boolean GotArgs,
char *keyserver,
PGPKey *key,
struct PgpTtyUI *ui);
static int KeySizeTable[5] = {0, 768, 1024, 2048, 4096};
/* Optional Arguments: (if you specify one, you've got to specify
*them all, except passphrase)
*
*argv[1] Key type (DSS or RSA)
*argv[2] Key Size (768-4096)
*argv[3] UserID (Brett A. Thomas <quark@baz.com>)
*argv[4] Validity period in days (0 - 999)
*argv[5] Passphrase (if '?', user will be prompted).
#argv[6] Keyserver to send key to, if any
*/
int
doKeyGenerate (PGPKeySet *defaultset, int argc, char *argv[], void *ui_arg)
{
int error = 0;
byte namebuf[256] = "\0",
passphrase[PASSLEN] = "\0";
int namelen = 0;
int keybits = 0, subkeybits = 0;
int validity = 0;
byte pkalg, subkalg;
PGPKey *key;
unsigned entropy_needed;
extern PgpEnv PGPKDBExport *pgpEnv;
Boolean GotArgs = FALSE;
char *keyserver = NULL;
if(argc > 1) {
GotArgs = TRUE;
namelen = sizeof(passphrase);
error = ParseKeyGenArgs(argc,
argv,
&pkalg,
&subkalg,
&keybits,
&subkeybits,
&namelen,
(char *) namebuf,
&validity,
(char *) passphrase,
sizeof(passphrase),
&keyserver);
}
/*This is inefficient in that a bad arg up above will cause six error==
*evaluations. However, it does mean that, if we have a memory allocation
*failure someplace, we don't then call all the other routines, and it
*also means that we do this without a bunch of exits or gotos all over
*the place.
*/
if(error == PGPERR_OK) {
error = KeyGenGetKeyType(GotArgs, &pkalg, &subkalg);
}
if(error == PGPERR_OK) {
error = KeyGenGetKeySize(GotArgs, pkalg, &keybits, &subkeybits);
}
if(error == PGPERR_OK) {
namelen = sizeof(namebuf);
error = KeyGenGetName(GotArgs, (char *) namebuf, &namelen);
}
if(error == PGPERR_OK) {
error = KeyGenGetValidity(GotArgs, &validity);
}
if(error == PGPERR_OK) {
error = KeyGenGetPassphrase(GotArgs,
(char *) passphrase,
sizeof(passphrase),
ui_arg);
}
if(error == PGPERR_OK) {
/* Assume fast DSA keygen */
pgpenvSetInt(pgpEnv, PGPENV_FASTKEYGEN, 1, PGPENV_PRI_PRIVDEFAULT);
/* Need to ask for randomness */
entropy_needed = pgpKeyEntropyNeeded (pkalg, keybits);
if (subkalg)
entropy_needed += pgpKeyEntropyNeeded (subkalg, subkeybits);
if (entropy_needed > pgpRandPoolEntropy()) {
fprintf (stderr, "Collecting randomness for key...\n");
pgpTtyRandAccum (ui_arg, entropy_needed);
}
pgpAssert(defaultset);
error = pgpGenerateKey (defaultset,
pkalg,
keybits,
validity,
(char *) namebuf,
namelen,
(char *) passphrase,
keygenProgress,
ui_arg,
&key);
fprintf (stderr, "\n");
if(subkalg && error == PGPERR_OK) {
error = pgpGenerateSubKey(key,
subkeybits,
validity,
(char *) passphrase,
(char *) passphrase,
keygenProgress,
ui_arg);
fprintf (stderr, "\n");
}
if (!error) {
fprintf (stderr, "Keypair created successfully.\n");
pgpCommitKeyRingChanges (defaultset);
KeyGenSendKey(GotArgs, keyserver, key, (struct PgpTtyUI *) ui_arg);
}
}
if(keyserver)
pgpFree(keyserver);
return(error);
}
static int
ParseKeyGenArgs(int argc,
char *argv[],
byte *pkalg,
byte *subkalg,
int *keybits,
int *subkeybits,
int *namelen,
char *namebuf,
int *validity,
char *passphrase,
int passphraselen,
char **keyserver)
{
int error = PGPERR_OK;
pgpAssert(argc == 4 || argc == 5);
pgpAssert(argv && pkalg && subkalg && keybits && subkeybits && namelen);
pgpAssert(namebuf && validity && passphrase && passphraselen);
/*Avoid warning on subkeybits. This is for future functionality, in case
*we ever want to allow others to specify this.
*/
(void) subkeybits;
if(argc == 5 || argc == 6) {
if(strcasecmp(argv[0], "DSS") == 0) {
*pkalg = PGP_PKALG_DSA;
*subkalg = PGP_PKALG_ELGAMAL;
}
else {
if(strcasecmp(argv[0], "RSA") == 0) {
#if (!NO_RSA_KEYGEN)
*pkalg = PGP_PKALG_RSA;
*subkalg = 0;
#else
fprintf(stderr, "\
RSA Key generation not supported in this verion of PGP.\n");
#endif
}
else {
fprintf(stderr, "Unknown algorithm %s.\n", argv[0]);
error = PGPERR_BADPARAM;
}
}
if(error == PGPERR_OK) {
*keybits = atol(argv[1]);
}
if(error == PGPERR_OK) {
strncpy(namebuf, argv[2], *namelen);
*namelen = strlen(argv[2]);
}
if(error == PGPERR_OK) {
*validity = atoi(argv[3]);
}
if(error == PGPERR_OK) {
strncpy(passphrase, argv[4], passphraselen);
}
if(error == PGPERR_OK && argc == 6) {
/*They specified a keyserver*/
if((*keyserver = pgpAlloc(sizeof(char) * (strlen(argv[5]) + 1)))) {
strcpy(*keyserver, argv[5]);
}
else
error = PGPERR_NOMEM;
}
}
else {
fprintf(stderr, "\
Error! If any command-line key generation options are specified, all\n\
options must be specified (with the exception of the server to send to).\n");
error = PGPERR_BADPARAM;
}
return(error);
}
static int
KeyGenGetKeyType(Boolean GotArgs, byte *pkalg, byte *subkalg)
{
int error = PGPERR_OK, keytype, len;
char buf[256];
pgpAssert(pkalg && subkalg);
if(!GotArgs) {
#if(!NO_RSA_KEYGEN)
do {
fprintf (stderr,
"\
Choose the type of your public key:\n\
1) DSS/Diffie-Hellman - New algorithm for 5.0 (default)\n\
2) RSA\n\
Choose 1 or 2: ");
len = pgpTtyGetString (buf, sizeof(buf), OUTPUT_INTERACTION);
if (len) {
keytype = atoi(buf);
}
else {
keytype = 1;
}
switch (keytype) {
case 1:
*pkalg = PGP_PKALG_DSA;
*subkalg = PGP_PKALG_ELGAMAL;
break;
case 2:
*pkalg = PGP_PKALG_RSA;
*subkalg = 0;
break;
default:
*pkalg = *subkalg = 0;
break;
}
}while(!*pkalg);
#else
fprintf(stderr, "Creating DSS/Diffie-Hellman key.\n");
*pkalg = PGP_PKALG_DSA;
*subkalg = PGP_PKALG_ELGAMAL;
#endif
}
return(error);
}
static int
KeyGenGetKeySize(Boolean GotArgs, byte pkalg, int *keybits, int *subkeybits)
{
int len = 0, maxlen = 0, error = PGPERR_OK;
char buf[256];
pgpAssert(pkalg && keybits && subkeybits);
do {
if(!GotArgs) {
switch(pkalg) {
case PGP_PKALG_DSA:
fputs (
"\nPick your public/private keypair key size:\n\
(Sizes are Diffie-Hellman/DSS; Read the user's guide for more information)\n\
1) 768/768 bits- Commercial grade, probably not currently breakable\n\
2) 1024/1024 bits- High commercial grade, secure for many years\n\
3) 2048/1024 bits- \"Military\" grade, secure for forseeable future\
(default)\n\
4) 3072/1024 bits- Archival grade, slow, highest security\n\
Choose 1, 2, 3 or 4, or enter desired number of Diffie-Hellman bits\n\
(768 - 4096): ", stderr);
fflush (stderr);
break;
case PGP_PKALG_RSA:
fputs (
"\nPick your public/private keypair key size:\n\
1) 768 bits- Commercial grade, probably not currently breakable\n\
2) 1024 bits- High commercial grade, secure for many years\n\
3) 2048 bits- \"Military\" grade, secure for the forseeable future\n\
Choose 1, 2 or 3, or enter desired number of bits\n\
(768 - 2048): ", stderr);
fflush (stderr);
break;
}
len = pgpTtyGetString (buf, sizeof(buf), OUTPUT_INTERACTION);
if(len) {
*keybits = atoi(buf);
if(*keybits > 0 && *keybits < 4) {
*keybits = KeySizeTable[*keybits];
}
}
else {
*keybits = 2048;
}
}
switch(pkalg) {
case PGP_PKALG_DSA:
maxlen = 4096;
break;
case PGP_PKALG_RSA:
maxlen = 2048;
break;
}
if(*keybits < MIN_KEY_SIZE) {
error = PGPERR_BADPARAM;
fprintf(stderr,
"Minimum key size is %u.\n",
MIN_KEY_SIZE);
}
else {
if(*keybits > maxlen) {
error = PGPERR_BADPARAM;
fprintf(stderr,
"Maximum key size is %u.\n",
maxlen);
}
else {
*subkeybits = *keybits;
if(*keybits >= 1024) {
*keybits = 1024;
}
if(!GotArgs) {
if(keybits != subkeybits) {
fprintf(stderr,
"\
(Producing a %i bit DSS and a %i bit Diffie-Hellman key)\n",
*keybits,
*subkeybits);
}
else
fprintf(stderr, "\n");
}
error = PGPERR_OK;
}
}
}while(!GotArgs && error != PGPERR_OK);
return(error);
}
static int
KeyGenGetName(Boolean GotArgs, char *namebuf, int *namelen)
{
int error = PGPERR_OK;
pgpAssert(namebuf);
pgpAssert(namelen);
pgpAssert(*namelen);
/*If we got a name on the command line, we've got to assume it's OK and
*the user knows what she's doing.
*/
do {
if(!GotArgs) {
fputs (
"\nYou need a user ID for your public key. The desired form for this\n"
"user ID is your FULL name, followed by your E-mail address enclosed in\n"
"<angle brackets>, if you have an E-mail address. For example:\n"
" Joe Smith <user@domain.com>\n"
"If you violate this standard, you will lose much of the benefits of\n"
"PGP 5.0's keyserver and email integration.\n\n"
"Enter a user ID for your public key: ", stderr);
fflush (stderr);
*namelen = pgpTtyGetString (namebuf, *namelen, OUTPUT_INTERACTION);
if (!namelen) {
*namebuf = '\0';
}
}
else
*namelen = strlen(namebuf);
if(!*namebuf) {
error = PGPERR_BADPARAM;
fputs(
"\nYou must enter something for your ID; otherwise, PGP will be unable to "
"manipulate your key.\n", stderr);
}
}while(!GotArgs && error != PGPERR_OK);
return(error);
}
static int
KeyGenGetValidity(Boolean GotArgs, int *validity)
{
int len, error = PGPERR_OK;
char buf[256];
pgpAssert(validity);
do {
if(!GotArgs) {
fputs ("\n"
"Enter the validity period of your key in days from 0 - 999\n"
"0 is forever (and the default): ",
stderr);
fflush (stderr);
len = pgpTtyGetString (buf, sizeof(buf), OUTPUT_INTERACTION);
if (len) {
*validity = atoi (buf);
}
else {
*validity = 0;
}
}
if(*validity < 0 || *validity > 999) {
error = PGPERR_BADPARAM;
fprintf(stderr, "Validity must be between 0 and 999!\n");
}
}while(!GotArgs && error != PGPERR_OK);
return(error);
}
static int
KeyGenGetPassphrase(Boolean GotArgs,
char *passphrase,
size_t passphraselen,
void *ui_arg)
{
int error = PGPERR_OK;
char pass2[PASSLEN];
pgpAssert(passphrase && passphraselen);
if(!GotArgs ||
(GotArgs && *passphrase == '?' && *(passphrase + 1) == '\0')) {
do {
fprintf(stderr, "\n\
You need a pass phrase to protect your private key(s).\n\
Your pass phrase can be any sentence or phrase and may have many\n\
words, spaces, punctuation, or any other printable characters.\n");
pgpTtyGetPass (FALSE, passphrase, passphraselen);
fprintf (stderr, "Enter again, for confirmation:\n");
pgpTtyGetPass (FALSE, pass2, sizeof(pass2));
if (strcmp (passphrase, pass2) != 0) {
fprintf (stderr,
"Passphrases are different; please re-enter:\n");
error = PGPERR_BADPARAM;
}
else
error = PGPERR_OK;
}while(error != PGPERR_OK);
}
return error;
}
static int
keygenProgress (void *arg, int c)
{
(void)arg; /* make the compiler happy */
putc (c, stderr);
fflush (stderr);
return 0;
}
static int KeyGenSendKey(Boolean GotArgs,
char *keyserver,
PGPKey *key,
struct PgpTtyUI *ui)
{
int error = PGPERR_OK, len;
char buf[1024];
int port = 0;
char server[1024], file[1024], protocol[16], url[1024] = "\0";
pgpAssert(key);
if(!GotArgs) {
fputs ("\n\
If you wish to send this new key to a server, enter the URL of the server,\n\
below. If not, enter nothing.\n", stderr);
fflush (stderr);
if((len = pgpTtyGetString (buf, sizeof(buf), OUTPUT_INTERACTION))) {
strcpy(url, buf);
}
}
else {
if(keyserver) {
strcpy(url, keyserver);
}
}
if(url[0]) {
char *buffer = NULL;
size_t length = 1;
PGPKeySet *keyset;
if(parse_url(protocol, server, file, &port, buf) == PGPERR_OK) {
if((keyset = pgpNewSingletonKeySet(key))) {
if((buffer = pgpAlloc(sizeof(char) * length))) {
pgpExportKeyBuffer(keyset,
(unsigned char *) buffer,
&length);
pgpFree(buffer);
++length; /*Make room for a null*/
if((buffer = pgpAlloc(sizeof(char) * length))) {
error = pgpExportKeyBuffer(keyset,
(unsigned char *) buffer,
&length);
if(error == PGPERR_OK) {
PutKeyInfoHkp(server, port, buffer);
pgpFree(buffer);
}
}
else
error = PGPERR_NOMEM;
}
pgpFreeKeySet(keyset);
}
else {
error = PGPERR_NOMEM;
}
}
else {
fprintf(ui->fp, "\
Badly formed URL. Use pgpk -xa -o <URL> to submit your key manually.\n");
}
}
return(error);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -