//============================================================================== // StreamCipherSpi.java //============================================================================== package tribble.crypto; // System imports import java.lang.Exception; import java.lang.NullPointerException; import java.lang.String; import java.lang.System; import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.ShortBufferException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; // Local imports import tribble.util.HexDump; /******************************************************************************* * Stream cipher service provider interface (SPI) implementation. * *

* A stream cipher encrypts or decrypts a stream of data, one word at a time. * A "word" of input is a fixed number of bits wide, and can be as small as one * bit or as large as 64 bits. Generally, stream ciphers are used to encrypt * single 8-bit bytes (octets), or 32-bit or 64-bit blocks. * *

* At the heart of a stream cipher engine is a symmetric block cipher. * The stream cipher is initialized with an initial vector (IV) which is the same * width as the underlying block cipher. The state of the stream cipher is * filled with the IV value prior to encrypting any data from the input stream. * The IV should be a random value, but it does not have to be kept secret; in * fact, it is typically prepended to the encrypted output data stream or * otherwise transmitted along with the encrypted data, so that the decrypting * side uses the same IV value. * *

* At each stage in the stream ciphering process, the state of the cipher is * represented by a block of data the same width as the block size of the * underlying block cipher. For each input word that is encrypted by the stream * cipher, the state block is encrypted using the block cipher and the encryption * key set up for the cipher. The rightmost N bits of the block * encryption are then exclusive-or'd with the next N-bit input * (plaintext) word, and the resulting (ciphertext) word is the next word of * output from the stream cipher. The state block is then updated by shifting * it N bits left and inserting either the N-bit ciphertext output * word (in CFB mode) or the rightmost N bits of the block encryption * (in OFB mode) in preparation for the next word. * *

* Thus any fixed-width symmetric block cipher can be used as the underlying * block cipher in a stream cipher. * *

* The following stream encryption modes are supported: *

* *

* The only padding scheme supported is "NoPadding" * ({@link #PADDING_NONE}), since every input word (byte) results in the * generation of an output word (byte), and therefore no input padding is * necessary. * *

* Note that none of these methods are synchronized. * * * @version API 2, $Revision: 1.4 $ $Date: 2006/04/18 03:00:30 $ * @since 2005-07-05 * @author * David R. Tribble * (david@tribble.com). * *

* Copyright ©2005-2006 by David R. Tribble, all rights reserved. *
* Permission is granted to freely use and distribute this source code * provided that the original copyright and authorship notices remain * intact. * * @see BlockCipherSpi * @see AbstractCipher */ public class StreamCipherSpi extends tribble.crypto.CipherSpi { // Identification /** Revision information. */ static final String REV = "@(#)tribble/crypto/StreamCipherSpi.java $Revision: 1.4 $ $Date: 2006/04/18 03:00:30 $\n"; /** Class series version. */ public static final int SERIES = 400; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Constants //---------------------------------- // Operating mode control flags /** Operating mode (block): ECB, electronic codebook (none). */ static final int MODEFLAG_NONE = 0; /** Operating mode (stream): CFB, cipher feedback. */ static final int MODEFLAG_CFB = 1; /** Operating mode (stream): OFB, output feedback. */ static final int MODEFLAG_OFB = 2; /** Operating mode (stream): PFB, plaintext feedback. */ static final int MODEFLAG_PFB = 3; /** Operating mode (stream): CTR, counter mode. */ static final int MODEFLAG_CTR = 4; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Static methods /*+++INCOMPLETE /*************************************************************************** * Test driver. * *

* Usage * * java tribble.crypto.SomeCipher [args...] * * * * @param ciph * Derived class cipher object to test. * * @param key * Symmetric key for the cipher. * * @param input * Input test vector. * This array should be exactly the same length as the cipher block size. * * @throws Exception * Thrown if an error occurs in the encryption engine. * * @since 1.1, 2005-07-05 *\/ +++INCOMPLETE protected static void test(StreamCipherSpi ciph) throws Exception { ...; } +++*/ /*************************************************************************** * Encrypt/decrypt a data file. * *

* Usage * * java tribble.crypto.SomeCipher * [-option...] in-file * * *

* Options: *

*

*
-e *
Encrypt the input file. * *
-d *
Decrypt the intput file. * *
-h *
If encrypting, include information about the input file * (modification date) in the encrypted output. * If decrypting, extract the file information from the decrypted output * and set the output file attributes (modification date) accordingly. * *
-o out-file *
Output file. * If this option is not specified, the output is written to the standard * output by default. * *
-p passphrase *
Encryption/decryption passphrase. * *
-pf passphrase-file *
Text file containing the encryption/decryption passphrase. *
* *

* Either the -e or the -d must be specified. * *

* If neither the -p nor the -pf option is specified, the * encryption/decryption passphrase is read from the standard input after a * prompt is written to the standard error output. * * * @param ciph * Derived class cipher object to test. * * @param args * Command line arguments. * * @throws Exception * Thrown if an error occurs in the encryption engine. * * @since 1.5, 2005-04-07 */ protected static void run(StreamCipherSpi ciph, String[] args) throws Exception { /*+++INCOMPLETE ...; +++*/ } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Variables /** Fundamental underlying block cipher. */ SymmetricCipher m_ciph; /** Stream cipher state. */ byte[] m_state; /** Underlying block cipher output block. */ byte[] m_eBuf; /** Cipher stream word size (in bytes). */ int m_streamWidth = 1; /** Operating mode control bitflags (see {@link #m_mode}). */ int m_modeFlags = MODEFLAG_NONE; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Constructors /*************************************************************************** * Constructor. * * @param ciph * Underlying block cipher. * * @param mode * Operating mode, which must match one of the * {@link #MODE_CFB MODE_XXX} constants. * * @param pad * Padding scheme, which must match one of the * {@link #PADDING_NONE PADDING_XXX} constants}. * * @throws NoSuchAlgorithmException * Thrown if mode does not specify a supported operating mode. * * @throws NoSuchPaddingException * Thrown if pad does not specify a supported padding scheme. * * @since 1.1, 2005-07-07 */ protected StreamCipherSpi(SymmetricCipher ciph, String mode, String pad) throws NoSuchAlgorithmException, NoSuchPaddingException { // Initialize super(ciph.getAlgorithm(), mode, pad); m_ciph = ciph; m_blockLen = ciph.getBlockSize(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Methods /*************************************************************************** * Initialize this cipher. * *

* This method invokes the {@link #initialize} method of the underlying * block cipher. * * * @param mode * Ciphering mode, which is either {@link #ENCRYPT_MODE} or * {@link #DECRYPT_MODE}. * * @param key * Symmetric (secret) key for this cipher to use. * * @param rand * Source of random values, or null if they are to be supplied by a default * source. * * @throws InvalidKeyException * Thrown if key is not the proper kind of key for use with this * cipher. * * @throws IllegalArgumentException (unchecked) * Thrown if mode is not a valid value. * * @see #engineGetParameters() engineGetParameters() * @see #engineGetIV engineGetIV() * @see #engineSetIV engineSetIV() * @see #initialize * * @since 1.1, 2005-07-07 */ protected void engineInit(int mode, Key key, SecureRandom rand) throws InvalidKeyException //overrides tribble.crypto.CipherSpi { try { // Initialize this cipher engineInit(mode, key, (AlgorithmParameterSpec) null, rand); } catch (InvalidAlgorithmParameterException ex) { // Should never occur, ignore } } /*************************************************************************** * Initialize this cipher. * *

* This method invokes the initialize() method of the underlying * cipher. * *

* Note that if this cipher is being initialized for decryption, it must be * provided with the same algorithm parameters that were used to initialize * the cipher that originally encrypted the data that will be fed into this * cipher. * * * @param mode * Ciphering mode, which is either {@link #ENCRYPT_MODE} or * {@link #DECRYPT_MODE}. * * @param key * Key for this cipher to use. * * @param parms * Algorithm-specific initialization parameters (e.g., an IV passed as a * javax.crypto.spec.IvParameterSpec object). If this parameter is * null and mode is ENCRYPT_MODE, the IV is initialized * from the random source rand; otherwise if mode is * DECRYPT_MODE, the IV is initialized to all zeros. * * @param rand * Source of random values, or null if this is to be supplied by a default * source. * * @throws InvalidKeyException * Thrown if key is not the proper kind of key * (i.e., a javax.crypto.spec.SecretKeySpec) for use with this * cipher. * * @throws InvalidAlgorithmParameterException * Thrown if parms is not a proper initialization parameter for this * cipher. * * @throws IllegalArgumentException (unchecked) * Thrown if mode is not a valid value. * * @see #engineGetParameters() engineGetParameters() * @see #engineGetIV engineGetIV() * @see #engineSetIV engineSetIV() * * @since 1.1, 2005-07-07 */ protected void engineInit(int mode, Key key, AlgorithmParameterSpec parms, SecureRandom rand) throws InvalidKeyException, InvalidAlgorithmParameterException //overrides tribble.crypto.CipherSpi { SecretKeySpec kspec; // Set up the mode if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) throw new IllegalArgumentException( "Cipher mode must be ENCRYPT_MODE or DECRYPT_MODE"); m_decrypt = (mode == DECRYPT_MODE); // Set up the encryption/decryption key if (!(key instanceof SecretKeySpec)) throw new InvalidKeyException("Key is not a SecretKeySpec"); kspec = (SecretKeySpec) key; // Set up the random number source if (rand == null) { if (s_rand == null) { // Create/initialize the default random source synchronized (this.getClass()) { if (s_rand == null) s_rand = new SecureRandom(); } } // Use the default random source rand = s_rand; } m_rand = rand; // Initialize the underlying cipher m_ciph.initialize(kspec.getEncoded(), m_decrypt); m_alg = m_ciph.m_alg; m_blockLen = m_ciph.m_blockLen; m_keyLen = m_ciph.m_keyLen; // Initialize the IV block m_iv = new byte[m_blockLen]; if (parms != null) { if (parms instanceof IvParameterSpec) { IvParameterSpec ivSpec; // Initialize the IV block ivSpec = (IvParameterSpec) parms; engineSetIV(ivSpec.getIV()); } else { // Invalid algorithm parameter, expecting an IV throw new InvalidAlgorithmParameterException( "Expecting an IvParameterSpec"); } } else if (!m_decrypt) { // Initialize the IV block from the random source m_rand.nextBytes(m_iv); m_state = new byte[m_blockLen]; System.arraycopy(m_iv, 0, m_state, 0, m_blockLen); } // Initialize the internal block buffers m_eBuf = new byte[m_blockLen]; m_in = new byte[m_blockLen]; m_inSize = 0; m_init = true; } /*************************************************************************** * Initialize this cipher. * *

* This method invokes the initialize() method of the underlying * cipher. * *

* Note that if this cipher is being initialized for decryption, it must be * provided with the same algorithm parameters that were used to initialize * the cipher that originally encrypted the data that will be fed into this * cipher. * * * @param mode * Ciphering mode, which is either {@link #ENCRYPT_MODE} or * {@link #DECRYPT_MODE}. * * @param key * Key for this cipher to use. * * @param parms * Algorithm-specific initialization parameters (e.g., an IV passed as a * javax.crypto.spec.IvParameterSpec object). * * @param rand * Source of random values, or null if this is to be supplied by a default * source. * * @throws InvalidKeyException * Thrown if key is not the proper kind of key for use with this * cipher. * * @throws InvalidAlgorithmParameterException * Thrown if parms is not a proper initialization parameter for this * cipher. * * @see #engineGetParameters() engineGetParameters() * @see #engineGetIV engineGetIV() * @see #engineSetIV engineSetIV() * * @since 1.1, 2005-07-07 */ protected void engineInit(int mode, Key key, AlgorithmParameters parms, SecureRandom rand) throws InvalidKeyException, InvalidAlgorithmParameterException //overrides tribble.crypto.CipherSpi { IvParameterSpec ivSpec = null; // Set up the IV from the parameters if (parms != null) { try { // Extract the IV from the parameters, if it is present ivSpec = (IvParameterSpec) parms.getParameterSpec(IvParameterSpec.class); } catch (InvalidParameterSpecException ex) { // Bad IV spec throw new InvalidAlgorithmParameterException(ex.getMessage()); } } // Initialize this cipher engineInit(mode, key, ivSpec, rand); } /*************************************************************************** * Set the operating mode of this cipher. * * @param mode * Cipher operating mode to use * (e.g., "CFB", "OFB", "CTR", etc.). * The default mode is "CFB". * See the {@link #MODE_CFB MODE_XXX} constants. * * @throws NoSuchAlgorithmException * Thrown if mode does not specify a operating mode supported by * this cipher. * * @throws NullPointerException (unchecked) * Thrown if mode is null. * * @since 1.1, 2005-07-07 */ protected void engineSetMode(String mode) throws NoSuchAlgorithmException //overrides tribble.crypto.CipherSpi { // Check args if (mode == null) throw new NullPointerException("Null cipher mode"); // Compare the operating mode to supported modes if (mode.equalsIgnoreCase(MODE_CFB) || mode.equalsIgnoreCase(MODE_CFB8)) { m_mode = MODE_CFB; m_modeFlags = MODEFLAG_CFB; } else if (mode.equalsIgnoreCase(MODE_OFB) || mode.equalsIgnoreCase(MODE_OFB8)) { m_mode = MODE_OFB; m_modeFlags = MODEFLAG_OFB; } else if (mode.equalsIgnoreCase(MODE_CTR) || mode.equalsIgnoreCase(MODE_CTR8)) { m_mode = MODE_CTR; m_modeFlags = MODEFLAG_CTR; } else if (mode.equalsIgnoreCase("None") || mode.equals("")) { m_mode = MODE_CFB; m_modeFlags = MODEFLAG_CFB; } else { // Unsupported cipher operating mode throw new NoSuchAlgorithmException("Unsupported cipher mode: '" + mode + "'"); } } /*************************************************************************** * Set the padding scheme of this cipher. * * @param padding * Cipher padding scheme to use. * Note that the only padding supported in stream mode is * "NoPadding" ({@link #PADDING_NONE}), which is the default scheme. * See the {@link #PADDING_NONE PADDING_XXX} constants. * * @throws NoSuchPaddingException * Thrown if padding does not specify a padding scheme supported by * this cipher. * * @throws NullPointerException (unchecked) * Thrown if padding is null. * * @since 1.1, 2005-07-07 */ protected void engineSetPadding(String padding) throws NoSuchPaddingException //overrides tribble.crypto.CipherSpi { // Check args if (padding == null) throw new NullPointerException("Null cipher padding"); // Compare the padding scheme to supported schemes if (padding.equalsIgnoreCase(PADDING_NONE) || padding.equals("")) m_padding = PADDING_NONE; else throw new NoSuchPaddingException("Unsupported cipher padding: " + padding); } /*************************************************************************** * Set the initial vector (IV) used by this cipher. * *

* This method is not part of the standard set defined in class * javax.crypto.CipherSpi, but is provided as a convenient * enhancement. * * * @param iv * Initial vector bytes to be used by this cipher. * This array must be no longer than the cipher block size * (see {@link #engineGetBlockSize}). * It can be shorter than the cipher block size, in which case the IV of this * cipher will be padded on the right with zeros. * Note that the contents of this array are copied to an internal buffer, so * that subsequent changes made to the array do not affect this cipher * object. * * @throws InvalidAlgorithmParameterException * Thrown if the length of iv is longer than the cipher block size. * * @throws NullPointerException (unchecked) * Thrown if iv is null. * * @since 1.1, 2005-07-08 */ protected void engineSetIV(/*const*/ byte[] iv) throws InvalidAlgorithmParameterException //overrides tribble.crypto.CipherSpi { // Set the IV block for this cipher super.engineSetIV(iv); // Initialize the state block with the IV value m_state = new byte[m_blockLen]; System.arraycopy(m_iv, 0, m_state, 0, m_blockLen); } /*************************************************************************** * Determine the size of a key for this cipher. * * @param key * A key suitable for use with this cipher. * * @return * Key size (in bits) of the given key. * * @throws InvalidKeyException * Thrown if the given key cannot be used with this cipher. * * @throws IllegalStateException (unchecked) * Thrown if this cipher has not been initialized. * * @throws UnsupportedOperationException (unchecked) * Thrown if this method is not overridden. * * @throws NullPointerException (unchecked) * Thrown if key is null. * * @since 1.1, 2005-07-07 */ protected int engineGetKeySize(/*const*/ Key key) throws InvalidKeyException /*const*/ //overrides tribble.crypto.CipherSpi { SymmetricKey kspec; // Sanity check if (!m_init) throw new IllegalStateException("Cipher not initialized"); // Check args if (key == null) throw new NullPointerException("Null cipher key"); // Determine the key size for the given key if (!(key instanceof SymmetricKey)) throw new InvalidKeyException("Key is not a SymmetricKey"); kspec = (SymmetricKey) key; return (kspec.m_key.length); } /*************************************************************************** * Determine the output buffer size of this cipher. * * @param n * Size of the input buffer. * * @return * Output buffer size (in bytes) that will be created by this cipher. * For stream ciphers, this is always equal to n, the input buffer * size. * * @throws IllegalStateException (unchecked) * Thrown if this cipher has not been initialized. * * @since 1.1, 2005-07-07 */ protected int engineGetOutputSize(int n) /*const*/ //overrides tribble.crypto.CipherSpi { // Sanity check if (!m_init) throw new IllegalStateException("Cipher not initialized"); // Compute the output buffer size for the given input buffer size; // for stream ciphers, this is always equal to the input size return (n); } /*************************************************************************** * Retrieve algorithm-specific initialization parameters for this cipher. * * @return * Algorithm-specific initialization parameters. * * @throws IllegalStateException (unchecked) * Thrown if this cipher has not been initialized. * * @since 1.1, 2005-07-07 */ protected AlgorithmParameters engineGetParameters() /*const*/ //overrides tribble.crypto.CipherSpi { // Can be overridden by classes extending this class /*+++INCOMPLETE m_ciph.xxx(...); +++*/ return (null); } /*************************************************************************** * Encrypt/decrypt an array of bytes using this cipher. * *

* This method handles the operating modes and so forth required of stream * ciphers. * *

* Note that the length of the output is equal to the length of the input, * regardless of the block size of the underlying block cipher. * * *

* Stream Encryption *

*

    *                       +---------+
    *                   IV  |         |
    *                       +---------+
    *                            :
    *                            v
    *                State  +-------+-+
    *                Block  |       | | <-------+
    *                     i +-------+-+         :
    *                            :              :
    *                            v              :
    *                      +===========+        :
    *                      [           ]        :
    *        +-------+     [  Block    ]        :
    *    Key |       | --> [  Cipher   ]        :
    *        +-------+     [           ]        :
    *                      +===========+        :
    *                            :              :
    *                            v              :
    *             Encrypted +-+-------+         o  Mode
    *               Block   | |       |        /|\
    *                       +-+-------+       / | \
    *                        :               /  |  \
    *                        v              o   o   o
    *                       +-+             :   :   :
    *                   Ei  | | ------------+   :   :
    *                       +-+                 :   :
    *                        :                  :   :
    *                        v                  :  +-+
    *                     [ XOR ] ---------------> | | --> Output
    *                        ^                  :  +-+     Stream
    *                        :                  :   Ci
    *    Input              +-+                 :
    *    Stream  ---------> | | ----------------+
    *                       +-+
    *                        Pi 
* * *

* Stream Decryption *

*

    *                       +---------+
    *                   IV  |         |
    *                       +---------+
    *                            :
    *                            v
    *                State  +-------+-+
    *                Block  |       | | <-------+
    *                     i +-------+-+         :
    *                            :              :
    *                            v              :
    *                      +===========+        :
    *                      [           ]        :
    *        +-------+     [  Block    ]        :
    *    Key |       | --> [  Cipher   ]        :
    *        +-------+     [           ]        :
    *                      +===========+        :
    *                            :              :
    *                            v              :
    *             Encrypted +-+-------+         o  Mode
    *               Block   | |       |        /|\
    *                       +-+-------+       / | \
    *                        :               /  |  \
    *                        v              o   o   o
    *                       +-+             :   :   :
    *                   Ei  | | ------------+   :   :
    *                       +-+                 :   :
    *                        :                  :   :
    *                        v                  :  +-+
    *                     [ XOR ] ---------------> | | --> Output
    *                        ^                  :  +-+     Stream
    *                        :                  :   Pi
    *    Input              +-+                 :
    *    Stream  ---------> | | ----------------+
    *                       +-+
    *                        Ci 
* * * @param in * Array of bytes to encrypt/decrypt. * The data from this array is appended to any input data previously added to * this cipher. * * @param inOff * Index of the first byte in array in to encrypt/decrypt. * * @param len * Number of bytes in array in to encrypt/decrypt. * * @param out * Resulting encrypted/decrypted output bytes. * * @param outOff * Index of the first byte in array out to write the resulting * output bytes to. * * @return * Number of encrypted/decrypted bytes written into array out. * * @throws ShortBufferException * Thrown if the output buffer is too small to hold the resulting data. * * @throws IllegalStateException (unchecked) * Thrown if this cipher has not been initialized. * * @throws IllegalArgumentException (unchecked) * Thrown if len is negative. * * @since 1.1, 2005-07-07 */ protected int engineUpdate(/*const*/ byte[] in, int inOff, int len, byte[] out, int outOff) throws ShortBufferException //overrides tribble.crypto.CipherSpi { // Sanity check if (!m_init) throw new IllegalStateException("Cipher not initialized"); // Check args if (len <= 0) { if (len == 0) return (0); // Bad input buffer length throw new IllegalArgumentException("Bad input length: " + len); } // Encrypt/decrypt the input buffer if (m_decrypt) return (decryptData(in, inOff, len, out, outOff)); else return (encryptData(in, inOff, len, out, outOff)); } /*************************************************************************** * Add final input bytes to this cipher. * The added bytes are encrypted/decrypted, being appended to any input bytes * that were previously added to this cipher. * *

* See * {@link #engineDoFinal(byte[], int, int len, byte[], int) engineDoFinal()} * for more details. * * * @param in * Array of bytes to add as input to this cipher. * * @param off * Index of the first byte in array in to input to this cipher. * * @param len * Number of bytes in array in to input to this cipher. * * @return * Array of bytes suitably encrypted/decrypted by this cipher. * * @throws IllegalArgumentException (unchecked) * Thrown if len is negative. * * @throws IllegalStateException (unchecked) * Thrown if this cipher has not been initialized. * * @since 1.1, 2005-07-07 */ protected byte[] engineDoFinal(/*const*/ byte[] in, int off, int len) //overrides tribble.crypto.CipherSpi { byte[] outBuf; // Sanity check if (!m_init) throw new IllegalStateException("Cipher not initialized"); // Check args if (len <= 0) { if (len == 0) return (new byte[0]); // Bad input buffer length throw new IllegalArgumentException("Bad input length: " + len); } // Allocate an output buffer outBuf = new byte[len]; // Encrypt/decrypt from the input buffer to the output buffer try { engineDoFinal(in, off, len, outBuf, 0); } catch (ShortBufferException ex) { // Should not occur, ignore } // Return the output buffer return (outBuf); } /*************************************************************************** * Add final input bytes to this cipher. * The added bytes are encrypted/decrypted, being appended to any input bytes * that were previously added to this cipher. * *

* See * {@link #engineDoFinal(byte[], int, int len, byte[], int) engineDoFinal()} * for more details. * * * @param in * Array of bytes to add as input to this cipher. * * @param inOff * Index of the first byte in array in to input to this cipher. * * @param len * Number of bytes in array in to input to this cipher. * * @param out * Output array to write the resulting encrypted/decrypted bytes to. * * @param outOff * Index of the first byte in array out to write the resulting * output bytes to. * * @return * Number of output bytes produced by this cipher. * * @throws ShortBufferException * Thrown if the output buffer is too small to hold the resulting data. * * @throws IllegalArgumentException (unchecked) * Thrown if len is negative. * * @throws IllegalStateException (unchecked) * Thrown if this cipher has not been initialized. * * @since 1.1, 2005-07-07 */ protected int engineDoFinal(/*const*/ byte[] in, int inOff, int len, byte[] out, int outOff) throws ShortBufferException //overrides tribble.crypto.CipherSpi { int inLen; int outLen; // Sanity check if (!m_init) throw new IllegalStateException("Cipher not initialized"); // Check args if (len <= 0) { if (len == 0) return (0); // Bad input buffer length throw new IllegalArgumentException("Bad input length: " + len); } if (out.length - outOff < len) throw new ShortBufferException(); // Encrypt/decrypt the input buffer, updating this cipher if (m_decrypt) outLen = decryptData(in, inOff, len, out, outOff); else outLen = encryptData(in, inOff, len, out, outOff); return (outLen); } /*************************************************************************** * Wrap a cipher key into a raw encoded form. * * @param key * Key suitable for use with this cipher. * * @return * The key in a raw encoded format. * * @throws IllegalBlockSizeException * Thrown if key is not encoded with a block length supported by * this cipher. * * @throws InvalidKeyException * Thrown if key is not a valid key for this cipher. * * @throws UnsupportedOperationException (unchecked) * Thrown if this operation is not supported by this cipher. * * @see #engineUnwrap engineUnwrap() * * @since 1.1, 2005-09-09 */ protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException //overrides javax.crypto.CipherSpi { /*+++INCOMPLETE ...; +++*/ return (null); } /*************************************************************************** * Unwrap a cipher key from a raw encoded form. * * @param key * Key in a raw encoded format. * * @return * The key, decoded into a form suitable for use with this cipher. * * @throws InvalidKeyException * Thrown if key is not a valid key for this cipher. * * @throws NoSuchAlgorithmException * Thrown if key is not encoded in a recognizable form. * * @throws UnsupportedOperationException (unchecked) * Thrown if this operation is not supported by this cipher. * * @see #engineWrap engineWrap() * * @since 1.1, 2005-09-09 */ protected Key engineUnwrap(byte[] wrappedKey, String alg, int type) throws InvalidKeyException, NoSuchAlgorithmException //overrides javax.crypto.CipherSpi { /*+++INCOMPLETE ...; +++*/ return (null); } /*************************************************************************** * Clear (wipe) this cipher. * Erases all sensitive information contained within this object. * *

* This method is not part of the standard set defined in class * javax.crypto.CipherSpi, but is provided as a convenient * enhancement. * *

* Note that this cipher object is no longer usable after calling this * method. * * @since 1.1, 2005-07-05 */ protected void engineClear() //overriddes tribble.crypto.CipherSpi { // Wipe sensitive data m_ciph.clear(); if (m_state != null) { for (int i = 0; i < m_state.length; i++) m_state[i] = 0x00; m_state = null; } if (m_eBuf != null) { for (int i = 0; i < m_eBuf.length; i++) m_eBuf[i] = 0x00; m_eBuf = null; } super.engineClear(); } /*************************************************************************** * Encrypt an array of bytes using this cipher. * *

* This method handles blocking of the input data, operating modes, and so * forth required of generic symmetric block ciphers. * *

* The various stream cipher modes are handled by this method: *

* * * @param in * Array of bytes to encrypt. * * @param inOff * Index of the first byte of array in to encrypt. * * @param len * The number of bytes in array in to encrypt. * * @param out * Resulting encrypted output bytes. * * @param outOff * Index of the first byte of array out to write. * * @return * Number of encrypted bytes written into array out. * * @see #engineUpdate(byte[], int, int, byte[], int) engineUpdate() * @see #engineDoFinal(byte[], int, int, byte[], int) engineDoFinal() * @see #decryptData decryptData() * * @since 1.1, 2005-07-07 */ private int encryptData(/*const*/ byte[] in, int inOff, int len, byte[] out, int outOff) { byte[] eBuf; byte[] state; int blockLen; int flags; int cnt; int bcnt; // Set up flags = m_modeFlags; blockLen = m_blockLen; state = m_state; eBuf = m_eBuf; // Encrypt data from the input stream using the underlying block cipher cnt = len; bcnt = m_streamWidth; while (cnt-- > 0) { int p; int e; int x; // Read the next data byte from the input buffer p = in[inOff++]; if (bcnt >= m_streamWidth) { // Cycle the stream cipher through one round m_ciph.blockEncrypt(state, 0, eBuf, 0); bcnt = 0; } // Encrypt the input data byte e = eBuf[bcnt++]; x = p ^ e; if (flags == MODEFLAG_CTR) { // Increment the state block for (int i = blockLen-1; i >= 0; i--) if (++state[i] != 0x00) break; } else { // Shift the state block for (int i = 1; i < blockLen; i++) state[i-1] = state[i]; switch (flags) { case MODEFLAG_OFB: state[blockLen-1] = (byte) e; break; case MODEFLAG_CFB: state[blockLen-1] = (byte) x; break; case MODEFLAG_PFB: state[blockLen-1] = (byte) p; break; } } // Write the encrypted data byte to the output buffer out[outOff++] = (byte) x; } return (len); } /*************************************************************************** * Decrypt an array of bytes using this cipher. * *

* This method handles blocking of the input data, operating modes, and so * forth required of generic symmetric block ciphers. * *

* The various stream cipher modes are handled by this method: *

* * * @param in * Array of bytes to decrypt. * * @param inOff * Index of the first byte of array in to decrypt. * * @param len * The number of bytes in array in to decrypt. * * @param out * Resulting decrypted output bytes. * * @param outOff * Index of the first byte of array out to write. * * @return * Number of decrypted bytes written into array out. * * @throws ShortBufferException * Thrown if the output buffer is too small to hold the resulting data. * * @see #engineUpdate(byte[], int, int, byte[], int) engineUpdate() * @see #engineDoFinal(byte[], int, int, byte[], int) engineDoFinal() * @see #encryptData encryptData() * * @since 1.1, 2005-07-07 */ private int decryptData(/*const*/ byte[] in, int inOff, int len, byte[] out, int outOff) throws ShortBufferException { byte[] eBuf; byte[] state; int blockLen; int flags; int cnt; int bcnt; // Set up blockLen = m_blockLen; state = m_state; eBuf = m_eBuf; flags = m_modeFlags; // Decrypt data from the input stream using the underlying block cipher cnt = len; bcnt = m_streamWidth; while (cnt-- > 0) { int e; int p; int x; // Read the next data byte from the input buffer e = in[inOff++]; if (bcnt >= m_streamWidth) { // Cycle the stream cipher through one round m_ciph.blockEncrypt(state, 0, eBuf, 0); bcnt = 0; } // Decrypt the input data byte x = eBuf[bcnt++]; p = e ^ x; if (flags == MODEFLAG_CTR) { // Increment the state block for (int i = blockLen-1; i >= 0; i--) if (++state[i] != 0x00) break; } else { // Shift the state block for (int i = 1; i < blockLen; i++) state[i-1] = state[i]; switch (flags) { case MODEFLAG_OFB: state[blockLen-1] = (byte) x; break; case MODEFLAG_CFB: state[blockLen-1] = (byte) e; break; case MODEFLAG_PFB: state[blockLen-1] = (byte) p; break; } } // Write the decrypted data byte to the output buffer out[outOff++] = (byte) p; } return (len); } } // End StreamCipherSpi.java