Cascades
========

Figure 4: Cascade class diagram

Direction
=========

An enumeration type for wiring Stage instances into Cascade chains, as well as for operating a Cascade in a given direction.

This class cannot be instantiated; but its (only) two possible values can be used for constructing Stage elements, and initializing Cascade instances:

  * FORWARD: equivalent to gnu.crypto.mode.IMode#ENCRYPTION; and its inverse value

  * REVERSED: equivalent to gnu.crypto.mode.IMode#DECRYPTION.

This class offers a Factory method to return the inverse of a designated Direction instance:

 -- Function: Direction reverse (Direction D)

Stage
=====

This class represents a Stage in a Cascade cipher.

Each stage may be either an implementation of a Block Cipher Mode of Operation (an instance of gnu.crypto.mode.IMode) or another Cascade cipher (an instance of Cascade). Each Stage has also a natural operational direction when constructed for inclusion within a Cascade. This natural direction dictates how data flows from one Stage into another when stages are chained together in a Cascade. One can think of a Stage and its natural direction as the specification of how to wire the Stage into the chain.

The following diagrams may help understand the paradigm. The first shows two stages chained together, each wired in the same direction (Direction#FORWARD).

Figure 5: Stages wired in same direction

The second diagram shows two stages, one in a Direction#FORWARD direction, while the other is wired in a Direction#REVERSED direction.

Figure 6: Stages wired in different directions

 -- Variable: gnu.crypto.assembly.Stage DIRECTION
     A property name in the attributes map that is passed to the init method, representing the stage's desired wiring direction. The mapped value should be a valid gnu.crypto.assembly.Direction value. If this attribute is omitted, Direction.FORWARD is used.

The following Factory methods, allow instantiation of concrete Stage class instances that adapt instances of either gnu.crypto.mode.IMode or (other) Cascade classes to operate as a Stage in a Cascade:

 -- Function: Stage getInstance (IMode MODE, Direction FORWARDDIRECTION)
     Given a designated MODE (an instance of gnu.crypto.mode.IMode, and a Direction, this method returns a Stage instance that adapts this designated MODE to operate as a Stage in a Cascade.

 -- Function: Stage getInstance (Cascade CASCADE, Direction FORWARDDIRECTION)
     Given a designated CASCADE (an instance of gnu.crypto.assembly.Cascade, and a Direction, this method returns a Stage instance that adapts this designated CASCADE to operate as a Stage in another Cascade.

The following instance methods are also available:

 -- Function: java.util.Set blockSizes ()
     Returns the Set of supported block sizes for this Stage. Each element in the returned Set is an instance of Integer.

 -- Function: void init (java.util.Map ATTRIBUTES) throws java.security.InvalidKeyException
     Initializes the stage for operation with specific characteristics. Those characteristics are defined in ATTRIBUTES: a set of name-value pairs that describes the desired future behavior of this instance. This method throws an IllegalStateException if the instance is already initialized. It throws an java.security.InvalidKeyException if the key data (used to initialize the underlying Mode or Cascade) is invalid.

 -- Function: int currentBlockSize () throws IllegalStateException
     Returns the current block size for this stage. Throws an IllegalStateException if the instance is not yet initialized.

 -- Function: void reset ()
     Resets the stage for re-initialization and use with other characteristics. This method always succeeds.

 -- Function: void update (byte[] IN, int INOFFSET, byte[] OUT, int OUTOFFSET)
     Processes exactly one block of plaintext (if wired in the Direction#FORWARD direction) or ciphertext (if wired in the Direction#REVERSED direction), from IN starting at INOFFSET, and storing the resulting bytes in OUT, starting at OUTOFFSET. An IllegalStateException will be thrown if the stage has not yet been initialized.

 -- Function: boolean selfTest ()
     Conducts a simple correctness test that consists of basic symmetric encryption / decryption test(s) for all supported block and key sizes of underlying block cipher(s) wrapped by Mode leafs. The test also includes one (1) variable key Known Answer Test (KAT) for each block cipher. It returns true if the tests succeed, and false otherwise.

Cascade
=======

A Cascade Cipher is the concatenation of two or more block ciphers each with independent keys. Plaintext is input to the first stage; the output stage i is input to stage i + 1; and the output of the last stage is the Cascade's ciphertext output.

In the simplest case, all stages in a Cascade have k-bit keys, and the stage inputs and outputs are all n-bit quantities. The stage ciphers may differ (general cascade of ciphers), or all be identical (cascade of identical ciphers).

The term block ciphers used above refers to implementations of gnu.crypto.mode.IMode, including the gnu.crypto.mode.ECB mode which basically exposes a symmetric-key block cipher algorithm as a Mode of Operations.

 -- Variable: String DIRECTION
     The name of a property in the attributes map that is passed to the init method, representing the cascade's desired wiring direction. The mapped value should be a valid gnu.crypto.assembly.Direction value. If this attribute is omitted, gnu.crypto.assembly.Direction.FORWARD is used.

 -- Function: Object append (Stage STAGE) throws IllegalArgumentException
     Adds to the end of the current chain, a designated STAGE. Returns a unique identifier for this added stage, within this cascade. An IllegalArgumentException is thrown if STAGE is already in the chain, or it has incompatible characteristics with the current elements already in the chain. On the other hand, an IllegalStateException will be thrown if the cascade has already been initialized, or if the designated STAGE is null.

 -- Function: Object prepend (Stage STAGE) throws IllegalArgumentException
     Adds to the beginning of the current chain, a designated STAGE. Returns a unique identifier for this added stage, within this cascade. An IllegalArgumentException is thrown if STAGE is already in the chain, or it has incompatible characteristics with the current elements already in the chain. On the other hand, an IllegalStateException will be thrown if the cascade has already been initialized, or if the designated STAGE is null.

 -- Function: Object insert (int INDEX, Stage STAGE) throws IllegalArgumentException, IndexOutOfBoundsException
     Inserts a designate STAGE Stage into the current Cascade, at the specified INDEX (zero-based) position. Returns a unique identifier for this added stage, within this cascade. Throws an IllegalArgumentException if STAGE is already in the chain, or it has incompatible characteristics with the current elements already in the chain. Throws an IllegalStateException if the instance is already initialized. Finally, this method throws an IndexOutOfBoundsException if INDEX is less than 0 or greater than the current size of this cascade.

 -- Function: int size ()
     Returns the current number of stages in this chain.

 -- Function: java.util.Iterator stages ()
     Returns an java.util.Iterator over the stages contained in this instance. Each element of this iterator is a concrete implementation of a gnu.crypto.assembly.Stage.

 -- Function: java.util.Set blockSizes ()
     Returns a java.util.Set of supported block sizes for this Cascade that are common to all of its chained stages. Each element in the returned set is an instance of Integer.

 -- Function: void init (java.util.Map ATTRIBUTES) throws InvalidKeyException
     Initializes the chain for operation with specific characteristics, as specified by the contents of ATTRIBUTES --a set of name-value pairs that describes the desired future behavior of this instance. Throws an IllegalStateException if the chain, or any of its stages, is already initialized. Throws an InvalidKeyException if the initialization data provided with the stage is incorrect or causes an invalid key to be generated.

 -- Function: int currentBlockSize ()
     Returns the currently set block size for the chain. Throws an IllegalStateException if the instance is not yet initialized.

 -- Function: void reset ()
     Resets the chain for re-initialization and use with other characteristics. This method always succeeds.

 -- Function: void update (byte[] IN, int INOFFSET, byte[] OUT, int OUTOFFSET)
     Processes exactly one block of plaintext (if initialized in the gnu.crypto.assembly.Direction#FORWARD direction) or ciphertext (if initialised in the gnu.crypto.assembly.Direction#REVERSED direction), from IN, starting at index position INOFFSET, returning the result in OUT, starting at index position OUTOFFSET. Throws an IllegalStateException if the instance is not yet initialized.

 -- Function: boolean selfTest ()
     Conducts a simple correctness test that consists of basic symmetric encryption / decryption test(s) for all supported block and key sizes of underlying block cipher(s) wrapped by Mode leafs. The test also includes one (1) variable key Known Answer Test (KAT) for each block cipher. Returns true if the implementation passes the tests. Returns false otherwise.

Example
=======

The following example demonstrates how a DES-EDE block cipher can be constructed as a Cascade of three DES Stages.

     HashMap map = new HashMap();
     HashMap map1 = new HashMap();
     HashMap map2 = new HashMap();
     HashMap map3 = new HashMap();

     Cascade new3DES = new Cascade();
     Object des1 = new3DES.append(
         Stage.getInstance(
             ModeFactory.getInstance(Registry.ECB_MODE, new DES(), 8),
             Direction.FORWARD));
     Object des2 = new3DES.append(
         Stage.getInstance(
             ModeFactory.getInstance(Registry.ECB_MODE, new DES(), 8),
             Direction.REVERSED));
     Object des3 = new3DES.append(
         Stage.getInstance(
             ModeFactory.getInstance(Registry.ECB_MODE, new DES(), 8),
             Direction.FORWARD));

     map.put(des1, map1);
     map.put(des2, map2);
     map.put(des3, map3);

     map1.put(IBlockCipher.KEY_MATERIAL, key1material);
     map2.put(IBlockCipher.KEY_MATERIAL, key2material);
     map3.put(IBlockCipher.KEY_MATERIAL, key3material);

     // encryption
     map.put(Cascade.DIRECTION, Direction.FORWARD);
     byte[] pt = ...; // some plaintext to encrypt
     byte[] ct = new byte[pt.length]; // where ciphertext is returned

     try
       {
         new3DES.init(map);
         new3DES.update(pt, 0, ct, 0);
       }
     catch (InvalidKeyException x)
       {
         x.printStackTrace(System.err);
       }