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