📄 pgprsakey.c
字号:
(void)format;
return kPGPError_FeatureNotAvailable;
#else
RSAsecPlus *sec = (RSAsecPlus *)seckey->priv;
BigNum bn;
int i;
unsigned t;
PGPMemoryMgrRef mgr = NULL;
mgr = PGPGetContextMemoryMgr( seckey->context );
/* We don't need these arguments, although other algorithms may... */
(void)rc;
(void)format;
ASSERTRSASIG(seckey->pkAlg);
if (sec->locked)
return kPGPError_KeyIsLocked;
bnBegin(&bn, mgr, TRUE);
#if PGP_USECAPIFORRSA
i = rsaSignHash(&bn, &sec->s, h, hash);
#else
t = h->DERprefixsize;
/* IKE does not put in hash OID */
if (format == kPGPPublicKeyMessageFormat_IKE)
t = 0;
if (t+h->hashsize > rsaSecMaxsig(seckey, format))
return kPGPError_PublicKeyTooSmall;
memcpy(sig, h->DERprefix, t);
memcpy(sig+t, hash, h->hashsize);
t += h->hashsize;
i = rsaPrivateEncrypt(&bn, sig, t, &sec->s);
pgpClearMemory( sig, t);
#endif
if (i >= 0) {
t = 0;
if (format == kPGPPublicKeyMessageFormat_X509) {
/* Output unformatted, but with no leading zeros */
format = kPGPPublicKeyMessageFormat_PKCS1;
t += pgpBnPutFormatted(&bn, sig+t, bnBytes(&bn), format);
} else {
t += pgpBnPutFormatted(&bn, sig+t, bnBytes(&sec->s.n), format);
}
if (siglen)
*siglen = (size_t)t;
i = 0;
}
bnEnd(&bn);
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 (=1 for RSA)
* The following:
* 0 2+u MPI for modulus
* 2+u 2+v MPI for exponent
* 4+u+v 1 Encryption algorithm (0 for none, 1 for IDEA)
* 5+u+v t Encryption IV: 0 or 8 bytes
* 5+t+u+v 2+w MPI for d
* 7+t+u+v+w 2+x MPI for p
* 9+t+u+v+w+x 2+y MPI for q
* 11+t+u+v+w+x+y 2+z MPI for u
* 13+t+u+v+w+x+y+z 2 Checksum (big-endian sum of all the bytes)
* 15+t+u+v+w+x+y+z
*
* 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
rsaChangeLock(PGPSecKey *seckey, PGPEnv const *env,
PGPRandomContext const *rc, char const *phrase, size_t plen,
PGPStringToKeyType s2ktype)
{
RSAsecPlus *sec = (RSAsecPlus *)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;
ASSERTRSA(seckey->pkAlg);
if (sec->locked)
return kPGPError_KeyIsLocked;
len = bnBytes(&sec->s.n) + bnBytes(&sec->s.e) +
bnBytes(&sec->s.d) + bnBytes(&sec->s.p) +
bnBytes(&sec->s.q) + bnBytes(&sec->s.u) + 15;
if (phrase) {
/* Create old-style s2k unless new features requested */
if (s2ktype == kPGPStringToKey_Simple)
s2k = pgpS2KdefaultV3(env, rc);
else
s2k = pgpS2Kcreate(env, rc, s2ktype);
if (!s2k)
return kPGPError_OutOfMemory;
cipher = pgpCipherDefaultKeyV3(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.n, p);
p += pgpBnPutPlain(&sec->s.e, 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 d, p, q and u, encrypted */
checksum = 0;
p += pgpBnPut(&sec->s.d, p, cfb, &checksum, sec->v3);
p += pgpBnPut(&sec->s.p, p, cfb, &checksum, sec->v3);
p += pgpBnPut(&sec->s.q, p, cfb, &checksum, sec->v3);
p += pgpBnPut(&sec->s.u, p, cfb, &checksum, sec->v3);
pgpChecksumPutOld(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
rsaSecBufferLength(PGPSecKey const *seckey)
{
RSAsecPlus const *sec = (RSAsecPlus *)seckey->priv;
return sec->cklen;
}
static void
rsaSecToBuffer(PGPSecKey const *seckey, PGPByte *buf)
{
RSAsecPlus const *sec = (RSAsecPlus *)seckey->priv;
memcpy(buf, sec->cryptkey, sec->cklen);
}
/* Fill in secret key structure */
static void
rsaFillSecKey(PGPSecKey *seckey, RSAsecPlus *sec)
{
seckey->pkAlg = kPGPPublicKeyAlgorithm_RSA;
seckey->priv = sec;
seckey->destroy = rsaSecDestroy;
seckey->pubkey = rsaPubkey;
seckey->islocked = rsaIslocked;
seckey->lockingalgorithm = rsaLockingAlgorithm;
seckey->s2ktype = rsaS2KType;
seckey->convertpassphrase = rsaConvertPassphrase;
seckey->unlock = rsaUnlock;
seckey->lock = rsaLock;
seckey->decrypt = rsaDecrypt;
seckey->maxdecrypted = rsaSecMaxdecrypted;
seckey->maxsig = rsaSecMaxsig;
seckey->maxesk = rsaSecMaxesk;
seckey->sign = rsaSign;
seckey->changeLock = rsaChangeLock;
seckey->bufferLength = rsaSecBufferLength;
seckey->toBuffer = rsaSecToBuffer;
}
PGPSecKey *
rsaSecFromBuf(
PGPContextRef context,
PGPByte const * buf,
size_t size,
PGPBoolean v3,
PGPError * error)
{
PGPSecKey *seckey;
RSAsecPlus *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 = (RSAsecPlus *)PGPNewSecureData( mgr, sizeof(*sec), 0 );
if (sec) {
pgpClearMemory( sec, sizeof(*sec) );
sec->context = context;
sec->v3 = v3;
seckey = (PGPSecKey *)
pgpContextMemAlloc(context,
sizeof(*seckey), kPGPMemoryMgrFlags_Clear);
if (seckey) {
seckey->context = context;
memcpy(cryptk, buf, size);
bnBegin(&sec->s.n, mgr, FALSE);
bnBegin(&sec->s.e, mgr, FALSE);
bnBegin(&sec->s.d, mgr, TRUE);
bnBegin(&sec->s.p, mgr, TRUE);
bnBegin(&sec->s.q, mgr, TRUE);
bnBegin(&sec->s.u, mgr, TRUE);
sec->cryptkey = cryptk;
sec->cklen = sec->ckalloc = size;
sec->locked = 1;
/* We only need this to try unlocking... */
seckey->pkAlg = kPGPPublicKeyAlgorithm_RSA;
seckey->priv = sec;
if (rsaUnlock(seckey, pgpEnv, NULL, 0, FALSE) >= 0) {
if (rsaKeyTooBig (NULL, &sec->s) ||
bnBits(&sec->s.n) > 2048) {
bnEnd (&sec->s.n);
bnEnd (&sec->s.e);
err = kPGPError_KeyTooLarge;
} else {
rsaFillSecKey(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;
}
#if PGP_RSA_KEYGEN
/*
* PGPRandomContext to use for primeGen callback. We really should enhance
* primeGen to pass an arg parameter along with the limit value.
*/
static PGPRandomContext const *staticrc;
/* Random callback for primeGen */
static unsigned randcallback(unsigned limit)
{
return pgpRandomRange(staticrc, limit);
}
/*
* Generate an RSA secret key with modulus of the specified number of bits.
* We choose public exponent from the #define value above.
* The high two bits of each prime are always
* set to make the number more difficult to factor by forcing the
* number into the high end of the range.
* Make callbacks to progress function periodically.
* Secret key is returned in the unlocked form, with no passphrase set.
* fastgen is an unused flag which is used by the discrete log keygens to
* allow use of canned primes.
*/
PGPSecKey *
rsaSecGenerate(
PGPContextRef context,
unsigned bits, PGPBoolean fastgen,
PGPRandomContext const *rc,
int progress(void *arg, int c), void *arg, PGPError *error)
{
PGPSecKey *seckey;
RSAsecPlus *sec;
BigNum t; /* temporary */
unsigned ent; /* Entropy */
int i;
int exp = RSA_DEFAULT_EXPONENT;
PGPMemoryMgrRef mgr = PGPGetContextMemoryMgr( context );
PGPEnv * pgpEnv = pgpContextGetEnvironment( context );
(void) fastgen;
*error = kPGPError_NoErr;
/* Initialize local pointers (simplify cleanup below) */
seckey = NULL;
sec = NULL;
bnBegin(&t, mgr, TRUE);
/* Allocate data structures */
seckey = (PGPSecKey *)pgpContextMemAlloc( context,
sizeof(*seckey), kPGPMemoryMgrFlags_Clear );
if (!seckey)
goto memerror;
seckey->context = context;
sec = (RSAsecPlus *)PGPNewSecureData( mgr, sizeof(*sec), 0 );
if (!sec)
goto memerror;
sec->context = context;
sec->v3 = TRUE;
/* n is not inherently sensitive, but holds sensitive intermediates */
bnBegin(&sec->s.n, mgr, TRUE);
bnBegin(&sec->s.e, mgr, FALSE);
bnBegin(&sec->s.d, mgr, TRUE);
bnBegin(&sec->s.p, mgr, TRUE);
bnBegin(&sec->s.q, mgr, TRUE);
bnBegin(&sec->s.u, mgr, TRUE);
if (bnSetQ(&sec->s.e, exp))
goto bnerror;
/* Find p - choose a starting place */
if (pgpBnGenRand(&sec->s.p, rc, bits/2, 0xC0, 1, bits/2-3) < 0)
goto bnerror;
/* And search for a prime */
staticrc = rc;
i = bnPrimeGen(&sec->s.p, randcallback, progress, arg, exp, 0);
if (i < 0)
goto bnerror;
pgpAssert(bnModQ(&sec->s.p, exp) != 1);
/* Make sure p and q aren't too close together */
/* Bits of entropy needed to generate q. */
ent = (bits+1)/2 - 3;
/* Pick random q until we get one not too close to p */
do {
/* Visual separator between the two progress indicators */
if (progress != NULL)
progress(arg, ' ');
if (pgpBnGenRand(&sec->s.q, rc, (bits+1)/2, 0xC0, 1, ent) < 0)
goto bnerror;
ent = 0; /* No entropy charge next time around */
if (bnCopy(&sec->s.n, &sec->s.q) < 0)
goto bnerror;
if (bnSub(&sec->s.n, &sec->s.p) < 0)
goto bnerror;
/* Note that bnSub(a,b) returns abs(a-b) */
} while (bnBits(&sec->s.n) < bits/2-5);
i = bnPrimeGen(&sec->s.q, randcallback, progress, arg, exp, 0);
if (i < 0)
goto bnerror;
pgpAssert(bnModQ(&sec->s.p, exp) != 1);
/* Wash the random number pool. */
pgpRandomStir(rc);
/* Ensure that q is larger */
if (bnCmp(&sec->s.p, &sec->s.q) > 0)
bnSwap(&sec->s.p, &sec->s.q);
/*
* Now we compute d,
* the decryption exponent, from the encryption exponent.
*/
/* Decrement q temporarily */
(void)bnSubQ(&sec->s.q, 1);
/* And u = p-1, to be divided by gcd(p-1,q-1) */
if (bnCopy(&sec->s.u, &sec->s.p) < 0)
goto bnerror;
(void)bnSubQ(&sec->s.u, 1);
/* Use t to store gcd(p-1,q-1) */
if (bnGcd(&t, &sec->s.q, &sec->s.u) < 0) {
goto bnerror;
}
/* Let d = (p-1) / gcd(p-1,q-1) (n is scratch for the remainder) */
i = bnDivMod(&sec->s.d, &sec->s.n, &sec->s.u, &t);
if (i < 0)
goto bnerror;
pgpAssert(bnBits(&sec->s.n) == 0);
/* Now we have q-1 and d = (p-1) / gcd(p-1,q-1) */
/* Find the product, n = lcm(p-1,q-1) = c * d */
if (bnMul(&sec->s.n, &sec->s.q, &sec->s.d) < 0)
goto bnerror;
/* Find the inverse of the exponent mod n */
i = bnInv(&sec->s.d, &sec->s.e, &sec->s.n);
if (i < 0)
goto bnerror;
pgpAssert(!i); /* We should NOT get an error here */
/*
* Now we have the comparatively simple task of computing
* u = p^-1 mod q.
*/
/* But it *would* be nice to have q back first. */
(void)bnAddQ(&sec->s.q, 1);
/* Now compute u = p^-1 mod q */
i = bnInv(&sec->s.u, &sec->s.p, &sec->s.q);
if (i < 0)
goto bnerror;
pgpAssert(!i); /* p and q had better be relatively prime! */
/* And finally, n = p * q */
if (bnMul(&sec->s.n, &sec->s.p, &sec->s.q) < 0)
goto bnerror;
/* And that's it... success! */
/* Fill in structs */
sec->cryptkey = NULL;
sec->ckalloc = sec->cklen = 0;
sec->locked = 0;
rsaFillSecKey(seckey, sec);
/* Fill in cryptkey structure, unencrypted */
rsaChangeLock (seckey, pgpEnv, rc, NULL, 0, kPGPStringToKey_Simple);
goto done;
bnerror:
bnEnd(&sec->s.n);
bnEnd(&sec->s.e);
bnEnd(&sec->s.d);
bnEnd(&sec->s.p);
bnEnd(&sec->s.q);
bnEnd(&sec->s.u);
/* 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(&t);
return seckey;
}
#endif /* PGP_RSA_KEYGEN */
#endif /* PGP_RSA */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -