📄 pgpdsakey.c
字号:
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 = (size_t)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 *phrase, size_t 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)
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(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(
PGPGetContextMemoryMgr( 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 ) ) {
sec->cryptkey = (PGPByte *)
pgpContextMemAlloc( sec->context, len, 0 );
if( IsNull( sec->cryptkey ) ) {
err = kPGPError_OutOfMemory;
}
} else {
err = pgpContextMemRealloc( sec->context,
(void **)&sec->cryptkey, len, 0 );
}
if( IsPGPError( err ) ) {
PGPFreeCFBContext(cfb);
pgpS2Kdestroy(s2k);
return err;
}
sec->ckalloc = (size_t)len;
}
sec->cklen = len;
p = sec->cryptkey;
/* Okay, no more errors possible! Start installing data */
p += pgpBnPutPlain(&sec->s.p, p);
p += pgpBnPutPlain(&sec->s.q, p);
p += pgpBnPutPlain(&sec->s.g, p);
p += pgpBnPutPlain(&sec->s.y, p);
/* Encryption parameters */
if (!phrase) {
*p++ = 0; /* Unencrypted */
} else {
if (oldf) {
*p++ = cipher->algorithm;
} else {
*p++ = 255;
*p++ = cipher->algorithm;
memcpy(p, s2k->encoding, s2k->encodelen);
p += s2k->encodelen;
}
/* Create IV */
pgpRandomGetBytes(rc, p, cipher->blocksize);
pgpStringToKey(s2k, phrase, plen, key, cipher->keysize);
PGPInitCFB(cfb, key, p);
pgpS2Kdestroy(s2k);
p += cipher->blocksize;
/* Wipe key *immediately* */
pgpClearMemory( key, cipher->keysize);
}
/* Now install x, encrypted */
checksum = 0;
p += pgpBnPutNew(&sec->s.x, p, cfb, &checksum);
pgpChecksumPutNew(checksum, p, cfb);
p += 2;
pgpAssert((ptrdiff_t)len == p - sec->cryptkey);
if (cfb)
PGPFreeCFBContext(cfb);
return 0; /* Success */
}
#if PGP_MACINTOSH
#pragma global_optimizer reset
#endif
static size_t
dsaSecBufferLength(PGPSecKey const *seckey)
{
DSAsecPlus const *sec = (DSAsecPlus *)seckey->priv;
return sec->cklen;
}
static void
dsaSecToBuffer(PGPSecKey const *seckey, PGPByte *buf)
{
DSAsecPlus const *sec = (DSAsecPlus *)seckey->priv;
memcpy(buf, sec->cryptkey, sec->cklen);
/* Return only algorithm-dependent portion */
}
/* Fill in secret key structure */
static void
dsaFillSecKey(PGPSecKey *seckey, DSAsecPlus *sec)
{
seckey->pkAlg = kPGPPublicKeyAlgorithm_DSA;
seckey->priv = sec;
seckey->destroy = dsaSecDestroy;
seckey->pubkey = dsaPubkey;
seckey->islocked = dsaIslocked;
seckey->lockingalgorithm = dsaLockingAlgorithm;
seckey->s2ktype = dsaS2KType;
seckey->convertpassphrase = dsaConvertPassphrase;
seckey->unlock = dsaUnlock;
seckey->lock = dsaLock;
seckey->decrypt = dsaDecrypt;
seckey->maxdecrypted = dsaSecMaxdecrypted;
seckey->maxesk = dsaSecMaxesk;
seckey->maxsig = dsaSecMaxsig;
seckey->sign = dsaSign;
seckey->changeLock = dsaChangeLock;
seckey->bufferLength = dsaSecBufferLength;
seckey->toBuffer = dsaSecToBuffer;
}
PGPSecKey *
dsaSecFromBuf(
PGPContextRef context,
PGPByte const * buf,
size_t size,
PGPError * error)
{
PGPSecKey *seckey;
DSAsecPlus *sec;
PGPByte *cryptk;
PGPError err = kPGPError_OutOfMemory;
PGPMemoryMgrRef mgr = PGPGetContextMemoryMgr( context );
PGPEnv * pgpEnv = pgpContextGetEnvironment( context );
bnInit();
cryptk = (PGPByte *)pgpContextMemAlloc( context,
size, kPGPMemoryMgrFlags_Clear);
if (cryptk) {
sec = (DSAsecPlus *)PGPNewSecureData( mgr, sizeof(*sec), 0 );
if (sec) {
pgpClearMemory( sec, sizeof(*sec) );
sec->context = context;
seckey = (PGPSecKey *) pgpContextMemAlloc( context,
sizeof(*seckey), kPGPMemoryMgrFlags_Clear);
if (seckey) {
seckey->context = context;
memcpy(cryptk, buf, size);
bnBegin(&sec->s.p, mgr, FALSE );
bnBegin(&sec->s.q, mgr, FALSE );
bnBegin(&sec->s.g, mgr, FALSE );
bnBegin(&sec->s.y, mgr, FALSE );
bnBegin(&sec->s.x, mgr, TRUE );
sec->cryptkey = cryptk;
sec->cklen = sec->ckalloc = size;
sec->locked = 1;
/* We only need this to try unlocking... */
seckey->pkAlg = kPGPPublicKeyAlgorithm_DSA;
seckey->priv = sec;
if (dsaUnlock(seckey, pgpEnv, NULL, 0, FALSE) >= 0) {
if (dsaKeyTooBig (NULL, &sec->s)) {
bnEnd(&sec->s.p);
bnEnd(&sec->s.q);
bnEnd(&sec->s.g);
bnEnd(&sec->s.y);
err = kPGPError_KeyTooLarge;
} else {
dsaFillSecKey(seckey, sec);
*error = 0;
return seckey; /* Success! */
}
}
/* Ka-boom. Delete and free everything. */
pgpClearMemory( cryptk, size);
pgpContextMemFree( context, seckey);
}
PGPFreeData( sec ); /* Wipes as it frees */
}
pgpContextMemFree( context, cryptk);
}
*error = err;
return NULL;
}
/*
* Generate an DSA secret key with prime of the specified number of bits.
* Make callbacks to progress function periodically.
* Secret key is returned in the unlocked form, with no passphrase set.
* fastgen tells us to use canned primes if available.
*
* PGP attempts to acquire enough true random entropy in the randpool to
* make the keys it generates fully random and unpredictable, even if the
* RNG used to generate them were later found to have some weaknesses. With
* RSA keys it gets as many bits as the size of the modulus since the sizes
* of the secret primes p and q will add up to the size of the modulus.
* (This is slight overkill since the entropy in a random prime is less
* than the entropy of a random number because not all numbers are prime.)
*
* With discrete log based keys, DSA and ElGamal, only the private exponent
* x needs to be kept secret. However, the public values are generated at
* the same time as x, and are seeded ultimately from the same randpool.
* These values could theoretically leak information about the state of the
* randpool when they were generated, and therefore about x. This would
* require a very powerful attack which will probably never be possible,
* but we want to defend against it. One approach would simply be to acquire
* as much additional entropy as is needed for the public values, but that
* is wasteful. The public values don't need to be random, we just want them
* to be different among users.
*
* Instead, we create a "firewall" between the randpool and the public
* key values. We instantiate a second PGPRandomContext which is not
* based on the randpool but is a simple pseudo RNG, and seed it with
* a fixed number of bits from the true RNG. We choose enough bits
* for the seeding that different keys will not share the same public
* values. Only this fixed number of bits reflects the state of the
* randpool, so we acquire that many bits of additional entropy before
* beginning the keygen. This second RNG, rcdummy below and in the
* ElGamal keygen, is used to generate the public values for the discrete
* log key.
*/
PGPSecKey *
dsaSecGenerate(
PGPContextRef context,
unsigned bits, PGPBoolean fastgen,
PGPRandomContext const *rc,
int progress(void *arg, int c), void *arg, PGPError *error)
{
PGPSecKey *seckey = NULL;
DSAsecPlus *sec;
PGPRandomContext *rcdummy = NULL;
BigNum h;
BigNum e;
unsigned qbits;
int i;
PGPByte dummyseed[DSADUMMYBITS/8];
PGPMemoryMgrRef mgr = PGPGetContextMemoryMgr( context );
PGPEnv * pgpEnv = pgpContextGetEnvironment( context );
*error = kPGPError_NoErr;
/*
* Make bits a multiple of 64. This is required by the standard,
* and also makes it likely that all the various crypto libraries,
* smart cards, etc. will be able to work with the keys.
*/
bits = 64 * ((bits + 63) / 64);
/* Initialize local pointers (simplify cleanup below) */
seckey = NULL;
sec = NULL;
bnBegin(&h, mgr, FALSE );
bnBegin(&e, mgr, FALSE );
/* Limit the size we will generate at this time */
if (bits > MAX_DSA_PRIME_BITS) {
*error = kPGPError_PublicKeyTooLarge;
goto done;
}
/* Allocate data structures */
seckey = (PGPSecKey *)pgpContextMemAlloc( context,
sizeof(*seckey), kPGPMemoryMgrFlags_Clear);
if (!seckey)
goto memerror;
seckey->context = context;
sec = (DSAsecPlus *)PGPNewSecureData( mgr, sizeof(*sec), 0 );
if (!sec)
goto memerror;
pgpClearMemory( sec, sizeof(*sec) );
sec->context = context;
bnBegin(&sec->s.p, mgr, FALSE );
bnBegin(&sec->s.q, mgr, FALSE );
bnBegin(&sec->s.g, mgr, FALSE );
bnBegin(&sec->s.y, mgr, FALSE );
bnBegin(&sec->s.x, mgr, TRUE );
/* Use fixed primes and generator if in our table */
if (fastgen) {
PGPByte const *fixedp, *fixedq;
size_t fixedplen, fixedqlen;
if (pgpDSAfixed (bits, &fixedp, &fixedplen, &fixedq, &fixedqlen) > 0) {
bnInsertBigBytes (&sec->s.q, fixedq, 0, fixedqlen);
if (progress != NULL)
progress(arg, ' ');
bnInsertBigBytes (&sec->s.p, fixedp, 0, fixedplen);
if (progress != NULL)
progress(arg, ' ');
qbits = bnBits (&sec->s.q);
goto choose_g;
}
}
/* Set up and seed local random number generator for p and q */
rcdummy = pgpPseudoRandomCreate ( rc->context );
if (!rcdummy)
goto memerror;
pgpRandomGetBytes (rc, dummyseed, sizeof(dummyseed));
pgpRandomAddBytes (rcdummy, dummyseed, sizeof(dummyseed));
/*
* Choose a random starting place for q, in the high end of the range
*/
if (bits <= 1024)
qbits = 160; /* Follow the published standard */
else
qbits = pgpDiscreteLogQBits(bits);
if (pgpBnGenRand(&sec->s.q, rcdummy, qbits, 0xFF, 1, qbits-9) < 0)
goto nomem;
/* And search for a prime */
i = bnPrimeGen(&sec->s.q, NULL, progress, arg, 0);
if (i < 0)
goto nomem;
if (progress != NULL)
progress(arg, ' ');
/* ...and now a random start for p (we discard qbits bits of it) */
(void)bnSetQ(&sec->s.p, 0);
if (pgpBnGenRand(&sec->s.p, rcdummy, bits, 0xC0, 1, bits-qbits) < 0)
goto nomem;
/* Temporarily double q */
if (bnLShift(&sec->s.q, 1) < 0)
goto nomem;
/* Set p = p - (p mod q) + 1, i.e. congruent to 1 mod 2*q */
if (bnMod(&e, &sec->s.p, &sec->s.q) < 0)
goto nomem;
if (bnSub(&sec->s.p, &e) < 0 || bnAddQ(&sec->s.p, 1) < 0)
goto nomem;
/* And search for a prime, 1+2kq for some k */
i = bnPrimeGenStrong(&sec->s.p, &sec->s.q, progress, arg);
if (i < 0)
goto nomem;
if (progress != NULL)
progress(arg, ' ');
/* Reduce q again */
bnRShift(&sec->s.q, 1);
/* May get here directly from above if fixed primes are used */
choose_g:
/* Now hunt for a suitable g - first, find (p-1)/q */
if (bnDivMod(&e, &h, &sec->s.p, &sec->s.q) < 0)
goto nomem;
/* e is now the exponent (p-1)/q, and h is the remainder (one!) */
pgpAssert(bnBits(&h)==1);
if (progress != NULL)
progress(arg, '.');
/* Search for a suitable h */
if (bnSetQ(&h, 2) < 0 ||
bnTwoExpMod(&sec->s.g, &e, &sec->s.p) < 0)
goto nomem;
while (bnBits(&sec->s.g) < 2) {
if (progress != NULL)
progress(arg, '.');
if (bnAddQ(&h, 1) < 0 ||
bnExpMod(&sec->s.g, &h, &e, &sec->s.p) < 0)
goto nomem;
}
if (progress != NULL)
progress(arg, ' ');
/* Choose a random 0 < x < q of reasonable size as secret key */
if (pgpBnGenRand(&sec->s.x, rc, qbits + 8, 0, 0, qbits) < 0 ||
bnMod(&sec->s.x, &sec->s.x, &sec->s.q) < 0)
goto nomem;
/* prob. failure < 2^-140 is awful unlikely... */
pgpAssert(bnBits(&sec->s.x) > 20);
/* And calculate g**x as public key */
if (bnExpMod(&sec->s.y, &sec->s.g, &sec->s.x, &sec->s.p) < 0)
goto nomem;
/* And that's it... success! */
/* Fill in structs */
sec->cryptkey = NULL;
sec->ckalloc = sec->cklen = 0;
sec->locked = 0;
dsaFillSecKey(seckey, sec);
/* Fill in cryptkey structure, unencrypted */
dsaChangeLock (seckey, pgpEnv, NULL, NULL, 0, kPGPStringToKey_Simple);
goto done;
nomem:
bnEnd(&sec->s.p);
bnEnd(&sec->s.q);
bnEnd(&sec->s.g);
bnEnd(&sec->s.y);
bnEnd(&sec->s.x);
/* Fall through */
memerror:
if ( IsntNull( seckey ) )
pgpContextMemFree( context, seckey);
if ( IsntNull( sec ) )
PGPFreeData( sec ); /* Wipes as it frees */
seckey = NULL;
*error = kPGPError_OutOfMemory;
/* Fall through */
done:
bnEnd(&h);
bnEnd(&e);
if (rcdummy)
{
pgpRandomDestroy (rcdummy);
}
return seckey;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -