📄 pgppubkey.c
字号:
/*____________________________________________________________________________
Copyright (C) 2002 PGP Corporation
All rights reserved.
$Id: pgpPubKey.c,v 1.19 2002/08/06 20:11:04 dallen Exp $
____________________________________________________________________________*/
#include "pgpSDKBuildFlags.h"
#include "pgpConfig.h"
#include "pgpDebug.h"
#include "pgpErrors.h"
#include "pgpPubKey.h"
#include "pgpKeyMisc.h"
#include "pgpMem.h"
#if PGP_RSA
#include "pgpRSAKey.h"
#include "pgpMSRSAGlue.h"
#endif
#include "pgpElGKey.h"
#include "pgpDSAKey.h"
#if PGP_EC
#include "pgpECKey.h"
#endif
#include "pgpP11Key.h"
#include "pgpFixedKey.h"
#ifndef PGP_RSA
#error "PGP_RSA requires a value"
#endif
#ifndef PGP_RSA_KEYGEN
#error "PGP_RSA_KEYGEN requires a value"
#endif
/* Error code used within this module for RSA not available */
#define kPGPLocalError_RSANotAvailable kPGPError_FeatureNotAvailable
struct PGPPkAlg
{
PGPByte pkAlg;
int use;
} ;
#if PGP_ENCRYPT_DISABLE && PGP_DECRYPT_DISABLE
#define LOCAL_ENCRYPT 0
#else
#define LOCAL_ENCRYPT PGP_PKUSE_ENCRYPT
#endif
#if PGP_SIGN_DISABLE && PGP_VERIFY_DISABLE
#define LOCAL_SIGN 0
#else
#define LOCAL_SIGN PGP_PKUSE_SIGN
#endif
#define LOCAL_SIGN_ENCRYPT (LOCAL_SIGN | LOCAL_ENCRYPT)
static PGPPkAlg const pgpKnownPkAlgs[] = {
#if PGP_RSA
{ kPGPPublicKeyAlgorithm_RSA, LOCAL_SIGN_ENCRYPT },
{ kPGPPublicKeyAlgorithm_RSASignOnly, LOCAL_SIGN },
{ kPGPPublicKeyAlgorithm_RSAEncryptOnly, LOCAL_ENCRYPT },
#else /* PGP_RSA */
{ kPGPPublicKeyAlgorithm_RSA, 0 },
{ kPGPPublicKeyAlgorithm_RSASignOnly, 0 },
{ kPGPPublicKeyAlgorithm_RSAEncryptOnly, 0 },
#endif /* PGP_RSA */
{ kPGPPublicKeyAlgorithm_ElGamal, LOCAL_ENCRYPT },
{ kPGPPublicKeyAlgorithm_DSA, LOCAL_SIGN },
#if PGP_EC
{ kPGPPublicKeyAlgorithm_ECSign, LOCAL_SIGN },
{ kPGPPublicKeyAlgorithm_ECEncrypt, LOCAL_ENCRYPT },
#else /* PGP_EC */
{ kPGPPublicKeyAlgorithm_ECSign, 0 },
{ kPGPPublicKeyAlgorithm_ECEncrypt, 0 },
#endif /* PGP_EC */
};
/* Error codes which permit signature checking to continue */
PGPBoolean
pgpIsKeyRelatedError( PGPError err )
{
if (err >= kPGPError_KEY_MIN && err <= kPGPError_KEY_MAX)
return TRUE;
if (err == kPGPLocalError_RSANotAvailable)
return TRUE;
if (err == kPGPError_KeyUnusableForSignature)
return TRUE;
return FALSE;
}
/* Return whether an algorithm can sign, encrypt, or do both */
PGPPkAlg const *
pgpPkalgByNumber(PGPByte pkalg)
{
unsigned i;
pkalg = ALGMASK(pkalg);
for (i = 0; i < sizeof(pgpKnownPkAlgs)/sizeof(*pgpKnownPkAlgs); i++) {
if (pgpKnownPkAlgs[i].pkAlg == pkalg)
return pgpKnownPkAlgs + i;
}
return NULL;
}
PGPUInt32
pgpKeyAlgUse(PGPPkAlg const *pkalg)
{
if (!pkalg)
return 0; /* It's no use... */
#if PGP_RSA && PGP_USECAPIFORRSA
if( pkalg->pkAlg == kPGPPublicKeyAlgorithm_RSA ||
pkalg->pkAlg == kPGPPublicKeyAlgorithm_RSASignOnly ||
pkalg->pkAlg == kPGPPublicKeyAlgorithm_RSAEncryptOnly ) {
return pkalg->use & pgpCAPIuse();
}
#endif
return pkalg->use;
}
PGPPubKey *
pgpPubKeyFromBuf(
PGPContextRef context,
PGPByte pkAlg,
PGPByte const * p,
PGPSize len,
PGPError * error)
{
PGPPubKey *pub;
switch (ALGMASK(pkAlg)) {
case kPGPPublicKeyAlgorithm_RSA:
case kPGPPublicKeyAlgorithm_RSASignOnly:
case kPGPPublicKeyAlgorithm_RSAEncryptOnly:
#if PGP_RSA
pub = rsaPubFromBuf( context, p, len, error);
if (pub)
pub->pkAlg = pkAlg;
#else /* PGP_RSA */
(void) p;
(void) len;
pub = NULL;
*error = kPGPLocalError_RSANotAvailable;
#endif /* PGP_RSA */
return pub;
case kPGPPublicKeyAlgorithm_ElGamal:
pub = elgPubFromBuf( context, p, len, error);
if (pub)
pub->pkAlg = pkAlg;
return pub;
case kPGPPublicKeyAlgorithm_DSA:
pub = dsaPubFromBuf( context, p, len, error);
if (pub)
pub->pkAlg = pkAlg;
return pub;
case kPGPPublicKeyAlgorithm_ECSign:
case kPGPPublicKeyAlgorithm_ECEncrypt:
#if PGP_EC
pub = ecPubFromBuf( context, p, len, error);
if (pub)
pub->pkAlg = pkAlg;
#else /* PGP_EC */
(void) p;
(void) len;
pub = NULL;
*error = kPGPError_UnknownPublicKeyAlgorithm;
#endif /* PGP_EC */
return pub;
default:
*error = kPGPError_UnknownPublicKeyAlgorithm;
return 0;
}
}
PGPSecKey *
pgpSecKeyFromBuf(
PGPContextRef context,
PGPByte pkAlg,
PGPByte const * p,
PGPSize len,
PGPBoolean v3,
void * tokenobj,
PGPError * error)
{
PGPSecKey *sec;
/* Handle token objects */
if( IsntNull( tokenobj ) )
{
sec = p11SecFromBuf( context, p, len, v3, tokenobj, error );
if( sec )
{
sec->pkAlg = pkAlg;
return sec;
}
}
switch(ALGMASK(pkAlg)) {
case kPGPPublicKeyAlgorithm_RSA:
case kPGPPublicKeyAlgorithm_RSASignOnly:
case kPGPPublicKeyAlgorithm_RSAEncryptOnly:
#if PGP_RSA
sec = rsaSecFromBuf( context, p, len, v3, error);
if (sec)
sec->pkAlg = pkAlg;
#else /* PGP_RSA */
(void) p;
(void) len;
(void) v3;
sec = NULL;
*error = kPGPLocalError_RSANotAvailable;
#endif /* PGP_RSA */
return sec;
case kPGPPublicKeyAlgorithm_ElGamal:
sec = elgSecFromBuf( context, p, len, error);
if (sec)
sec->pkAlg = pkAlg;
return sec;
case kPGPPublicKeyAlgorithm_DSA:
sec = dsaSecFromBuf( context, p, len, error);
if (sec)
sec->pkAlg = pkAlg;
return sec;
case kPGPPublicKeyAlgorithm_ECSign:
case kPGPPublicKeyAlgorithm_ECEncrypt:
#if PGP_EC
sec = ecSecFromBuf( context, p, len, error);
if (sec)
sec->pkAlg = pkAlg;
#else /* PGP_EC */
(void) p;
(void) len;
(void) v3;
sec = NULL;
*error = kPGPError_UnknownPublicKeyAlgorithm;
#endif /* PGP_EC */
return sec;
default:
*error = kPGPError_UnknownPublicKeyAlgorithm;
return 0;
}
}
/*
* Scan a buffer and return the size of the part which corresponds to
* a public key. This is intended to be "lightweight" and not require
* the overhead of instantiating a PGPPubKey.
*
* This rturns 0 if the size is unknown.
*/
PGPSize
pgpPubKeyPrefixSize(PGPByte pkAlg, PGPByte const *p, PGPSize len)
{
switch(ALGMASK(pkAlg)) {
case kPGPPublicKeyAlgorithm_RSA:
case kPGPPublicKeyAlgorithm_RSASignOnly:
case kPGPPublicKeyAlgorithm_RSAEncryptOnly:
#if PGP_RSA
return rsaPubKeyPrefixSize(p, len);
#else
/* We know it is 2 MPI values, just parse past those */
return pgpBnParse(p, len, 2, NULL, NULL);
#endif
case kPGPPublicKeyAlgorithm_ElGamal:
return elgPubKeyPrefixSize(p, len);
case kPGPPublicKeyAlgorithm_DSA:
return dsaPubKeyPrefixSize(p, len);
case kPGPPublicKeyAlgorithm_ECSign:
case kPGPPublicKeyAlgorithm_ECEncrypt:
#if PGP_EC
return ecPubKeyPrefixSize(p, len);
#else
return 0;
#endif
default:
return 0;
}
}
/*
* The "progress" function is called periodically during key
* generation to indicate that *something* is happening.
* The "int c" gives a bit of indication as to *what* is
* happening. In fact, this is just the character that text-mode
* PGP prints! It will do as well as any other sort of enum
* and makes life simple.
*
* The meaning of the character is somewhat type-dependent, but
* the convention so far is:
* '.' - Failed pseudoprimality test
* '/' - Redoing initial setup work
* '-' - Passed pseudoprimality test, further work needed
* '+' - Passed pseudoprimality test, further work needed
* '*' - Passed pseudoprimality test - almost done!
* ' ' - Completed part of key generation, on to next phase.
* (Sorry, no way to know how many phases there are...)
*/
PGPSecKey *
pgpSecKeyGenerate(
PGPContextRef context,
PGPPkAlg const *alg, unsigned bits,
PGPBoolean fastgen, PGPBoolean v3,
PGPRandomContext const *rc,
int (*progress)(void *arg, int c), void *arg,
void *tokenobj,
PGPByte const *passphrase, PGPSize passphraseLength,
PGPBoolean genMaster, PGPError *error)
{
PGPSecKey *sec;
PGPByte pkAlg;
(void) v3;
pgpAssert (alg);
pkAlg = alg->pkAlg;
/* Handle token objects */
if( IsntNull( tokenobj ) )
{
sec = p11SecGenerate( context, pkAlg, bits, fastgen, v3, progress,
arg, tokenobj, passphrase, passphraseLength,
genMaster, error );
if( sec )
{
sec->pkAlg = pkAlg;
}
return sec;
}
switch(ALGMASK(pkAlg)) {
case kPGPPublicKeyAlgorithm_RSA:
case kPGPPublicKeyAlgorithm_RSASignOnly:
case kPGPPublicKeyAlgorithm_RSAEncryptOnly:
#if PGP_RSA && PGP_RSA_KEYGEN
/* Use V3 for plain RSA keys, V4 for sign/encrypt versions */
sec = rsaSecGenerate( context, bits, fastgen, v3,
rc, progress, arg, error);
if (sec)
sec->pkAlg = pkAlg;
return sec;
#else
*error = kPGPLocalError_RSANotAvailable;
return NULL;
#endif
case kPGPPublicKeyAlgorithm_ElGamal:
sec = elgSecGenerate(context, bits, fastgen, rc, progress, arg, error);
if (sec)
sec->pkAlg = pkAlg;
return sec;
case kPGPPublicKeyAlgorithm_DSA:
sec = dsaSecGenerate(context, bits, fastgen, rc, progress, arg, error);
if (sec)
sec->pkAlg = pkAlg;
return sec;
case kPGPPublicKeyAlgorithm_ECSign:
case kPGPPublicKeyAlgorithm_ECEncrypt:
#if PGP_EC
sec = ecSecGenerate( context, bits, fastgen,
rc, progress, arg, error);
if (sec)
sec->pkAlg = pkAlg;
return sec;
#else
*error = kPGPError_UnknownPublicKeyAlgorithm;
return NULL;
#endif
default:
*error = kPGPError_UnknownPublicKeyAlgorithm;
return 0;
}
}
/*
* Return the amount of entropy needed to generate this key. Entropy
* is a security parameter, controlling the amount of unpredictability
* needed in the key. We have to be sure to return a value at least
* as big as the actual depletion of the randpool which the keygen
* creates. For simplicity and predictability, we return the
* non-fastgen values throughout, even though they are a bit larger
* for DSA & ELG keys. (The +128 is for the secret key encryption IV
* and salt when the secret key is encrypted with the passphrase.)
*/
unsigned
pgpSecKeyEntropy(PGPPkAlg const *pkAlg, unsigned bits, PGPBoolean fastgen,
PGPBoolean v3, void *tokenobj)
{
unsigned xbits;
if( IsntNull(tokenobj) )
{
return 0;
}
switch (ALGMASK(pkAlg->pkAlg)) {
case kPGPPublicKeyAlgorithm_RSA:
case kPGPPublicKeyAlgorithm_RSASignOnly:
case kPGPPublicKeyAlgorithm_RSAEncryptOnly:
if( v3 )
{
/* In fastgen, use an estimate of the strength of the key. */
/* Note that the dlog estimate gives twice what we need */
if (fastgen) {
return pgpMax (384,
pgpDiscreteLogExponentBits (bits));
} else {
return bits + 128;
}
} else {
/*
* Need to return the exact number consumed by the
* algorithm here, since we will generate two keys. This is
* more than the effective strength of the key, which is
* the estimate used for RSA above.
*/
return bits + 128;
}
case kPGPPublicKeyAlgorithm_ElGamal:
xbits = pgpDiscreteLogExponentBits(bits)*3/2 + 128;
/* Always return fastgen value
* if (!fastgen || !pgpElGfixed (bits, NULL, NULL, NULL, NULL))
*/
xbits += ELGDUMMYBITS;
return xbits;
case kPGPPublicKeyAlgorithm_DSA:
/* We make bits a multiple of 64, rounding up, in keygen */
bits = 64 * ((bits + 63) / 64);
/*
* Count the ~160 bits each needed to generate the self signature
* on the key's userid, and on the subkey, in addition to the
* "q bits" secret exponent. That is why the 2* below.
*/
xbits = 2*((bits<=1024)?160:pgpDiscreteLogExponentBits(bits))
+ ((bits<=1024)?160:pgpDiscreteLogQBits(bits)) + 128;
/* Always return fastgen value
* if (!fastgen || !pgpDSAfixed (bits, NULL, NULL, NULL, NULL))
*/
xbits += DSADUMMYBITS;
return xbits;
case kPGPPublicKeyAlgorithm_ECSign:
case kPGPPublicKeyAlgorithm_ECEncrypt:
/*
* Count the ~160 bits each needed to generate the self signature
* on the key's userid, and on the subkey, in addition to the
* "q bits" secret exponent. That is why the 2* below.
*/
return 2*bits;
}
pgpAssert (0);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -