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

📄 pgpprsbin.c

📁 PGP—Pretty Good Privacy
💻 C
📖 第 1 页 / 共 5 页
字号:
	PrsBinContext *ctx;
	size_t len;
	PGPByte const *p;
	size_t size0 = size;

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

	ctx = (PrsBinContext *)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;

	/* No error until told otherwise */
	*error = kPGPError_NoErr;

	switch (ctx->state) {
	  case 0:	/* Get packet header byte */
		if (!size)
			return 0;

		/* We know it's a literal packet, so no worries. */
		(void)inputStart(&ctx->input, *buf);
		buf++;
		size--;
		ctx->state++;
		/* FALLTHROUGH */
	  case 1:	/* Get internal header */
		len = inputMerge(&ctx->input, buf, size, 2, error);
		buf += len;
		size -= len;
		if (*error)
			break;
		p = inputPeek(&ctx->input, NULL, 0, &len);
		if (len < 2) {
			if (!inputFinished(&ctx->input.head))
				break;
		} else {
			len = inputMerge(&ctx->input, buf, size, 6+p[1],
					error);
			buf += len;
			size -= len;
			if (*error)
				break;
			if (inputMerged(&ctx->input) < (size_t)6+p[1]) {
				if (!inputFinished(&ctx->input.head))
					break;
			}
		}
		/* We've got as much as we need */
		ctx->state++;
		myself->write = DoWriteNext;
		size -= DoWriteNext (myself, buf, size, error);
		break;
	  default:
		pgpAssert(0);
	}
	return size0-size;
}

/*
 * This function just does a little bit of trivial initialization,
 * including setting the state to 0, and then falls through to
 * parseSignedLiteralMagic.  The Do functions can be called from a
 * variety of states, due to the way they are set up from callbacks
 * that may be called from a variety of states, so they can't depend on
 * the ctx->state.  Thus, the need for this little wrapper function.
 */
static size_t
DoSignedLiteralMagic (PGPPipeline *myself, PGPByte const *buf, size_t size,
		      PGPError *error)
{
	PrsBinContext *ctx;

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

	ctx = (PrsBinContext *)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 (PGPPipeline *myself, PGPByte const *buf, size_t size,
	       PGPError *error)
{
	PrsBinContext *ctx;
	size_t size0 = size;
	PGPByte const *p;
	size_t len;
	PGPPipeline *tail;

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

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

	*error = kPGPError_NoErr;
	/* 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 (PrsBinContext *ctx)
{
	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 PGPCFBContext *
CheckKey (
	PGPContextRef	cdkContext,
	PrsBinContext	*ctx,
	PGPByte const	*string,
	size_t			size,
	PGPError		*error
	)
{
	PGPByte buf[MAXIVLEN+2];
	PGPCFBContext *cfb;
	PGPCipherVTBL const *cipher;
	PGPSize ivlen;
	unsigned char const *p;
	size_t len;

	if (!size) {
		*error = kPGPError_BadKeyLength;	/* Um, I guess? */
		return (PGPCFBContext *)0;
	}
	cipher = pgpCipherGetVTBL ( (PGPCipherAlgorithm)string[0]);
	if (!cipher) {
		*error = kPGPError_BadCipherNumber;
		return (PGPCFBContext *)0;
	}
	if (size != cipher->keysize+1) {
		*error = kPGPError_BadKeyLength;
		return (PGPCFBContext *)0;
	}

	cfb = pgpCFBCreate ( PGPGetContextMemoryMgr( cdkContext ), cipher);
	if (!cfb) {
		*error = kPGPError_OutOfMemory;
		return (PGPCFBContext *)0;
	}

	ivlen = pgpCFBGetBlockSize( cfb );
	p = inputPeek(&ctx->input, NULL, 0, &len);
	if (len < ivlen+2) {
		PGPFreeCFBContext (cfb);
		*error = kPGPError_CantDecrypt;
		return (PGPCFBContext *)0;
	}

	/* Set up with zero IV, decrypt first ivlen+2 bytes */
	PGPInitCFB (cfb, string+1, NULL);
	pgpCFBDecryptInternal (cfb, p, ivlen+2, buf);

	if (buf[ivlen] != buf[ivlen-2] || buf[ivlen+1] != buf[ivlen-1]) {
		PGPFreeCFBContext (cfb);
		*error = kPGPError_CantDecrypt;
		return (PGPCFBContext *)0;
	}

	/* Advance pointer to skip the bytes we've used */
	ctx->input.bufptr += ivlen+2;
	if (ctx->input.bufptr != ctx->input.bufend)
		ctx->nopurge = TRUE;

#if 0
	/* Only do sync with small block ciphers */
	if (pgpCFBGetBlockSize( cfb ) <= 8)
#endif
		PGPCFBSync (cfb);

	*error = kPGPError_NoErr;
	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 PGPError
ProcessCallback (PGPPipeline *myself, int type,
                 PGPByte const *string, size_t size)
{
	PrsBinContext *ctx = (PrsBinContext *)myself->priv;
	PGPPipeline *oldhead;
	PGPCFBContext *cfb;
	PGPError	error = kPGPError_NoErr;
	PGPContextRef	cdkContext;
    PGPMemoryMgrRef	memoryMgr	= NULL;
	
	pgpAssertAddrValid( myself, PGPPipeline );
	cdkContext	= myself->cdkContext;
	memoryMgr	= PGPGetContextMemoryMgr( cdkContext );

	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 ( myself->cdkContext, ctx->end);
		if (!ctx->end) {
			error = kPGPError_OutOfMemory;
			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_PROCESS &&
				ctx->subtype == PGP_LITERAL_RECURSE) {
				/* Decided not to recurse, fixup subtype and type */
				type = PGPANN_PARSER_RECURSE;
				ctx->subtype = PGP_LITERAL_TEXT;
				error = oldhead->annotate (oldhead, myself,
		                              PGPANN_LITERAL_TYPE, &ctx->subtype, 1);
			}
			if (type == PGPANN_PARSER_RECURSE &&
			    ctx->subtype == PGP_LITERAL_TEXT) {
				PGPByte const *charmap;
				PGPLineEndType lineEnd = pgpGetDefaultLineEndType();
				charmap = (PGPByte const *)
					pgpenvGetPointer
					(ctx->env, PGPENV_CHARMAPTOLOCAL, NULL);
				/* Recurse means filter the text */
				ctx->end = pgpTextFiltCreate ( myself->cdkContext,
							ctx->end,  charmap,  0, lineEnd );
				if (!ctx->end) {
					error = kPGPError_OutOfMemory;
					break;
				}
			} else if (type == PGPANN_PARSER_RECURSE &&
					   ctx->subtype == PGP_LITERAL_RECURSE) {
				/* Want to recurse inside literal packet */
				PGPPipeline **temp = ctx->end;
				PGPBoolean trueflag = TRUE;

				ctx->end = pgpParseAscCreate ( myself->cdkContext,
							ctx->end, ctx->env, &pgpByteFifoDesc,
							ctx->ui, ctx->ui_arg );
				ctx->nextparser = *temp;
				if (!ctx->end) {
					error = kPGPError_OutOfMemory;
					break;
				}
				/* Chain end of pipeline so can do annotation */
				*(ctx->end) = oldhead;
				ctx->needcallback--;
				/* Set ascii armor to passthroughclearsign mode */
				ctx->nextparser->annotate( ctx->nextparser, NULL,
										   PGPANN_PASSTHROUGH_CLEARSIGN,
										   &trueflag, 1 );
				if (!ctx->nopurge)
					inputPurge(&ctx->input);
				ctx->nopurge = FALSE;
				myself->write = DoWrite;
				return error;
			}
			type = PGPANN_PARSER_PROCESS;
			break;
		case PGPANN_CIPHER_END:
			cfb = CheckKey (myself->cdkContext, ctx, string, size, &error);
			if (!cfb)
				break;
			ctx->end = pgpCipherModDecryptCreate ( myself->cdkContext,
				ctx->end, cfb, ctx->env, kPGPHashAlgorithm_Invalid, 0);
			if (!ctx->end)
				error = kPGPError_OutOfMemory;
			break;
		case PGPANN_COMPRESSED_END:
			ctx->end = pgpDecompressModCreate ( cdkContext, ctx->end,
					         *inputMergedPtr(&ctx->input), &error);
			break;
		case PGPANN_COMMENT_END:
		case PGPANN_UNKNOWN_END:
			type = PGPANN_PARSER_PROCESS;
			break;
		case PGPANN_SIGNED_END:
		{
			PGPUInt32	numHashes	=0;
			
			if (ctx->nextparser)
				type = PGPANN_PARSER_PROCESS;
			/* Set up all requested hashes */
			pgpAssert(!ctx->hashes);
			if (!size)
				return kPGPError_NoErr;
			/* Get all the PgpHashContexts */
			error = (PGPError)pgpHashListCreate ( memoryMgr,
				string, &ctx->hashes, size);
			if ( IsPGPError( error ) )
				break;
			numHashes	= pgpHashListGetSize( ctx->hashes );
			/* Make a pipeline out of them */
			ctx->end = pgpHashModListCreate ( cdkContext,
							ctx->end,  ctx->hashes, numHashes);
			if (!ctx->end) {
				pgpHashListDestroy (ctx->hashes );
				ctx->hashes = NULL;
				error = kPGPError_OutOfMemory;
				break;
			}
			pgpAssert(inputFinished(&ctx->input.head));
			ctx->input.head.pktlen = (PGPUInt32)-1l; /* Write through rest */
			ctx->input.silent_trunc = 1;
			error = kPGPError_NoErr;
			break;
		}

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

		/*
		 * 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) {
			PGPPipeline **temp = ctx->end;

			ctx->end = pgpParseBinCreate ( myself->cdkContext,
						ctx->end, ctx->env, ctx->ui, ctx->ui_arg);
			if (!ctx->end)
				error = kPGPError_OutOfMemory;
			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 ( myself->cdkContext, ctx->end);
				if (!ctx->end)
					error = kPGPError_OutOfMemory;
			}
		}
		/* 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 {
					if( !ctx->nopurge )
						inputPurge( &ctx->input );
					ctx->nopurge = FALSE;
					myself->write = DoWrite;
				}
			} else {
				if (ctx->end_scope == PGPANN_PGPKEY_END)
					myself->write = parseKey;
				else {
					if( !ctx->nopurge )
						inputPurge( &ctx->input );
					ctx->nopurge = FALSE;

⌨️ 快捷键说明

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