123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- /* BaseMode.java --
- Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
- This file is a part of GNU Classpath.
- GNU Classpath is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or (at
- your option) any later version.
- GNU Classpath is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNU Classpath; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
- USA
- Linking this library statically or dynamically with other modules is
- making a combined work based on this library. Thus, the terms and
- conditions of the GNU General Public License cover the whole
- combination.
- As a special exception, the copyright holders of this library give you
- permission to link this library with independent modules to produce an
- executable, regardless of the license terms of these independent
- modules, and to copy and distribute the resulting executable under
- terms of your choice, provided that you also meet, for each linked
- independent module, the terms and conditions of the license of that
- module. An independent module is a module which is not derived from
- or based on this library. If you modify this library, you may extend
- this exception to your version of the library, but you are not
- obligated to do so. If you do not wish to do so, delete this
- exception statement from your version. */
- package gnu.javax.crypto.mode;
- import gnu.java.lang.CPStringBuilder;
- import gnu.javax.crypto.cipher.IBlockCipher;
- import java.security.InvalidKeyException;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map;
- /**
- * A basic abstract class to facilitate implementing block cipher modes of
- * operations.
- */
- public abstract class BaseMode
- implements IMode
- {
- /** The canonical name prefix of this mode. */
- protected String name;
- /** The state indicator of this instance. */
- protected int state;
- /** The underlying block cipher implementation. */
- protected IBlockCipher cipher;
- /** The block size, in bytes, to operate the underlying block cipher in. */
- protected int cipherBlockSize;
- /** The block size, in bytes, in which to operate the mode instance. */
- protected int modeBlockSize;
- /** The initialisation vector value. */
- protected byte[] iv;
- /** The instance lock. */
- protected Object lock = new Object();
- /**
- * Trivial constructor for use by concrete subclasses.
- *
- * @param name the canonical name prefix of this mode.
- * @param underlyingCipher the implementation of the underlying cipher.
- * @param cipherBlockSize the block size, in bytes, in which to operate the
- * underlying cipher.
- */
- protected BaseMode(String name, IBlockCipher underlyingCipher,
- int cipherBlockSize)
- {
- super();
- this.name = name;
- this.cipher = underlyingCipher;
- this.cipherBlockSize = cipherBlockSize;
- state = -1;
- }
- public void update(byte[] in, int inOffset, byte[] out, int outOffset)
- throws IllegalStateException
- {
- synchronized (lock)
- {
- switch (state)
- {
- case ENCRYPTION:
- encryptBlock(in, inOffset, out, outOffset);
- break;
- case DECRYPTION:
- decryptBlock(in, inOffset, out, outOffset);
- break;
- default:
- throw new IllegalStateException();
- }
- }
- }
- public String name()
- {
- return new CPStringBuilder(name).append('(').append(cipher.name()).append(')')
- .toString();
- }
- /**
- * Returns the default value, in bytes, of the mode's block size. This value
- * is part of the construction arguments passed to the Factory methods in
- * {@link ModeFactory}. Unless changed by an invocation of any of the
- * <code>init()</code> methods, a <i>Mode</i> instance would operate with
- * the same block size as its underlying block cipher. As mentioned earlier,
- * the block size of the underlying block cipher itself is specified in one of
- * the method(s) available in the factory class.
- *
- * @return the default value, in bytes, of the mode's block size.
- * @see ModeFactory
- */
- public int defaultBlockSize()
- {
- return cipherBlockSize;
- }
- /**
- * Returns the default value, in bytes, of the underlying block cipher key
- * size.
- *
- * @return the default value, in bytes, of the underlying cipher's key size.
- */
- public int defaultKeySize()
- {
- return cipher.defaultKeySize();
- }
- /**
- * Returns an {@link Iterator} over the supported block sizes. Each element
- * returned by this object is an {@link Integer}.
- * <p>
- * The default behaviour is to return an iterator with just one value, which
- * is that currently configured for the underlying block cipher. Concrete
- * implementations may override this behaviour to signal their ability to
- * support other values.
- *
- * @return an {@link Iterator} over the supported block sizes.
- */
- public Iterator blockSizes()
- {
- ArrayList al = new ArrayList();
- al.add(Integer.valueOf(cipherBlockSize));
- return Collections.unmodifiableList(al).iterator();
- }
- /**
- * Returns an {@link Iterator} over the supported underlying block cipher key
- * sizes. Each element returned by this object is an instance of
- * {@link Integer}.
- *
- * @return an {@link Iterator} over the supported key sizes.
- */
- public Iterator keySizes()
- {
- return cipher.keySizes();
- }
- public void init(Map attributes) throws InvalidKeyException,
- IllegalStateException
- {
- synchronized (lock)
- {
- if (state != -1)
- throw new IllegalStateException();
- Integer want = (Integer) attributes.get(STATE);
- if (want != null)
- {
- switch (want.intValue())
- {
- case ENCRYPTION:
- state = ENCRYPTION;
- break;
- case DECRYPTION:
- state = DECRYPTION;
- break;
- default:
- throw new IllegalArgumentException();
- }
- }
- Integer bs = (Integer) attributes.get(MODE_BLOCK_SIZE);
- modeBlockSize = (bs == null ? cipherBlockSize : bs.intValue());
- byte[] iv = (byte[]) attributes.get(IV);
- if (iv != null)
- this.iv = (byte[]) iv.clone();
- else
- this.iv = new byte[modeBlockSize];
- cipher.init(attributes);
- setup();
- }
- }
- public int currentBlockSize()
- {
- if (state == -1)
- throw new IllegalStateException();
- return modeBlockSize;
- }
- public void reset()
- {
- synchronized (lock)
- {
- state = -1;
- iv = null;
- cipher.reset();
- teardown();
- }
- }
- public boolean selfTest()
- {
- int ks;
- Iterator bit;
- for (Iterator kit = keySizes(); kit.hasNext();)
- {
- ks = ((Integer) kit.next()).intValue();
- for (bit = blockSizes(); bit.hasNext();)
- if (! testSymmetry(ks, ((Integer) bit.next()).intValue()))
- return false;
- }
- return true;
- }
- public abstract Object clone();
- /** The initialisation phase of the concrete mode implementation. */
- public abstract void setup();
- /** The termination phase of the concrete mode implementation. */
- public abstract void teardown();
- public abstract void encryptBlock(byte[] in, int i, byte[] out, int o);
- public abstract void decryptBlock(byte[] in, int i, byte[] out, int o);
- private boolean testSymmetry(int ks, int bs)
- {
- try
- {
- IMode mode = (IMode) this.clone();
- byte[] iv = new byte[cipherBlockSize]; // all zeroes
- byte[] k = new byte[ks];
- int i;
- for (i = 0; i < ks; i++)
- k[i] = (byte) i;
- int blockCount = 5;
- int limit = blockCount * bs;
- byte[] pt = new byte[limit];
- for (i = 0; i < limit; i++)
- pt[i] = (byte) i;
- byte[] ct = new byte[limit];
- byte[] cpt = new byte[limit];
- Map map = new HashMap();
- map.put(KEY_MATERIAL, k);
- map.put(CIPHER_BLOCK_SIZE, Integer.valueOf(cipherBlockSize));
- map.put(STATE, Integer.valueOf(ENCRYPTION));
- map.put(IV, iv);
- map.put(MODE_BLOCK_SIZE, Integer.valueOf(bs));
- mode.reset();
- mode.init(map);
- for (i = 0; i < blockCount; i++)
- mode.update(pt, i * bs, ct, i * bs);
- mode.reset();
- map.put(STATE, Integer.valueOf(DECRYPTION));
- mode.init(map);
- for (i = 0; i < blockCount; i++)
- mode.update(ct, i * bs, cpt, i * bs);
- return Arrays.equals(pt, cpt);
- }
- catch (Exception x)
- {
- x.printStackTrace(System.err);
- return false;
- }
- }
- }
|