📄 pgpeckey.c
字号:
ASSERTEC( pubkey->pkAlg );
(void) x1;
(void) x2;
(void) x3;
(void) x4;
(void) x5;
(void) x6;
(void) x7;
(void) x8;
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.
*/
static int
ecEncrypt(PGPPubKey const *pubkey, PGPByte const *key,
PGPSize keylen, PGPByte *esk, PGPSize *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 */ /* ] [ */
ECpub const *pub = (ECpub *)pubkey->priv;
ecContextRef ec = pub->ec;
unsigned t;
int i;
PGPUInt32 coordSize, scalarSize, pointSize;
BigNum bn, bntq, bnorder;
ecScalarRef td=NULL, td2=NULL;
ecPointRef tq=NULL, dh=NULL;
PGPByte *tdbuf=NULL, *maskbuf=NULL, *kbuf=NULL;
PGPMemoryMgrRef mgr = NULL;
mgr = PGPPeekContextMemoryMgr( pubkey->context );
ASSERTECENC(pubkey->pkAlg);
ecGetBufferSize( ec, &coordSize, &scalarSize, NULL, &pointSize );
if (keylen > MASKBUF_SIZE)
return kPGPError_PublicKeyTooSmall; /* data too big for pubkey */
if( format == kPGPPublicKeyMessageFormat_PGP ) {
if (keylen+2 > MASKBUF_SIZE)
return kPGPError_PublicKeyTooSmall; /* data too big for pubkey */
/* 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;
}
bnBegin(&bn, mgr, SECURE );
bnBegin(&bntq, mgr, SECURE );
bnBegin(&bnorder, mgr, INSECURE );
if( ecScalarCreate( ec, &td, SECURE ) < 0
|| ecScalarCreate( ec, &td2, SECURE ) < 0
|| ecPointCreate( ec, &tq ) < 0
|| ecPointCreate( ec, &dh ) < 0
|| sScalartoBN( pub->order, &bnorder, mgr, scalarSize ) < 0 )
goto nomem;
/* Choose the random td scalar to be used for this encryption */
tdbuf = PGPNewSecureData( mgr, scalarSize+8, 0 );
if( IsNull( tdbuf ) )
goto nomem;
pgpRandomGetBytes( rc, tdbuf, scalarSize+8 );
if( bnInsertBigBytes( &bn, tdbuf, 0, scalarSize+8 ) < 0
|| bnMod( &bn, &bn, &bnorder ) < 0
|| sBNtoScalar( &bn, td, mgr, scalarSize ) < 0 )
goto nomem;
/* Also calculate td*cofactor % order */
if( bnMulQ( &bn, &bn, pub->cofactor ) < 0
|| bnMod( &bn, &bn, &bnorder ) < 0
|| sBNtoScalar( &bn, td2, mgr, scalarSize ) < 0 )
goto nomem;
/* Do EC multiplication to get tq value */
if( ecPointMul( pub->g, td, FALSE, tq ) < 0 )
goto nomem;
/* Calculate shared secret curve point dh */
if( ecPointMul( pub->y, td2, FALSE, dh ) < 0 )
goto nomem;
/* Create maskbuf from shared secret */
maskbuf = PGPNewSecureData( mgr, MASKBUF_SIZE, 0 );
if( IsNull( maskbuf ) )
goto nomem;
i = sFillEncryptMaskBuf( pubkey->context, dh, coordSize,
kPGPHashAlgorithm_SHA, maskbuf, MASKBUF_SIZE );
if( i < 0 )
goto done;
/* PKCS-1 pad the key to encode its length */
if (pgpPKCSPack(&bn, key, keylen, PKCS_PAD_ENCRYPTED, MASKBUF_SIZE, rc)<0)
goto nomem;
kbuf = PGPNewSecureData( mgr, MASKBUF_SIZE, 0 );
if( IsNull( kbuf ) )
goto nomem;
bnExtractBigBytes( &bn, kbuf, 0, MASKBUF_SIZE );
/* XOR the key with the shared secret */
for( i=0; i<MASKBUF_SIZE; ++i )
kbuf[i] ^= maskbuf[i];
/* Prepare to output results */
t = 0;
esk[t++] = kPGPHashAlgorithm_SHA;
if( sPointtoBN( tq, &bntq, mgr, pointSize ) < 0
|| bnInsertBigBytes( &bn, kbuf, 0, MASKBUF_SIZE ) < 0 )
goto nomem;
if (format == kPGPPublicKeyMessageFormat_X509) {
/* Put in SEQUENCE header for 509 encrypted data */
PGPUInt32 len_seq, lenlen_seq;
/* Count size of sequence, counting a 0 byte if hi bit is set */
if (8*pointSize == bnBits(&bntq))
len_seq = pgpBnX509LenLen(pointSize+1) + 1 + pointSize+1;
else
len_seq = pgpBnX509LenLen(pointSize) + 1 + pointSize;
if (8*MASKBUF_SIZE == bnBits(&bn))
len_seq += pgpBnX509LenLen(MASKBUF_SIZE+1) + 1 + MASKBUF_SIZE+1;
else
len_seq += pgpBnX509LenLen(MASKBUF_SIZE) + 1 + MASKBUF_SIZE;
lenlen_seq = pgpBnX509LenLen(len_seq);
esk[t++] = X509_TAG_SEQUENCE | X509_TAG_CONSTRUCTED;
if (--lenlen_seq == 0) {
esk[t++] = len_seq;
} else {
esk[t++] = 0x80 | lenlen_seq;
len_seq <<= 8 * (4-lenlen_seq);
while (lenlen_seq--) {
esk[t++] = (PGPByte)(len_seq >> 24);
len_seq <<= 8;
}
}
}
/* Pack the two values into the esk, first tq and then xbuf^key */
t += pgpBnPutFormatted(&bntq, esk+t, pointSize, format);
t += pgpBnPutFormatted(&bn, esk+t, MASKBUF_SIZE, format);
if (esklen)
*esklen = (PGPSize)t;
i = 0;
goto done;
nomem:
i = kPGPError_OutOfMemory;
done:
bnEnd(&bn);
bnEnd(&bntq);
bnEnd(&bnorder);
if( IsntNull( tq ) )
ecPointFree(tq);
if( IsntNull( dh ) )
ecPointFree(dh);
if( IsntNull( td ) )
ecScalarFree(td);
if( IsntNull( td2 ) )
ecScalarFree(td2);
if( IsntNull( maskbuf ) )
PGPFreeData( maskbuf );
if( IsntNull( tdbuf ) )
PGPFreeData( tdbuf );
if( IsntNull( kbuf ) )
PGPFreeData( kbuf );
return i;
#endif /* PGP_ENCRYPT_DISABLE */ /* ] */
}
/*
* Return 1 if (sig,siglen) is a valid MPI which signs
* hash, of type h. Check the DER-encoded prefix and the
* hash itself.
*/
static int
ecVerify(PGPPubKey const *pubkey, PGPByte const *sig,
PGPSize siglen, PGPHashVTBL const *h, PGPByte const *hash,
PGPPublicKeyMessageFormat format)
{
#if PGP_VERIFY_DISABLE /* [ */
(void)pubkey;
(void)sig;
(void)siglen;
(void)h;
(void)hash;
(void)format;
return kPGPError_FeatureNotAvailable;
#else /* PGP_VERIFY_DISABLE */ /* ] [ */
ECpub const *pub = (ECpub *)pubkey->priv;
ecContextRef ec = pub->ec;
PGPUInt32 coordSize, scalarSize, pointSize;
BigNum r, s, w, u2, bnorder;
ecPointRef gu1=NULL, yu2=NULL, ecv=NULL;
ecScalarRef ecu1=NULL, ecu2=NULL;
int i;
PGPSize off;
PGPMemoryMgrRef mgr = PGPPeekContextMemoryMgr( pubkey->context );
ASSERTECSIG(pubkey->pkAlg);
ecGetBufferSize( ec, &coordSize, &scalarSize, NULL, &pointSize );
#if 0
/* Hashsize must be at least as big as size of field for legal sig */
if (h->hashsize < scalarSize) {
return 0;
}
#endif
#if 0
/* Allow generalizations of SHA, as long as they are big enough */
if (h->algorithm != kPGPHashAlgorithm_SHA)
return 0; /* No match for sure! */
#endif
bnBegin(&r, mgr, INSECURE );
bnBegin(&s, mgr, INSECURE );
bnBegin(&w, mgr, INSECURE );
bnBegin(&u2, mgr, INSECURE );
bnBegin(&bnorder, mgr, INSECURE );
if( ecPointCreate( ec, &gu1 ) < 0
|| ecPointCreate( ec, &yu2 ) < 0
|| ecPointCreate( ec, &ecv ) < 0
|| ecScalarCreate( ec, &ecu1, INSECURE ) < 0
|| ecScalarCreate( ec, &ecu2, INSECURE ) < 0
|| sScalartoBN( pub->order, &bnorder, mgr, scalarSize ) < 0 )
goto nomem;
/* sig holds two values. Get first, r, from sig. */
off = 0;
if (format == kPGPPublicKeyMessageFormat_X509) {
/* Parse SEQUENCE header for 509 sig data */
PGPByte const *sigp = sig + off;
PGPUInt32 len;
if (pgpBnX509TagLen(&sigp, &len) != X509_TAG_SEQUENCE) {
i = kPGPError_MalformedKeyComponent;
goto done;
}
off += sigp - sig;
if (len != siglen - off) {
i = kPGPError_MalformedKeyComponent;
goto done;
}
}
i = pgpBnGetFormatted(&r, sig+off, siglen-off, scalarSize, format);
if (i <= 0)
goto fail;
/* Get 2nd value, s, from SIG */
off += i;
i = pgpBnGetFormatted(&s, sig+off, siglen-off, scalarSize, format);
if (i <= 0)
goto fail;
off += i;
if (off != siglen) {
i = kPGPError_BadSignatureSize;
goto done;
}
/*
* Sanity-check r and s against the group order. Both should
* be less than that. If not, the signature is clearly bad.
*/
if (bnCmp(&r, &bnorder) >= 0 || bnCmp(&s, &bnorder) >= 0) {
i = 0; /* FAIL */
goto done;
}
/* Reconstruct hash as u2 */
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 = X coord of (u1*G + u2*Y)
* if v == r the signature checks.
*
* To save space, we put u1 into s, H into u2, and v into w.
*/
if (bnInv(&w, &s, &bnorder) < 0)
goto nomem;
if (bnMul(&s, &u2, &w) < 0 || bnMod(&s, &s, &bnorder) < 0)
goto nomem;
if (bnMul(&u2, &r, &w) < 0 || bnMod(&u2, &u2, &bnorder) < 0)
goto nomem;
if( sBNtoScalar( &s, ecu1, mgr, scalarSize ) < 0 )
goto nomem;
if( sBNtoScalar( &u2, ecu2, mgr, scalarSize ) < 0 )
goto nomem;
/* Now for the expensive part... */
if( ecPointMul( pub->g, ecu1, FALSE, gu1 ) < 0
|| ecPointMul( pub->y, ecu2, FALSE, yu2 ) < 0
|| ecPointAdd( gu1, yu2, ecv ) < 0 )
goto nomem;
if( sPointXtoBN( ecv, &w, mgr, coordSize ) < 0
|| bnMod( &w, &w, &bnorder ) < 0 )
goto nomem;
/* Compare result with r, should be equal */
i = bnCmp(&w, &r) == 0;
goto done;
fail:
if (!i)
i = kPGPError_BadSignatureSize;
goto done;
nomem:
i = kPGPError_OutOfMemory;
goto done;
done:
bnEnd(&bnorder);
bnEnd(&u2);
bnEnd(&w);
bnEnd(&s);
bnEnd(&r);
if( IsntNull( gu1 ) )
ecPointFree( gu1 );
if( IsntNull( yu2 ) )
ecPointFree( yu2 );
if( IsntNull( ecv ) )
ecPointFree( ecv );
if( IsntNull( ecu1 ) )
ecScalarFree( ecu1 );
if( IsntNull( ecu2 ) )
ecScalarFree( ecu2 );
return i;
#endif /* PGP_VERIFY_DISABLE */ /* ] */
}
/*
* Turn a PGPPubKey into the algorithm-specific parts of a public key.
* A public 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
*/
static PGPSize
ecPubBufferLength(PGPPubKey const *pubkey)
{
ECpub const *pub = (ECpub *)pubkey->priv;
PGPUInt32 pointSize;
PGPUInt32 scalarSize;
PGPInt32 curve;
ASSERTEC(pubkey->pkAlg);
ecGetBufferSize( pub->ec, NULL, &scalarSize, NULL, &pointSize );
curve = sCurveIndexFromScalarsize( scalarSize );
pgpAssert( curve >= 0 );
return 6 + pointSize + strlen( sCurves[curve].name );
}
static void
ecPubToBuffer(PGPPubKey const *pubkey, PGPByte *buf)
{
ECpub const *pub = (ECpub *)pubkey->priv;
PGPUInt32 pointSize;
PGPUInt32 scalarSize;
PGPInt32 curve;
PGPSize namelen;
PGPUInt32 i;
BigNum bny;
PGPMemoryMgrRef mgr = PGPPeekContextMemoryMgr( pubkey->context );
ASSERTEC(pubkey->pkAlg);
ecGetBufferSize( pub->ec, NULL, &scalarSize, NULL, &pointSize );
i = 0;
buf[i++] = 0;
buf[i++] = 0;
curve = sCurveIndexFromScalarsize( scalarSize );
pgpAssert( curve >= 0 );
namelen = strlen( sCurves[curve].name );
buf[i++] = ((8*namelen-1) >> 8) & 0xff;
buf[i++] = ((8*namelen-1) >> 0) & 0xff;
pgpCopyMemory( sCurves[curve].name, buf+1, namelen );
i += namelen;
bnBegin( &bny, mgr, INSECURE );
(void)sPointtoBN( pub->y, &bny, mgr, pointSize );
i += pgpBnPutPlain( &bny, buf+i );
bnEnd( &bny );
}
/* A little helper function that's used twice */
static void
ecFillPubkey(PGPPubKey *pubkey, ECpub *pub)
{
pubkey->next = NULL;
pubkey->pkAlg = kPGPPublicKeyAlgorithm_ECSign;
pubkey->priv = pub;
pubkey->destroy = ecPubDestroy;
pubkey->maxesk = ecPubMaxesk;
pubkey->maxdecrypted = ecPubMaxdecrypted;
pubkey->maxsig = ecPubMaxsig;
pubkey->encrypt = ecEncrypt;
pubkey->verify = ecVerify;
pubkey->bufferLength = ecPubBufferLength;
pubkey->toBuffer = ecPubToBuffer;
pubkey->pubparams= ecPubParams;
pubkey->setkeyid= ecPubSetKeyID;
}
/*
* Turn the algorithm-specific parts of a public key into a PGPPubKey
* structure. A public 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
*/
PGPPubKey *
ecPubFromBuf(
PGPContextRef context,
PGPByte const * buf,
PGPSize size,
PGPError * error)
{
PGPPubKey *pubkey;
ECpub *pub;
unsigned i, t;
PGPInt32 curve;
PGPError err = kPGPError_OutOfMemory;
PGPMemoryMgrRef mgr = PGPPeekContextMemoryMgr( context );
bnInit();
if (size < 6)
return NULL;
if( buf[0] != 0 || buf[1] != 0 )
{
*error = kPGPError_MalformedKeyComponent;
return NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -