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

📄 pgpeckey.c

📁 可以实现对邮件的加密解密以及签名
💻 C
📖 第 1 页 / 共 5 页
字号:
bnSub( &bnnegx, &bnx );
ecScalarCreate( ec, &negx, SECURE );
sBNtoScalar( &bnnegx, negx, mgr, scalarSize );
ecPointCreate( ec, &neggx );
ecPointMul( sec->s.g, negx, FALSE, neggx );
ecPointCreate( ec, &zero );
ecPointAdd( neggx, sec->s.y, zero );
pgpAssert( ecPointIsZero( zero ) );
ecPointFree( zero );
ecPointFree( neggx );
ecScalarFree( negx );
bnEnd (&bnnegx);
} 
#endif

		sec->locked = 0;
		if (cfb)
			PGPFreeCFBContext (cfb);
		bnEnd(&bny);
		bnEnd(&bnx);
		bnEnd(&bnorder);
		return 1;	/* Decrypted */
	}

	/* Fail, undo above */
	if( IsntNull( sec->s.y ) )
		ecPointFree( sec->s.y );
	if( IsntNull( sec->s.g ) )
		ecPointFree( sec->s.g );
	if( IsntNull( sec->s.order ) )
		ecScalarFree( sec->s.order );
	if( IsntNull( sec->s.x ) )
		ecScalarFree( sec->s.x );
	pgpClearMemory( &sec->s, sizeof( ECsec ) );
	/* Fall through */

nomem:
	i = kPGPError_OutOfMemory;
	goto done;
badpass:
	i = 0;	/* Incorrect passphrase */
	goto done;
fail:
	if (!i)
		i = kPGPError_KeyPacketTruncated;
	goto done;
done:
	if (cfb)
		PGPFreeCFBContext (cfb);
       if( checksumHash != NULL )
                PGPFreeHashContext( checksumHash );
	bnEnd( &bny );
	bnEnd( &bnorder );
	bnEnd( &bnx );
	return i;
}

/*
 * Relock the key.
 */
static void
ecLock(PGPSecKey *seckey)
{
	ECsecPlus *sec = (ECsecPlus *)seckey->priv;

	ASSERTEC(seckey->pkAlg);
	sec->locked = 1;

	ecPointFree( sec->s.y );
	ecPointFree( sec->s.g );
	ecScalarFree( sec->s.order );
	ecScalarFree( sec->s.x );
	ecFreeContext( sec->s.ec );
	pgpClearMemory( &sec->s, sizeof( ECsec ) );
}

static PGPSize
ecSecMaxdecrypted(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format);


/*
 * Try to decrypt the given esk.  If the key is locked, try the given
 * passphrase.  It may or may not leave the key unlocked in such a case.
 * (Some hardware implementations may insist on a password per usage.)
 */
static int
ecDecrypt(PGPSecKey *seckey, PGPByte const *esk, PGPSize esklen,
		   PGPByte *key, PGPSize *keylen,
		   char const *phrase, PGPSize plen,
		   PGPPublicKeyMessageFormat format)
{
#if PGP_DECRYPT_DISABLE /* [ */

	(void)seckey;
	(void)esk;
	(void)esklen;
	(void)key;
	(void)keylen;
	(void)phrase;
	(void)plen;
	(void)format;
	return kPGPError_FeatureNotAvailable;

#else /* PGP_DECRYPT_DISABLE */  /* ]  [ */

	ECsecPlus *sec = (ECsecPlus *)seckey->priv;
	ecContextRef ec = sec->s.ec;
	PGPUInt32 coordSize, scalarSize, pointSize;
	BigNum k, bn, bnorder, bnx;
	ecPointRef tq=NULL, dh=NULL;
	ecScalarRef td2=NULL;
	int i, j;
	unsigned t;
	PGPUInt32 hashalg;
	PGPUInt32 masksize;
	PGPSize len;
	PGPSize off;
	PGPByte *secbuf = NULL;
	PGPByte *maskbuf = NULL;
	PGPMemoryMgrRef		mgr	= NULL;

	mgr	= PGPPeekContextMemoryMgr( seckey->context );

	ASSERTECENC(seckey->pkAlg);
	if (sec->locked) {
		i = ecUnlock(seckey, phrase, plen, FALSE);
		if (i <= 0)
			return i ? i : kPGPError_KeyIsLocked;
		pgpAssert(!sec->locked);
	}

	if (esklen < 2)
		return kPGPError_BadSessionKeySize;
	
	ecGetBufferSize( ec, &coordSize, &scalarSize, NULL, &pointSize );

	off = 0;
	hashalg = esk[off++];
	if (hashalg != kPGPHashAlgorithm_SHA)
		return kPGPError_MalformedKeyComponent;

	bnBegin(&bn, mgr, SECURE);
	bnBegin(&k, mgr, SECURE);
	bnBegin(&bnx, mgr, SECURE);
	bnBegin(&bnorder, mgr, INSECURE);

	if( ecPointCreate( ec, &tq ) < 0
		|| ecPointCreate( ec, &dh ) < 0
		|| ecScalarCreate( ec, &td2, SECURE ) < 0
		|| sScalartoBN( sec->s.order, &bnorder, mgr, scalarSize ) < 0
		|| sScalartoBN( sec->s.x, &bnx, mgr, scalarSize ) < 0 )
		goto nomem;

	/* ESK holds two values.  Get first, tq, from ESK. */
	if (format == kPGPPublicKeyMessageFormat_X509) {
		/* Parse SEQUENCE header for 509 encrypted data */
		PGPByte const *eskp = esk + off;
		PGPUInt32 len;
		if (pgpBnX509TagLen(&eskp, &len) != X509_TAG_SEQUENCE) {
			i = kPGPError_MalformedKeyComponent;
			goto done;
		}
		off += eskp - esk;
		if (len != esklen - off) {
			i = kPGPError_BadSessionKeySize;
			goto done;
		}
	}
	i = pgpBnGetFormatted(&bn, esk+off, esklen-off, pointSize, format);
	if (i <= 0)
		goto fail;
	/* Get 2nd value, k, from ESK */
	off += i;
	i = pgpBnGetFormatted(&k, esk+off, esklen-off, MASKBUF_SIZE, format);
	if (i <= 0)
		goto fail;
	off += i;
	if (off != esklen) {
		i = kPGPError_BadSessionKeySize;
		goto done;
	}
	
	/* Convert tq to EC point; k is key xor shared secret */
	if( sBNtoPoint( &bn, tq, mgr, pointSize ) < 0 )
		goto nomem;
	masksize = bnBytes(&k);
	secbuf = PGPNewSecureData( mgr, masksize, 0 );
	if( IsNull( secbuf ) )
		goto nomem;
	bnExtractBigBytes( &k, secbuf, 0, masksize );

	/* Calculate td2 = x*cofactor % order */
	if( bnMulQ( &bn, &bnx, sec->s.cofactor ) < 0
		|| bnMod( &bn, &bn, &bnorder ) < 0
		|| sBNtoScalar( &bn, td2, mgr, scalarSize ) < 0 )
		goto nomem;

	/* Calculate shared secret curve point dh */
	if( ecPointMul( tq, td2, FALSE, dh ) < 0 )
		goto nomem;

	/* Create maskbuf from shared secret */
	maskbuf = PGPNewSecureData( mgr, masksize, 0 );
	if( IsNull( maskbuf ) )
		goto nomem;
	i = sFillEncryptMaskBuf( seckey->context, dh, coordSize,
							 kPGPHashAlgorithm_SHA, maskbuf, masksize );
	if( i < 0 )
		goto fail;

	/* XOR into secbuf to recover PKCS1-padded value */
	for( t=0; t<masksize; t++ )
		secbuf[t] ^= maskbuf[t];

	if( bnInsertBigBytes( &bn, secbuf, 0, masksize ) < 0 )
		goto nomem;
	len = ecSecMaxdecrypted( seckey, format );
	i = pgpPKCSUnpack( key, len, &bn, PKCS_PAD_ENCRYPTED, masksize );
	if( i < 0 )
		goto fail;
	
	if (format == kPGPPublicKeyMessageFormat_PGP) {
		/* Check checksum */
		t = 0;
		for (j = 1; j < i-2; j++)
			t += key[j];
		if (t != ((unsigned)key[i-2]<<8) + key[i-1])
		{
			i = kPGPError_CorruptData;
			goto fail;
		}
		pgpClearMemory(key+i-2, 2);

		/* The actual key */
		if (keylen)
			*keylen = (PGPSize)i-2;
	} else {
		if( keylen)
			*keylen = (PGPSize)i;
	}
	
	i = 0;
	goto done;

fail:
	if (!i)
		i = kPGPError_BadSessionKeySize;
	goto done;
nomem:
	i = kPGPError_OutOfMemory;
	goto done;
done:
	if( IsntNull( secbuf ) )
		PGPFreeData( secbuf );
	if( IsntNull( maskbuf ) )
		PGPFreeData( maskbuf );
	bnEnd(&k);
	bnEnd(&bn);
	bnEnd(&bnx);
	bnEnd(&bnorder);
	if( IsntNull( tq ) )
		ecPointFree( tq );
	if( IsntNull( dh ) )
		ecPointFree( dh );
	if( IsntNull( td2 ) )
		ecScalarFree( td2 );
	return i;

#endif /* PGP_DECRYPT_DISABLE */ /* ] */
}


/*
 * Return the size of the buffer needed, worst-case, for the decrypted
 * output.
 */
static PGPSize
ecSecMaxdecrypted(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format)
{
	(void) format;
	ASSERTECENC(seckey->pkAlg);

	return MASKBUF_SIZE - 3;
}

/* Return the largest possible PGPESK size for a given key */
static PGPSize
ecSecMaxesk(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format)
{
	ECsecPlus const *sec = (ECsecPlus *)seckey->priv;
	PGPUInt32 pointSize;

	ASSERTECENC(seckey->pkAlg);

	ecGetBufferSize( sec->s.ec, NULL, NULL, NULL, &pointSize );

	if (format == kPGPPublicKeyMessageFormat_PGP)
		return 1 + 2 + pointSize + 2 + MASKBUF_SIZE;
	else if (format == kPGPPublicKeyMessageFormat_PKCS1 ||
			 format == kPGPPublicKeyMessageFormat_IKE)
		return 1 + pointSize + MASKBUF_SIZE;
	else if (format == kPGPPublicKeyMessageFormat_X509) {
		/* SEQUENCE, length, INT, INT */
		PGPUInt32 len;
		len = pgpBnX509LenLen(pointSize+1) + 1 + pointSize+1 +
			pgpBnX509LenLen(MASKBUF_SIZE+1) + 1 + MASKBUF_SIZE+1;
		return 1 + 1 + pgpBnX509LenLen(len) + len;
	}
	pgpAssert(0);
	return 0;
}

static PGPSize
ecSecMaxsig(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format)
{
	ECsecPlus const *sec = (ECsecPlus *)seckey->priv;
	PGPUInt32 scalarSize;

	ASSERTECSIG(seckey->pkAlg);

	ecGetBufferSize( sec->s.ec, NULL, &scalarSize, NULL, NULL );
	if (format == kPGPPublicKeyMessageFormat_PGP)
		return 2*( 2 + scalarSize );
	else if (format == kPGPPublicKeyMessageFormat_PKCS1 ||
			 format == kPGPPublicKeyMessageFormat_IKE)
		return 2 * scalarSize;
	else if (format == kPGPPublicKeyMessageFormat_X509) {
		/* SEQUENCE, length, INT, INT */
		PGPUInt32 len;
		len = 2*(pgpBnX509LenLen(scalarSize+1) + 1 + scalarSize+1);
		return 1 + pgpBnX509LenLen(len) + len;
	}
	pgpAssert(0);
	return 0;
}

static int
ecSign(PGPSecKey *seckey, PGPHashVTBL const *h, PGPByte const *hash,
	PGPByte *sig, PGPSize *siglen, PGPRandomContext const *rc,
	PGPPublicKeyMessageFormat format)
{
#if PGP_SIGN_DISABLE /* [ */

	(void)seckey;
	(void)h;
	(void)hash;
	(void)sig;
	(void)siglen;
	(void)rc;
	(void)format;
	return kPGPError_FeatureNotAvailable;

#else

	ECsecPlus *sec = (ECsecPlus *)seckey->priv;
	ecContextRef ec = sec->s.ec;
	PGPUInt32 coordSize, scalarSize, pointSize;
	BigNum r, s, bn, k, bnx, bnorder;
	ecScalarRef eck=NULL;
	ecPointRef kg=NULL;
	unsigned t;
	int i;
	PGPRandomContext *rc2 = NULL;
	PGPMemoryMgrRef		mgr	= NULL;
	PGPCipherAlgorithm	cipherAlg;
	
	mgr	= PGPPeekContextMemoryMgr( seckey->context );

	ASSERTECSIG(seckey->pkAlg);

	ecGetBufferSize( ec, &coordSize, &scalarSize, NULL, &pointSize );

	/* Allow generalizations of SHA as long as they are big enough */
#if 0
	pgpAssert(h->algorithm == kPGPHashAlgorithm_SHA);
#else
//	pgpAssert(h->hashsize >= scalarSize);
#endif

	if (sec->locked)
		return kPGPError_KeyIsLocked;

	/*
	 * Of these values, only k is inherently sensitive, but others may
	 * hold some intermediate results we would prefer not to have leaked.
	 * So mark all as sensitive.
	 */
	bnBegin(&r, mgr, SECURE );
	bnBegin(&s, mgr, SECURE );
	bnBegin(&bn, mgr, SECURE );
	bnBegin(&k, mgr, SECURE );
	bnBegin(&bnx, mgr, SECURE );
	bnBegin(&bnorder, mgr, INSECURE );

	if( ecScalarCreate( ec, &eck, SECURE ) < 0
		|| ecPointCreate( ec, &kg ) < 0
		|| sScalartoBN( sec->s.order, &bnorder, mgr, scalarSize ) < 0
		|| sScalartoBN( sec->s.x, &bnx, mgr, scalarSize ) < 0 )
		goto nomem;

	/*
	 * EC requires a secret k.  This k is *very* important
	 * to keep secret.  Consider, the EC signing equations are:
	 * r = x-coordinate of k*G mod n
	 * s = k^-1 * (H(m) + x*r) mod q,
	 * so if you know k (and, the signature r, s and H), then
	 * x = r^-1 * (k*s - H(m))
	 * If we ever pick two k values the same, then
	 * r = x-coordinate of k*G mod n is the same for both signatures, and
	 * s1 = k^-1 * (H1 + x * r) 
	 * s2 = k^-1 * (H2 + x * r) 
	 * k = (H1-H2) / (s1-s2)
	 * and proceed from there.
	 *
	 * So we need to make *very* sure there's no problem.  To make
	 * sure, we add a layer on top of the passed-in RNG.  We assume
	 * the passed-in RNG is good enough to never repeat (not a
	 * difficult task), and apply an additional X9.17 generator on
	 * top of that, seeded with the secret x, which is destroyed
	 * before leaving this function.
	 *
	 * In addition, we add entropy from the hash to the original RNG.
	 * This will prevent us from using the same k value twice if the
	 * messages are different.
	 */
	pgpRandomAddBytes(rc, hash, h->hashsize);
	
	if( pgpFIPSModeEnabled() )
	{
		cipherAlg = kPGPCipherAlgorithm_3DES;
	}
	else
	{
		cipherAlg = kPGPCipherAlgorithm_CAST5;
	}
	
	rc2 = pgpRandomCreateX9_17( rc->context, cipherAlg, rc);
	if (!rc2)
		goto nomem;
	pgpRandomBnSeed(rc2, &bnx);

	/*
	 * Choose the random k value to be used for this signature.
	 * Make it a bit bigger than order so it is fairly uniform mod order.
	 */
	if (pgpBnGenRand(&k, rc2, 8*(scalarSize+8), 0, 1, 8*scalarSize) < 0
	    || bnMod(&k, &k, &bnorder) < 0
		|| sBNtoScalar( &k, eck, mgr, scalarSize ) < 0 )
		goto nomem;
	
	/* Multiply k*G and get r as x-coord */
	if( ecPointMul( sec->s.g, eck, FALSE, kg ) < 0
		|| sPointXtoBN( kg, &r, mgr, coordSize ) < 0
		|| bnMod( &r, &r, &bnorder ) < 0 )
		goto nomem;
	      
	/* r*x mod q into s */
	if (bnMul(&s, &r, &bnx) < 0 ||
	    bnMod(&s, &s, &bnorder) < 0)
		goto nomem;

	/* Pack message hash M into buffer bn */
	if (bnInsertBigBytes(&bn, hash, 0, h->hashsize) < 0
		|| bnMod(&bn, &bn, &bnorder) < 0)
		goto nomem;

	/* Add into s */
	if (bnAdd(&s, &bn) < 0 ||
	    bnMod(&s, &s, &bnorder) < 0)
		goto nomem;

	/* Divide by k, mod q (k inverse held in bn) */
	if (bnInv(&bn, &k, &bnorder) < 0 ||
	    bnMul(&s, &s, &bn) < 0 ||
	    bnMod(&s, &s, &bnorder) < 0)
		goto nomem;

	/* That's it, now to pack r and then s into the buffer */
	t = 0;
	if (format == kPGPPublicKeyMessageFormat_X509) {
		/* Put in SEQUENCE header for 509 sig data */
		PGPUInt32 len_seq, lenlen_seq;
		/* Count size of sequence, counting a 0 byte if hi bit is set */

⌨️ 快捷键说明

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