📄 pgpkeyman.c
字号:
/* Return the amount of entropy needed to create a key of the specified
type and size. The application must call pgpRandpoolEntropy() itself
until it has accumulated this much. */
PGPUInt32
pgpKeyEntropyNeededInternal(
PGPContextRef context,
PGPOptionListRef optionList
)
{
PGPEnv *pgpEnv;
PGPUInt32 fastgen;
PGPBoolean fastgenop;
PGPUInt32 noentropy = FALSE;
PGPUInt32 pkalg;
PGPUInt32 bits;
PGPError err = kPGPError_NoErr;
if (IsPGPError( err = pgpCheckOptionsInSet( optionList,
keyentOptionSet, elemsof( keyentOptionSet ) ) ) )
return err;
/* If generating with existing entropy, we don't need any amount */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_KeyGenUseExistingEntropy, FALSE,
"%d", &noentropy ) ) )
goto error;
if (noentropy)
return 0;
pgpEnv = pgpContextGetEnvironment( context );
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_KeyGenParams, TRUE,
"%d%d", &pkalg, &bits ) ) )
goto error;
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_KeyGenFast, FALSE,
"%b%d", &fastgenop, &fastgen ) ) )
goto error;
if( !fastgenop ) {
fastgen = pgpenvGetInt (pgpEnv, PGPENV_FASTKEYGEN, NULL, NULL);
}
return pgpSecKeyEntropy (pgpPkalgByNumber ((PGPByte)pkalg), bits,
(PGPBoolean)fastgen);
/* Should not have an error unless bad parameters */
error:
pgpAssert(0);
return ~(PGPUInt32)0;
}
/* Internal function for passphraseIsValid */
static PGPError
sPassphraseIsValid(
PGPKeyRef key,
const char * passphrase,
PGPSize passphraseLength,
PGPBoolean hashedPhrase,
PGPBoolean * isValid)
{
RingObject * keyobj;
PGPKeyDBRef keys;
RingSet const * ringset;
PGPContextRef context;
PGPEnv * pgpEnv;
PGPSecKey * seckey;
PGPError err = kPGPError_NoErr;
PGPValidateKey( key );
PGPValidateParam( passphrase );
PGPValidateParam( isValid );
/* Default return value */
*isValid = FALSE;
/* Dig stuff out of key structure */
keyobj = key->key;
keys = key->keyDB;
ringset = pgpKeyDBRingSet (keys);
context = keys->context;
pgpEnv = pgpContextGetEnvironment( context );
seckey = ringSecSecKey (ringset, keyobj, 0);
/* If not a secret key, just return */
if( !seckey )
return err;
/* Returns 1 on success, 0 on failure, else error */
err = (PGPError)pgpSecKeyUnlock (seckey, pgpEnv, passphrase,
passphraseLength, hashedPhrase);
pgpSecKeyDestroy( seckey );
if (err == (PGPError)1) {
*isValid = TRUE;
err = kPGPError_NoErr;
}
return err;
}
static const PGPOptionType passphraseisvalidOptionSet[] = {
kPGPOptionType_Passphrase,
kPGPOptionType_Passkey
};
PGPBoolean
pgpPassphraseIsValidInternal(
PGPKeyRef key,
PGPOptionListRef optionList
)
{
PGPContextRef context;
char * passphrase;
PGPSize passphraseLength;
PGPBoolean hashedPhrase = FALSE;
PGPBoolean rslt;
PGPError err = kPGPError_NoErr;
pgpa(pgpaPGPKeyValid(key));
if ( ! pgpKeyIsValid( key ) )
return( FALSE );
context = key->keyDB->context;
if (IsPGPError( err = pgpCheckOptionsInSet( optionList,
passphraseisvalidOptionSet,
elemsof( passphraseisvalidOptionSet ) ) ) )
return FALSE;
/* Pick up mandatory options */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_Passphrase, FALSE,
"%p%l", &passphrase, &passphraseLength ) ) )
return FALSE;
if (IsNull( passphrase )) {
hashedPhrase = TRUE;
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_Passkey, TRUE,
"%p%l", &passphrase, &passphraseLength ) ) )
return FALSE;
}
if( IsPGPError( sPassphraseIsValid( key, passphrase, passphraseLength,
hashedPhrase, &rslt ) ) )
return FALSE;
return rslt;
}
/*____________________________________________________________________________
Key Generation
____________________________________________________________________________*/
/*
* Callback impedence matching, convert from internal state to callback
* state.
*/
typedef struct PGPKeyGenProgressState {
PGPContextRef context;
PGPEventHandlerProcPtr progress;
PGPUserValue userValue;
} PGPKeyGenProgressState;
static int /* Return < 0 to abort run */
genProgress(
void *arg,
int c
)
{
PGPKeyGenProgressState *s = (PGPKeyGenProgressState *)arg;
PGPError err = kPGPError_NoErr;
PGPOptionListRef newOptionList = NULL;
if (IsntNull (s->progress)) {
err = pgpEventKeyGen (s->context, &newOptionList,
s->progress, s->userValue, (PGPUInt32)c);
if (IsntNull (newOptionList))
pgpFreeOptionList (newOptionList);
}
return err;
}
/* Common code for generating master keys and subkeys. *masterkey
is NULL when generating a master key, and is used to return
the master PGPKey object. If *masterkey contains a value,
a subkey is to be generated associated with the PGPKey object. */
static PGPError
pgpDoGenerateKey (
PGPKeyDB * keyDB,
PGPKey ** masterkey,
PGPSubKey ** newsubkey,
PGPByte pkalg,
unsigned bits,
PGPTime creationDate,
PGPUInt16 expirationDays,
char const * name,
int name_len,
char const * passphrase,
PGPSize passphraseLength,
PGPBoolean passphraseIsKey,
char const * masterpass,
PGPSize masterpassLength,
PGPEventHandlerProcPtr progress,
PGPUserValue userValue,
PGPBoolean fastgen,
PGPBoolean checkentropy,
RingSet const * adkset,
PGPByte adkclass,
RingSet const * rakset,
PGPByte rakclass,
PGPCipherAlgorithm const * prefalg,
PGPSize prefalgLength)
{
RingSet const *allset;
RingSet *addset = NULL;
union RingObject *newobj = NULL;
PGPError error = kPGPError_NoErr;
PGPSecKey *seckey = NULL, *masterseckey = NULL;
PGPKeySpec *keyspec = NULL;
long entropy_needed, entropy_available;
PGPBoolean genMaster = (*masterkey == NULL);
PGPEnv *pgpEnv;
PGPRandomContext *pgpRng;
PGPKeyGenProgressState progressState;
PGPContextRef context = pgpGetKeyDBContext( keyDB );
PGPByte *prefalgByte;
PGPUInt32 i;
const PGPPkAlg * algInfo;
if ( !pgpKeyDBIsMutable( keyDB ) )
return kPGPError_ItemIsReadOnly;
algInfo = pgpPkalgByNumber( pkalg );
if( IsntNull( algInfo ) )
{
if( ( pgpKeyUse( algInfo ) & PGP_PKUSE_SIGN ) == 0 &&
genMaster )
{
pgpDebugMsg( "Invalid master key algorithm" );
error = kPGPError_BadParams;
}
else if( ( pgpKeyUse( algInfo ) & PGP_PKUSE_ENCRYPT ) == 0 &&
! genMaster )
{
pgpDebugMsg( "Invalid subkey algorithm" );
error = kPGPError_BadParams;
}
}
else
{
pgpDebugMsg( "Invaid public key algorithm" );
error = kPGPError_BadParams;
}
if( IsPGPError( error ) )
goto cleanup;
pgpEnv = pgpContextGetEnvironment( keyDB->context );
if( checkentropy )
{
/* Check we have sufficient random bits to generate the keypair */
entropy_needed = pgpSecKeyEntropy (algInfo, bits, fastgen);
entropy_available = PGPGlobalRandomPoolGetEntropy ( );
if (entropy_needed > entropy_available)
{
error = kPGPError_OutOfEntropy;
goto cleanup;
}
}
/* Generate the secret key */
progressState.progress = progress;
progressState.userValue = userValue;
progressState.context = keyDB->context;
pgpRng = pgpContextGetX9_17RandomContext( keyDB->context );
seckey = pgpSecKeyGenerate( context, algInfo, bits, fastgen, pgpRng,
genProgress, &progressState, &error);
if (error)
goto cleanup;
pgpRandomStir (pgpRng);
/* Need to lock the SecKey with the passphrase. */
if (passphrase && passphraseLength > 0) {
PGPStringToKeyType s2ktype;
if (passphraseIsKey) {
s2ktype = kPGPStringToKey_LiteralShared;
} else if (seckey->pkAlg <= kPGPPublicKeyAlgorithm_RSA + 2) {
s2ktype = kPGPStringToKey_Simple;
} else {
s2ktype = kPGPStringToKey_IteratedSalted;
}
error = (PGPError)pgpSecKeyChangeLock (seckey, pgpEnv, pgpRng,
passphrase, passphraseLength,
s2ktype);
if (error)
goto cleanup;
}
/* Generate the keyring objects. Use keyspec defaults except for
expiration (validity) period */
keyspec = pgpKeySpecCreate (pgpEnv);
if (!keyspec) {
error = kPGPError_OutOfMemory;
goto cleanup;
}
if( creationDate != 0 )
{
pgpKeySpecSetCreation(keyspec, creationDate +
(60 * 60 * pgpenvGetInt(pgpEnv, PGPENV_TZFIX, NULL, NULL)));
}
pgpKeySpecSetValidity (keyspec, expirationDays);
allset = pgpKeyDBRingSet (keyDB);
if (genMaster) {
/* Generating master signing key */
addset = ringSetCreate (ringSetPool (allset));
if (!addset) {
error = kPGPError_OutOfMemory;
goto cleanup;
}
prefalgByte = NULL;
if (prefalgLength > 0) {
/* Convert preferred algorithm to byte array */
prefalgLength /= sizeof(PGPCipherAlgorithm);
prefalgByte = (PGPByte *)pgpContextMemAlloc( context,
prefalgLength, 0);
if( IsNull( prefalgByte ) ) {
error = kPGPError_OutOfMemory;
goto cleanup;
}
for (i=0; i<prefalgLength; ++i) {
prefalgByte[i] = (PGPByte)prefalg[i];
}
}
newobj = ringCreateKeypair (pgpEnv, seckey, keyspec, name,
name_len, pgpRng, addset, addset,
rakset, rakclass,
prefalgByte, prefalgLength,
adkset, adkclass,
&error);
if( IsntNull( prefalgByte ) ) {
pgpContextMemFree( context, prefalgByte );
}
}
else {
/* Generating encryption subkey. Get the master seckey and
unlock it */
error = pgpCopyKey (allset, (*masterkey)->key, &addset);
if (error)
goto cleanup;
masterseckey = ringSecSecKey (allset, (*masterkey)->key,
PGP_PKUSE_SIGN);
if (!masterseckey) {
error = ringSetError(allset)->error;
goto cleanup;
}
if (pgpSecKeyIslocked (masterseckey)) {
if (IsNull( masterpass )) {
error = kPGPError_BadPassphrase;
goto cleanup;
}
error = (PGPError)pgpSecKeyUnlock (masterseckey, pgpEnv,
masterpass, masterpassLength, FALSE);
if (error != 1) {
if (error == 0)
error = kPGPError_BadPassphrase;
goto cleanup;
}
}
newobj = ringCreateSubkeypair (pgpEnv, masterseckey, seckey,
keyspec, pgpRng, addset, addset, &error);
}
pgpRandomStir (pgpRng); /* this helps us count randomness in pool */
if (error)
goto cleanup;
/* Add objects to main KeyDB. Before doing so, locate
the master key object and return it. */
ringSetFreeze (addset);
error = pgpAddObjects (keyDB, addset);
if (genMaster && !error) {
*masterkey = pgpGetKeyByRingObject (keyDB, newobj);
} else if (!genMaster && !error && IsntNull( newsubkey ) ) {
PGPSubKey *subk = (PGPSubKey *) (*masterkey)->subKeys.next;
while( subk != (PGPSubKey *) &(*masterkey)->subKeys ) {
if( subk->subKey == newobj )
break;
subk = subk->next;
}
pgpAssert( subk->subKey == newobj );
*newsubkey = subk;
}
cleanup:
if (addset)
ringSetDestroy (addset);
if (seckey)
pgpSecKeyDestroy (seckey);
if (masterseckey)
pgpSecKeyDestroy (masterseckey);
if (keyspec)
pgpKeySpecDestroy (keyspec);
return error;
}
static const PGPOptionType keygenOptionSet[] = {
kPGPOptionType_KeySetRef,
kPGPOptionType_KeyGenParams,
kPGPOptionType_KeyGenName,
kPGPOptionType_Passphrase,
kPGPOptionType_Passkey,
kPGPOptionType_Expiration,
kPGPOptionType_CreationDate,
kPGPOptionType_EventHandler,
kPGPOptionType_PreferredAlgorithms,
kPGPOptionType_AdditionalRecipientRequestKeySet,
kPGPOptionType_RevocationKeySet,
kPGPOptionType_KeyGenFast,
kPGPOptionType_KeyGenUseExistingEntropy
};
PGPError
pgpGenerateKeyInternal(
PGPContextRef context,
PGPKeyRef *key,
PGPOptionListRef optionList
)
{
PGPKeySetRef keyset;
PGPUInt32 pkalg;
PGPUInt32 bits;
PGPUInt32 expiration;
PGPTime creationDate;
PGPByte *name;
PGPUInt32 nameLength;
PGPByte *passphrase;
PGPUInt32 passphraseLength;
PGPBoolean passphraseIsKey = FALSE;
PGPKeySetRef adkset;
PGPUInt32 adkclass;
PGPKeySetRef rakset = NULL;
PGPUInt32 rakclass = 0;
PGPEventHandlerProcPtr progress;
PGPUserValue userValue;
RingSet const *adkringset = NULL;
RingSet const *rakringset = NULL;
PGPKeyRef newkey;
PGPCipherAlgorithm *prefalg;
PGPSize prefalgLength;
PGPEnv *pgpEnv;
PGPBoolean fastgenop;
PGPUInt32 fastgen;
PGPUInt32 noentropy = FALSE;
PGPError err;
if (IsPGPError( err = pgpCheckOptionsInSet( optionList,
keygenOptionSet, elemsof( keygenOptionSet ) ) ) )
return err;
if( IsNull( key ) )
return kPGPError_BadParams;
pgpEnv = pgpContextGetEnvironment( context );
/* First pick up mandatory options */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_KeySetRef, TRUE,
"%p", &keyset ) ) )
goto error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -