📄 pgpdsakey.c
字号:
}
pub = (DSApub *)pgpContextMemAlloc( context,
sizeof(*pub), kPGPMemoryMgrFlags_Clear);
if (pub) {
pubkey = (PGPPubKey *)pgpContextMemAlloc( context,
sizeof(*pubkey), kPGPMemoryMgrFlags_Clear);
if (pubkey) {
pubkey->context = context;
bnBegin(&pub->p, mgr, FALSE );
bnBegin(&pub->q, mgr, FALSE );
bnBegin(&pub->g, mgr, FALSE );
bnBegin(&pub->y, mgr, FALSE );
if (bnInsertBigBytes(&pub->p, buf+i+2, 0, t-i-2) >= 0
&& bnInsertBigBytes(&pub->q, buf+t+2, 0, u-t-2) >= 0
&& bnInsertBigBytes(&pub->g, buf+u+2, 0, v-u-2) >= 0
&& bnInsertBigBytes(&pub->y, buf+v+2, 0, w-v-2) >= 0)
{
if (dsaKeyTooBig (pub, NULL)) {
err = kPGPError_KeyTooLarge;
} else {
dsaFillPubkey(pubkey, pub);
*error = 0;
return pubkey;
}
}
/* Failed = clean up and return NULL */
bnEnd(&pub->p);
bnEnd(&pub->q);
bnEnd(&pub->g);
bnEnd(&pub->y);
pgpContextMemFree( context, pubkey);
}
pgpContextMemFree( context, pub);
}
*error = err;
return NULL;
}
/*
* Return the size of the public portion of a key buffer.
*/
int
dsaPubKeyPrefixSize(PGPByte const *buf, PGPSize size)
{
return pgpBnParse(buf, size, 4, NULL, NULL, NULL, NULL);
}
/** Secret key functions **/
static void
dsaSecDestroy(PGPSecKey *seckey)
{
DSAsecPlus *sec = (DSAsecPlus *)seckey->priv;
PGPContextRef context;
pgpAssertAddrValid( seckey, PGPSecKey );
context = seckey->context;
ASSERTDSA(seckey->pkAlg);
bnEnd(&sec->s.p);
bnEnd(&sec->s.q);
bnEnd(&sec->s.g);
bnEnd(&sec->s.y);
bnEnd(&sec->s.x);
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 *
dsaPubkey(PGPSecKey const *seckey)
{
DSAsecPlus const *sec = (DSAsecPlus *)seckey->priv;
PGPPubKey *pubkey;
DSApub *pub;
PGPContextRef context;
PGPMemoryMgrRef mgr = NULL;
pgpAssertAddrValid( seckey, PGPSecKey );
context = seckey->context;
mgr = PGPPeekContextMemoryMgr( context );
ASSERTDSA(seckey->pkAlg);
pub = (DSApub *)pgpContextMemAlloc( context,
sizeof(*pub), kPGPMemoryMgrFlags_Clear);
if (pub) {
pubkey = (PGPPubKey *)pgpContextMemAlloc( context,
sizeof(*pubkey), kPGPMemoryMgrFlags_Clear);
if (pubkey) {
pubkey->context = context;
bnBegin(&pub->p, mgr, FALSE );
bnBegin(&pub->q, mgr, FALSE );
bnBegin(&pub->g, mgr, FALSE );
bnBegin(&pub->y, mgr, FALSE );
if (bnCopy(&pub->p, &sec->s.p) >= 0
&& bnCopy(&pub->q, &sec->s.q) >= 0
&& bnCopy(&pub->g, &sec->s.g) >= 0
&& bnCopy(&pub->y, &sec->s.y) >= 0)
{
dsaFillPubkey(pubkey, pub);
pubkey->pkAlg = seckey->pkAlg;
memcpy(pubkey->keyID, seckey->keyID,
sizeof(pubkey->keyID));
return pubkey;
}
/* Failed = clean up and return NULL */
bnEnd(&pub->p);
bnEnd(&pub->q);
bnEnd(&pub->g);
bnEnd(&pub->y);
pgpContextMemFree( context, pubkey);
}
pgpContextMemFree( context, pub);
}
return NULL;
}
/*
* Set keyid
*/
static void
dsaSecSetKeyID(PGPSecKey *seckey, PGPByte *keyid)
{
pgpCopyMemory(keyid, seckey->keyID, sizeof(seckey->keyID));
}
/*
* Yes, there *is* a reason that this is a function and not a variable.
* On a hardware device with an automatic timeout,
* it actually might need to do some work to find out.
*/
static int
dsaIslocked(PGPSecKey const *seckey)
{
DSAsecPlus const *sec = (DSAsecPlus *)seckey->priv;
ASSERTDSA(seckey->pkAlg);
return sec->locked;
}
/*
* Return the algorithm and (symmetric) key size used for locking/unlocking
* the secret key.
*/
static PGPError
dsaLockingAlgorithm(
PGPSecKey const *seckey,
PGPCipherAlgorithm *pAlg,
PGPSize *pAlgKeySize
)
{
DSAsecPlus *sec = (DSAsecPlus *)seckey->priv;
PGPCipherVTBL const *cipher;
PGPByte alg;
int i;
ASSERTDSA(seckey->pkAlg);
if( IsntNull( pAlg ) )
*pAlg = (PGPCipherAlgorithm) 0;
if( IsntNull( pAlgKeySize ) )
*pAlgKeySize = (PGPSize) 0;
/* Check packet for basic consistency */
i = pgpBnParse(sec->cryptkey, sec->cklen, 4, NULL, NULL, NULL, NULL);
if (i < 0)
return (PGPError)i;
/* 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
dsaS2KType(
PGPSecKey const *seckey,
PGPStringToKeyType *s2kType
)
{
DSAsecPlus *sec = (DSAsecPlus *)seckey->priv;
PGPByte alg;
int i;
ASSERTDSA(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, sec->cklen, 4, NULL, NULL, NULL, NULL);
if (i < 0)
return (PGPError)i;
/* 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
dsaConvertPassphrase(PGPSecKey *seckey, PGPEnv const *env,
char const *phrase, PGPSize plen, PGPByte *outbuf)
{
DSAsecPlus *sec = (DSAsecPlus *)seckey->priv;
PGPStringToKey *s2k;
PGPByte alg;
PGPBoolean hasS2K;
PGPCipherVTBL const *cipher;
int i;
ASSERTDSA(seckey->pkAlg);
pgpAssert (IsntNull( outbuf ) );
/* Check packet for basic consistency */
i = pgpBnParse(sec->cryptkey, sec->cklen, 4, NULL, NULL, NULL, NULL);
if (i < 0)
return (PGPError)i;
/* 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, pgpenvGetContext( env ), sec->cryptkey+i, sec->cklen-i);
} else {
s2k = pgpS2Ksimple(pgpenvGetContext( env ), 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 DSA-specific part is:
*
* 0 2+u MPI for prime p
* 2+u 2+v MPI for order q
* 4+u+v 2+w MPI for generator g
* 6+u+v+w 2+x MPI for public key y
* 8+u+v+w+x 1 Encryption algorithm (0 for none, 1 for IDEA)
* 9+u+v+w+x t Encryption IV: 0 or 8 bytes
* 9+t+u+v+w+x 2+y MPI for x (discrete log of public key)
* 11+t+u+v+w+x+y 2 Checksum
* 13+t+u+v+w+x+y
*
* Actually, that's the old-style, if pgpS2KoldVers is true.
* If it's false, the algorithm ('alg0') is 0xff or 0xfe, and is followed by the
* algorithm, then the (varaible-length, self-delimiting)
* string-to-key descriptor.
*/
static int
dsaUnlock( PGPSecKey *seckey,
char const *phrase, PGPSize plen, PGPBoolean hashedPhrase)
{
DSAsecPlus *sec = (DSAsecPlus *)seckey->priv;
BigNum x;
BigNum tmp1, tmp2, tmp3;
PGPCFBContext *cfb = NULL;
unsigned v, v_copy;
unsigned 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;
int i;
PGPBoolean validityChecked;
PGPBoolean twofishRetry = FALSE;
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 );
bnBegin(&x, mgr, TRUE);
bnBegin( &tmp1, mgr, TRUE );
bnBegin( &tmp2, mgr, TRUE );
bnBegin( &tmp3, mgr, TRUE );
ASSERTDSA(seckey->pkAlg);
/* Check packet for basic consistency */
i = pgpBnParse(sec->cryptkey, sec->cklen, 4, &v, NULL, NULL, NULL);
if (i <= 0)
goto fail;
/* OK, read the public data */
i = pgpBnGetPlain(&sec->s.p, sec->cryptkey+v, sec->cklen-v);
if (i <= 0)
goto fail;
v += i;
i = pgpBnGetPlain(&sec->s.q, sec->cryptkey+v, sec->cklen-v);
if (i <= 0)
goto fail;
v += i;
i = pgpBnGetPlain(&sec->s.g, sec->cryptkey+v, sec->cklen-v);
if (i <= 0)
goto fail;
v += i;
i = pgpBnGetPlain(&sec->s.y, sec->cryptkey+v, sec->cklen-v);
if (i <= 0)
goto fail;
v += i;
/* Fast consistency checks (more below) */
if (bnCmp(&sec->s.y, &sec->s.p) >= 0) {
i = kPGPError_CorruptPrivateKey;
goto done;
}
/* Calculate p-1 mod q in tmp1; should be 0 */
bnCopy( &tmp1, &sec->s.p );
bnSubQ( &tmp1, 1 );
bnMod( &tmp1, &tmp1, &sec->s.q );
if( bnCmpQ( &tmp1, 0 ) != 0 ) {
i = kPGPError_CorruptPrivateKey;
goto done;
}
/* Check for reasonable size; g and y checks are somewhat arbitrary */
if( bnBits(&sec->s.q) < 160 || bnBits(&sec->s.p) < 512
|| bnBits(&sec->s.g) < 100 || bnBits(&sec->s.y) < 100 ) {
i = kPGPError_CorruptPrivateKey;
goto done;
}
/* 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)
goto badpass1;
hashEntry = pgpHashByNumberWithMask( alg0!=0xfe ? kPGPHashAlgorithm_Checksum16 : kPGPHashAlgorithm_SHA, 0xffffffff );
checksumHash = pgpHashCreate( mgr, hashEntry );
if( checksumHash == NULL ) {
i = kPGPError_BadHashNumber;
goto done;
}
v_copy = v;
twofishRetry:
i = pgpCipherSetup(sec->cryptkey + v, sec->cklen - v, phrase, plen,
hashedPhrase, twofishRetry, seckey->context, &cfb);
if (i < 0)
goto done;
v += i;
PGPResetHash( checksumHash );
i = pgpBnGet(&x, sec->cryptkey + v, sec->cklen - v, cfb, alg0, FALSE/*old*/, checksumHash);
if (i <= 0)
goto badpass;
v += i;
if (bnCmp(&x, &sec->s.q) >= 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -