pgprngpriv.c

来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 902 行 · 第 1/2 页

C
902
字号
/*
* pgpRngPriv.c -- Private helper functions for keyring manipulation.
*
* Copyright (C) 1994-1997 Pretty Good Privacy, Inc. All rights reserved.
*
* Written by Colin Plumb.
*
* $Id: pgpRngPriv.c,v 1.13.2.3 1997/06/07 09:50:39 mhw Exp $
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <errno.h>
#include <string.h>
#include <stdio.h>

#include "pgpDebug.h"
#include "pgpPktByte.h"
#include "pgpRngPriv.h"
#include "pgpRngRead.h"			/* For ringFilePurgeTrouble */
#include "pgpTrstPkt.h"
#include "pgpHash.h"
#include "pgpEnv.h"
#include "pgpErr.h"
#include "pgpMem.h"
#include "pgpSigSpec.h"	/* for PGP_SIGTYPE */
#include "pgpTrust.h"
#include "pgpUsuals.h"

#ifndef NULL
#define NULL 0
#endif

#define PGP_TRUST_DECADE_INTERNAL (PGP_TRUST_DECADE >> 6)
#define PGP_TRUST_OCTAVE_INTERNAL (PGP_TRUST_OCTAVE >> 6)

/*
* Small helpers to report errors
*/
/* Report an general I/O error */
void
ringErr(struct RingFile *file, word32 pos, int code)
	{
			struct RingError *err = &file->set.pool->e;

			err->f = file;
			err->fpos = pos;
			err->error = code;
			err->syserrno = errno;
	}

/* Report a non-I/O error */
void
ringSimpleErr(struct RingPool *pool, int code)
{
	pool->e.f = (struct RingFile *)NULL;
	pool->e.fpos = (word32)-1;
pool->e.error = code;
pool->e.syserrno = errno;
}

/* Report an allocation failure (called from many places) */
void
ringAllocErr(struct RingPool *pool)
{
	ringSimpleErr(pool, PGPERR_NOMEM);
}

/*
* Hash a string of bytes. Uses the CRC-32 polynomial, preset
* to -1, non-invert. Used to reduce userID collisions and to
* create a fake keyID for unparseable keys.
*
* CRC-32 polynomial in little-endian order:
* 1+x+x^2+x^4+x^5+x^7+x^8+x^10+x^11+x^12+x^16+x^22+x^23+x^26+x^32
* 1 1 2 2 2 3
* 0 4 8 2 6 0 4 8 2
* = 111011011011100010000011001000001
* = e d b 8 8 3 2 0
* = 0xedb88320
*/
#define CRCPOLY 0xedb88320
word32
ringHashBuf(byte const *buf, size_t len)
	{
			word32 crc;
			int i, j;
			static word32 crctable[256];

			if (!crctable[255]) {
					/* crctable[0] is already 0 */
					crctable[128] = crc = CRCPOLY;
					i = 64;
					do {
							crc = crc>>1 ^ (crc & 1 ? CRCPOLY : 0);
							for (j = 0; j < 256; j += 2*i)
								 crctable[i+j] = crc ^ crctable[j];
					} while (i >>= 1);
			}

			crc = 0xffffffff;
			while (len--)
				 crc = (crc >> 8) ^ crctable[(crc ^ *buf++) & 255];
			return crc;
	}

/*
* Return the index of the least significant bit in the given mask,
* or -1 if the mask is all 0. This uses (almost) no branches,
* so should be nice and fast on modern processors.
*
* Oh, how does it *work*, you ask? I do confess that this uses
* two evil bit-twiddling tricks. The first is one to get a mask
* of the least-significant set bit in few instructions.
* Consider a binary number x, be it 11010000 or 00101111.
* Then think about the form of x-1, 11001111 or 00101110.
* Notice that the only difference is that some least-significant
* bits have been complemented. The bits complemented are
* those up to and including the least-significant set bit.
* (x+1 does the same with *clear* bits). So ANDing the two
* results in a number like the original, only without the
* least-significant set bit. XORing them produces a mask
* with a number of least-significant bits set, depending on
* the least-significant set bit, 00011111 or 00000001.
*
* Other tricks: x & (x-1) returns x, but with the least-significant
* bit cleared. Twos complement negation is -x = ~x+1 = ~(x-1),
* so x & -x = x & ~(x-1) returns only the least-significant bit
* set in x.
*
* All we need is a routine to count the bits, and we're done.
* This is the *second* trick. Consider an 8-bit word:
* +-+-+-+-+-+-+-+-+
* |a|b|c|d|e|f|g|h|
* +-+-+-+-+-+-+-+-+
* Now copy this word, shift one copy down one bit, and AND both
* copies with 0x55 (01010101), to produce even and odd bits:
* +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
* | |b| |d| |f| |h| | |a| |c| |e| |g| (the blank squares are zero)
* +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
* Then add the words together:
* +-+-+-+-+-+-+-+-+
* |a+b|c+d|e+f|g+h|
* +-+-+-+-+-+-+-+-+
* Note that each two-bit field contains a count of the number of
* bits set in that part of the original word. Repeating this produces:
* +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
* |   |c+d|   |g+h| + |   |a+b|   |e+f| = |a+b+c+d|e+f+g+h|
* +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
* and once more produces:
* +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
* |       |e+f+g+h| + |       |a+b+c+d| = |a+b+c+d+e+f+g+h|
* +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
*
* Ther masking is needed so that fields don't overflow into
* adjacent fields. Once the fields have gotten wide enough,
* some of it can be reduced or eliminated. In the last step,
* ab+c+d and e+f+g+h are both at most 4 (binary 100) and
* their sum is at most 8 (binary 1000), which still fits into a
* 4-bit field, so it is possible to not mask the inputs to
* the addition. It's still necessary to mask the output, though,
* since the next step (adding up to a maximum of 16) won't
* fit into a 4-bit field. Once you have an 8-bit field, though,
* you can stop masking until the very end unless you have a
* 256-bit word.
*/
int
ringLsBitFind(ringmask mask)
{
	if (!mask)
		return -1;
	mask ^= mask-1;	/* Number of bits set is position of lsbit + 1 */
#if RINGMASKBITS > 32
			mask = (mask & 0x5555555555555555) + (mask >> 1 & 0x5555555555555555);
			mask = (mask & 0x3333333333333333) + (mask >> 2 & 0x3333333333333333);
			mask = (mask + (mask >> 4)) & 0x0F0F0F0F0F0F0F0F;
			mask += mask >> 8;
			mask += mask >> 16;
			mask += mask >> 32;
			return (int)(mask & 255)-1;
#elif RINGMASKBITS > 16
			mask = (mask & 0x55555555) + (mask >> 1 & 0x55555555);
			mask = (mask & 0x33333333) + (mask >> 2 & 0x33333333);
			mask = (mask + (mask >> 4)) & 0x0F0F0F0F;
			mask += mask >> 8;
			mask += mask >> 16;
			return (int)(mask & 255)-1;
#elif RINGMASKBITS > 8
			mask = (mask & 0x5555) + (mask >> 1 & 0x5555);
			mask = (mask & 0x3333) + (mask >> 2 & 0x3333);
			mask = (mask + (mask >> 4)) & 0x0F0F;
			mask += mask >> 8;
			return (int)(mask & 255)-1;
#else
			mask = (mask & 0x55) + (mask >> 1 & 0x55);
			mask = (mask & 0x33) + (mask >> 2 & 0x33);
			mask = (mask + (mask >> 4)) & 0x0F;
			return (int)(mask - 1);
#endif
}

/*
* Return the mask of bits which are actually in use, excepting the
* given RingSet, if non-null. I.e. the mask which would be in use
* if that RingSet were discarded. RingFile structures are not
* included on the sets list, so they are accounted for in the
* pool->filemask.
*/
ringmask
ringAllocMask(struct RingPool const *pool, struct RingSet const *set0)
	{
			struct RingSet const *set;
			ringmask mask = pool->filemask;

			for (set = pool->sets; set; set = set->next)
				 mask |= set->mask;
			if (set0)		/* set0 may or may not be on the sets list */
				 mask &= ~set0->mask;
			return mask;
	}

/* Helper function for ringGarbageCollect */
ringmask
ringClearMask(struct RingPool *pool, union RingObject **objp, ringmask mask)
	{
			union RingObject *robj;
			ringmask omask;
			ringmask remmask = 0;

			while ((robj = *objp) != (union RingObject *) 0) {
			omask = robj->g.mask &= mask;
				if (!OBJISBOT(robj))
				remmask |= ringClearMask(pool, &robj->g.down, mask);
				/* Skip dummy objects (robj->g.mask == 0), but delete
				objects that are only in the memory ring. Also skip
					keys which must be kept as dummy keys (because they've
					signed something). */
				if (robj->g.mask && !(omask&~MEMRINGMASK) &&
					!(OBJISKEY(robj) && robj->k.sigsby != NULL)) {
					/*
					* Delete no-longer-used object.
					* This does not free the memring data area, however it will
					* be reclaimed in ringGarbageCollect once no objects are using
					* that area.
					*
					*/
				pgpAssert(OBJISBOT(robj) || !robj->g.down);
					*objp = robj->g.next;
					ringFreeObject(pool, robj);
				}
				else {
				/* Skip to next object */
				remmask |= omask;
					objp = &robj->g.next;
				}
			}
			return remmask;
	}

/*
* Reclaim all unused bits and delete any unreferenced memory objects.
*/
int
ringGarbageCollect(struct RingPool *pool)
{
		ringmask mask;

		/* Build sig lists so we know which keys act as signers.
		These should be left as dummy keys rather than freed. */
		ringPoolListSigsBy (pool);
			mask = ringAllocMask(pool, (struct RingSet const *)NULL);
			if (mask != pool->allocmask) {
					pool->allocmask = mask;
					mask = ringClearMask(pool, &pool->keys, mask);
					if (!(mask & MEMRINGMASK)) {
							memPoolEmpty(&pool->files[MEMRINGBIT].strings);
							memPoolEmpty(&pool->files[MEMRINGBIT].fpos);
							pool->files[MEMRINGBIT].freepos = NULL;
							return 1;	/* Something freed */
					}
			}
			return 0;			/* Nothing freed */
	}

/* Remove a single key from its hash chain */
static void
ringGarbageHackKey(struct RingPool *pool, struct RingKey *key)
{
	struct RingKey **keyp;
	
	keyp = &pool->hashtable[key->keyID[0]];

while (*keyp != key) {
	pgpAssert(*keyp);
	keyp = &(*keyp)->util;
	}

	*keyp = key->util;
}

/* Remove a single signature from its sigsby list */
static void
ringGarbageHackSig(struct RingSig *sig)
	{
			struct RingKey *key;
			struct RingSig **sigp;
		
			key = &sig->by->k;
			pgpAssert(KEYISKEY(key));

			/*
			* This could be one loop but for type rules, sigh...
			* The problem doesn't happen often, fortunately.
			* (The single loop can be expressed in C using the
			* cheat sigp = (struct RingSig **)&key->sigsby; but
			* while that's portable in practice, we eschew it
			* for the sake of ANSI C purity.)
			*/
			if (&key->sigsby->s == sig) {
				 key->sigsby = (union RingObject *)sig->nextby;
			} else {
					sigp = &key->sigsby->s.nextby;
					while (*sigp != sig)
						sigp = &(*sigp)->nextby;
					*sigp = sig->nextby;
			}
}

/*
* Delete a single object from the global pool if it is an unreferenced
* memory object.
*/
void
ringGarbageCollectObject(struct RingPool *pool, union RingObject *robj)
	{
			union RingObject **objp;

			if (robj->g.mask == MEMRINGMASK) {
					pgpAssert(!robj->g.down);
					objp = OBJISTOP(robj) ? &pool->keys : &robj->g.up->g.down;
					while (*objp != robj) {
						pgpAssert(*objp);
						objp = &(*objp)->g.next;
					}
					*objp = robj->g.next;
					if (OBJISKEY(robj))
						ringGarbageHackKey(pool, &robj->k);
else if (OBJISSIG(robj))
	ringGarbageHackSig(&robj->s);
ringFreeObject(pool, robj);
}
}

int
ringBitAlloc(struct RingPool *pool)
	{
			ringmask mask;

			/* Allocate a new bit */
			mask = ~pool->allocmask;
			if (!mask) {
					/* Wups, out of bits - try something before dying */
					ringGarbageCollect(pool);
					mask = ~pool->allocmask;
					if (!mask) {
						ringSimpleErr(pool, PGPERR_NO_KEYBITS);
						return PGPERR_NO_KEYBITS;
					}
			}
			return ringLsBitFind(mask);
	}

/*
* Allocate and deallocate useful structures.
* Note the interesting shenanigans used to allocate
* a structure the alignment of an enclosing union, ensuring
* that even on a maximally-perverse ANSI C implementation,
* it is safe to cast the returned structure pointer to a union
* pointer.
*/
union RingObject *
ringNewObject(struct RingPool *pool, int objtype)
	{
			union RingObject *robj;
			/* How to initialize each object to empty */
			static struct RingKey const nullkey = NULLRINGKEY;
			static struct RingSec const nullsec = NULLRINGSEC;
			static struct RingName const nullname = NULLRINGNAME;
			static struct RingSig const nullsig = NULLRINGSIG;
			static struct RingUnk const nullunk = NULLRINGUNK;
			static void const *nullobjs[RINGTYPE_MAX] = {
					&nullkey, &nullsec, &nullname, &nullsig, &nullunk
			};
			size_t const sizes[RINGTYPE_MAX] = {
				 sizeof(struct RingKey), sizeof(struct RingSec),
				 sizeof(struct RingName), sizeof(struct RingSig),
				 sizeof(struct RingUnk)
			};

		/* Object types are 1-based */
		pgpAssert(objtype > 0);
		pgpAssert(objtype <= RINGTYPE_MAX);

			robj = pool->freeobjs[objtype-1];
			if (robj) {
pool->freeobjs[objtype-1] = robj->g.next;
} else {
robj = (union RingObject *)
	memPoolAlloc(&pool->structs, sizes[objtype-1],
		alignof(union RingObject));
if (!robj) {
	ringAllocErr(pool);
	return NULL;
}
}
memcpy(robj, nullobjs[objtype-1], sizes[objtype-1]);
pgpAssert(ringObjectType(robj) == objtype);
return robj;
}

/*
* Free an object. This does not do any cleanup with any pointers in the
* object.
*/
void
ringFreeObject(struct RingPool *pool, union RingObject *obj)
{
int type = ringObjectType(obj);

pgpAssert(type > 0);
pgpAssert(type <= RINGTYPE_MAX);

obj->g.next = pool->freeobjs[type-1];
pool->freeobjs[type-1] = obj;
}

/*
* Remove an object from its parent and free it. This does not do
* anything with the object's FilePos list.
*/
void
ringRemObject(struct RingPool *pool, union RingObject *obj)
{
			union RingObject **objp;

			pgpAssert(!OBJISTOP(obj));
			objp = &obj->g.up->g.down;

			/* Unlink the object from its parent */
			while (*objp != obj) {

⌨️ 快捷键说明

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