📄 pgpencode.c
字号:
/*____________________________________________________________________________
pgpEncode.c
High level encode functionality
Copyright (C) 1997 Network Associates Inc. and affiliated companies.
All rights reserved.
$Id: pgpEncode.c,v 1.107 1999/05/07 23:47:45 hal Exp $
____________________________________________________________________________*/
#include "pgpConfig.h" /* or pgpConfig.h in the CDK */
#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 "pgpKeyDB.h"
#include "pgpKDBInt.h"
#include "pgpMem.h"
#include "pgpMemMod.h"
#include "pgpOptionList.h"
#include "pgpPipeline.h"
#include "pgpPubKey.h"
#include "pgpRandomPoolPriv.h"
#include "pgpRndSeed.h"
#include "pgpRngPub.h"
#include "pgpSigSpec.h"
#include "pgpTextFilt.h"
#include "pgpTrstPkt.h"
#include "pgpVMemMod.h"
#include "pgpX509Priv.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 */
};
typedef struct PGPPreferredAlgs_ PGPPreferredAlgs;
/* 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 ) );
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,
PGPKey *key,
RingSet const *ringSet
)
{
RingObject *ringObj;
PGPByte const *prefs;
PGPSize plen;
PGPByte algDefault[3];
PGPByte alg;
PGPUInt32 i;
PGPError err;
if( IsPGPError( err = pgpGetKeyRingObject( key, TRUE, &ringObj ) ) )
goto error;
prefs = ringKeyFindSubpacket (ringObj, ringSet,
SIGSUB_PREFERRED_ENCRYPTION_ALGS,
0, &plen, NULL, NULL, NULL, NULL, &err);
if( IsNull( prefs ) ) {
/* Use a default. RSA keys get IDEA, later get CAST. */
PGPByte pkalg;
ringKeyID8 (ringSet, ringObj, &pkalg, NULL);
if (pkalg <= kPGPPublicKeyAlgorithm_RSA+2) {
algDefault[0] = kPGPCipherAlgorithm_IDEA;
prefs = algDefault;
plen = 1;
} else {
algDefault[0] = kPGPCipherAlgorithm_CAST5;
algDefault[1] = kPGPCipherAlgorithm_IDEA;
algDefault[2] = kPGPCipherAlgorithm_3DES;
prefs = algDefault;
plen = 3;
}
}
++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;
error:
return err;
}
/*
* 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 */
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];
/* Don't bother with a preference vote, handled below */
}
}
/* 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;
if (prefalgLength != 0) {
PGPUInt32 j;
/* Choose acceptable algorithm which sender likes best */
for( j=0; j<prefalgLength; ++j ) {
if (prefalg[j] == (PGPCipherAlgorithm)(i+1))
break;
}
pgpAssert (j < prefalgLength);
if( bestalg == 0 || j < bestvote ) {
/* First acceptable, or best one so far */
bestvote = j;
bestalg = i+1;
}
} else {
/* Case of no sender preferences, choose favorite of others */
if( bestalg == 0 || algInfo->votes[i] < bestvote ) {
/* First acceptable, or best one so far */
bestvote = algInfo->votes[i];
bestalg = i+1;
}
}
}
}
/* If no choice OK for all, choose sender's favorite if any */
if (algsOK == 0 && prefalgLength != 0) {
for (i=0; i<prefalgLength; ++i) {
/* Find highest-sender-preference supported one */
if( IsntNull( pgpCipherGetVTBL(
(PGPCipherAlgorithm) prefalg[i] ) ) ) {
bestalg = prefalg[i];
algsOK = 1;
break;
}
}
}
/* If still no acceptable algorithms, choose most acceptable one */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -