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

📄 pgpkeyman.c

📁 著名的加密软件的应用于电子邮件中
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
* pgpKeyMan.c -- Key Manipulation functions
*
* Copyright (C) 1996,1997 Pretty Good Privacy, Inc. All rights reserved.
*
* $Id: pgpKeyMan.c,v 1.61.2.6 1997/06/07 09:50:26 mhw Exp $
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "pgpKDBint.h"
#include "pgpDebug.h"
#include "pgpRngPub.h"
#include "pgpRngRead.h"
#include "pgpPubKey.h"
#include "pgpRndom.h"
#include "pgpSigSpec.h"
#include "pgpKeySpec.h"
#include "pgpTrstPkt.h"
#include "pgpTrust.h"
#include "pgpHash.h"
#include "pgpEnv.h"
#include "bn.h"

/* INTERNAL FUNCTIONS */

/* Internal function for certifying a key or userid. Object to be signed
	must be	in dest. Signing key should be in src. selfsig should be
set for self-certifying names. */

static PGPError
pgpCertifyObject (union RingObject *to_sign, struct RingSet *dest,
				union RingObject *signer, struct RingSet *src,
				byte sigtype, char *passphrase, Boolean selfsig)
{
struct PgpSecKey *seckey = NULL;
struct PgpSigSpec	*sigspec = NULL;
PGPError				error = PGPERR_OK;

	if (passphrase && strlen (passphrase) == 0)
		passphrase = NULL;

	if (!signer || !ringKeyIsSec (src, signer) ||
		!(ringKeyUse (src, signer) & PGP_PKUSE_SIGN))
		return PGPERR_NO_SECKEY;

  seckey = ringSecSecKey (src, signer, PGP_PKUSE_SIGN);
  if (!seckey)
		return ringSetError(src)->error;
  if (pgpSecKeyIslocked (seckey)) {
	if (!passphrase) {
		pgpSecKeyDestroy (seckey);
			return PGPERR_KEYDB_BADPASSPHRASE;
		}
	error = pgpSecKeyUnlock (seckey, pgpEnv, passphrase,
								strlen (passphrase));
		if (error != 1) {
	pgpSecKeyDestroy (seckey);
			if (error == 0)
			  error = PGPERR_KEYDB_BADPASSPHRASE;
			return error;
	}
  }
	ringKeySetAxiomatic (src, signer); /* user knows the passphrase */
		sigspec = pgpSigSpecCreate (pgpEnv, seckey, sigtype);
		if (!sigspec) {
			pgpSecKeyDestroy (seckey);
			return PGPERR_NOMEM;
		}
	if (seckey->pkAlg > PGP_PKALG_RSA + 2 &&
			sigtype == PGP_SIGTYPE_KEY_GENERIC && selfsig) {
		/* Propagate sig subpacket information */
		byte const *p;
		size_t plen;
		pgpSigSpecSetVersion (sigspec, PGPVERSION_3);
		if ((p=ringKeyFindSubpacket (signer, src, SIGSUB_PREFERRED_ALGS, 0,
				&plen, NULL, NULL, NULL, NULL, NULL)) != 0) {
			pgpSigSpecSetPrefAlgs (sigspec, p, plen);
		}
		if (ringKeyExpiration (src, signer)) {
			word32 period = ringKeyExpiration (src, signer) -
				ringKeyCreation (src, signer);
			pgpSigSpecSetKeyExpiration (sigspec, period);
		}
	}
	error = ringSignObject (dest, to_sign, sigspec, pgpRng);
	pgpSecKeyDestroy (seckey);
	pgpSigSpecDestroy (sigspec);
	return error;
}


/* Check for a 'dead' key. A dead key is revoked or expired.
	There's not much you can do with such a key. */

static Boolean
pgpKeyIsDead (PGPKey *key)
{
Boolean revoked, expired;
	
	pgpGetKeyBoolean (key, kPGPKeyPropIsRevoked, &revoked);
	pgpGetKeyBoolean (key, kPGPKeyPropIsExpired, &expired);
	return (revoked || expired);
}


/* Same for subkey... */

static Boolean
pgpSubKeyIsDead (PGPSubKey *subkey)
{
Boolean revoked, expired;
	
	pgpGetSubKeyBoolean (subkey, kPGPKeyPropIsRevoked, &revoked);
	pgpGetSubKeyBoolean (subkey, kPGPKeyPropIsExpired, &expired);
	return (revoked || expired);
}


/* Find the default private key. Get the name (or keyid) from the
	environment, and find the PGPKey object. If there is no default
	key defined in the environment, return NULL unless there is
	only one private key in the key database. */

static PGPKey *
pgpGetDefaultPrivateKeyInternal (PGPKeyDB *keyDB)
{
	union RingObject	*keyobj = NULL, *selectedkey = NULL, *secobj;
	struct RingSet		*ringset;
	struct RingIterator *iter;
	PGPKey *key = NULL;
	char const			*myname = pgpenvGetString
							(pgpEnv, PGPENV_MYNAME, NULL, NULL);
	
	ringset = (*keyDB->getRingSet) (keyDB);
	iter = ringIterCreate (ringset);
	if (!iter)
		return NULL;

	if (!myname || strlen (myname) == 0) {
		/* If only one private key, return that */
		while (ringIterNextObject (iter, 1) > 0) {
			keyobj = ringIterCurrentObject (iter, 1);
			pgpa(pgpaAssert(ringObjectType(keyobj) == RINGTYPE_KEY));
			if (ringKeyIsSec (ringset, keyobj) &&
				(ringKeyUse (ringset, keyobj) & PGP_PKUSE_SIGN)!=0) {
			 		 if (selectedkey) {	/* already found one */
			 		 selectedkey = NULL;
			 		 	goto cleanup;
			 		 }
			 		 else
			 		 	selectedkey = keyobj;	/* found first one */
			 	}
			 }
		}
		else {
		secobj = ringLatestSecret (ringset, myname, pgpGetTime(), 0);
		if (secobj) {
		ringIterSeekTo (iter, secobj);
			selectedkey = ringIterCurrentObject (iter, 1);
			/* Make sure it can sign */
			if (!(ringKeyUse (ringset, selectedkey) & PGP_PKUSE_SIGN))
			selectedkey = NULL;
		}
	}
cleanup:
	ringIterDestroy (iter);
	if (selectedkey) {
	key = pgpGetKeyByRingObject (keyDB, selectedkey);
		/* Ignore revoked or expired key */
		if (key && pgpKeyIsDead (key))
		key = NULL;
	}
	return key;
}

/* END OF INTERNAL FUNCTIONS */


/* Copy an entire key to a new ringset. The newly created ringset is
	returned. This function is necessary for two reasons:
	1. ringRaiseName requires all names to be present on the ringset to have
	any effect.
	2. to ensure a complete key (i.e. all it's sub-objects) are copied from
	a modified read-only key to a writable keyring.
*/

PGPError
pgpCopyKey (struct RingSet *src, union RingObject *obj, struct RingSet **dest)
{
	struct RingIterator *iter = NULL;
	int					level;

	if (!ringSetIsMember (src, obj))
		return PGPERR_BADPARAM;
	*dest = ringSetCreate (ringSetPool (src));
	if (!*dest)
		return PGPERR_NOMEM;
	iter = ringIterCreate (src);
	if (!iter) {
		ringSetDestroy (*dest);
		return PGPERR_NOMEM;
	}

	ringIterSeekTo (iter, obj);
	ringIterRewind (iter, 2); /* reset iterator to key object */
	/* Loop adding objects until next key (level 1), or no more keys
		(level 0) */
	while ((level = ringIterNextObjectAnywhere (iter)) > 1) {
		obj = ringIterCurrentObject (iter, level);
		ringSetAddObject (*dest, obj);
	}
	ringIterDestroy (iter);
	return PGPERR_OK;
}


/* Given a key ring object, find the corresponding PGPKey object. */

PGPKey *
pgpGetKeyByRingObject (PGPKeyDB *keyDB, union RingObject *keyobj)
{
	PGPKey				*keyptr;

	pgpAssert (ringObjectType (keyobj) == RINGTYPE_KEY);

	for (keyptr = keyDB->firstKeyInDB; keyptr; keyptr = keyptr->nextKeyInDB) {
		if (keyobj == keyptr->key)
			return keyptr;
	}
		return NULL;
}


PGPError
pgpRevokeKey (PGPKey *key, char *passphrase)
{
  PGPKeyDB			*keys = NULL;
	struct RingSet *allset = NULL, *addset = NULL;
	union RingObject *keyobj;
	PGPError			error = PGPERR_OK;
	
	pgpa(pgpaPGPKeyValid(key));
	keys =		key->keyDB;
	keyobj =	key->key;

	if (!(*keys->isMutable) (keys))
		return PGPERR_KEYDB_KEYDBREADONLY;
	if (pgpKeyIsDead (key))
	return PGPERR_OK; /* no need */
	
	allset = pgpKeyDBRingSet (keys);
	if (!ringKeyIsSec (allset, keyobj))
		return PGPERR_NO_SECKEY;			/* not our key */

	error = pgpCopyKey (allset, keyobj, &addset);
	if (error)
		return error;
	error = pgpCertifyObject (keyobj, addset, keyobj, allset,
							PGP_SIGTYPE_KEY_COMPROMISE, passphrase, FALSE);
	if (error) {
		ringSetDestroy (addset);
		return error;
	}
	
	/* Update the KeyDB */
	error = pgpAddObjects (keys, addset);
	ringSetDestroy (addset);
	return error;
}


/* Check whether sufficient entropy exists to generate a key of the
   requested type with the requested number of keys. Returns
   0 if sufficient entropy exists, or a positive integer representing the
   number of bits required. */

unsigned
pgpQueryEntropyNeeded (byte pkalg, unsigned bits)
{
	long bits_needed;
	Boolean		fastgen = pgpenvGetInt (pgpEnv, PGPENV_FASTKEYGEN,
												NULL, NULL);

	bits_needed = pgpSecKeyEntropy (pgpPkalgByNumber(pkalg), bits, fastgen) -
						pgpRandPoolEntropy ();
	return (unsigned) ((bits_needed <= 0) ? 0 : bits_needed);
}


/* Return the amount of entropy needed to create a key of the specified
   type and size. The application must call pgpRandpoolEntropy() itself
   until it has accumulated this much. */

unsigned
pgpKeyEntropyNeeded (byte pkalg, unsigned bits)
{
	Boolean		fastgen = pgpenvGetInt (pgpEnv, PGPENV_FASTKEYGEN,
												NULL, NULL);

	return pgpSecKeyEntropy (pgpPkalgByNumber (pkalg), bits, fastgen);
}


/*	Allows the caller to add entropy to the random number pool. This will not
	normally be called - the app will call Aurora functions directly. */

PGPError
pgpAddRandomBits (byte *random_bits, unsigned num_bytes)
{
pgpRandomAddBytes (pgpRng, random_bits, num_bytes);
	return PGPERR_OK;
}


#if 0	/* [ */

static int (*generateYieldProgressFunc)(void *arg, int phase) = NULL;
static void *generateYieldArg = NULL;

static int
generateYieldFunc(void)
{
	/* Will this actually work consistently to abort from here? */
	if (generateYieldProgressFunc != NULL)
		return (*generateYieldProgressFunc)(generateYieldArg, 0);
	else
		return 0;
}

#endif	/* ] */

/* Common code for generating master keys and subkeys. *masterkey
is NULL when generating a master key, and is used to return
	the master PGPKey object. If *masterkey contains a value,
	a subkey is to be generated associated with the PGPKey object. */

static PGPError
pgpGenerateKeyInternal (PGPKeyDB *keyDB, PGPKey **masterkey,
						byte pkalg, unsigned bits,
						word16 expiration, char *name, int name_len,
						char *passphrase, char *masterpass,
						int (*progress) (void *arg, int phase),
						void *arg)
{
	struct RingSet		*allset, *addset = NULL;
	union RingObject *newobj = NULL;
	PGPError error = PGPERR_OK;
	struct PgpSecKey	*seckey = NULL, *masterseckey = NULL;
	struct PgpKeySpec *keyspec = NULL;
	long entropy_needed, entropy_available;
	Boolean genMaster = (*masterkey == NULL);
	Boolean				fastgen = pgpenvGetInt (pgpEnv, PGPENV_FASTKEYGEN,
												NULL, NULL);
#if 0	/* [ */
	int					(*oldBNYield)(void);

	generateYieldProgressFunc = progress;
	generateYieldArg = arg;
	oldBNYield = bnYield;
	bnYield = &generateYieldFunc;
#endif	/* ] */

	/* Check we have sufficient random bits to generate the keypair */
	entropy_needed = pgpSecKeyEntropy (pgpPkalgByNumber(pkalg), bits, fastgen);
	entropy_available = pgpRandPoolEntropy ();
	if (entropy_needed > entropy_available) {
	return PGPERR_KEYDB_NEEDMOREBITS;
		goto cleanup;
	}
	
	/* Generate the secret key */
	seckey = pgpSecKeyGenerate(pgpPkalgByNumber(pkalg), bits, fastgen, pgpRng,
								progress, arg, &error);
	if (error)
		goto cleanup;
	pgpRandomStir (pgpRng);

	/* Need to lock the SecKey with the passphrase. */
	if (passphrase && strlen (passphrase) > 0) {
		error = pgpSecKeyChangeLock (seckey, pgpEnv, pgpRng,
									passphrase, strlen (passphrase));
		if (error)
			goto cleanup;
	}

	/* Generate the keyring objects. Use keyspec defaults except for
		expiration (validity) period */
	keyspec = pgpKeySpecCreate (pgpEnv);
	if (!keyspec) {
		error = PGPERR_NOMEM;
		goto cleanup;
	}
	pgpKeySpecSetValidity (keyspec, expiration);

	allset = pgpKeyDBRingSet (keyDB);

	if (genMaster) {
	/* Generating master signing key */
	addset = ringSetCreate (ringSetPool (allset));
		if (!addset) {
		error = PGPERR_NOMEM;
			goto cleanup;
		}
	error = ringCreateKeypair (pgpEnv, seckey, keyspec, name, name_len,
								pgpRng, addset, addset);
	}
	else {
	/* Generating encryption subkey. Get the master seckey and
				unlock it */
	error = pgpCopyKey (allset, (*masterkey)->key, &addset);
		if (error)
		goto cleanup;
	masterseckey = ringSecSecKey (allset, (*masterkey)->key,
									PGP_PKUSE_SIGN);
		if (!masterseckey) {
		error = ringSetError(allset)->error;
			goto cleanup;
		}
		if (pgpSecKeyIslocked (masterseckey)) {
		if (!passphrase) {
			error = PGPERR_KEYDB_BADPASSPHRASE;
			goto cleanup;
			}
			error = pgpSecKeyUnlock (masterseckey, pgpEnv, masterpass,
									strlen (masterpass));
			if (error != 1) {
			if (error == 0)
				error = PGPERR_KEYDB_BADPASSPHRASE;
				goto cleanup;
			}
		}
	error = ringCreateSubkeypair (pgpEnv, masterseckey, seckey, keyspec,
									pgpRng, addset, addset);
	}
	pgpRandomStir (pgpRng);		/* this helps us count randomness in pool */
	if (error)
		goto cleanup;

	/* Add objects to main KeyDB. Before doing so, locate
	the master key object and return it. */
	ringSetFreeze (addset);
	if (genMaster) {
	RingIterator *iter = ringIterCreate (addset);
		if (!iter) {
		error = ringSetError(addset)->error;
			goto cleanup;
		}
		ringIterNextObject (iter, 1);
		newobj = ringIterCurrentObject (iter, 1);
		ringIterDestroy (iter);
	}
	error = pgpAddObjects (keyDB, addset);
	if (genMaster && !error)
	*masterkey = pgpGetKeyByRingObject (keyDB, newobj);

cleanup:
#if 0
	bnYield = oldBNYield;
#endif
	if (addset)
		ringSetDestroy (addset);
	if (seckey)
		pgpSecKeyDestroy (seckey);
	if (masterseckey)
	pgpSecKeyDestroy (masterseckey);
	if (keyspec)
		pgpKeySpecDestroy (keyspec);
	return error;
}


/* Generate a new master keypair. The caller must have already generated
sufficient entropy for the keys to be generated. The newly generated
keys are added to the PGPKeyDB referenced by "keyset". */

PGPError
pgpGenerateKey (PGPKeySet *keyset, byte pkalg, unsigned bits,
				word16 expiration, char *name, int name_len,
				char *passphrase, int (*progress) (void *arg, int phase),
				void *arg, PGPKey **key)
{
	PGPError error = PGPERR_OK;
	PGPKey *newkey = NULL;

	pgpa(pgpaPGPKeySetValid(keyset));

	if (bits < 512 || bits > 4096 ||
		(pkalg != PGP_PKALG_RSA && pkalg != PGP_PKALG_DSA) ||
		!name || name_len < 1 || name_len > 256)
	return PGPERR_BADPARAM;
	
	*key = NULL;
	error = pgpGenerateKeyInternal (keyset->keyDB, &newkey, pkalg, bits,
									expiration, name, name_len, passphrase,
									NULL, progress, arg);
	if (!error && key)
	*key = newkey;
	return error;
}


/* Generate a subkey pair. The passphrase is that of the master
	key. Note that the subkey is protected by the same passphrase
	as its master. */

PGPError
pgpGenerateSubKey (PGPKey *masterkey, unsigned bits,
				word16 expiration, char *passphrase, char *masterpass,
				int (*progress) (void *arg, int phase), void *arg)
{
	long pkalg = 0;

	pgpa(pgpaPGPKeyValid(masterkey));

	if (bits < 512 || bits > 4096)
	return PGPERR_BADPARAM;
	if (pgpKeyIsDead (masterkey))
	return PGPERR_BADPARAM;

	pgpGetKeyNumber (masterkey, kPGPKeyPropAlgId, &pkalg);
	if (pkalg != PGP_PKALG_DSA)
	return PGPERR_BADPARAM;

	return pgpGenerateKeyInternal (masterkey->keyDB, &masterkey,
								PGP_PKALG_ELGAMAL, bits,

⌨️ 快捷键说明

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