⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgparmor.c

📁 vc环境下的pgp源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * pgpArmor.c -- a module to perform Ascii Armor
 *
 * Written by:	Derek Atkins <warlord@MIT.EDU>
 *
 * $Id: pgpArmor.c,v 1.46 1999/03/25 18:22:52 melkins Exp $
 */

#include "pgpConfig.h"

#include <stdio.h>
#include <ctype.h>
#include <string.h>

#include "pgpDebug.h"
#include "pgpArmor.h"
#include "pgpCRC.h"
#include "pgpPktByte.h"
#include "pgpRadix64.h"
#include "pgpAnnotate.h"
#include "pgpFIFO.h"
#include "pgpHashPriv.h"
#include "pgpJoin.h"
#include "pgpEnv.h"
#include "pgpMem.h"
#include "pgpEnv.h"
#include "pgpPipeline.h"
#include "pgpRandomX9_17.h"
#include "pgpSplit.h"
#include "pgpUsuals.h"
#include "pgpFeatures.h"
#include "pgpContext.h"

#define ARMORMAGIC	0xa4904f11
		
/* Max length of a line in MIME content-printable encoding */
#define MIMEMAX 76

/* Number characters in our random MIME separator */
#define NSEPCHARS	48

/*
 * PGP-MIME headers.  We chose "=-" as boundary since it can't occur in
 * a quoted-printable encoding, nor in base64.
 */
#define MIMEENCSEP "=--"
#define MIMESIGHDR1a "Mime-Version: 1.0\n"
#define MIMESIGHDR1b \
	"Content-Type: multipart/signed;\n boundary=\""
#define MIMESIGHDR2 "\";\n" \
	" protocol=\"application/pgp-signature\"; "
#define MIMESIGHDRLINESa 1
#define MIMESIGHDRLINESb 2
#define MIMEENCHDR1a "Mime-Version: 1.0\n"
#define MIMEENCHDR1b \
	"Content-Type: multipart/encrypted; boundary=\"" MIMEENCSEP "\";\n" \
	" protocol=\"application/pgp-encrypted\"\n\n"
#define MIMEENCHDR2 "--" MIMEENCSEP "\n" \
	"Content-Type: application/pgp-encrypted\n\n" \
	"Version: 1\n\n--" MIMEENCSEP "\n" \
	"Content-Type: application/octet-stream\n\n"
#define MIMEENCHDRLINES1a	1
#define MIMEENCHDRLINES1b	3
#define MIMEMIC "micalg=pgp-"
#define MIMEDFLTMIC "pgp-md5"
#define MIMEMIDBOUND "Content-Type: application/pgp-signature\n\n"

typedef struct ArmorContext
{
	/* by placing this here, we can just allocate everything at once */
	PGPPipeline	pipe;
	
	PGPPipeline *tail;
	PGPFifoDesc const *fd;
	PGPFifoContext *fifo;
	PGPFifoContext *header;
	PGPContextRef cdkContext;
	unsigned long	crc;
	unsigned long	armorlines;
	unsigned long	lineno;
	unsigned	thispart;
	unsigned	maxparts;
	int	scope_depth;
	PGPByte	input[48];	/* Maximum 48 bytes */
#if 0
	char	output[65];	/* Maximum 63 buyes + \r and/or \n */
#else
	char	output[MIMEMAX+2]; /* MIME line plus \n plus null */
#endif
	char	mimesigsep[NSEPCHARS+1];
	char *	outptr;
	PGPBoolean needmessageid;
	char *	messageid;
	char const *	blocktype;
	char const *	comment;
	char const *	charset;
	char const *	versionString;
	PGPSize		mimebodyoff;		/* Offset to start of body (1 char/nl) */
	PGPUInt32	mimeheaderlines;	/* # lines in mime header */
	PgpVersion	version;
	PGPByte	inlen;
	PGPByte	outlen;
	PGPByte	clearsign;
	PGPByte	pgpmime;
#define PGPMIMESIG 1
#define PGPMIMEENC 2
	PGPByte pgpmimeversionline;
	PGPByte	didheader;
	PGPByte	didfooter;
	PGPByte	sizevalid;
	PGPByte	state;
	PGPByte	linebuf;
	DEBUG_STRUCT_CONSTRUCTOR( ArmorContext )
} ArmorContext;


/* Forward declarations */
static int
armorLine (PGPByte const *in, unsigned inlen, char *out);



/*
 * Armor 3 raw bytes into 4
 * If armoring n < 3 bytes, make the trailers zero, and
 * then overwrite the trailing 3-n bytes with '='
 */
static void
armorMorsel(PGPByte const raw[3], char armor[4])
{
        armor[0] = armorTable[raw[0] >> 2 & 0x3f];
        armor[1] = armorTable[(raw[0] << 4 & 0x30) + (raw[1] >> 4 & 0x0f)];
        armor[2] = armorTable[(raw[1] << 2 & 0x3c) + (raw[2] >> 6 & 0x03)];
        armor[3] = armorTable[raw[2] & 0x3f];
}

static void
armorWriteClassify (ArmorContext *context, PGPByte const *buf)
{
	if (context->blocktype)
		return;

	if (PKTBYTE_TYPE(*buf) == PKTBYTE_PUBKEY)
		context->blocktype = "PUBLIC KEY BLOCK";
	else if (PKTBYTE_TYPE(*buf) == PKTBYTE_SECKEY)
		context->blocktype = "PRIVATE KEY BLOCK";
	else
		context->blocktype = "MESSAGE";
}

/* Message ID is derived by hashing the beginning of the message data */
static void
armorDeriveMessageID (ArmorContext *context)
{
	PGPHashVTBL const *h;
	PGPHashContext *hc;
    PGPMemoryMgrRef	memoryMgr;
	PGPByte const *p;
	PGPUInt32 len;
	PGPByte hashdata[24];		/* Produces 32 chars of messageid */

	memoryMgr = PGPGetContextMemoryMgr( context->cdkContext );
	pgpAssert (IsntNull (memoryMgr) );
	h = pgpHashByNumber (kPGPHashAlgorithm_SHA);
	if (!h)
		goto error;
	hc = pgpHashCreate (memoryMgr, h);
	if (!hc)
		goto error;
	PGPContinueHash (hc, context->input, context->inlen);
	p = (PGPByte *) pgpHashFinal (hc);
	pgpClearMemory (hashdata, sizeof(hashdata));
	pgpCopyMemory (p, hashdata, pgpMin (h->hashsize, sizeof(hashdata)));
	PGPFreeHashContext (hc);
	context->messageid = (char *)PGPNewData (memoryMgr,
											 sizeof(hashdata)*4/3 + 1, 0);
	if (!context->messageid)
		return;

	len = armorLine (hashdata, sizeof(hashdata), context->messageid);
	context->messageid[len] = '\0';

	return;

error:
	/* Create an empty messageid */
	context->messageid = (char *)PGPNewData ( memoryMgr, 1, 0 );
	context->messageid[0] = '\0';
	return;
}

static PGPError
armorFlushHeader (ArmorContext *context)
{
	PGPByte const *ptr;
	PGPSize len;
	PGPError	error;
	size_t retlen;

	ptr = pgpFifoPeek (context->fd, context->header, &len);
	while (len) {
		retlen = context->tail->write (context->tail, ptr, len,
					       &error);
		pgpFifoSeek (context->fd, context->header, retlen);
		if (error)
			return error;
		
		ptr = pgpFifoPeek (context->fd, context->header, &len);
	}
	return kPGPError_NoErr;
}

static void
armorMakeHeader (ArmorContext *context)
{
	char temp[20];

	if (context->pgpmime == PGPMIMEENC) {
		context->mimebodyoff = 0;
		context->mimeheaderlines = 0;
		if( context->pgpmimeversionline ) {
			pgpFifoWrite (context->fd, context->header,
			      (PGPByte const *)MIMEENCHDR1a, strlen(MIMEENCHDR1a));
			context->mimebodyoff += strlen(MIMEENCHDR1a);
			context->mimeheaderlines += MIMEENCHDRLINES1a;
		}
		pgpFifoWrite (context->fd, context->header,
			      (PGPByte const *)MIMEENCHDR1b, strlen(MIMEENCHDR1b));
		context->mimebodyoff += strlen(MIMEENCHDR1b);
		context->mimeheaderlines += MIMEENCHDRLINES1b;
		pgpFifoWrite (context->fd, context->header,
			      (PGPByte const *)MIMEENCHDR2, strlen(MIMEENCHDR2));
	}
	pgpFifoWrite (context->fd, context->header,
		      (PGPByte const *)"-----BEGIN PGP ", 15);
	pgpFifoWrite (context->fd, context->header, (PGPByte *)context->blocktype,
		      strlen (context->blocktype));

	if (context->maxparts) {
		pgpFifoWrite (context->fd, context->header,
			      (PGPByte const *)", PART ", 7);
		sprintf (temp, "%02u", context->thispart);
		pgpFifoWrite (context->fd, context->header, (PGPByte const *)temp,
			      strlen (temp));
		if (context->version <= PGPVERSION_3 ||
		       context->thispart == context->maxparts) {
			pgpFifoWrite (context->fd, context->header,
				      (PGPByte const *)"/", 1);
			sprintf (temp, "%02u", context->maxparts);
			pgpFifoWrite (context->fd, context->header,
				      (PGPByte const *)temp, strlen (temp));
		}
	}

	pgpFifoWrite (context->fd, context->header,
		      (PGPByte const *)"-----\nVersion: ", 15);
	if( IsntNull( context->versionString ) ) {
		pgpFifoWrite (context->fd, context->header,
		      (PGPByte const *)context->versionString,
		      strlen (context->versionString));
	} else {
		char sVersionString[ 256 ];
		PGPGetSDKString( sVersionString );
		pgpFifoWrite (context->fd, context->header,
		      (PGPByte const *)sVersionString, strlen (sVersionString));
	}

	if (context->needmessageid && context->maxparts) {
		if (!context->messageid) {
			armorDeriveMessageID (context);
		}
		if (context->messageid) {
			pgpFifoWrite (context->fd, context->header,
					  (PGPByte const *)"\nMessageID: ", 12);
			pgpFifoWrite (context->fd, context->header,
					  (PGPByte const *)context->messageid,
					  strlen (context->messageid));
		}
	}

	/* Don't do comment if empty string.  This is more convenient for
	 * callers who want no comment, in some cases. */
	if (context->comment && context->comment[0]) {
		pgpFifoWrite (context->fd, context->header,
			      (PGPByte const *)"\nComment: ", 10);
		pgpFifoWrite (context->fd, context->header,
			      (PGPByte const *)context->comment,
			      strlen (context->comment));
	}

	if (context->charset) {
		pgpFifoWrite (context->fd, context->header,
			      (PGPByte const *)"\nCharset: ", 10);
		pgpFifoWrite (context->fd, context->header,
			      (PGPByte const *)context->charset,
			      strlen (context->charset));
	}

	pgpFifoWrite (context->fd, context->header, (PGPByte *)"\n\n", 2);
	context->didheader = 1;
}

static void
armorMakeFooter (ArmorContext *context)
{
	char temp[20];
	PGPByte crc[3];

	/* Emit CRC, MSB-first */
	crc[0] = (PGPByte)(context->crc >> 16);
	crc[1] = (PGPByte)(context->crc >> 8);
	crc[2] = (PGPByte)context->crc;
	armorMorsel (crc, temp);

	pgpFifoWrite (context->fd, context->header, (PGPByte const *)"=", 1);
	pgpFifoWrite (context->fd, context->header, (PGPByte const *)temp, 4);

	/* Now emit the end */
	pgpFifoWrite (context->fd, context->header,
		      (PGPByte const *)"\n-----END PGP ", 14);
	pgpFifoWrite (context->fd, context->header,
		      (PGPByte const *)context->blocktype,
		      strlen (context->blocktype));

	if (context->maxparts) {
		pgpFifoWrite (context->fd, context->header,
			      (PGPByte const *)", PART ", 7);
		sprintf (temp, "%02u", context->thispart);
		pgpFifoWrite (context->fd, context->header,
			      (PGPByte const *)temp, strlen (temp));
		if (context->version <= PGPVERSION_3 ||
		    context->thispart == context->maxparts) {
			pgpFifoWrite (context->fd, context->header,
				      (PGPByte const *)"/", 1);
			sprintf (temp, "%02u", context->maxparts);
			pgpFifoWrite (context->fd, context->header,
				      (PGPByte const *)temp, strlen (temp));
		}
	}
	pgpFifoWrite (context->fd, context->header,
		      (PGPByte const *)"-----\n", 6);

	if (context->pgpmime) {
		pgpFifoWrite (context->fd, context->header, (PGPByte *)"\n--", 3);
		if (context->pgpmime == PGPMIMEENC) {
			pgpFifoWrite (context->fd, context->header,
						  (PGPByte *)MIMEENCSEP, strlen(MIMEENCSEP));
		} else {
			pgpFifoWrite (context->fd, context->header,
						  (PGPByte *)context->mimesigsep, NSEPCHARS);
		}
		pgpFifoWrite (context->fd, context->header, (PGPByte *)"--\n", 3);
	}

	context->didfooter = 1;
	context->crc = CRC_INIT;
}

static PGPError
armorNewFile (PGPPipeline *myself)
{
	ArmorContext *context = (ArmorContext *)myself->priv;
	PGPError	error;
	PGPSize thispart;

	/*
	 * First, if we're already in a part, then close off the last
	 * one.
	 */
	if (context->thispart) {
		if (!context->didfooter)
			armorMakeFooter (context);

		error = armorFlushHeader (context);
		if (error)
			return error;

		error = context->tail->sizeAdvise (context->tail, 0);
		if (error)
			return error;

		error = context->tail->annotate (context->tail, myself,
						 PGPANN_MULTIARMOR_END, 0, 0);
		if (error)
			return error;
	}

	thispart = context->thispart+1;
	error = context->tail->annotate (context->tail, myself,
					 PGPANN_MULTIARMOR_BEGIN,
					 (PGPByte const *)&thispart,
					 sizeof (thispart));
	if (error)
		return error;

	context->thispart++;
	context->didheader = 0;
	context->didfooter = 0;
	context->lineno = 0;

	/* And give it an appropriate header */
	armorMakeHeader (context);

	return kPGPError_NoErr;
}

/*
 * The method here to do the armoring is somewhat tricky.
 * Most lines just have inlen = 48 which maps to 48*4/3 = 64
 * output characters.  But the last line has a short inlen.
 * This leads to a truncated last group, which looks like one of:
 * xx== (if the last group contains 1 byte - 4 bits of padding are zero)
 * xxx= (if the last group contains 2 bytes - 2 bits of padding are zero)
 * xxxx (if the last group contains 3 bytes)
 * To do this, we make sure that we've added an extra 0 byte to the
 * end of the input, then encode it in blocks of 3 bytes, then note by
 * how much the encoding overshot the input length, len - inlen.
 * This is 2, 1, or 0.  Overwrite that many trailing characters with '='.
 * Then a newline can be appended for output.
 */
static int
armorLine (PGPByte const *in, unsigned inlen, char *out)
{
	unsigned len;
	int t;
	char const *out0 = out;

	/* Fill the output buffer from the input buffer */
	for (len = 0; len < inlen; len += 3) {
		armorMorsel (in, out);
		in += 3;
		out += 4;
	}

	/* Now back up and erase any overrun */
	t = (int)(inlen - len);		/* Zero or negative */
	while (t)
		out[t++] = '=';
	      
	return (out - out0);
}

static void
armorProcessLine (ArmorContext *context)
{
	/* Update CRC */
	context->crc = crcUpdate (context->crc, context->input,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -