Description of the control system used in the driver
of a crypt-channel to decide about its actions upon
input-requests.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

General background
------------------

We have to deal with:

-	Statically different buffersizes, smaller or greater
	than a block of the used cryptosystem.

-	Buffersizes not being a multiple of the blocksize.

-	Buffersizes dynamically changing between calls to the
	driver function.

-	Partial data given from the underlying channel.

-	Eof from the underlying buffer (We have to avoid an Eof
	check on the crypt channel as long as there is internally
	buffered data).


Implementation basics
---------------------

The driver uses an internal buffer to hold already decrypted
data waiting for retrieval from the generic layer.  Alternatively
this buffer may contain a partial (encrypted) block waiting for
more incoming data.

State information therefore contains:

-	The buffer, its actual and maximal length.
-	An indicator flag to differentiate between wait for
	retrieval and wait for more data.

Although desirable, the buffer is NOT an instance of Tcl_DString.
This type is unable to handle data with embedded zeros.


Conditions and variables for a decision table
---------------------------------------------

	WaitRead - waiting for read of encrypted data
	WaitData - waiting for more data from source

		These 2 are complementary, exactly
		one of has to be true at all times.

	+WR	=> Set WaitRead to True, WaitData to False
	+WD	=> Set WaitData to True, WaitRead to False

	eS:	Size of external buffer.
	iS:	Size of internal buffer = number of bytes
		stored in it.
	bS:	Blocksize used during de/encryption.
		Dependent on the used mode. For ECB, CBC it
		is the size of single block of the used
		cryptosystem. Otherwise (CFB, OFB) it is
		equal to the used shiftwidth.

	iB = internal buffer
	eB = external buffer

	bl(x)	number of blocks contained in x bytes.
		(x/bS)

	bby(x)	number of bytes making full blocks
		contained in x bytes.
		(bS * bl(x))

	Eof	source reached end of its input.


Actions
-------
	Stop		Return from invocation of driver
			procedure with actual state.

	Recurse		Determine next actions with the
			table again, use the conditions
			set by the previously executed
			actions.

	iB->eB/x	Transfer x bytes from iB to eB.
			Remove the moved bytes from iB
			and reduce iS by x.  Increase
			number of read bytes by x too.

	Expand iB/x	Make iB big enough to hold x bytes.

	Get x		Read at most x bytes into iB and
			set iS to number of actually read bytes.

	Decrypt x	Decrypt 1 blocks in iB.


Decisiontable
-------------

Conditions			| Actions		Possible destination states
================================+===============================================================
WaitRead, eS <= iS		| iB->eB/eS
\				| Stop.
A\				|			(-> A, B)
================================+===============================================================
WaitRead,  eS > iS		| iB->eB/iS.	(is == 0 fact now)
				| Reduce eS by iS, step buffer start behind data.
				| +WD
\				| Recurse.
B\				|		(-> D, E) (es>is -> eS' >0 -> not C)
================================+===============================================================
WaitData, iS == 0, eS = 0	| Read 0	\  should be impossible,
\				| Stop.		 > indicates error in generic layer.
C\				|		/
================================+===============================================================
WaitData, iS == 0, eS < bS	| Expand iB/bS.
				| Get bS.
empty internal buffer		| iS < bS ?	//eof reached on source (AND crypt!)
less than a block is requested	|	Read 0.
				|	+WD.
				|	Stop.	(-> D, E, H)
				| else
				|	Decrypt 1.
\				|	+WR.
D\				|	Recurse.	(-> A)
================================+===============================================================
WaitData, iS == 0, eS >= bS	| Expand iB/(bby(eS)+bS)	(try to get one block more than)
				| Get (bby(eS)+bS)		(required for buffer)
empty internal buffer		| bl(iS) == 0 ?
big chunk requested,		|	Read 0.		//eof reached on source (AND crypt!)
several blocks			|	+WD.
				|	Stop.		(-> D, E, H)
				| Decrypt bl(iS).
				| iB->eB/min(bby(iS),eS)
				| iS > 0 ?
				|	+WD.
				|	Stop.		(-> H)
				| else
\				|	+WR.
E\				|	Stop.		(-> A, B)
================================+===============================================================
WaitData, is >= bS		| << IMPOSSIBLE >>
\				|
F\				|
================================+===============================================================
WaitData, 0 < iS < bS, eS = 0	| << IMPOSSIBLE >>
\				|
G\				|
================================+===============================================================
WaitData, 0 < iS < bS		| Expand iB/bS.
				| Get (bS-'old iS').
incomplete block pending	| iS < bS ?
try to complete it		|	Read 0.		//eof reached on source (AND crypt!)
				|	+WD
				|	Stop.		(-> H)
				| else
				|	Decrypt 1.
\				|	+WR
H\				|	Recurse.	(-> A, B)
================================+===============================================================



Statediagrams
-------------

Possible states are A, B, D, E, H.

	Table recurse creates the transitions:
	======================================
	H	->	B	-> E
				-> D	->	A
		->	A

	This graph does not contain loops.
	The gotos in the implementation are therefore
	save, infinite looping will not occur.

