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

📄 pgpprsasc.c

📁 vc环境下的pgp源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	size -= retlen;
	ctx->armorlen += retlen;

	/* Set EOB if we hit the end of the armorline buffer */
	if (ctx->armorlen >= LINE_LEN-1)
		ctx->eob = 1;

	/*
	 * At this point we are either at EOL or not.  If not, then we
	 * either ran out of input data or ran out of buffer space.  If
	 * we are at EOL and eol==2 and we have more data, check if its a
	 * \n or something else.  If so, copy that in and set eol=1.
	 */
	if (eol) {
		ctx->crlf = (eol == 2 ? kPGPLineEnd_CR : kPGPLineEnd_LF);

		if (eol == 2 && size) {
			if (*buf == '\n') {
				*ptr = *buf;
				ctx->armorlen++;
				ctx->crlf = kPGPLineEnd_CRLF;
				size--;
			}
			eol = 1;
		}
	}

	/* Save off the EOL and return the number of bytes used */
	ctx->eol = eol;
	ctx->bytesread += size0-size;
	return size0-size;
}


/* memCmpPrefix works like memcmp except it allows certain material to
 * prefix the 1st arg.  The intention is to generalize the search for
 * "-----BEGIN PGP MESSAGE-----" so that quoted versions can be matched.
 * The rule presently is that material in angle brackets is ignored, like
 * "<bigger>", because Eudora in richtext mode sometimes puts those in.
 * Likewise non-alphabetic characters will be allowed, because people may
 * be quoting a PGP message or key with "> " and similar conventions.
 * Only the number of chars specified in testlen must match.
 * In addition to returning the error code, this function returns the
 * number of skipped chars in *skiplen.
 */
static int
memCmpPrefix(const char *orig, size_t origlen, const char *test,
			 size_t testlen, size_t *skiplen)
{
	char ctest, corig;
	size_t len = 0;
	PGPBoolean inbracket = FALSE;

	pgpAssert (IsntNull(skiplen));
	pgpAssert (testlen > 0);
	
	*skiplen = 0;
	if (origlen == 0)
		return 0;

	ctest = test[0];
	for ( ; ; ) {
		if (origlen-len < testlen)
			return 1;			/* Failure, no match */
		corig = orig[len];
		if (!inbracket) {
			if (corig == ctest && memcmp (orig+len, test, testlen) == 0) {
				*skiplen = len;
				return 0;			/* Success */
			}
			if (isalnum((int) corig))
				return 1;		/* Failure, not a legal prefix */
			if (corig == '<')
				inbracket = TRUE;
		} else {
			if (corig == '>')
				inbracket = FALSE;
		}
		++len;
	}
}


/*
 * Contained in buf (of length size) should be a Header-line.  Parse
 * it appropriately, and store it as necessary.
 *
 * A headerline must fit in the armorline buffer (I.e., it must be
 * less that LINE_LEN-1 bytes long), it must start with an Alpha
 * character and then have up to 64 AlphaNumeric characters or dashes,
 * followed by a colon and then a space.  A header that does not
 * conform to this is an error.
 * 
 * Returns 0 on success, or a HEADER_ error code.
 */
#define HEADER_TOOLONG	-1
#define HEADER_INVALID	-2
static int
parseHeader (PrsAscContext *ctx, PGPByte const *buf, size_t size)
{
	int i;
	char const *ptr = (char const *)buf;
	static char const messageid[] = "MessageID:";
	char c;

	(void)size;		/* So, why do I have this arg? */

	/* Make sure this is the WHOLE line -- if not, it is an error */
	if (!ctx->eol)
		return HEADER_TOOLONG;

	/* The first character must be an Alpha character */
	if (!isalpha ((int) (*ptr++)))
		return HEADER_INVALID;

	i = 1;
	for (;;) {
		c = *ptr++;
		/* header ends in a colon */
		if (c == ':')
			break;
		/* Arbitrary label length restriction */
		if (++i > 64)
			return HEADER_TOOLONG;	/* Error */
		/* Following chars much be alphanumeric or '-' */
		if (!isalnum((int) c) && c != '-')
			return HEADER_INVALID;	/* Error */
	}

	/* Must be a space after the ':' */
	if (*ptr++ != ' ')
		return HEADER_INVALID;

	/*
	 * Now process the header
	 *
	 * ptr points to the value; buf points to the key (of length
	 * (ptr - buf - 2), plus a colon)
	 */
	i = ptr - (char const *)buf - 1;

	/* Process message ID header */
	if (i == sizeof (messageid) - 1 && !memcmp (buf, messageid, i))
		memcpy (ctx->messageid, ptr,
			pgpMin ((strlen (ptr) + 1), sizeof (ctx->messageid)));

	/* XXX: signal an unknown header? */

	return 0;
}

/* Write data to be dearmored.
 *
 * The main FSM to control dearmoring.  The actual FSM is kind of
 * complicated so I'll try to explain it by comments in the code.
 * Suffice it to say that there are two main parts of the machine.
 * The first part deals with armor'ed data, and the second part deals
 * with out-of-armored text.  There is a little glue between them, and
 * there you have it...
 *
 * Here are the states, categorized into general phases of activity:
 *
 *	 0			Start state, outside PGP data
 *
 *	 10 -  50		Waiting for start of PGP data
 *
 *	 90 - 100		Process -----BEGIN PGP line
 *
 *	110 - 130		Process headers after -----BEGIN PGP
 *
 *	140 - 160		Setup to begin processing armored data
 *
 *	170 - 200		Process PGP armored data
 *
 *	210 - 230		Process CRC at end of armored data
 *
 *	240 - 270		Process -----END PGP line, finish up, back to 0
 *
 *	300 - 330		Clearsigned message, process Hash: lines if any
 *
 *	340 - 360		Setup to begin processing clearsigned message
 *
 *	390 - 430		Process clearsigned message body, then to 90 for sig
 *
 *	500 - 530		Process binary message, to 260 to finish up when done
 *
 *	600 - 630		Scan MIME headers, get boundary string
 *
 *	650 - 680		Look for initial MIME boundary string, to 340 when found
 *
 *	700 - 720		Check apparent initial MIME separator, to 340 if looks OK
 *
 *	750 - 770		Look for start of PGP sig in MIME clearsig sig part, to 90
 *
 *	800 - 830		Look for final MIME clearsign boundary after PGP sig
 *
 */
static size_t
Write (PGPPipeline *myself, PGPByte const *buf, size_t size, PGPError *error)
{
	PrsAscContext *ctx;
	Message *msg;
	MsgPart *part;
	PGPByte *ptr, *num;
	static char const prefix1[] = "-----BEGIN PGP ";
	static char const prefix2[] = ", PART ";
	static char const prefix3[] = "-----END PGP ";
	static char const suffix[] = "-----";	/* With trailing nul */
	static char const signedmsg[] = "SIGNED MESSAGE";
	static char const pubkey[] = "PUBLIC KEY";
	static char const privkey[] = "PRIVATE KEY";
	static char const sigprefix[] = "-----BEGIN PGP SIGNATURE-----";
	static char const signedprefix[] = "-----BEGIN PGP SIGNED MESSAGE-----";
#if MIMEPARSE
	PGPByte *ptr2;
	static char prefix_mimesig2[] = "-----BEGIN PGP MESSAGE-----";
	static char prefix_mime1[] = "content-type: multipart/signed;";
	static char prefix_mime2[] = "protocol=\"application/pgp-signature\"";
	static char prefix_mime3[] = "boundary=";
#if 0
	static char prefix_mime4[] = "micalg=";
	static char prefix_mime5[] = "pgp-";
#endif /* 0 */
#endif /* MIMEPARSE */
	int i, thispart, maxparts, lineused;
	size_t retval, written = 0;
	unsigned inlen;
	long crc;
	char temp_c;
	PGPContextRef	cdkContext;
	
	pgpAssertAddrValid( myself, PGPPipeline );
	cdkContext	= myself->cdkContext;

	pgpAssert (myself);
	pgpAssert (myself->magic == DEARMORMAGIC);
	pgpAssert (error);

	ctx = (PrsAscContext *)myself->priv;
	pgpAssert (ctx);
	pgpAssert (ctx->tail);

	switch (ctx->state) {
	case 0:
state_start:
		ctx->state = 0;
		/*
		 * This is the "start" position.  Check if we are
		 * buffering and flush buffers if we are not.  Then go
		 * to the next state.
		 */

		if (!ctx->buffering) {
			*error = flushBuffers (ctx);
			if (*error)
				break;
		}

		/* FALLTHROUGH */
	case 10:
state_wait_for_pgp:
		ctx->state = 10;
		/* call readline until we have EOB or EOL */

		retval = readLine (ctx, buf, size);
		size -= retval;
		buf += retval;
		written += retval;

		if (ctx->eol || ctx->eob)
			;
		else
			break;

		/* FALLTHROUGH */
	case 20:
		ctx->state = 20;
		/*
		 * check the line for BEGIN.  If it is not a begin
		 * then we should output this line.  If it is a begin,
		 * then we need to parse it as an armor beginning.
		 * Use special compare routine which skips some prefixes of the
		 * test line so we can recognize "- -----BEGIN PGP" and such.
		 */

		if (ctx->armorlen > sizeof (prefix1) - 1 &&
		    !memCmpPrefix ((char *)ctx->armorline, ctx->armorlen,
						   prefix1, sizeof (prefix1) - 1,
						   &ctx->skipPrefixLength)) {
			/*
			 * Don't allow a prefix on BEGIN PGP SIGNATURE or BEGIN PGP
			 * SIGNED MESSAGE.  People often quote signed messages in replies
			 * and we don't want to trigger on those.  And the SIGNATURE
			 * is the last part of the signed message.
			 */
			if (ctx->skipPrefixLength == 0 ||
				(memcmp(ctx->armorline+ctx->skipPrefixLength, sigprefix,
										sizeof(sigprefix)-1)!=0 &&
				 memcmp(ctx->armorline+ctx->skipPrefixLength, signedprefix,
						  				sizeof(signedprefix)-1)!=0 )) {
				if (ctx->skipPrefixLength > 0) {
					pgpAssert (ctx->skipPrefixLength <
							   				sizeof(ctx->skipPrefix));
					pgpCopyMemory (ctx->armorline, ctx->skipPrefix,
								   ctx->skipPrefixLength);
					ctx->skipPrefix[ctx->skipPrefixLength] = '\0';
				}
				goto state_pgp_begin;
			}
		}
		/*
		 * check the line to see if it is the beginning of a
		 * PGP binary message.  This check is only done the
		 * first time through this loop, using ctx->annotation
		 * as the loop detector.  If this is a PGP message,
		 * then treat it as such and buffer the data for
		 * processing through a parser.
		 */
		 
		if (! ctx->annotation) {
			if (pgpFileTypePGP (ctx->armorline, ctx->armorlen))
			{
				/*
				 * ooh, a binary PGP message fed into the
				 * ascii armor parser!
				 */
				goto state_pgp_binary;
			}
		}

#if MIMEPARSE
		/*
		 * Look for either the MIME content-type message, or what looks
		 * like a MIME message boundary (in case we don't have headers).
		 */
		if (ctx->armorlen > sizeof (prefix_mime1) - 1 &&
			!strncmp_ignorecase ((char *)ctx->armorline, prefix_mime1,
						  sizeof (prefix_mime1) - 1)) {
			/* MIME header */
			goto state_pgpmime;
		}

		/*
		 * If no_mime_headers, we have only a body, so assume that a line
		 * starting with -- is a pgp/mime signed part.  This is not a very
		 * good assumption in general, so we will assume that we had some
		 * reason to think so.
		 */
		if (ctx->no_mime_headers && ctx->eol &&
			ctx->armorlen > 2 && !memcmp (ctx->armorline, "--", 2) &&
			ctx->eol) {
			/* Potential MIME initial body indicator */
			goto state_pgpmime_body_noheaders;
		}
#endif

		/* FALLTHROUGH */
	case 30:
state_nonpgp:
		ctx->state = 30;
		/* send annotation if we need to */
		/* Get here with armorlen==0 only on flush call, don't annotate then */
		ctx->sectoff = ctx->prevlineoff;
 		if (!ctx->annotation && ctx->armorlen!=0) {
 			*error = sendAnnotate (ctx, myself, PGPANN_NONPGP_BEGIN,
								(PGPByte *)&ctx->sectoff, sizeof(ctx->sectoff));
 			if (*error)
 				break;
 			ctx->annotation = PGPANN_NONPGP_END;
			ctx->depth_at_ann = ctx->scope_depth;
 		}
		/* FALLTHROUGH */
	case 40:
state_nonpgp_output:
		ctx->state = 40;
		/* output armorline buffer */
		while (ctx->armorlen) {
			retval = writeExtraData (ctx, ctx->armorptr,
						 ctx->armorlen, error);
			ctx->armorptr += retval;
			ctx->armorlen -= retval;
			if (*error)
				return written;
		}
		ctx->armorptr = ctx->armorline;
		/* FALLTHROUGH */
	case 50:
		ctx->state = 50;
		/*
		 * if EOL == 1, clear state and goto state wait_for_pgp, otherwise
		 * read data and return to state nonpgp_output to output the line.
		 */
		if (ctx->eol == 1) {
			ctx->eol = 0;
			ctx->eob = 0;
			goto state_wait_for_pgp;
		}

		if (!size)
			break;

		retval = readLine (ctx, buf, size);
		size -= retval;
		buf += retval;
		written += retval;

		goto state_nonpgp_output;

	case 90:
state_pgp_begin:
		ctx->state = 90;
		/* 
		 * parse begin line.  If this is not a valid begin
		 * line, assume that it is not and output it as
		 * non-PGP text (in state nonpgp).
		 * skipPrefixLength holds extra chars to skip at beginning
		 */
		ctx->sectoff = ctx->prevlineoff;
		ptr = ctx->armorline + sizeof (prefix1) - 1 + ctx->skipPrefixLength;
		lineused = ctx->armorlen - (sizeof (prefix1) - 1)
									- ctx->skipPrefixLength;
		thispart = maxparts = 0;

		do {
			if (lineused == 0) {
				/* not a valid BEGIN line */
				goto state_nonpgp;
			}

		} while (isspace (ptr[--lineused]));

		/* temporarily null-terminate this string */
		temp_c = ptr[++lineused];
		ptr[lineused] = '\0';

		if (!memcmp (ptr, signedmsg, sizeof (signedmsg)-1)) {
			/* This is a clearsigned message */

			if (ctx->eol) {
				/*
				 * This looks like a clearsigned
				 * message.  jump into the clearsigned
				 * parser and parse it.
				 */
				ptr[lineused] = temp_c;		/* restore terminator */
				goto state_cleartext;
			}
			/*
			 * Someone is playing with us.. This is an
			 * error.  
			 */
			goto err_state_pgp_begin;
		}

		if (ctx->passthroughkey &&
			(memcmp (ptr, pubkey, sizeof(pubkey)-1) == 0 ||
			 memcmp (ptr, privkey, sizeof(privkey)-1) == 0)) {
			/* Go into passthrough mode on key block */
			ctx->passthrough = TRUE;

⌨️ 快捷键说明

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