📄 pgpeckey.c
字号:
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 + -