📄 pgpencode.c
字号:
/*____________________________________________________________________________
Copyright (C) 2002 PGP Corporation
All rights reserved.
$Id: pgpEncode.c,v 1.31 2002/11/15 04:40:11 ajivsov Exp $
____________________________________________________________________________*/
/*
* pgpEncode.c -- High level encode functionality
*/
#include "pgpConfig.h"
#include <string.h>
/* Public headers */
#include "pgpPubTypes.h"
#include "pgpContext.h"
#include "pgpEncode.h"
#include "pgpErrors.h"
#include "pgpKeys.h"
#include "pgpMem.h"
/* Private headers */
#include "pgpDebug.h"
#include "pgpEncodePriv.h"
#include "pgpAnnotate.h"
#include "pgpArmor.h"
#include "pgpBufMod.h"
#include "pgpSymmetricCipherPriv.h"
#include "pgpConvKey.h"
#include "pgpDevNull.h"
#include "pgpEncPipe.h"
#include "pgpEnv.h"
#include "pgpEventPriv.h"
#include "pgpFile.h"
#include "pgpFileMod.h"
#include "pgpFileRef.h"
#include "pgpFileSpec.h"
#include "pgpFileType.h"
#include "pgpHash.h"
#include "pgpKeyPriv.h"
#include "pgpMem.h"
#include "pgpMemMod.h"
#include "pgpOptionList.h"
#include "pgpPipeline.h"
#include "pgpPubKey.h"
#include "pgpRandomPoolPriv.h"
#include "pgpRndSeed.h"
#include "pgpSigSpec.h"
#include "pgpTextFilt.h"
#include "pgpVMemMod.h"
#include "pgpX509Priv.h"
#include "pgpFIPSPriv.h"
#define elemsof(x) ((unsigned)(sizeof(x)/sizeof(*x)))
/*********************** Helper functions for below ************************/
/* Set up PGPEnv structure for library internals */
static PGPError
pgpMakeEnvFromOptionList(
PGPOptionListRef optionList,
PGPEnv *env
)
{
PGPError err; /* Error flag */
PGPUInt32 hashalg; /* Default hash alg */
PGPUInt32 cipheralg; /* Default cipher alg */
PGPUInt32 fOption; /* Generic option flag */
PGPBoolean fDefault; /* True if have the option from usr */
char *comment; /* Comment string for output */
char *version; /* Version string for output */
/* Ascii armor mode */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_ArmorOutput, FALSE,
"%d", &fOption ) ) )
goto error;
pgpenvSetInt( env, PGPENV_ARMOR, fOption, PGPENV_PRI_FORCE );
/* Text mode (as compared to binary) */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_DataIsASCII, FALSE,
"%d", &fOption ) ) )
goto error;
pgpenvSetInt( env, PGPENV_TEXTMODE, fOption, PGPENV_PRI_FORCE );
/* Control of compression (default on) */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_Compression, FALSE,
"%b%d", &fDefault, &fOption ) ) )
goto error;
if( !fDefault )
fOption = TRUE;
pgpenvSetInt( env, PGPENV_COMPRESS, fOption, PGPENV_PRI_FORCE );
/* Clearsign mode, implies textmode and ascii armor */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_ClearSign, FALSE,
"%d", &fOption ) ) )
goto error;
if( fOption ) {
pgpenvSetInt( env, PGPENV_CLEARSIG, TRUE, PGPENV_PRI_FORCE );
pgpenvSetInt( env, PGPENV_TEXTMODE, TRUE, PGPENV_PRI_FORCE );
pgpenvSetInt( env, PGPENV_ARMOR, TRUE, PGPENV_PRI_FORCE );
} else {
pgpenvSetInt( env, PGPENV_CLEARSIG, FALSE, PGPENV_PRI_FORCE );
}
/* PGP-MIME output, implies ascii armor */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_PGPMIMEEncoding, FALSE,
"%b%d", &fDefault, &fOption ) ) )
goto error;
if( fDefault ) {
pgpenvSetInt( env, PGPENV_PGPMIME, fOption, PGPENV_PRI_FORCE );
pgpenvSetInt( env, PGPENV_ARMOR, TRUE, PGPENV_PRI_FORCE );
}
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_OmitMIMEVersion, FALSE,
"%d", &fOption ) ) )
goto error;
pgpenvSetInt( env, PGPENV_PGPMIMEVERSIONLINE, !fOption, PGPENV_PRI_FORCE );
/* Non-default hash algorithm */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_HashAlgorithm, FALSE,
"%b%d", &fDefault, &hashalg ) ) )
goto error;
if( fDefault ) {
pgpenvSetInt( env, PGPENV_HASH, hashalg, PGPENV_PRI_FORCE );
}
/* Non-default cipher algorithm - only effective with conv encr */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_CipherAlgorithm, FALSE,
"%b%d", &fDefault, &cipheralg ) ) )
goto error;
if( fDefault ) {
if( IsNull( pgpCipherGetVTBL ( (PGPCipherAlgorithm)cipheralg ) ) ) {
pgpDebugMsg( "Unsupported cipher algorithm" );
err = kPGPError_FeatureNotAvailable;
goto error;
}
pgpenvSetInt( env, PGPENV_CIPHER, cipheralg, PGPENV_PRI_FORCE );
}
/* Comment string */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_CommentString, FALSE,
"%b%p", &fDefault, &comment ) ) )
goto error;
if( fDefault ) {
pgpenvSetString( env, PGPENV_COMMENT, comment, PGPENV_PRI_FORCE );
}
/* Comment string */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_VersionString, FALSE,
"%b%p", &fDefault, &version ) ) )
goto error;
if( fDefault ) {
pgpenvSetString( env, PGPENV_VERSION_STRING,
version, PGPENV_PRI_FORCE );
}
return kPGPError_NoErr;
error:
return err;
}
/* Preferred algorithm calculations */
/* Data structure to record preferences of recipients */
struct PGPPreferredAlgs_ {
PGPUInt32 n; /* Number of algorithms */
PGPByte *algok; /* # recips who can accept this */
PGPUInt32 *votes; /* Preference voting, lower=better */
PGPUInt32 counts; /* Number of recips */
PGPBoolean oldkeys; /* Had old keys in a set */
};
typedef struct PGPPreferredAlgs_ PGPPreferredAlgs;
#define kPGPCipherAlgorithm_Last kPGPCipherAlgorithm_Twofish256
/* Init the structure we will use to choose the conv encryption alg */
static PGPError
pgpInitPreferredAlgorithms(
PGPContextRef context,
PGPPreferredAlgs *algInfo
)
{
PGPUInt32 n;
PGPError err;
pgpa( pgpaAddrValid( algInfo, PGPPreferredAlgs ) );
pgpClearMemory( algInfo, sizeof( *algInfo ) );
n = kPGPCipherAlgorithm_Last + 1;
algInfo->n = n;
algInfo->algok = (PGPByte *)pgpContextMemAlloc( context, n, 0 );
if ( IsNull( algInfo->algok ) ) {
err = kPGPError_OutOfMemory;
goto error;
}
algInfo->votes = (PGPUInt32 *)
pgpContextMemAlloc( context, n * sizeof( PGPUInt32 ), 0 );
if ( IsNull( algInfo->votes ) ) {
err = kPGPError_OutOfMemory;
goto error;
}
pgpClearMemory( algInfo->algok, n );
pgpClearMemory( algInfo->votes, n * sizeof( PGPUInt32 ) );
algInfo->oldkeys = FALSE;
return kPGPError_NoErr;
error:
if( IsntNull( algInfo->algok ) )
pgpContextMemFree( context, algInfo->algok );
if( IsntNull( algInfo->votes ) )
pgpContextMemFree( context, algInfo->votes );
return err;
}
/*
* Add info for the preferred algs for one recipient. We record which algs
* are acceptable and then use preference voting.
*/
static PGPError
pgpCheckPreferredAlgorithms(
PGPPreferredAlgs *algInfo,
PGPKeyDBObj *key
)
{
PGPByte const *prefs;
PGPSize plen;
PGPByte algDefault[3];
PGPByte alg;
PGPUInt32 i;
PGPBoolean hashed;
PGPError err;
if( pgpFIPSModeEnabled() )
{
/* Force the use of 3DES */
algDefault[0] = kPGPCipherAlgorithm_3DES;
prefs = algDefault;
plen = 1;
}
else
{
PGPByte pkalg;
PGPBoolean oldkeys;
pgpKeyID8 ( key, &pkalg, NULL );
oldkeys = (pkalg <= kPGPPublicKeyAlgorithm_RSA+2 && pgpKeyV3(key));
prefs = pgpKeyFindSubpacket (key,
SIGSUB_PREFERRED_ENCRYPTION_ALGS,
0, &plen, NULL, &hashed, NULL, NULL, &err);
if( IsNull( prefs ) || !hashed ) {
/* Use a default. RSA V3 keys get IDEA, later get 3DES. */
if (oldkeys) {
algDefault[0] = kPGPCipherAlgorithm_IDEA;
prefs = algDefault;
plen = 1;
} else {
algDefault[0] = kPGPCipherAlgorithm_3DES;
algDefault[1] = kPGPCipherAlgorithm_CAST5;
algDefault[2] = kPGPCipherAlgorithm_IDEA;
prefs = algDefault;
plen = 3;
}
}
if( oldkeys && ! algInfo->oldkeys )
algInfo->oldkeys = oldkeys;
}
++algInfo->counts;
for( i=0; i<plen; ++i ) {
alg = prefs[i];
if( alg > algInfo->n )
continue;
algInfo->votes[alg-1] += i; /* Preference voting, lower=better */
++algInfo->algok[alg-1];
}
return kPGPError_NoErr;
}
/*
* Choose the most popular algorithm of those which were acceptable to all,
* taking into consideration sender preferences if any
*/
static PGPError
pgpSetPreferredAlgorithm(
PGPOptionListRef optionList,
PGPPreferredAlgs *algInfo,
PGPEnv *env
)
{
PGPUInt32 bestvote = 0; /* Silence warning */
PGPUInt32 bestalg = 0;
PGPUInt32 i;
PGPUInt32 algsOK = 0; /* Number of acceptable algs */
PGPCipherAlgorithm *prefalg;
PGPCipherAlgorithm alg;
PGPSize prefalgLength;
PGPError err = kPGPError_NoErr;
/* See if sender has a preferred algorithm specification.
* Treat it as unordered set */
if( IsPGPError( err = pgpFindOptionArgs( optionList,
kPGPOptionType_PreferredAlgorithms, FALSE,
"%p%l", &prefalg, &prefalgLength ) ) )
goto error;
/* Convert prefalgLength from bytes to number of entries */
prefalgLength /= sizeof(PGPCipherAlgorithm);
/* If so, let sender have a veto vote too */
if( prefalgLength != 0 ) {
++algInfo->counts;
for( i=0; i<prefalgLength; ++i ) {
alg = prefalg[i];
if( (PGPUInt32)alg > algInfo->n )
continue;
++algInfo->algok[alg-1];
/* no voting is done here */
}
}
/* Loop for all algorithms we know about, see how many are OK */
for( i=0; i<algInfo->n; ++i ) {
if( algInfo->algok[i] == algInfo->counts ) {
/* This algorithm was acceptable to all */
/* Skip if not supported by this library */
if( IsNull( pgpCipherGetVTBL( (PGPCipherAlgorithm)(i+1) ) ) )
continue;
algsOK += 1;
/* Choose favorite of others from algInfo.
* Some of those alg preferences can be generated by us */
if( bestalg == 0 || algInfo->votes[i] < bestvote ) {
/* First acceptable, or best one so far */
bestvote = algInfo->votes[i];
bestalg = i+1;
}
}
}
/* If still no acceptable algorithms, choose most acceptable one */
if (algsOK == 0) {
/* Choose an algorithm which we support and most people accept */
for( i=0; i<algInfo->n; ++i ) {
if( IsNull( pgpCipherGetVTBL( (PGPCipherAlgorithm)(i+1) ) ) )
continue;
algsOK += 1;
if ( bestalg == 0 || algInfo->algok[i] > bestvote ) {
/* First acceptable, or best one so far */
bestvote = algInfo->algok[i];
bestalg = i+1;
}
}
}
if (algsOK == 0) {
/* None of the algs we support are acceptable to anyone;
* choose IDEA if at least one key is old, else 3DES. */
algsOK = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -