Ciphers
*******

This chapter describes the symmetric ciphers implemented by GNU Crypto, and how to create and use them. The package name for all GNU Crypto ciphers is gnu.crypto.cipher. The ciphers implemented by GNU Crypto are:

  * The Advanced Encryption Standard, or the AES. The AES is a symmetric block cipher with a 128 bit block size and a key size of 128, 192, or 256 bits. The AES was adopted as US FIPS PUB 197 [NIST01] by the National Institute of Standards and Technology (NIST) in November 2001 after a five-year process of standarization and public comment. The AES was written by Joan Daemen and Vincent Rijmen for the AES process, and is derived from the Rijndael cipher.

  * Anubis. The Anubis cipher is a symmetric block cipher with a 128 bit block size and a key size from 128 to 320 bits, with increments of 32 bits. Anubis was designed by Paulo Barreto and Vincent Rijmen, and has been submitted as a candidate cipher to the New European Schemes for Signatures, Integrity, and Encryption (NESSIE) process.

  * Blowfish. The Blowfish symmetric block cipher was designed by Bruce Schneier. It has a 64 bit block size and a key size of up to 448 bits. Blowfish encryption and decryption are very fast in software, especially on 32 bit microprocessor architectures.

  * DES. DES is the Data encryption standard, a 64-bit cipher with a 56-bit key. DES was developed by IBM in the 1970's for a standardization process begun by the National Bureau of Standards (now NIST). DES should not be used in new applications in favor of the new standard, AES, except for compatibility.

  * Identity cipher. The identity, or null cipher, is not a true cipher as it does not transform the data input, but rather copies it directly to the output.

  * Khazad. The Khazad cipher is a symmetric block cipher with a 64 bit block size and a 128 bit key size. Khazad was designed by Paulo Barreto and Vincent Rijmen, and has been submitted as a candidate cipher to the New European Schemes for Signatures, Integrity, and Encryption (NESSIE) process.

  * Rijndael. Rijndael is a symmetric block cipher written by Joan Daemen and Vincent Rijmen as a candidate to the Advanced Encryption Standard process, and was adopted as the AES. Rijndael additionally has a 192 and 256 bit block size.

  * Serpent. The Serpent cipher was designed by Ross Anderson, Eli Biham, and Lars Knudsen as a proposed cipher for the Advanced Encryption Standard. Serpent has a 128 bit block size, and a key size of 128, 192, or 256 bits.

  * Square. The Square cipher was designed by Joan Daemen and Vincent Rijmen and was cryptanalyzed by Lars Knudsen. It has a 128 bit block size and a 128 bit key size.

  * Triple-DES, or DESede, is a combined cipher based on the Data Encryption Standard. It is the iteration of three seperate instances of DES with three independent keys, and therefore has a 64 bit block size and a key size of 168 bits.

  * Twofish. The Twofish cipher was designed by Bruce Schneier, John Kelsey, Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson as a proposed cipher for the Advanced Encryption Standard. Twofish has a 128 bit block size, and a key size of 128, 192, or 256 bits.

The IBlockCipher Interface
==========================

Figure 1: Ciphers class diagram

All ciphers in GNU Crypto implement the IBlockCipher interface, and support all the methods listed in this section.

 -- Variable: java.lang.String CIPHER_BLOCK_SIZE
     A property name in the attributes map that is passed to the init method, representing the cipher's desired block size. The mapped value should be a java.lang.Integer of the cipher's block size, in bytes. If this attribute is omitted, the cipher's default block size is used.

 -- Variable: java.lang.String KEY_MATERIAL
     A property name in the attributes map that is passed to the init method, representing the bytes that are to compose the cipher's key. The mapped value must be a byte array, and its length must be one of the cipher's supported key sizes.

 -- Function: void init (java.util.Map ATTRIBUTES) throws java.security.InvalidKeyException, java.lang.IllegalStateException
     Initializes the cipher for transforming data. The ATTRIBUTES parameter must be a java.util.Map that has, at least, a mapping between the KEY_MATERIAL property name to a byte array containing the key. Ciphers may define other property names. If the supplied byte array is not an acceptable key, this method throws a java.security.InvalidKeyException. If this instance has already been initialized, this method throws a java.lang.IllegalStateException.

 -- Function: java.lang.String name ( )
     Returns the cipher's canonical name.

 -- Function: int defaultBlockSize ( )
     Returns the default block size, in bytes.

 -- Function: int defaultKeySize ( )
     Returns the default key size, in bytes.

 -- Function: java.util.Iterator blockSizes ( )
     Returns a java.util.Iterator of the cipher's supported block sizes. Each element of the iterator is a java.lang.Integer.

 -- Function: java.util.Iterator keySizes ( )
     Returns a java.util.Iterator of the cipher's supported key sizes. Each element of the iterator is a java.lang.Integer.

 -- Function: java.lang.Object clone ( )
     Returns a clone of this cipher. The cloned instance must be initialized, as this method will not clone the cipher's internal key.

 -- Function: int currentBlockSize ( ) throws java.lang.IllegalStateException
     Returns the cipher's current block size, in bytes, or will throw a java.lang.IllegalStateException if this instance has not been initialized.

 -- Function: void reset ( )
     Resets this instance, which may then be re-initialized.

 -- Function: void encryptBlock (byte[] PLAINTEXT, int INOFFSET, byte[] CIPHERTEXT, int OUTOFFSET) throws java.lang.IllegalStateException
     Encrypts a block of bytes from PLAINTEXT starting at INOFFSET, storing the encrypted bytes in CIPHERTEXT, starting at OUTOFFSET. It is up to the programmer to ensure that there is at least one full block in PLAINTEXT from INOFFSET and space for one full block in CIPHERTEXT from OUTOFFSET. A java.lang.IllegalStateException will be thrown if the cipher has not been initialized.

 -- Function: void decryptBlock (byte[] CIPHERTEXT, int INOFFSET, byte[] PLAINTEXT, int OUTOFFSET) throws java.lang.IllegalStateException
     Decrypts a block of bytes from CIPHERTEXT starting at INOFFSET, storing the encrypted bytes in PLAINTEXT, starting at OUTOFFSET. It is up to the programmer to ensure that there is at least one full block in CIPHERTEXT from INOFFSET and space for one full block in PLAINTEXT from OUTOFFSET. A java.lang.IllegalStateException will be thrown if the cipher has not been initialized.

 -- Function: boolean selfTest ( )
     Performs a simple test of conformance, to ensure that there are no implementation or system errors. This method returns true if the test succeeds; false otherwise.

The CipherFactory Class
=======================

The ciphers in GNU Crypto can usually be initiallized directly through their constructors, but the preferred way is to use the CipherFactory class, with the following method:

 -- Function: static IBlockCipher getInstance (java.lang.String NAME)
     Returns a new cipher instance for the cipher named NAME, or null if no such cipher exists. This method will throw a java.lang.InternalError if the new instance's self-test fails.

The class also defines this method:

 -- Function: static java.util.Set getNames ( )
     This method returns a java.util.Set of the names (each element of type java.lang.String) of all supported ciphers.

Example
=======

The following example transforms the plaintext to the ciphertext, and the ciphertext back to the plaintext, using the AES in electronic codebook mode with no padding. Note also the classes for cipher modes and padding schemes for more complex constructions.

     IBlockCipher cipher = CipherFactory.getInstance("AES");
     Map attributes = new HashMap();
     attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(16));
     attributes.put(IBlockCipher.KEY_MATERIAL, key_bytes);
     cipher.init(attributes);
     int bs = cipher.currentBlockSize();

     for (int i = 0; i + bs < pt.length; i += bs)
        {
           cipher.encryptBlock(pt, i, ct, i);
        }

     for (int i = 0; i + bs < cpt.length; i += bs)
        {
           cipher.decryptBlock(ct, i, cpt, i);
        }