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

📄 pgpeckey.c

📁 可以实现对邮件的加密解密以及签名
💻 C
📖 第 1 页 / 共 5 页
字号:

	i = ((unsigned)buf[2] << 8) + buf[3];
	if (!i || buf[3] >> ((i-1) & 7) != 1) {
		*error = kPGPError_MalformedKeyComponent;
		return NULL;	/* Bad bit length */
	}
	i = (i+7)/8;
	if (size < 4+i) {
		*error = kPGPError_KeyPacketTruncated;
		return NULL;
	}
	curve = sCurveIndexFromName( buf+4, i );
	if( curve < 0 )
	{
		/* Unrecognized name */
		*error = kPGPError_MalformedKeyComponent;
		return NULL;
	}

	t = ((unsigned)buf[4+i] << 8) + buf[5+i];
	if (!t || buf[6+i] >> ((t-1) & 7) != 1) {
		*error = kPGPError_MalformedKeyComponent;
		return NULL;	/* Bad bit length */
	}
	t = (t+7)/8;
	if (size < 6+i+t) {
		*error = kPGPError_KeyPacketTruncated;
		return NULL;
	}

	pub = (ECpub *)pgpContextMemAlloc( context,
		sizeof(*pub), kPGPMemoryMgrFlags_Clear );
	if (pub) {
		pubkey = (PGPPubKey *)pgpContextMemAlloc( context,
			sizeof(*pubkey), kPGPMemoryMgrFlags_Clear);
		if (pubkey) {
			ecContextRef ec;
			BigNum bnorder;
			PGPUInt32 scalarSize;

			pubkey->context	= context;

			if( ecCreate2mContext( mgr, sCurves[curve].bitsize,
								   EC_MEM_USAGE_HIGH, &pub->ec )<0 )
			{
				pgpContextMemFree( context, pubkey );
				*error = kPGPError_OutOfMemory;
				return NULL;
			}
			ec = pub->ec;

			ecSetEC2mParamAInt( ec, sCurves[curve].a );
			ecSetEC2mParamB( ec, sCurves[curve].b );

			ecGetBufferSize( pub->ec, NULL, &scalarSize, NULL, NULL );

			bnBegin( &bnorder, mgr, INSECURE );
			pub->cofactor = sCurves[curve].cofactor;

			if( ecPointCreate( ec, &pub->y ) >= 0
				&& ecPointCreate( ec, &pub->g ) >= 0
				&& ecScalarCreate( ec, &pub->order, INSECURE ) >= 0
				&& ecPointInsertBytes( pub->g, sCurves[curve].g, 0 ) >= 0
				&& bnInsertBigBytes( &bnorder, sCurves[curve].order,
									 0, scalarSize ) >= 0
				&& sBNtoScalar( &bnorder, pub->order, mgr, scalarSize )>=0
				&& ecPointInsertBytes( pub->y, buf+6+i, 0 ) >= 0 )
			{
				ecFillPubkey(pubkey, pub);
				bnEnd( &bnorder );
				*error = 0;
				return pubkey;
			}
			/* Failed = clean up and return NULL */
			err = kPGPError_OutOfMemory;
			bnEnd( &bnorder );
			if( IsntNull( pub->y ) )
				ecPointFree( pub->y );
			if( IsntNull( pub->g ) )
				ecPointFree( pub->g );
			if( IsntNull( pub->order ) )
				ecScalarFree( pub->order );
		}
		pgpContextMemFree( context, pub);
	}

	*error = err;
	return NULL;
}

/*
 * Return the size of the public portion of a key buffer.
 */
int
ecPubKeyPrefixSize(PGPByte const *buf, PGPSize size)
{
	return 2 + pgpBnParse(buf+2, size-2, 2, NULL, NULL);
}



/** Secret key functions **/

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

	pgpAssertAddrValid( seckey, PGPPubKey );
	context	= seckey->context;

	ASSERTEC(seckey->pkAlg);

	if( !sec->locked )
	{
		/* Locked keys have no data in these fields */
		ecPointFree( sec->s.y );
		ecPointFree( sec->s.g );
		ecScalarFree( sec->s.order );
		ecScalarFree( sec->s.x );
		ecFreeContext( sec->s.ec );
	}

	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 *
ecPubkey(PGPSecKey const *seckey)
{
	/* Not implemented - only needed for X.509 and smart card keys */
	(void) seckey;
	pgpAssert( 0 );
	return NULL;
}

/*
 * Set keyid
 */
static void
ecSecSetKeyID(PGPSecKey *seckey, PGPByte *keyid)
{
	pgpCopyMemory(keyid, seckey->keyID, sizeof(seckey->keyID));
}

/*
 * 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
ecIslocked(PGPSecKey const *seckey)
{
	ECsecPlus const *sec = (ECsecPlus *)seckey->priv;

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


/*
 * Return the algorithm and (symmetric) key size used for locking/unlocking
 * the secret key.
 */
static PGPError
ecLockingAlgorithm(
	PGPSecKey const *seckey,
	PGPCipherAlgorithm *pAlg,
	PGPSize *pAlgKeySize
	)
{
	ECsecPlus *sec = (ECsecPlus *)seckey->priv;
	PGPCipherVTBL const *cipher;
	PGPByte alg;
	int i;

	ASSERTEC(seckey->pkAlg);

	if( IsntNull( pAlg ) )
		*pAlg = (PGPCipherAlgorithm) 0;
	if( IsntNull( pAlgKeySize ) )
		*pAlgKeySize = (PGPSize) 0;

	/* Check packet for basic consistency */
	i = pgpBnParse(sec->cryptkey+2, sec->cklen-2, 2, NULL, NULL);
	if (i < 0)
		return (PGPError)i;
	i += 2;

	/* Get the encryption algorithm (cipher number).  0 == no encryption */
	alg = sec->cryptkey[i] & 255;

	/* New style has 0xff or 0xfe then algorithm value */
	if (alg == 0xff || alg == 0xfe)
		alg = sec->cryptkey[i+1] & 255;

	cipher = pgpCipherGetVTBL( (PGPCipherAlgorithm)alg);
	if (!cipher)
		return kPGPError_BadCipherNumber;

	/* Success */
	if( IsntNull( pAlg ) )
		*pAlg = (PGPCipherAlgorithm) alg;
	if( IsntNull( pAlgKeySize ) )
		*pAlgKeySize = cipher->keysize;

	return kPGPError_NoErr;
}


/*
 * Return the StringToKey type for unlocking the given key.  We use
 * kPGPStringToKey_Literal to flag a secret split unlocking buffer.
 * Returns kPGPStringToKey_Simple if key has no passphrase.
 */
static PGPError
ecS2KType(
	PGPSecKey const *seckey,
	PGPStringToKeyType *s2kType
	)
{
	ECsecPlus *sec = (ECsecPlus *)seckey->priv;
	PGPByte alg;
	int i;

	ASSERTEC(seckey->pkAlg);

	/* note that 0 is a valid type, but use it as default anyway */
	if( IsntNull( s2kType ) )
		*s2kType = (PGPStringToKeyType) 0;

	/* Check packet for basic consistency */
	i = pgpBnParse(sec->cryptkey+2, sec->cklen-2, 2, NULL, NULL);
	if (i < 0)
		return (PGPError)i;
	i += 2;

	/* Get the encryption algorithm (cipher number).  0 == no encryption */
	alg = sec->cryptkey[i] & 255;

	if (alg == 0xff || alg == 0xfe) {
		/* New style has 0xff or 0xfe then algorithm value then S2K */
		*s2kType = (PGPStringToKeyType) sec->cryptkey[i+2];
	} else {
		/* Unencrypted or old-style simple encryption */
		*s2kType = kPGPStringToKey_Simple;
	}

	return kPGPError_NoErr;
}


/*
 * Convert a passphrase into a s2k literal buffer for the key.
 * Returns error code.  Output buffer will be size of the *pAlgKeySize
 * parameter from pgpSecKeyLockingalgorithm.
 */
static PGPError
ecConvertPassphrase(PGPSecKey *seckey, PGPEnv const *env,
	  char const *phrase, PGPSize plen, PGPByte *outbuf)
{
	ECsecPlus *sec = (ECsecPlus *)seckey->priv;
	PGPStringToKey *s2k;
	PGPByte alg;
	PGPBoolean hasS2K;
	PGPCipherVTBL const *cipher;
	int i;
	PGPContextRef	context	= pgpenvGetContext( env );

	ASSERTEC(seckey->pkAlg);
	pgpAssert (IsntNull( outbuf ) );

	/* Check packet for basic consistency */
	i = pgpBnParse(sec->cryptkey+2, sec->cklen-2, 2, NULL, NULL, NULL, NULL);
	if (i < 0)
		return (PGPError)i;
	i += 2;

	/* Get the encryption algorithm (cipher number).  0 == no encryption */
	alg = sec->cryptkey[i++] & 255;

	hasS2K = (alg == 0xff || alg == 0xfe);

	/* New style has 255 then algorithm value */
	if (hasS2K)
		alg = sec->cryptkey[i++] & 255;

	/* Now we are looking at the s2k object if there is one. */
	if (alg == 0) {
		/* Key is not locked */
		return kPGPError_BadParams;
	}
	cipher = pgpCipherGetVTBL( (PGPCipherAlgorithm)alg);
	if( IsNull( cipher ) )
		return kPGPError_BadCipherNumber;

	if (hasS2K) {
		pgpS2Kdecode(&s2k, context, sec->cryptkey+i, sec->cklen-i);
	} else {
		s2k = pgpS2Ksimple(context, pgpHashByNumber(kPGPHashAlgorithm_MD5));
	}
	if (IsNull( s2k ) )
		return kPGPError_OutOfMemory;
	pgpStringToKey(s2k, phrase, plen, outbuf, cipher->keysize);
	pgpS2Kdestroy (s2k);

	return kPGPError_NoErr;
}


/*
 * Try to decrypt the secret key wih the given passphrase.  Returns >0
 * if it was the correct passphrase. =0 if it was not, and <0 on error.
 * Does not alter the key even if it's the wrong passphrase and already
 * unlocked.  A NULL passphrae will work if the key is unencrypted.
 * 
 * A (secret) key's EC-specific part is:
 *
 *  0      2    Curve type (=0)
 *  2      2+s  Curve name (s=strlen(name))
 * 4+s     2+p  Public curve point (p=pointSize)
 * 6+s+p   e    Encryption algorithm data, S2K info
 * 6+s+p+e 2+w  MPI for x, secret part (w=scalarSize)
 * 8+s+p+e+w
 */

static int
ecUnlock(PGPSecKey *seckey,
	  char const *phrase, PGPSize plen, PGPBoolean hashedPhrase)
{
	ECsecPlus *sec = (ECsecPlus *)seckey->priv;
	ecContextRef ec;
	BigNum bnx, bny, bnorder;
	PGPCFBContext *cfb = NULL;	/* Necessary */
	PGPUInt32 v, t, yoff;
	
	PGPByte alg /* actual algorithm */, alg0 /* first algorithm descriptor */;
        PGPHashContextRef checksumHash = NULL;
        PGPHashVTBL const *hashEntry = NULL;
        PGPByte checksumStored[20], checksum[20];       /* size no less then the max return value from pgpChecksumGetEx */
        unsigned checksumSize;
	
	PGPUInt32 scalarSize, pointSize;
	PGPInt32 curve;
	int i;
	PGPMemoryMgrRef		mgr	= NULL;

	if( pgpFIPSModeEnabled() )
	{
		/* FIPS does not allow using keys with NULL passphrases */
		if( IsNull( phrase ) || plen == 0 )
			return( 0 );
	}
	
	mgr	= PGPPeekContextMemoryMgr( seckey->context );

	ASSERTEC(seckey->pkAlg);
	bnInit();

	if (sec->cklen < 8)
		return kPGPError_KeyPacketTruncated;
	if( sec->cryptkey[0] != 0 || sec->cryptkey[1] != 0 )
		return kPGPError_MalformedKeyComponent;

	v = ((unsigned)sec->cryptkey[2] << 8) + sec->cryptkey[3];
	if (!v || sec->cryptkey[4] >> ((v-1) & 7) != 1) {
		return kPGPError_MalformedKeyComponent;
	}
	v = (v+7)/8;
	if (sec->cklen < 8+v)
		return kPGPError_KeyPacketTruncated;
	curve = sCurveIndexFromName( sec->cryptkey+4, v );
	if( curve < 0 )
	{
		/* Unrecognized name */
		return kPGPError_MalformedKeyComponent;
	}

	t = ((unsigned)sec->cryptkey[4+v] << 8) + sec->cryptkey[5+v];
	if (!t || sec->cryptkey[6+v] >> ((t-1) & 7) != 1) {
		return kPGPError_MalformedKeyComponent;
	}
	t = (t+7)/8;
	if (sec->cklen < 6+v+t)
		return kPGPError_KeyPacketTruncated;
	yoff = 6+v;
	v += t + 6;
	if (sec->cklen < v+1)
		return kPGPError_KeyPacketTruncated;

	/* Get the encryption algorithm (cipher number).  0 == no encryption */
	alg0 = alg = sec->cryptkey[v];
	if( alg0 == 0xff || alg0 == 0xfe  )
		alg = sec->cryptkey[v+1];

	/* If the phrase is empty, set it to NULL */
	if (plen == 0)
		phrase = NULL;
	/*
	 * We need a pass if it is encrypted, and we cannot have a
	 * password if it is NOT encrypted.  I.e., this is a logical
	 * xor (^^)
	 */
	if (!phrase != !alg0)
		return 0;

	hashEntry = pgpHashByNumberWithMask( alg0!=0xfe ? kPGPHashAlgorithm_Checksum16 : kPGPHashAlgorithm_SHA, 0xffffffff );
	checksumHash = pgpHashCreate( mgr, hashEntry );
	if( checksumHash == NULL )  { 
		i = kPGPError_BadHashNumber;
		goto done;
	}

	i = pgpCipherSetup(sec->cryptkey + v, sec->cklen - v, phrase, plen,
					   hashedPhrase, FALSE, seckey->context, &cfb);
	if (i < 0)
		return i;
	v += i;

	PGPResethash( checksumHash );
	bnBegin( &bnx, mgr, SECURE );
	bnBegin( &bny, mgr, INSECURE );
	bnBegin( &bnorder, mgr, INSECURE );

	if (bnInsertBigBytes(&bny, sec->cryptkey+yoff, 0, t) < 0)
		goto nomem;

	i = pgpBnGet(&bnx, sec->cryptkey + v, sec->cklen - v, cfb, alg0, FALSE/*old*/, checksumHash);
	if (i <= 0)
		goto badpass;
	v += i;

        /* Check that we ended in the right place */
	checksumSize = pgpChecksumGet( sec->cryptkey+v, NULL, alg, NULL );
	pgpAssert( checksumSize <= sizeof(checksumStored) );    /* programmer's error */
	if (sec->cklen - v != checksumSize)  {
		i = kPGPError_KEY_LONG;
		goto fail;
	}

	pgpChecksumGet(sec->cryptkey+v, cfb, alg, checksumStored);
	PGPFinalizeHash( checksumHash, checksumHash );
	if( !pgpMemoryEqual( checksumStored, checksumHash, checksumSize ) )
		goto badpass;
	
	if( ecCreate2mContext( mgr, sCurves[curve].bitsize,
						   EC_MEM_USAGE_HIGH, &sec->s.ec ) < 0 )
		goto nomem;
	ec = sec->s.ec;

	ecSetEC2mParamAInt( ec, sCurves[curve].a );
	ecSetEC2mParamB( ec, sCurves[curve].b );
	ecGetBufferSize( ec, NULL, &scalarSize, NULL, &pointSize );

	sec->s.cofactor = sCurves[curve].cofactor;

	if( ecPointCreate( ec, &sec->s.y ) >= 0
		&& ecPointCreate( ec, &sec->s.g ) >= 0
		&& ecScalarCreate( ec, &sec->s.order, INSECURE ) >= 0
		&& ecScalarCreate( ec, &sec->s.x, SECURE ) >= 0
		&& ecPointInsertBytes( sec->s.g, sCurves[curve].g, 0 )>=0
		&& bnInsertBigBytes( &bnorder, sCurves[curve].order,
							 0, scalarSize ) >= 0
		&& sBNtoScalar( &bnorder, sec->s.order, mgr, scalarSize ) >= 0
		&& sBNtoPoint( &bny, sec->s.y, mgr, pointSize ) >= 0
		&& sBNtoScalar( &bnx, sec->s.x, mgr, scalarSize ) >= 0 )
	{

#if 0
// Debugging sanity check that g^x == y
{
ecPointRef zero, neggx;
ecScalarRef negx;
BigNum bnnegx;
bnBegin( &bnnegx, mgr, SECURE );
bnCopy( &bnnegx, &bnorder );

⌨️ 快捷键说明

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