📄 pgpdsakey.c
字号:
goto badpass; /* Wrong passphrase: x must be < q */
/* Check that we ended in the right place */
checksumSize = pgpChecksumGet( sec->cryptkey+v, NULL, alg0, checksumHash, NULL );
pgpAssert( checksumSize <= sizeof(checksumStored) ); /* programmer's error */
if (sec->cklen - v != checksumSize)
goto badpass;
pgpChecksumGet(sec->cryptkey+v, cfb, alg0, checksumHash, checksumStored);
PGPFinalizeHash( checksumHash, checksum );
if( !pgpMemoryEqual( checksumStored, checksum, checksumSize ) )
goto badpass;
validityChecked = pgpKeyDBObjIsValid( seckey->keyDBObj )
&& pgpSecIsValidated( seckey->keyDBObj );
if( !validityChecked )
{
/* Do careful checks of validity */
if (bnCmp(&x, &sec->s.q) >= 0) {
if( alg == kPGPCipherAlgorithm_Twofish256 && !twofishRetry )
goto badpass;
i = kPGPError_CorruptPrivateKey;
goto done;
}
/* Calculate g^x mod p in tmp2; should be y */
bnExpMod( &tmp2, &sec->s.g, &x, &sec->s.p );
if( bnCmp( &tmp2, &sec->s.y ) != 0 ) {
if( alg == kPGPCipherAlgorithm_Twofish256 && !twofishRetry )
goto badpass;
i = kPGPError_CorruptPrivateKey;
goto done;
}
/* Calculate g^q mod p in tmp3; should be 1 */
bnExpMod( &tmp3, &sec->s.g, &sec->s.q, &sec->s.p );
if( bnCmpQ( &tmp3, 1 ) != 0 ) {
if( alg == kPGPCipherAlgorithm_Twofish256 && !twofishRetry )
goto badpass;
i = kPGPError_CorruptPrivateKey;
goto done;
}
if( pgpKeyDBObjIsValid( seckey->keyDBObj ) )
pgpSecSetValidated( seckey->keyDBObj );
}
/*
* Note that the "nomem" case calls bnEnd()
* more than once, but this is guaranteed harmless.
*/
if (bnCopy(&sec->s.x, &x) < 0)
goto nomem;
i = 1; /* Decrypted! */
sec->locked = 0;
goto done;
nomem:
i = kPGPError_OutOfMemory;
goto done;
fail:
if (!i)
i = kPGPError_KeyPacketTruncated;
goto done;
badpass:
if( alg == kPGPCipherAlgorithm_Twofish256 && !twofishRetry )
{
/* Had a mis-implementation of Twofish on bigendian machines, so for
* backwards compatibility we must retry unlocking failures using
* the old, bad algorithm
*/
twofishRetry = TRUE;
v = v_copy;
if (cfb)
PGPFreeCFBContext(cfb);
goto twofishRetry;
}
badpass1:
i = 0; /* Incorrect passphrase */
goto done;
done:
bnEnd(&x);
bnEnd(&tmp1);
bnEnd(&tmp2);
bnEnd(&tmp3);
if (cfb)
PGPFreeCFBContext(cfb);
if( checksumHash != NULL )
PGPFreeHashContext( checksumHash );
return i;
}
/*
* Relock the key.
*/
static void
dsaLock(PGPSecKey *seckey)
{
DSAsecPlus *sec = (DSAsecPlus *)seckey->priv;
ASSERTDSA(seckey->pkAlg);
sec->locked = 1;
/* bnEnd is documented as also doing a bnBegin */
bnEnd(&sec->s.x);
}
/*
* 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
dsaDecrypt(PGPSecKey *seckey, PGPByte const *esk, PGPSize esklen,
PGPByte *key, PGPSize *keylen, char const *phrase, PGPSize plen,
PGPPublicKeyMessageFormat format)
{
(void)seckey;
(void)esk;
(void)esklen;
(void)key;
(void)keylen;
(void)phrase;
(void)plen;
(void)format;
return kPGPError_PublicKeyUnimplemented;
}
/*
* Return the size of the buffer needed, worst-case, for the decrypted
* output.
*/
static PGPSize
dsaSecMaxdecrypted(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format)
{
(void)seckey;
(void)format;
return kPGPError_PublicKeyUnimplemented;
}
static PGPSize
dsaSecMaxesk(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format)
{
(void)seckey;
(void)format;
return kPGPError_PublicKeyUnimplemented;
}
static PGPSize
dsaSecMaxsig(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format)
{
DSAsecPlus const *sec = (DSAsecPlus *)seckey->priv;
ASSERTDSA(seckey->pkAlg);
if (format == kPGPPublicKeyMessageFormat_PGP)
return 2*( 2 + bnBytes(&sec->s.q) );
else if (format == kPGPPublicKeyMessageFormat_PKCS1 ||
format == kPGPPublicKeyMessageFormat_IKE)
return 2*( bnBytes(&sec->s.q) );
else if (format == kPGPPublicKeyMessageFormat_X509) {
/* SEQUENCE, length, INT, INT */
PGPUInt32 len;
PGPUInt32 qbytes = bnBytes(&sec->s.q);
len = 2*(pgpBnX509LenLen(qbytes+1) + 1 + qbytes+1);
return 1 + pgpBnX509LenLen(len) + len;
}
pgpAssert(0);
return 0;
}
static int
dsaSign(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 /* PGP_SIGN_DISABLE */ /* ] [ */
DSAsecPlus *sec = (DSAsecPlus *)seckey->priv;
BigNum r, s, bn, k;
unsigned t;
unsigned qbits;
unsigned qbytes;
int i;
PGPRandomContext *rc2;
PGPMemoryMgrRef mgr = NULL;
PGPCipherAlgorithm cipherAlg;
mgr = PGPPeekContextMemoryMgr( seckey->context );
(void)h;
/* We don't need this argument, although other algorithms may... */
(void)format;
ASSERTDSA(seckey->pkAlg);
/* Allow generalizations of SHA as long as they are big enough */
#if 0
pgpAssert(h->algorithm == kPGPHashAlgorithm_SHA);
#else
pgpAssert(h->hashsize*8 >= bnBits(&sec->s.q));
/* Make sure that q is the right size of we are using regular SHA hash */
pgpAssert( ! (h->algorithm == kPGPHashAlgorithm_SHA
&& bnBits(&sec->s.q) != h->hashsize*8) );
#endif
if (sec->locked)
return kPGPError_KeyIsLocked;
/*
* DSA requires a secret k. This k is *very* important
* to keep secret. Consider, the DSA signing equations are:
* r = (g^k mod p) mod q, and
* 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 = (g^k mod p) mod q 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, bnBytes(&sec->s.q));
if( pgpFIPSModeEnabled() )
{
cipherAlg = kPGPCipherAlgorithm_3DES;
}
else
{
cipherAlg = kPGPCipherAlgorithm_CAST5;
}
rc2 = pgpRandomCreateX9_17( rc->context, cipherAlg, rc);
if (!rc2)
return kPGPError_OutOfMemory;
pgpRandomBnSeed(rc2, &sec->s.x);
/*
* 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, TRUE );
bnBegin(&s, mgr, TRUE );
bnBegin(&bn, mgr, TRUE );
bnBegin(&k, mgr, TRUE );
/*
* Choose the random k value to be used for this signature.
* Make it a bit bigger than q so it is fairly uniform mod q.
*/
qbits = bnBits(&sec->s.q);
qbytes = bnBytes(&sec->s.q);
if (pgpBnGenRand(&k, rc2, qbits+8, 0, 1, qbits) < 0 ||
bnMod(&k, &k, &sec->s.q) < 0)
goto nomem;
/* Raise g to k power mod p then mod q to get r */
if (bnExpMod(&r, &sec->s.g, &k, &sec->s.p) < 0 ||
bnMod(&r, &r, &sec->s.q) < 0)
goto nomem;
/* r*x mod q into s */
if (bnMul(&s, &r, &sec->s.x) < 0 ||
bnMod(&s, &s, &sec->s.q) < 0)
goto nomem;
/* Pack message hash M into buffer bn */
if (bnInsertBigBytes(&bn, hash, 0, bnBytes(&sec->s.q)) < 0)
goto nomem;
if (bnMod(&bn, &bn, &sec->s.q) < 0)
goto nomem;
/* Add into s */
if (bnAdd(&s, &bn) < 0 ||
bnMod(&s, &s, &sec->s.q) < 0)
goto nomem;
/* Divide by k, mod q (k inverse held in bn) */
if (bnInv(&bn, &k, &sec->s.q) < 0 ||
bnMul(&s, &s, &bn) < 0 ||
bnMod(&s, &s, &sec->s.q) < 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 */
if (8*qbytes == bnBits(&r))
len_seq = pgpBnX509LenLen(qbytes+1) + 1 + qbytes+1;
else
len_seq = pgpBnX509LenLen(qbytes) + 1 + qbytes;
if (8*qbytes == bnBits(&s))
len_seq += pgpBnX509LenLen(qbytes+1) + 1 + qbytes+1;
else
len_seq += pgpBnX509LenLen(qbytes) + 1 + qbytes;
lenlen_seq = pgpBnX509LenLen(len_seq);
sig[t++] = X509_TAG_SEQUENCE | X509_TAG_CONSTRUCTED;
if (--lenlen_seq == 0) {
sig[t++] = len_seq;
} else {
sig[t++] = 0x80 | lenlen_seq;
len_seq <<= 8 * (4-lenlen_seq);
while (lenlen_seq--) {
sig[t++] = (PGPByte)(len_seq >> 24);
len_seq <<= 8;
}
}
}
t += pgpBnPutFormatted(&r, sig+t, qbytes, format);
t += pgpBnPutFormatted(&s, sig+t, qbytes, format);
if (siglen)
*siglen = (PGPSize)t;
i = 0;
goto done;
nomem:
i = kPGPError_OutOfMemory;
/* fall through */
done:
pgpRandomDestroy(rc2);
bnEnd(&k);
bnEnd(&bn);
bnEnd(&s);
bnEnd(&r);
return i;
#endif /* PGP_SIGN_DISABLE */ /* ] */
}
/*
* Re-encrypt a PGPSecKey with a new urn a PGPSecKey into a secret key.
* A secret key is, after a non-specific prefix:
* 0 1 Version (= 2 or 3)
* 1 4 Timestamp
* 5 2 Validity (=0 at present)
* 7 1 Algorithm (=kPGPPublicKeyAlgorithm_DSA for DSA)
* The following:
* 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
*
* The Encryption algorithm is the cipher algorithm for the old-style
* string-to-key conversion. For the new type, it's 255, then a cipher
* algorithm, then a string-to-key algorithm (variable-length),
* then the encryption IV. That's 16 bytes plus the string-to-key
* conversion length.
*/
#if PGP_MACINTOSH
#pragma global_optimizer on
#endif
static int
dsaChangeLock(PGPSecKey *seckey, PGPEnv const *env,
PGPRandomContext const *rc, char const *ophrase, PGPSize oplen,
PGPBoolean oHashedPhrase, char const *phrase, PGPSize plen,
PGPStringToKeyType s2ktype)
{
DSAsecPlus *sec = (DSAsecPlus *)seckey->priv;
PGPStringToKey *s2k = NULL; /* Shut up warnings */
PGPCipherVTBL const *cipher = NULL; /* Shut up warnings */
PGPCFBContext *cfb = NULL; /* This is realy needed */
PGPByte *p;
PGPByte key[PGP_CIPHER_MAXKEYSIZE];
int oldf = 0; /* Shut up warnings */
unsigned len;
unsigned checksum;
ASSERTDSA(seckey->pkAlg);
if (sec->locked)
if( IsPGPError(dsaUnlock( seckey, ophrase, oplen, oHashedPhrase )) )
return kPGPError_KeyIsLocked;
len = bnBytes(&sec->s.p) + bnBytes(&sec->s.q) + bnBytes(&sec->s.g) +
bnBytes(&sec->s.y) + bnBytes(&sec->s.x) + 13;
if (phrase) {
s2k = pgpS2Kcreate(pgpenvGetContext( env ), rc, s2ktype);
if (!s2k)
return kPGPError_OutOfMemory;
cipher = pgpCipherDefaultKey(env);
pgpAssert(cipher);
if (!cipher) {
pgpS2Kdestroy(s2k);
return kPGPError_OutOfMemory;
}
len += cipher->blocksize;
cfb = pgpCFBCreate(
PGPPeekContextMemoryMgr( pgpenvGetContext( env ) ), cipher);
if (!cfb) {
pgpS2Kdestroy(s2k);
return kPGPError_OutOfMemory;
}
oldf = pgpS2KisOldVers(s2k);
if (!oldf)
len += 1 + s2k->encodelen;
}
if (len > sec->ckalloc) {
PGPError err = kPGPError_NoErr;
if( IsNull( sec->cryptkey ) ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -