pgpdsakey.c

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

C
1,290
字号
/*
 * pgpDSAKey.c -- Signatures using the Digital Signature Algorithm
 *
 * Copyright (C) 1996,1997 Pretty Good Privacy, Inc.  All rights reserved.
 *
 * $Id: pgpDSAKey.c,v 1.10.2.4 1997/06/13 04:15:25 hal Exp $
 */

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

#include "pgpDebug.h"
#include "pgpDSAKey.h"
#include "pgpKeyMisc.h"
#include "bn.h"
#include "pgpCipher.h"
#include "pgpCFB.h"
#include "pgpHash.h"
#include "pgpMem.h"
#include "pgpErr.h"
#include "pgpFixedKey.h"
#include "bnprime.h"
#include "pgpPubKey.h"
#include "pgpRndom.h"
#include "pgpStr2Key.h"
#include "pgpUsuals.h"

#ifndef NULL
#define NULL 0
#endif

#define ASSERTDSA(alg) pgpAssert((ALGMASK(alg))==PGP_PKALG_DSA)

#define MAX_DSA_PRIME_BITS		1024

struct DSApub {
	struct BigNum p;		/* Public prime */
	struct BigNum q;		/* Public order of generator */
	struct BigNum g;		/* Public generator */
	struct BigNum y;		/* Public key, g**x mod p */
};

struct DSAsec {
	struct BigNum p;		/* Copy of public parameters */
	struct BigNum q;
	struct BigNum g;
	struct BigNum y;
	struct BigNum x;		/* Secret key, discrete log of y */
};


/* A PgpSecKey's priv points to this, an DSAsec plus the encrypted form... */
struct DSAsecPlus {
	struct DSAsec s;
	byte *cryptkey;
	size_t ckalloc, cklen;
	int locked;
};

/** Public key functions **/

static void
dsaPubDestroy(struct PgpPubKey *pubkey)
{
	struct DSApub *pub = (struct DSApub *)pubkey->priv;

	ASSERTDSA(pubkey->pkAlg);
	
	bnEnd(&pub->p);
	bnEnd(&pub->q);
	bnEnd(&pub->g);
	bnEnd(&pub->y);
	memset(pub, 0, sizeof(pub));
	pgpMemFree(pub);
	memset(pubkey, 0, sizeof(pubkey));
	pgpMemFree(pubkey);
}

/*
 * This returns TRUE if the key is too big, returning the
 * maximum number of bits that the library can accept.
 */
static int
dsaKeyTooBig(struct DSApub const *pub, struct DSAsec const *sec)
{
	unsigned maxsize = MAX_DSA_PRIME_BITS;
	if (pub) {
		if (bnBits(&pub->p) > maxsize)
			return maxsize;
	}
	if (sec) {
		if (bnBits(&sec->p) > maxsize)
			return maxsize;
	}
	/* Else OK */
	return 0;
}

#if 0
static void
dsaPubId8(struct PgpPubKey const *pubkey, byte *buf)
{
	pgpAssert(0);
	struct DSApub const *pub = (struct DSApub *)pubkey->priv;
	byte *keybuf;
	size_t keybuflen;
	struct PgpHash const *h;
	struct PgpHashContext *hc;

	ASSERTDSA(pubkey->pkAlg);

	/* Unfortunately we have no way of indicating failure */
	h = pgpHashByNumber (PGP_HASH_SHA);
	pgpAssert(h);
	hc = pgpHashCreate(h);
	pgpAssert(hc);

	keybuflen = dsaPubBufferLength(pubkey);
	keybuf = pgpMemAlloc(keybuflen);
	pgpAssert(keybuf);
	dsaPubToBuffer(pubkey, keybuf);

	pgpHashUpdate(hc, keybuf, keybuflen);
	memcpy (buf, pgpHashFinal(hc), 8);
	pgpHashDestroy(hc);
}
#endif

/* Return the largest possible PgpESK size for a given key */
static size_t
dsaMaxesk(struct PgpPubKey const *pubkey, PgpVersion version)
{
	(void)pubkey;
	(void)version;
	return PGPERR_PUBKEY_UNIMP;
}

/*
 * Given a buffer of at least "maxesk" bytes, make an PgpESK
 * into it and return the size of the PgpESK, or <0.
 */
static int
dsaEncrypt(struct PgpPubKey const *pubkey, byte const *key,
           size_t keylen, byte *esk, size_t *esklen,
           struct PgpRandomContext const *rc, PgpVersion version)
{
	(void)pubkey;
	(void)key;
	(void)keylen;
	(void)esk;
	(void)esklen;
	(void)rc;
	(void)version;
	return PGPERR_PUBKEY_UNIMP;
}

/*
 * Return 1 if (sig,siglen) is a valid MPI which signs
 * hash, of type h.  Verify that the type is SHA.1 and
 * the hash itself matches.
 */
static int
dsaVerify(struct PgpPubKey const *pubkey, int sigtype, byte const *sig,
	size_t siglen, struct PgpHash const *h, byte const *hash)
{
	struct DSApub const *pub = (struct DSApub *)pubkey->priv;
	struct BigNum r, s, w, u2;
	int i;
	size_t off;

	(void)sigtype;

	ASSERTDSA(pubkey->pkAlg);

	if (h->type != PGP_HASH_SHA)
		return 0;	/* No match for sure! */

	bnBegin(&r);
	bnBegin(&s);
	bnBegin(&w);
	bnBegin(&u2);

	/* sig holds two values.  Get first, r, from sig. */
	off = 0;
	i = pgpBnGetPlain(&r, sig+off, siglen-off);
	if (i <= 0)
		goto fail;
	/* Get 2nd value, s, from SIG */
	off += i;
	i = pgpBnGetPlain(&s, sig+off, siglen-off);
	if (i <= 0)
		goto fail;
	off += i;
	if (off != siglen) {
		i = PGPERR_SIG_TOOLONG;
		goto done;
	}

	/*
	 * Sanity-check r and s against the subprime q.  Both should
	 * be less than q.  If not, the signature is clearly bad.
	 */
	if (bnCmp(&r, &pub->q) >= 0 || bnCmp(&s, &pub->q) >= 0) {
		i = 0;	/* FAIL */
		goto done;
	}
	
	/* Reconstruct hash as u2 */
	/* @@@: complicated issues re packing, 160 bits is tight... */
	if (bnInsertBigBytes(&u2, hash, 0, h->hashsize) < 0)
		goto nomem;

	/*
	 * Calculate DSS check function....
	 * Given signature (r,s) and hash H (in bn), compute:
	 * w = s^-1 mod q
	 * u1 = H * w mod q
	 * u2 = r * w mod q
	 * v = g^u1 * y^u2 mod p
	 * if v == r mod q, the signature checks.
	 *
	 * To save space, we put u1 into s, H into u2, and v into w.
	 */
	if (bnInv(&w, &s, &pub->q) < 0)
		goto nomem;
	if (bnMul(&s, &u2, &w) < 0 || bnMod(&s, &s, &pub->q) < 0)
		goto nomem;
	if (bnMul(&u2, &r, &w) < 0 || bnMod(&u2, &u2, &pub->q) < 0)
		goto nomem;

        /* Now for the expensive part... */

        if (bnDoubleExpMod(&w, &pub->g, &s, &pub->y, &u2, &pub->p) < 0)
                goto nomem;
        if (bnMod(&w, &w, &pub->q) < 0)
                goto nomem;

	/* Compare result with r, should be equal */
	i = bnCmp(&w, &r) == 0;

	goto done;

fail:
	if (!i)
		i = PGPERR_SIG_TOOSHORT;
	goto done;
nomem:
	i = PGPERR_NOMEM;
	goto done;
done:
	bnEnd(&u2);
	bnEnd(&w);
	bnEnd(&s);
	bnEnd(&r);

	return i;
}

/*
 * Turn a PgpPubKey into the algorithm-specific parts of a public key.
 * A public key's DSA-specific part is:
 *
 *  0      2+i  MPI for prime
 * 2+i     2+t  MPI for order
 * 4+i+t   2+u	MPI for generator
 * 6+i+t+u 2+v	MPI for public key
 * 8+i+t+u+v
 */
static size_t
dsaPubBufferLength(struct PgpPubKey const *pubkey)
{
	struct DSApub const *pub = (struct DSApub *)pubkey->priv;

	return 8 + (bnBits(&pub->p)+7)/8 + (bnBits(&pub->q)+7)/8 +
		   (bnBits(&pub->g)+7)/8 + (bnBits(&pub->y)+7)/8;
}

static void
dsaPubToBuffer(struct PgpPubKey const *pubkey, byte *buf)
{
	struct DSApub const *pub = (struct DSApub *)pubkey->priv;
	unsigned off;

	off = 0;
	off += pgpBnPutPlain(&pub->p, buf+off);
	off += pgpBnPutPlain(&pub->q, buf+off);
	off += pgpBnPutPlain(&pub->g, buf+off);
	off += pgpBnPutPlain(&pub->y, buf+off);
}


/* A little helper function that's used twice */
static void
dsaFillPubkey(struct PgpPubKey *pubkey, struct DSApub *pub)
{
	pubkey->next	 = NULL;
	pubkey->pkAlg	 = PGP_PKALG_DSA;
	pubkey->priv	 = pub;
	pubkey->destroy  = dsaPubDestroy;
#if 0
	pubkey->id8      = dsaPubId8;
#endif
	pubkey->maxesk   = dsaMaxesk;
	pubkey->encrypt  = dsaEncrypt;
	pubkey->verify   = dsaVerify;
	pubkey->bufferLength  = dsaPubBufferLength;
	pubkey->toBuffer = dsaPubToBuffer;
}


/*
 * Turn the algorithm-specific parts of a public key into a PgpPubKey
 * structure.  A public key's DSA-specific part is:
 *
 *  0      2+i  MPI for prime
 * 2+i     2+t  MPI for order
 * 4+i+t   2+u	MPI for generator
 * 6+i+t+u 2+v	MPI for public key
 * 8+i+t+u+v
 */
struct PgpPubKey *
dsaPubFromBuf(byte const *buf, size_t size, int *error)
{
	struct PgpPubKey *pubkey;
	struct DSApub *pub;
	int err = PGPERR_NOMEM;
	unsigned i, t, u, v;
	int w;

	bnInit();

	w = pgpBnParse(buf, size, 4, &i, &t, &u, &v);
	if (w < 0) {
		*error = w;
		return NULL;
	}
	if (t <= i+2 || (buf[t-1] & 1) == 0) {	/* Too small or even prime p */
		*error = PGPERR_KEY_MPI;
		return NULL;
	}
	if (u <= t+2 || (buf[u-1] & 1) == 0) {	/* Too small or even order q */
		*error = PGPERR_KEY_MPI;
		return NULL;
	}
	pub = (struct DSApub *)pgpMemAlloc(sizeof(*pub));
	if (pub) {
		pubkey = (struct PgpPubKey *)pgpMemAlloc(sizeof(*pubkey));
		if (pubkey) {
			bnBegin(&pub->p);
			bnBegin(&pub->q);
			bnBegin(&pub->g);
			bnBegin(&pub->y);
			if (bnInsertBigBytes(&pub->p, buf+i+2, 0, t-i-2) >= 0
			 && bnInsertBigBytes(&pub->q, buf+t+2, 0, u-t-2) >= 0
			 && bnInsertBigBytes(&pub->g, buf+u+2, 0, v-u-2) >= 0
			 && bnInsertBigBytes(&pub->y, buf+v+2, 0, w-v-2) >= 0)
			{
				if (dsaKeyTooBig (pub, NULL)) {
					err = PGPERR_KEY_UNSUPP;
				} else {
					dsaFillPubkey(pubkey, pub);
					*error = 0;
					return pubkey;
				}
			}
			/* Failed = clean up and return NULL */
			bnEnd(&pub->p);
			bnEnd(&pub->q);
			bnEnd(&pub->g);
			bnEnd(&pub->y);
			pgpMemFree(pubkey);
		}
		pgpMemFree(pub);
	}
	*error = err;
	return NULL;
}

/*
 * Return the size of the public portion of a key buffer.
 */
int
dsaPubKeyPrefixSize(byte const *buf, size_t size)
{
	return pgpBnParse(buf, size, 4, NULL, NULL, NULL, NULL);
}


/** Secret key functions **/

static void
dsaSecDestroy(struct PgpSecKey *seckey)
{
	struct DSAsecPlus *sec = (struct DSAsecPlus *)seckey->priv;

	ASSERTDSA(seckey->pkAlg);
	bnEnd(&sec->s.p);
	bnEnd(&sec->s.q);
	bnEnd(&sec->s.g);
	bnEnd(&sec->s.y);
	bnEnd(&sec->s.x);
	memset(sec->cryptkey, 0, sec->ckalloc);
	pgpMemFree(sec->cryptkey);
	memset(sec, 0, sizeof(sec));
	pgpMemFree(sec);
	memset(seckey, 0, sizeof(seckey));
	pgpMemFree(seckey);
}

#if 0
static void
dsaSecId8(struct PgpSecKey const *seckey, byte *buf)
{
	struct DSAsecPlus const *sec = (struct DSAsecPlus *)seckey->priv;

	ASSERTDSA(seckey->pkAlg);
	bnExtractBigBytes(&sec->s.p, buf, 0, 8);
}
#endif

/*
 * Generate a PgpPubKey from a PgpSecKey
 */
static struct PgpPubKey *
dsaPubkey(struct PgpSecKey const *seckey)
{
	struct DSAsecPlus const *sec = (struct DSAsecPlus *)seckey->priv;
	struct PgpPubKey *pubkey;
	struct DSApub *pub;

⌨️ 快捷键说明

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