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

📄 pgpelgkey.c

📁 vc环境下的pgp源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * pgpElGKey.c
 * El Gamal encryption
 *
 * $Id: pgpElGKey.c,v 1.56.6.1 1999/06/04 00:28:55 heller Exp $
 */

#include "pgpConfig.h"
#include <string.h>
#include <stddef.h>

#include "pgpSDKBuildFlags.h"
#include "pgpDebug.h"
#include "pgpElGKey.h"
#include "pgpKeyMisc.h"
#include "bn.h"
#include "bnprime.h"
#include "pgpCFBPriv.h"
#include "pgpSymmetricCipherPriv.h"
#include "pgpHashPriv.h"
#include "pgpFixedKey.h"
#include "bngermain.h"
#include "pgpHash.h"
#include "pgpMem.h"
#include "pgpErrors.h"
#include "bnprime.h"
#include "pgpPubKey.h"
#include "pgpRandomX9_17.h"
#include "pgpStr2Key.h"
#include "pgpContext.h"
#include "pgpEnv.h"

#ifndef NULL
#define NULL 0
#endif

#define ASSERTELG(alg) pgpAssert((ALGMASK(alg))==kPGPPublicKeyAlgorithm_ElGamal)

typedef struct ELGpub
{
	BigNum p;		/* Public prime */
	BigNum g;		/* Public generator */
	BigNum y;		/* Public key, g**x mod p */
} ELGpub;

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

/* A PGPSecKey's priv points to this, an ELGsec plus the encrypted form... */
/* This struct is always allocated using PGPNewSecureData */
typedef struct ELGsecPlus
{
	PGPContextRef	context;
	
	ELGsec s;
	PGPByte *cryptkey;
	size_t ckalloc, cklen;
	int locked;
} ELGsecPlus;

/** Public key functions **/

static void
elgPubDestroy(PGPPubKey *pubkey)
{
	ELGpub *pub = (ELGpub *)pubkey->priv;
	PGPContextRef	context	= pubkey->context;

	ASSERTELG(pubkey->pkAlg);
	
	bnEnd(&pub->p);
	bnEnd(&pub->g);
	bnEnd(&pub->y);
	pgpClearMemory( pub,  sizeof(pub));
	pgpContextMemFree( context, pub);
	pgpClearMemory( pubkey,  sizeof(pubkey));
	pgpContextMemFree( context, pubkey);
}

/*
 * Return the largest possible PGPESK size for a given key.
 * Must hold two numbers up to p in size.
 */
static size_t
elgPubMaxesk(PGPPubKey const *pubkey, PGPPublicKeyMessageFormat format)
{
	ELGpub const *pub = (ELGpub *)pubkey->priv;

	ASSERTELG(pubkey->pkAlg);
	if (format == kPGPPublicKeyMessageFormat_PGP)
		return 2*( 2 + bnBytes(&pub->p) );
	else if (format == kPGPPublicKeyMessageFormat_PKCS1 ||
			 format == kPGPPublicKeyMessageFormat_IKE)
		return 2*( bnBytes(&pub->p) );

	pgpAssert(0);
	return 0;
}

/*
 * Return the size of the buffer needed, worst-case, for the decrypted
 * output.  A trivially padded key (random padding length = 0)
 * can just be 0 2 0 <key>.
 */
static size_t
elgPubMaxdecrypted(PGPPubKey const *pubkey, PGPPublicKeyMessageFormat format)
{
	ELGpub const *pub = (ELGpub *)pubkey->priv;
	size_t size;

	ASSERTELG(pubkey->pkAlg);
	(void) format;

	size = bnBytes(&pub->p);
	return size < 3 ? 0 : size-3;
}


static size_t
elgPubMaxsig(PGPPubKey const *pubkey, PGPPublicKeyMessageFormat format)
{
	(void)pubkey;
	(void)format;
	return kPGPError_PublicKeyUnimplemented;
}


/*
 * Given a buffer of at least "maxesk" bytes, make an PGPESK
 * into it and return the size of the PGPESK, or <0.
 *
 * ElGamal encryption is a simple variant on non-interactove
 * Diffie-Hellman.  The recipient publishes g, p, and y = g**x mod p.
 * the sender picks a random xx, computes yy = g**xx mod p, and
 * the shared secret z = y**xx mod p = yy**x mod p = g**(x*xx) mod p, then
 * then sends z*m, where m is the message.  (Padded in the usual
 * PKCS manner.)
 */
static int
elgEncrypt(PGPPubKey const *pubkey, PGPByte const *key,
           size_t keylen, PGPByte *esk, size_t *esklen,
           PGPRandomContext const *rc, PGPPublicKeyMessageFormat format)
{
#if PGP_ENCRYPT_DISABLE /* [ */

	(void)pubkey;
	(void)key;
	(void)keylen;
	(void)esk;
	(void)esklen;
	(void)rc;
	(void)format;
	return kPGPError_FeatureNotAvailable;

#else /* PGP_ENCRYPT_DISABLE */  /* ]  [ */

	ELGpub const *pub = (ELGpub *)pubkey->priv;
	BigNum xx;		/* Random exponent */
	BigNum yy;		/* g**xx mod p */
	BigNum z;		/* y**xx mod p */
	unsigned t;
	unsigned xxbits, pbytes;
	int i;
	PGPMemoryMgrRef		mgr	= NULL;
	
	mgr	= PGPGetContextMemoryMgr( pubkey->context );

	/* We don't need this argument, although other algorithms may... */
	(void)format;
	
	/*
	 * Of these values, only xx is inherently sensitive, but others may
	 * hold some intermediate results we would prefer not to have leaked.
	 * So mark all as sensitive.
	 */
	bnBegin(&xx, mgr, TRUE );
	bnBegin(&yy, mgr, TRUE );
	bnBegin(&z, mgr, TRUE );

	ASSERTELG(pubkey->pkAlg);
	t = bnBits(&pub->p);
	if (t > 0xffff)
		return kPGPError_PublicKeyTooLarge;
	pbytes = (t + 7) / 8;
	if (keylen > pbytes)
		return kPGPError_PublicKeyTooSmall; /* data too big for pubkey */

	if( format == kPGPPublicKeyMessageFormat_PGP ) {
		/* Add checksum to key, place temporarily in esk buffer */
		t = 0;
		esk[0] = key[0];
		for (i = 1; i < (int)keylen; i++)
			t += esk[i] = key[i];
		esk[keylen] = (PGPByte)(t >> 8 & 255);
		esk[keylen+1] = (PGPByte)(t & 255);
		keylen += 2;
		key = esk;
	}

	/* Choose the random xx value to be used for this encryption */
	xxbits = pgpDiscreteLogExponentBits(bnBits(&pub->p))*3/2;
	if (pgpBnGenRand(&xx, rc, xxbits, 0, 0, xxbits) < 0)
		goto nomem;

	/* Do the two exponentiations necessary to compute yy and z */
	if (bnExpMod(&yy, &pub->g, &xx, &pub->p) < 0 ||
	    bnExpMod(&z,  &pub->y, &xx, &pub->p) < 0)
		goto nomem;

	/* Re-use xx to hold the PKCS-padded conventional key */
	if (pgpPKCSPack(&xx, key, keylen, PKCS_PAD_ENCRYPTED, pbytes, rc)<0)
		goto nomem;
	pgpAssert (bnCmp(&xx, &pub->p) < 0);
	
	/* Compute xx*z mod p, the encrypted session key we will transmit */
	if (bnMul(&z, &z, &xx) < 0 ||
	    bnMod(&z, &z, &pub->p) < 0)
		goto nomem;

	/* Pack the two values into the esk, first yy and then k+z */
	t  = pgpBnPutFormatted(&yy, esk, pbytes, format);
	t += pgpBnPutFormatted(&z, esk+t, pbytes, format);
	if (esklen)
		*esklen = (size_t)t;
	
	i = 0;
	goto done;
nomem:
	i = kPGPError_OutOfMemory;
done:
	bnEnd(&z);
	bnEnd(&yy);
	bnEnd(&xx);
	return i;

#endif /* PGP_ENCRYPT_DISABLE */ /* ] */
}



/*
 * Return 1 if (sig,siglen) is a valid MPI which signs
 * (hash, hashlen).
 * Not implementing ElGamal signatures, using DSS.
 */
static int
elgVerify(PGPPubKey const *pubkey, PGPByte const *sig,
	size_t siglen, PGPHashVTBL const *h, PGPByte const *hash,
	PGPPublicKeyMessageFormat format)
{
	(void)pubkey;
	(void)sig;
	(void)siglen;
	(void)h;
	(void)hash;
	(void)format;
	return kPGPError_PublicKeyUnimplemented;
}

/*
 * Turn a PGPPubKey into the algorithm-specific parts of a public key.
 * A public key's ELG-specific part is:
 *
 *  0      2+i  MPI for prime
 * 2+i     2+t  MPI for generator
 * 4+i+t   2+u	MPI for public key
 * 6+i+t+u
 */
static size_t
elgPubBufferLength(PGPPubKey const *pubkey)
{
	ELGpub const *pub = (ELGpub *)pubkey->priv;

	return 6 + bnBytes(&pub->p) + bnBytes(&pub->g) +
		bnBytes(&pub->y);
}

static void
elgPubToBuffer(PGPPubKey const *pubkey, PGPByte *buf)
{
	ELGpub const *pub = (ELGpub *)pubkey->priv;
	unsigned off;

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


/* A little helper function that's used twice */
static void
elgFillPubkey(PGPPubKey *pubkey, ELGpub *pub)
{
	pubkey->next	 = NULL;
	pubkey->pkAlg	 = kPGPPublicKeyAlgorithm_ElGamal;
	pubkey->priv	 = pub;
	pubkey->destroy  = elgPubDestroy;
	pubkey->maxesk   = elgPubMaxesk;
	pubkey->maxdecrypted   = elgPubMaxdecrypted;
	pubkey->maxsig   = elgPubMaxsig;
	pubkey->encrypt  = elgEncrypt;
	pubkey->verify   = elgVerify;
	pubkey->bufferLength  = elgPubBufferLength;
	pubkey->toBuffer = elgPubToBuffer;
}


/*
 * Turn the algorithm-specific parts of a public key into a PGPPubKey
 * structure.  A public key's ELG-specific part is:
 *
 *  0      2+i  MPI for prime
 * 2+i     2+t  MPI for generator
 * 4+i+t   2+u	MPI for public key
 * 6+i+t+u
 */
PGPPubKey *
elgPubFromBuf(
	PGPContextRef	context,
	PGPByte const *buf, size_t size, PGPError *error)
{
	PGPPubKey *pubkey;
	ELGpub *pub;
	unsigned i, t, u;
	int v;
	PGPError	err	= kPGPError_OutOfMemory;
	PGPMemoryMgrRef		mgr	= PGPGetContextMemoryMgr( context );
	
	bnInit();

	v = pgpBnParse(buf, size, 3, &i, &t, &u);
	if (v < 0) {
		*error = (PGPError)v;
		return NULL;
	}
	if ((buf[t-1] & 1) == 0) {	/* Too small or even prime p */
		*error = kPGPError_MalformedKeyComponent;
		return NULL;
	}

	pub = (ELGpub *)pgpContextMemAlloc( context,
			sizeof(*pub), kPGPMemoryMgrFlags_Clear);
	if (pub) {
		pubkey = (PGPPubKey *)pgpContextMemAlloc( context,
			sizeof(*pubkey), kPGPMemoryMgrFlags_Clear);
		if (pubkey) {
			pubkey->context	= context;
			bnBegin(&pub->p, mgr, FALSE );
			bnBegin(&pub->g, mgr, FALSE );
			bnBegin(&pub->y, mgr, FALSE );
			if (bnInsertBigBytes(&pub->p, buf+i+2, 0, t-i-2) >= 0
			    && bnInsertBigBytes(&pub->g, buf+t+2, 0,
						u-t-2) >= 0
			    && bnInsertBigBytes(&pub->y, buf+u+2, 0,
						v-u-2) >= 0)
			{
				elgFillPubkey(pubkey, pub);

				*error = kPGPError_NoErr;
				return pubkey;
			}
			else
			{
				err	= kPGPError_UnknownError;
			}
			
			/* Failed = clean up and return NULL */
			bnEnd(&pub->p);
			bnEnd(&pub->g);
			bnEnd(&pub->y);
			pgpContextMemFree( context, pubkey);
		}
		pgpContextMemFree( context, pub);
	}
	
	*error = err;
	return NULL;
}

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


/** Secret key functions **/

static void
elgSecDestroy(PGPSecKey *seckey)
{
	ELGsecPlus *sec = (ELGsecPlus *)seckey->priv;
	PGPContextRef		context;

	pgpAssertAddrValid( seckey, PGPSecKey );
	context	= seckey->context;
	
	pgpAssert( pgpContextIsValid( context ) );

	ASSERTELG(seckey->pkAlg);
	bnEnd(&sec->s.p);
	bnEnd(&sec->s.g);
	bnEnd(&sec->s.y);
	bnEnd(&sec->s.x);
	pgpClearMemory(sec->cryptkey, sec->ckalloc);
	pgpContextMemFree( context, sec->cryptkey);
	PGPFreeData( sec );			/* Wipes as it frees */
	pgpClearMemory( seckey,  sizeof(seckey));
	pgpContextMemFree( context, seckey);
}

/*
 * Generate a PGPPubKey from a PGPSecKey
 */
static PGPPubKey *
elgPubkey(
	PGPSecKey const *seckey)
{
	ELGsecPlus const *sec = (ELGsecPlus *)seckey->priv;
	PGPPubKey *pubkey;
	ELGpub *pub;
	PGPContextRef		context;
	PGPMemoryMgrRef		mgr	= NULL;

	pgpAssertAddrValid( seckey, PGPSecKey );
	context	= seckey->context;
	mgr	= PGPGetContextMemoryMgr( context );

	ASSERTELG(seckey->pkAlg);
	pub = (ELGpub *)pgpContextMemAlloc( context,
		sizeof(*pub), kPGPMemoryMgrFlags_Clear);
	if (pub) {
		pubkey = (PGPPubKey *)pgpContextMemAlloc( context,
			sizeof(*pubkey), kPGPMemoryMgrFlags_Clear);
		if (pubkey) {
			pubkey->context	= context;
			
			bnBegin(&pub->p, mgr, FALSE );
			bnBegin(&pub->g, mgr, FALSE );
			bnBegin(&pub->y, mgr, FALSE );
			if (bnCopy(&pub->p, &sec->s.p) >= 0
			    && bnCopy(&pub->g, &sec->s.g) >= 0
			    && bnCopy(&pub->y, &sec->s.y) >= 0)
			{
				elgFillPubkey(pubkey, pub);
				pubkey->pkAlg = seckey->pkAlg;
				memcpy(pubkey->keyID, seckey->keyID,
				       sizeof(pubkey->keyID));
				return pubkey;
			}
			/* Failed = clean up and return NULL */
			bnEnd(&pub->p);
			bnEnd(&pub->g);
			bnEnd(&pub->y);
			pgpContextMemFree( context, pubkey);
		}
		pgpContextMemFree( context, pub);
	}
	return NULL;
}

/*
 * Yes, there *is* a reason that this is a function and no a variable.
 * On a hardware device with an automatic timeout,
 * it actually might need to do some work to find out.
 */
static int
elgIslocked(PGPSecKey const *seckey)
{
	ELGsecPlus const *sec = (ELGsecPlus *)seckey->priv;

	ASSERTELG(seckey->pkAlg);
	return sec->locked;
}


/*
 * Return the algorithm and (symmetric) key size used for locking/unlocking

⌨️ 快捷键说明

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