pgparmor.c
来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 1,332 行 · 第 1/3 页
C
1,332 行
if (context->scope_depth)
return 0;
/* Then compute maxparts */
if (!context->maxparts) {
pgpAssert(context->armorlines);
/* Add buffered bytes */
total = bytes + pgpFifoSize (context->fd, context->fifo);
/* Convert to lines */
total = (total + ARMOR_LINE_INPUT-1) / ARMOR_LINE_INPUT;
/* Add already-output lines (> PGPVERSION_2_6) */
total += context->lineno;
/* Convert to parts */
total = (total + context->armorlines-1) / context->armorlines;
/* Add already-emitted parts */
total += context->thispart - (context->thispart != 0);
context->maxparts = (unsigned)total;
}
if (bytes)
return 0; /* Stop futzing with non-zero sizeAdvises */
/* The real end - this is it */
context->at_eof = 1;
/* Flush out any buffered data */
error = armorFlushFifo (myself, (size_t)-1);
if (error)
return error;
/* Force a write out of last partial line. */
error = armorWritePartial (myself);
if (error)
return error;
if (context->clearsign) {
/* Clear out the clearsign buffer, if we have it. */
if (context->linebuf) {
pgpFifoWrite (context->fd, context->header,
context->input, context->linebuf);
context->linebuf = 0;
}
/*
* If clearsign input ended with '\r', will be hashed with
* '\r\n' but the output file will be missing the '\n'.
* Add it here.
*/
if (context->state == 2) {
pgpFifoWrite (context->fd, context->header,
(const unsigned char *) "\n", 1);
context->state = 0;
}
} else {
if (!context->didfooter)
armorMakeFooter (context);
error = armorFlushPending (myself);
if (error)
return error;
}
/* Finally, the downstream SizeAdvise */
return context->tail->sizeAdvise (context->tail, 0);
}
/* Push anything available through */
static int
Flush (struct PgpPipeline *myself)
{
struct Context *context = (struct Context *)myself->priv;
int error;
error = armorFlushPending (myself);
if (error)
return error;
return context->tail->flush (context->tail);
}
/* Straightforward deallocate & destroy */
static void
Teardown (struct PgpPipeline *myself)
{
struct Context *context;
pgpAssert (myself);
pgpAssert (myself->magic == ARMORMAGIC);
context = (struct Context *)myself->priv;
pgpAssert (context);
if (context->tail)
context->tail->teardown (context->tail);
pgpFifoDestroy (context->fd, context->fifo);
pgpFifoDestroy (context->fd, context->header);
if (context->messageid)
pgpMemFree (context->messageid);
memset (context, 0, sizeof (*context));
pgpMemFree (context);
memset (myself, 0, sizeof (*myself));
pgpMemFree (myself);
}
/*
* Add a "Hash: foo, bar, baz" header to the given FIFO if needed.
* it is not needed if there are no hashes, or there is only MD5.
*/
static void
armorWriteHashHeader (struct PgpFifoDesc const *fd,
struct PgpFifoContext *header,
byte const *hashlist, unsigned hashlen)
{
int dohash = 0;
struct PgpHash const *hash;
if (!hashlen || (hashlen == 1 && *hashlist == PGP_HASH_MD5))
return;
pgpFifoWrite (fd, header, (byte const *)"\nHash: ", 7);
while (hashlen--) {
hash = pgpHashByNumber (*hashlist++);
if (!hash)
continue;
if (dohash)
pgpFifoWrite (fd, header, (byte const *)", ", 2);
pgpFifoWrite (fd, header,
(byte const *)hash->name, strlen (hash->name));
dohash = 1;
}
}
/*
* The slightly different types of ASCII armoring that we do.
*/
#define ATYPE_NORMAL 0
#define ATYPE_CLEARSIG 10
#define ATYPE_SEPSIG 20
#define ATYPE_SEPSIGMSG 21
#define ATYPE_MIMESIG 30
#define ATYPE_MIMEENC 40
#define ATYPE_MIMESEPSIG 50
/*
* The all-purpose ASCII armor pipeline module creator.
*/
static struct PgpPipeline **
armorDoCreate (struct PgpPipeline **head, struct PgpEnv const *env,
PgpVersion version, struct PgpFifoDesc const *fd,
struct PgpRandomContext const *rc, unsigned long armorlines,
int armortype, byte const *hashlist, unsigned hashlen)
{
struct PgpPipeline *mod;
struct Context *context;
struct PgpFifoContext *fifo;
struct PgpFifoContext *header;
char *mid;
byte message[24]; /* Messageid (binary) */
int len;
if (!head)
return NULL;
pgpAssert (fd);
context = (struct Context *)pgpMemAlloc (sizeof (*context));
if (!context)
return NULL;
mod = (struct PgpPipeline *)pgpMemAlloc (sizeof (*mod));
if (!mod) {
pgpMemFree (context);
return NULL;
}
fifo = pgpFifoCreate (fd);
if (!fifo) {
pgpMemFree (context);
pgpMemFree (mod);
return NULL;
}
header = pgpFifoCreate (fd);
if (!header) {
pgpFifoDestroy (fd, fifo);
pgpMemFree (context);
pgpMemFree (mod);
return NULL;
}
if (rc) {
mid = (char *)pgpMemAlloc ((sizeof(message)+3)*4/3 + 1);
if (!mid) {
pgpFifoDestroy (fd, fifo);
pgpFifoDestroy (fd, header);
pgpMemFree (context);
pgpMemFree (mod);
return NULL;
}
/* Create a random message id */
pgpRandomGetBytes (rc, message, sizeof (message));
len = armorLine (message, sizeof(message), mid);
mid[len] = '\0';
} else {
mid = NULL;
}
mod->magic = ARMORMAGIC;
mod->write = Write;
mod->flush = Flush;
mod->sizeAdvise = SizeAdvise;
mod->annotate = Annotate;
mod->teardown = Teardown;
mod->name = "ASCII Armor Write Module";
mod->priv = context;
memset (context, 0, sizeof (*context));
context->outptr = context->output;
context->armorlines = armorlines;
context->maxparts = armorlines ? 0 : 1; /* 0 = unknown */
context->crc = CRC_INIT;
context->fd = fd;
context->fifo = fifo;
context->header = header;
context->messageid = mid;
context->comment = pgpenvGetString (env, PGPENV_COMMENT, NULL, NULL);
context->version = version;
/* The armortype-dependent whatnot */
if (armortype == ATYPE_CLEARSIG) {
static char const CLRSIGN[] =
"-----BEGIN PGP SIGNED MESSAGE-----";
pgpFifoWrite (fd, header, (byte const *)CLRSIGN,
sizeof(CLRSIGN)-1);
context->clearsign = 1;
context->armorlines = 0;
armorWriteHashHeader (fd, header, hashlist, hashlen);
pgpFifoWrite (fd, header, (byte const *)"\n\n", 2);
} else if (armortype == ATYPE_MIMESIG) {
pgpFifoWrite (fd, header, (byte const *)MIMETOPHDR,
strlen(MIMETOPHDR));
context->clearsign = 1;
context->armorlines = 0;
context->pgpmime = PGPMIMESIG;
} else if (armortype == ATYPE_SEPSIG) {
context->blocktype = "SIGNATURE";
} else if (armortype == ATYPE_SEPSIGMSG) {
context->blocktype = "MESSAGE";
} else if (armortype == ATYPE_MIMESEPSIG) {
context->blocktype = "MESSAGE";
context->pgpmime = PGPMIMESIG;
context->armorlines = 0;
} else if (armortype == ATYPE_MIMEENC) {
context->pgpmime = PGPMIMEENC;
context->armorlines = 0;
}
context->tail = *head;
*head = mod;
return &context->tail;
}
/*
* Create a generic ASCII armor output filter.
*/
struct PgpPipeline **
pgpArmorWriteCreate (struct PgpPipeline **head, struct PgpEnv const *env,
struct PgpFifoDesc const *fd,
struct PgpRandomContext const *rc, PgpVersion version,
byte armortype)
{
int type = 0;
unsigned long armorlines;
int error;
if (!head)
return NULL;
if (armortype == PGP_ARMOR_NORMAL) {
if (pgpenvGetInt (env, PGPENV_PGPMIME, NULL, &error)) {
type = ATYPE_MIMEENC;
rc = NULL; /* prevents messageid appearing */
} else {
type = ATYPE_NORMAL;
}
} else if (armortype == PGP_ARMOR_SEPSIG) {
type = ATYPE_SEPSIG;
} else if (armortype == PGP_ARMOR_SEPSIGMSG) {
type = ATYPE_SEPSIGMSG;
} else {
return NULL;
}
armorlines = pgpenvGetInt (env, PGPENV_ARMORLINES, NULL, NULL);
return (armorDoCreate (head, env, version, fd, rc, armorlines,
type, NULL, 0));
}
/*
* Create a clearsigned armored output. This takes two tail pointers,
* the text being signed (which will be lightly quoted on output) and
* the signature (which will be ASCII-armored). We build an ASCII armor
* pipeline module for each (with different settings), and join them together.
*/
struct PgpPipeline **
pgpArmorWriteCreateClearsig (struct PgpPipeline **texthead,
struct PgpPipeline **signhead,
struct PgpEnv const *env,
struct PgpFifoDesc const *fd,
PgpVersion version, byte *hashlist,
unsigned hashlen)
{
struct PgpPipeline *txthead = NULL, *sighead = NULL;
struct PgpPipeline **joinhead, **sigtail, **tail;
struct Context *context;
if (!texthead || !signhead)
return NULL;
joinhead = armorDoCreate (&txthead, env, version, fd, NULL, 0,
ATYPE_CLEARSIG, hashlist, hashlen);
if (!joinhead)
return NULL;
tail = pgpJoinCreate (joinhead, fd);
if (!tail) {
txthead->teardown (txthead);
return NULL;
}
sigtail = armorDoCreate (&sighead, env, version, fd, NULL, 0,
ATYPE_SEPSIG, NULL, 0);
if (!sigtail) {
txthead->teardown (txthead);
return NULL;
}
/* Add the charset used when generating the clearsigned message */
context = (struct Context *)sighead->priv;
pgpAssert (context);
context->charset = pgpenvGetString (env, PGPENV_CHARSET, NULL, NULL);
*sigtail = pgpJoinAppend (*joinhead);
if (!*sigtail) {
txthead->teardown (txthead);
sighead->teardown (sighead);
return NULL;
}
pgpJoinBuffer (*sigtail, (byte *)"\n", 1);
*texthead = txthead;
*signhead = sighead;
return tail;
}
/*
* Create a multipart/signed output. This takes two tail pointers,
* the text being signed (which will be lightly quoted on output) and
* the signature (which will be ASCII-armored). We build an ASCII armor
* pipeline module for each (with different settings), and join them together.
*/
struct PgpPipeline **
pgpArmorWriteCreatePgpMimesig (struct PgpPipeline **texttail,
struct PgpPipeline **signtail,
struct PgpEnv const *env,
struct PgpFifoDesc const *fd,
PgpVersion version, byte *hashlist,
unsigned hashlen)
{
struct PgpPipeline *txthead = NULL, *sighead = NULL;
struct PgpPipeline **joinhead, **sigtail, **tail;
struct PgpPipeline **splithead, **splittail;
if (!texttail || !signtail)
return NULL;
splithead = armorDoCreate (&txthead, env, version, fd, NULL, 0,
ATYPE_MIMESIG, hashlist, hashlen);
if (!splithead)
return NULL;
/* Create split to take output from clearmime armor module */
joinhead = pgpSplitCreate(splithead);
/* Set second split output to go to signing pipeline */
splittail = pgpSplitAdd (*splithead);
*splittail = *texttail;
tail = pgpJoinCreate (joinhead, fd);
if (!tail) {
txthead->teardown (txthead);
return NULL;
}
sigtail = armorDoCreate (&sighead, env, version, fd, NULL, 0,
ATYPE_MIMESEPSIG, NULL, 0);
if (!sigtail) {
txthead->teardown (txthead);
return NULL;
}
*sigtail = pgpJoinAppend (*joinhead);
if (!*sigtail) {
txthead->teardown (txthead);
sighead->teardown (sighead);
return NULL;
}
pgpJoinBuffer (*joinhead, (byte *)MIMESIGHDR, strlen(MIMESIGHDR));
if (!hashlen) {
pgpJoinBuffer (*joinhead, (byte *)MIMEMIC, strlen(MIMEMIC));
pgpJoinBuffer (*joinhead, (byte *)MIMEDFLTMIC,
strlen(MIMEDFLTMIC));
} else {
while (hashlen--) {
struct PgpHash const *hash = NULL;
unsigned i, len;
char hashname[30]; /* lower case name */
hash = pgpHashByNumber (*hashlist++);
pgpAssert(hash);
len = strlen(hash->name);
pgpAssert (len < sizeof(hashname));
pgpJoinBuffer (*joinhead, (byte *)MIMEMIC,
strlen(MIMEMIC));
for (i=0; i<len; ++i)
hashname[i] = tolower(hash->name[i]);
pgpJoinBuffer (*joinhead, (byte *)hashname,
len);
pgpJoinBuffer (*joinhead, (byte *)";", 1);
}
}
pgpJoinBuffer (*joinhead, (byte *)MIMETOPBOUND, strlen(MIMETOPBOUND));
pgpJoinBuffer (*sigtail, (byte *)MIMEMIDBOUND, strlen(MIMEMIDBOUND));
*texttail = txthead;
*signtail = sighead;
return tail;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?