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

📄 pgpprsbin.c

📁 著名的加密软件的应用于电子邮件中
💻 C
📖 第 1 页 / 共 5 页
字号:
	ctx = (struct Context *)myself->priv;
	pgpAssert (ctx);
	pgpAssert (ctx->tail);
	pgpAssert (error);
	pgpAssert (!size || !ctx->eof);

	/* Make sure nothing confusing can happen here! */
	pgpAssert(!ctx->needcallback);

	/* Do NOT complain on truncation. */
	ctx->input.silent_trunc = 1;
	/* Reset state for parseSignedLiteralMagic */
	ctx->state = 0;
	myself->write = parseSignedLiteralMagic;
	return parseSignedLiteralMagic(myself, buf, size, error);
}

/*
* Pass through the full ciphertext of the current packet, headers and
* all, to the tail module
*/
static size_t
DoPassthrough (struct PgpPipeline *myself, byte const *buf, size_t size,
	int *error)
{
	struct Context *ctx;
	size_t size0 = size;
	byte const *p;
	size_t len;
	struct PgpPipeline *tail;

	pgpAssert (myself);
	pgpAssert (myself->magic == PARSERMAGIC);

	ctx = (struct Context *)myself->priv;
	pgpAssert (ctx);
	tail = ctx->tail;
	pgpAssert (tail);
	pgpAssert (error);
	pgpAssert (!size || !ctx->eof);

	*error = 0;
	/* empty out the buffered data and then the packet */
	for (;;) {
		p = inputRawPeek(&ctx->input, buf, size, &len);
		if (!len)
			break;
		len = tail->write (tail, p, len, error);
		len = inputRawSeek (&ctx->input, buf, size, len);
		buf += len;
		size -= len;
		if (*error)
			return size0-size;
	}

	/* If that's the end of this packet, continue with the next. */
	if (inputFinished (&ctx->input.head)) {
		/* End of input */
		myself->write = nextScope;
		size -= nextScope (myself, buf, size, error);
	}

	return size0-size;
}

/*
* Tear down the pipeline connected to our tail for the processing of the
* current packet. This is the pipeline starting with ctx->tail and
* ending at *ctx->end. Note that myself may be zero length, i.e.
* ctx->end == &ctx->tail!
*/
static void
parsePipelineTeardown (struct Context *ctx)
{
	struct PgpPipeline *temp;

	pgpAssert (ctx->end);

	/*
	* End the pipeline I created, tear it down, and re-attach the
	* original pipeline
	*/
	temp = *(ctx->end);
	*(ctx->end) = NULL;

	/*
	* Make sure this isn't a zero-length pipeline, since ctx->end
	* can point to the address of ctx->tail!
	*/	
	if (ctx->tail)
		ctx->tail->teardown (ctx->tail);
	ctx->tail = temp;
	ctx->end = NULL;
}

/*
* Given a candidate encryption key, verify it against the IV that we have
* stored in the buffer. If it checks, return the PgpCfbContext set up
* to decrypt the rest of the packet. Otherwise, return NULL.
*/
static struct PgpCfbContext *
CheckKey (struct Context *ctx, byte const *string, size_t size, int *error)
{
	byte buf[IVLEN];
	struct PgpCfbContext *cfb;
	struct PgpCipher const *cipher;
	unsigned char const *p;
	size_t len;

	if (!size) {
		*error = PGPERR_BAD_KEYLEN;	/* Um, I guess? */
		return (struct PgpCfbContext *)0;
	}
	cipher = pgpCipherByNumber (string[0]);
	if (!cipher) {
		*error = PGPERR_BAD_CIPHERNUM;
		return (struct PgpCfbContext *)0;
	}
	if (size != cipher->keysize+1) {
		*error = PGPERR_BAD_KEYLEN;
		return (struct PgpCfbContext *)0;
	}

	cfb = pgpCfbCreate (cipher);
	if (!cfb) {
		*error = PGPERR_NOMEM;
		return (struct PgpCfbContext *)0;
	}

	p = inputPeek(&ctx->input, NULL, 0, &len);
	pgpAssert(len >= IVLEN);
	pgpCfbInit (cfb, string+1, NULL);
	pgpCfbDecrypt (cfb, p, buf, IVLEN);

	if (buf[IVLEN-2] != buf[IVLEN-4] || buf[IVLEN-1] != buf[IVLEN-3]) {
		pgpCfbDestroy (cfb);
		*error = PGPERR_CANNOT_DECRYPT;
		return (struct PgpCfbContext *)0;
	}

	pgpCfbSync (cfb);
	*error = 0;
	return cfb;
}

/*
 * Process one of the incoming annotations that's expected in response to
 * one of our own annotations. These can happen either during the
 * ctx->tail->annotate() call, or after that call has returned an error
 * to the top level, which makes the call in turn. Either way, we have
 * to change state appropraitely.
 *
 * Currently, there are 4 things that can be done with any given packet:
 * - Eat it silently. No data will be emitted before the end scope
 *   annotation.
 * - Pass it through as ciphertext.
 * - Decode it, and pass the body through as plaintext. The body is *not*
 *   parsed further.
 * - Decode it and parse it recursively.
 *
 * The latter two options depend on the type of packet we're inside, as
 * recorded in the ctx->end_scope variable. They do some special
 * processing setting up a pipeline to do the decoding, then everyone
 * appends another parser to the chain and sets things up to write the
 * packet body to the decoding pipe.
 */
static int
ProcessCallback (struct PgpPipeline *myself, int type,
byte const *string, size_t size)
{
	struct Context *ctx = (struct Context *)myself->priv;
	struct PgpPipeline *oldhead;
	struct PgpCfbContext *cfb;
	int error = 0;

	pgpAssert(ctx->needcallback);	 /* Maybe a less nasty failure? */

	pgpAssert(!ctx->end);	 /* This will change in future, but for now */

	if (!ctx->end)
		ctx->end = &ctx->tail;
	oldhead = *ctx->end;
	*ctx->end = NULL;

	/* The other option is to make this illegal... */
	if (ctx->end_scope == PGPANN_NONPACKET_END &&
(type == PGPANN_PARSER_PROCESS || type == PGPANN_PARSER_RECURSE))
		type = PGPANN_PARSER_PASSTHROUGH;

	/* Type will ONLY be one of these! */
	switch (type) {
	case PGPANN_PARSER_EATIT:
		myself->write = DoSkip;
		break;
	case PGPANN_PARSER_PASSTHROUGH:
		if (ctx->end_scope == PGPANN_PGPKEY_END) {
			/* Passthrough is unreasonable on keys */
			type = PGPANN_PARSER_PROCESS;
			break;
		}
		ctx->end = pgpHeaderCreate (ctx->end);
		if (!ctx->end) {
			error = PGPERR_NOMEM;
			break;
		}
		myself->write = DoPassthrough;
		break;
	case PGPANN_PARSER_PROCESS:
	case PGPANN_PARSER_RECURSE:
		switch (ctx->end_scope) {
		case PGPANN_LITERAL_END:
			if (type == PGPANN_PARSER_RECURSE &&
			ctx->subtype == 't') {
				byte const *charmap;
				charmap = (byte const *)
					pgpenvGetPointer
					(ctx->env, PGPENV_CHARMAPTOLOCAL,
					NULL, NULL);
				/* Recurse means filter the text */
				ctx->end = pgpTextFiltCreate (ctx->end,
							charmap,
							0,
#if defined(MSDOS)
							PGP_TEXTFILT_CRLF
#elif defined(MACINTOSH)
							PGP_TEXTFILT_CR
#else /* UNIX */
							PGP_TEXTFILT_LF
#endif
							);
				if (!ctx->end) {
					error = PGPERR_NOMEM;
					break;
				}
			}
			type = PGPANN_PARSER_PROCESS;
			break;
		case PGPANN_CIPHER_END:
			cfb = CheckKey (ctx, string, size, &error);
			if (!cfb)
				break;
			ctx->end = pgpCipherModDecryptCreate (ctx->end, cfb, ctx->env);
			if (!ctx->end)
				error = PGPERR_NOMEM;
			break;
		case PGPANN_COMPRESSED_END:
			ctx->end = pgpDecompressModCreate (ctx->end,
					*inputMergedPtr(&ctx->input));
			if (!ctx->end)
				error = PGPERR_NOMEM;
			break;
		case PGPANN_COMMENT_END:
		case PGPANN_UNKNOWN_END:
			type = PGPANN_PARSER_PROCESS;
			break;
		case PGPANN_SIGNED_END:
			if (ctx->nextparser)
				type = PGPANN_PARSER_PROCESS;
			/* Set up all requested hashes */
			pgpAssert(!ctx->hashes);
			if (!size)
				return 0;
			/* Get all the PgpHashContexts */
			error = pgpHashListCreate (string, &ctx->hashes, size);
			if (error < 0)
				break;
			ctx->numhashes = error;
			/* Make a pipeline out of them */
			ctx->end = pgpHashModListCreate (ctx->end,
				ctx->hashes, error);
			if (!ctx->end) {
				pgpHashListDestroy (ctx->hashes, error);
				ctx->hashes = 0;
				error = PGPERR_NOMEM;
				break;
			}
			pgpAssert(inputFinished(&ctx->input.head));
			ctx->input.head.pktlen = -1ul; /* Write through rest */
			ctx->input.silent_trunc = 1;
			error = 0;
			break;

		case PGPANN_PGPKEY_END:
			type = PGPANN_PARSER_PROCESS;
			break;
		default:
			error = PGPERR_CB_INVALID;
		}

		/*
		* Processing for all packet types... set up parser if
		* desired, then skip any header prifix in the buffer,
		* then arrange to write out what we have.
		*/
		/* If we want to create a parser, do that */
		if (!error && type == PGPANN_PARSER_RECURSE) {
			struct PgpPipeline **temp = ctx->end;
			byte const *charmap;

			charmap = (byte const *)
				pgpenvGetPointer (ctx->env,
						PGPENV_CHARMAPTOLOCAL,
						NULL, NULL);

			ctx->end = pgpParseBinCreate (ctx->end, ctx->env);
			if (!ctx->end)
				error = PGPERR_NOMEM;
			ctx->nextparser = *temp;
		}
		if (!error && type == PGPANN_PARSER_PROCESS) {
			/* Add a header if appropriate */
			switch (ctx->end_scope) {
			case PGPANN_CIPHER_END:
			case PGPANN_COMPRESSED_END:
			case PGPANN_SIGNED_END:
				ctx->end = pgpHeaderCreate (ctx->end);
				if (!ctx->end)
					error = PGPERR_NOMEM;
			}
		}
		/* Success! Flush data and write through the rest */
		if (!error) {
			if (ctx->end_scope == PGPANN_SIGNED_END) {
				if (ctx->state >= 10)
					myself->write = DoSignedLiteralMagic;
				else if (ctx->sig1pass)
					myself->write = DoWriteSignedPackets;
				else {
					inputPurge(&ctx->input);
					myself->write = DoWrite;
				}
			} else {
				if (ctx->end_scope == PGPANN_PGPKEY_END)
					myself->write = parseKey;
				else {
					inputPurge(&ctx->input);
					myself->write = DoWrite;
				}
			}
			break;
		}
		break;
	default:
		error = PGPERR_CB_INVALID;
	}

	if (error) {
		/* Get rid of partial pipelines (if any) */
		if (! *(ctx->end))
			ctx->end = &oldhead;
		parsePipelineTeardown (ctx);
	} else {
		/* Splice the new into the old */
		*(ctx->end) = oldhead;
		ctx->needcallback--;
	}

	return error;
}

static size_t
parseLiteral (struct PgpPipeline *myself, byte const *buf, size_t size,
		int *error)
{
	struct Context *ctx;
	size_t len;
	size_t size0 = size;
	byte const *p;

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

	ctx = (struct Context *)myself->priv;
	pgpAssert (ctx);
	pgpAssert (ctx->tail);
	pgpAssert (!size || !ctx->eof);

	*error = 0;

	switch (ctx->state) {
	case 0:
	case 10:	/* flags oldliteral, where length doesn't include prefix */
				/* may also be pgpHeader.c packet, type 'P' */
		/* Parse header; needed before callbacks are allowed */
		len = inputMerge(&ctx->input, buf, size, 2, error);
		buf += len;
		size -= len;
		if (*error || !size)
			break;
		/* Size is non-zero but we haven't got desired? EOP */
		if (inputMerged(&ctx->input) < 2) {
			pgpAssert(inputFinished(&ctx->input.head));
			*error = ctx->tail->annotate(ctx->tail, myself,
			PGPANN_PACKET_SHORT,
						0, 0);
			if (*error)
				break;
			myself->write = nextScope;
			size -= nextScope (myself, buf, size, error);
			break;
		}
		p = inputMergedPtr(&ctx->input);
		/* Deal with "oldliteral" packets specially */
		if (ctx->state == 10) {
			if (p[0] == 'P') {
				/* Special PGP 3 header */
				myself->write = DoSkip;
				size -= DoSkip (myself, buf, size, error);
				break;
			}
			/* Else old-style packets; some PGPcompatible program does these */
			/*
			* That program uses "literal" length conventions, not
			* "oldliteral", so don't do this:
			*
			* if (ctx->input.head.pktlen != ~0UL) {
			*   ctx->input.head.pktlen += 6 + p[1];
			* }
			*/
			ctx->state = 0;
		}
		/* Get the name and timestamp fields */
		len = inputMerge(&ctx->input, buf, size, 6+p[1], error);
		buf += len;
		size -= len;
		if (*error || !size)
			break;
		/* Size is non-zero but we haven't got desired? EOP */
		if (inputMerged(&ctx->input) < (unsigned)6+p[1]) {
			pgpAssert(inputFinished(&ctx->input.head));
			*error = ctx->tail->annotate(ctx->tail, myself,
			PGPANN_PACKET_SHORT,
						0, 0);
			if (*error)
				break;
			myself->write = nextScope;
			size -= nextScope (myself, buf, size, error);
			break;
		}

ctx->subtype = p[0];
		ctx->needcallback = 1;
		ctx->end_scope = PGPANN_LITERAL_END;
		*error = ctx->tail->annotate (ctx->tail, myself,
		PGPANN_LITERAL_BEGIN, 0, 0);
		if (*error)
			break;

		ctx->state++;
		/* FALLTHROUGH */
	case 1:
		p = inputMergedPtr(&ctx->input);
		*error = ctx->tail->annotate (ctx->tail, myself,
		PGPANN_LITERAL_TYPE, p, 1);
		if (*error)
			break;
		
		ctx->state++;
		/* FALLTHROUGH */
	case 2:
		p = inputMergedPtr(&ctx->input);
		*error = ctx->tail->annotate (ctx->tail, myself,
		PGPANN_LITERAL_NAME,
		p+2, (size_t)p[1]);
		if (*error)
			break;

		ctx->state++;
		/* FALLTHROUGH */
	case 3:
		/* Parse 4-byte timestamp */
		p = inputMergedPtr(&ctx->input);
		*error = ctx->tail->annotate (ctx->tail, myself,
		PGPANN_LITERAL_TIMESTAMP,
		p+2+p[1], 4);
		if (*error)
			break;

		ctx->state++;
		/* FALLTHROUGH */
	case 4:
		if (ctx->needcallback) {
			*error = ctx->tail->annotate (ctx->tail, myself,
			PGPANN_COMMIT, 0, 0);
			if (*error)
				break;
		}
		ctx->state++;
		/* FALLTHROUGH */
	case 5:
		if (ctx->needcallback) {
			*error = ProcessCallback (myself,
						PGPANN_PARSER_PROCESS,
						0, 0);
			if (*error)
				break;
		}
		ctx->state++;
		size -= myself->write(myself, buf, size, error);
		break;
	default:
		pgpAssert (0);	/* I should never get here */
	}

⌨️ 快捷键说明

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