001: /* $Id: BlockCipher.java,v 1.1 2004/01/19 02:03:50 rgrimm Exp $
002: *
003: * Copyright (C) 1995-2000 The Cryptix Foundation Limited.
004: * All rights reserved.
005: *
006: * Use, modification, copying and distribution of this software is subject
007: * the terms and conditions of the Cryptix General Licence. You should have
008: * received a copy of the Cryptix General Licence along with this library;
009: * if not, you can download a copy from http://www.cryptix.org/ .
010: */
011: package cryptix.jce.provider.cipher;
012:
013: import java.security.AlgorithmParameters;
014: import java.security.InvalidAlgorithmParameterException;
015: import java.security.InvalidKeyException;
016: import java.security.Key;
017: import java.security.NoSuchAlgorithmException;
018: import java.security.NoSuchProviderException;
019: import java.security.SecureRandom;
020: import java.security.spec.AlgorithmParameterSpec;
021: import java.security.spec.InvalidParameterSpecException;
022: import javax.crypto.BadPaddingException;
023: import javax.crypto.Cipher;
024: import javax.crypto.CipherSpi;
025: import javax.crypto.IllegalBlockSizeException;
026: import javax.crypto.NoSuchPaddingException;
027: import javax.crypto.ShortBufferException;
028:
029: /**
030: * <p>
031: * A fully constructed Cipher instance looks like this:
032: * <pre>
033: * +------------------------------------------+
034: * | CipherSpi (API methods) |
035: * | |
036: * | +--------------------------------------+ |
037: * | | Padding | |
038: * | | | |
039: * | | +----------------------------------+ | |
040: * | | | Mode | | |
041: * | | | | | |
042: * | | | +------------------------------+ | | |
043: * | | | | CipherSpi | | | |
044: * | | | | (blockcipher implementation) | | | |
045: * | | | | | | | |
046: * | | | +------------------------------+ | | |
047: * | | | | | |
048: * | | +----------------------------------+ | |
049: * | | | |
050: * | +--------------------------------------+ |
051: * | |
052: * +------------------------------------------+
053: * </pre>
054: *
055: * @author Jeroen C. van Gelderen (gelderen@cryptix.org)
056: * @author Paul Waserbrot (pw@cryptix.org)
057: * @version $Revision: 1.1 $
058: */
059: public abstract class BlockCipher extends CipherSpi {
060:
061: // Variables and constants
062: //............................................................................
063:
064: /** State */
065: private int state = STATE_UNINITIALIZED;
066: private static final int STATE_UNINITIALIZED = 0,
067: STATE_DECRYPT = 1, STATE_ENCRYPT = 2;
068:
069: /** Our blocksize */
070: private final int BLOCK_SIZE;
071:
072: /** Our key. We need it when we reset ourselves. */
073: private Key key;
074:
075: /** What algorithm is used */
076: private String algorithm;
077:
078: private Padding padding;
079:
080: private Mode mode;
081:
082: // Constructors and Object() methods
083: //............................................................................
084:
085: /**
086: * Construct a new BlockCipher (CipherSpi) with an zero-length name ""
087: * and given block size.
088: */
089: protected BlockCipher(int blockSize) {
090: this ("", blockSize);
091: }
092:
093: /**
094: * Construct a new BlockCipher (CipherSpi) with the given name and
095: * block size.
096: */
097: protected BlockCipher(String algorithm, int blockSize) {
098: super ();
099:
100: BLOCK_SIZE = blockSize;
101: this .algorithm = algorithm;
102:
103: try {
104: // set default mode and padding
105: this .mode = Mode.getInstance("ECB", this );
106: this .padding = Padding.getInstance("None", this .mode);
107: } catch (NoSuchPaddingException e) {
108: throw new InternalError(
109: "PANIC: Installation corrupt, default padding not available.");
110: } catch (NoSuchAlgorithmException E) {
111: throw new InternalError(
112: "PANIC: Installation corrupt, default mode not available.");
113: }
114: }
115:
116: /**
117: * Always throws a CloneNotSupportedException (cloning of ciphers is not
118: * supported for security reasons).
119: */
120: public final Object clone() throws CloneNotSupportedException {
121: throw new CloneNotSupportedException();
122: }
123:
124: // CipherSPI implementation
125: //............................................................................
126:
127: protected final void engineSetMode(String mode)
128: throws NoSuchAlgorithmException {
129: this .mode = Mode.getInstance(mode, this );
130: }
131:
132: protected final void engineSetPadding(String padding)
133: throws NoSuchPaddingException {
134: this .padding = Padding.getInstance(padding, this .mode);
135: }
136:
137: protected final int engineGetBlockSize() {
138: return padding.getBlockSize();
139: }
140:
141: protected int engineGetKeySize(Key key) throws InvalidKeyException {
142: if (key == null)
143: throw new IllegalArgumentException("Key missing");
144:
145: if (!key.getFormat().equalsIgnoreCase("RAW"))
146: throw new InvalidKeyException(
147: "Wrong format: RAW bytes needed");
148:
149: byte[] userkey = key.getEncoded();
150: if (userkey == null)
151: throw new InvalidKeyException("RAW bytes missing");
152:
153: return (userkey.length * 8);
154: }
155:
156: /**
157: * Returns the length in bytes that an output buffer would need to be in
158: * order to hold the result of the next update or doFinal operation, given
159: * the input length <code>inputLen</code> (in bytes).
160: *
161: * This call takes into account any unprocessed (buffered) data from a
162: * previous update call(s), and padding.
163: *
164: * The actual output length of the next <code>update or doFinal</code> call
165: * may be smaller than the length returned by this method. For ciphers with
166: * a padding, calling the update method will generally return less data
167: * than predicted by this function.
168: *
169: * @param inputLen the length in bytes.
170: *
171: * @return the maximum amount of data that the cipher will return.
172: */
173: protected final int engineGetOutputSize(int inputLen) {
174: return padding.getOutputSize(inputLen);
175: }
176:
177: /**
178: * Returns a copy of the initialization vector (IV) used in this cipher.
179: *
180: * @return A copy of the IV or null if this cipher does not have an IV or
181: * null if the IV has not yet been set.
182: */
183: protected final byte[] engineGetIV() {
184: return padding.getIV();
185: }
186:
187: protected final AlgorithmParameters engineGetParameters() {
188: AlgorithmParameterSpec aps = padding.getParamSpec();
189:
190: if (aps == null)
191: return (AlgorithmParameters) null;
192:
193: // Fix the parameters
194: AlgorithmParameters ap = null;
195: try {
196: ap = AlgorithmParameters.getInstance(algorithm,
197: "CryptixCrypto");
198: ap.init(aps);
199: } catch (InvalidParameterSpecException e) {
200: throw new RuntimeException(
201: "PANIC: Unreachable code reached.");
202: } catch (NoSuchAlgorithmException e) {
203: throw new RuntimeException(
204: "PANIC: Unreachable code reached.");
205: } catch (NoSuchProviderException e) {
206: throw new RuntimeException(
207: "PANIC: Unreachable code reached.");
208: }
209: return ap;
210: }
211:
212: /**
213: * Initialize this blockcipher for encryption or decryption.
214: *
215: * If the cipher requires randomness, it is taken from <code>random</code>.
216: * Randomness is required for modes that use IVs and might be required for
217: * some padding schemes.
218: *
219: * @param opmode Cipher.ENCRYPT_MODE or Cipher.DECRYPT_MODE.
220: * @param key secret key
221: * @param random source of randomness
222: */
223: protected final void engineInit(int opmode, Key key,
224: SecureRandom random) throws InvalidKeyException {
225: AlgorithmParameterSpec aps = padding.getParamSpec();
226: try {
227: this .engineInit(opmode, key, aps, random);
228: } catch (InvalidAlgorithmParameterException e) {
229: throw new InternalError("Unreachable code reached.");
230: }
231: }
232:
233: protected final void engineInit(int opmode, Key key,
234: AlgorithmParameterSpec params, SecureRandom random)
235: throws InvalidKeyException,
236: InvalidAlgorithmParameterException {
237: boolean decrypt = (opmode == Cipher.DECRYPT_MODE); // FIXME?
238: padding.init(decrypt, key, params, random);
239: }
240:
241: protected final void // FIXME: add this to cipher suite?? (pw)
242: engineInit(int opmode, Key key, AlgorithmParameters params,
243: SecureRandom random) throws InvalidKeyException,
244: InvalidAlgorithmParameterException {
245: throw new RuntimeException("Not supported on this cipher.");
246: }
247:
248: protected final int engineUpdate(byte[] input, int inputOffset,
249: int inputLen, byte[] output, int outputOffset)
250: throws ShortBufferException {
251: if (inputLen == 0)
252: return 0;
253: return padding.update(input, inputOffset, inputLen, output,
254: outputOffset);
255: }
256:
257: /** Implemented in terms of engineUpdate(byte[], int, int, byte[], int) */
258: protected final byte[] engineUpdate(byte[] input, int inputOffset,
259: int inputLen) {
260: if (inputLen == 0)
261: return null;
262: try {
263: byte[] tmp = new byte[this .engineGetOutputSize(inputLen)];
264: int i = this .engineUpdate(input, inputOffset, inputLen,
265: tmp, 0);
266: if (i != tmp.length) {
267: byte[] t = new byte[i];
268: System.arraycopy(tmp, 0, t, 0, i);
269: tmp = t;
270: }
271: return tmp;
272: } catch (ShortBufferException e) {
273: throw new RuntimeException(
274: "PANIC: Unreachable code reached.");
275: }
276: }
277:
278: /**
279: * @throws BadPaddingException
280: * (decryption only) if padding is expected but not found at the
281: * end of the data or the padding is found but corrupt
282: * @throws IllegalBlockSizeException
283: * if no padding is specified and the input data is not a multiple
284: * of the blocksize.
285: * @throws ShortBufferException if the given buffer is to short to hold
286: * the result.
287: */
288: protected final int engineDoFinal(byte[] input, int inputOffset,
289: int inputLen, byte[] output, int outputOffset)
290: throws ShortBufferException, IllegalBlockSizeException,
291: BadPaddingException {
292: return padding.doFinal(input, inputOffset, inputLen, output,
293: outputOffset);
294: }
295:
296: /**
297: * Implemented in terms of engineDoFinal(byte[], int, int, byte[], int)
298: *
299: * @throws BadPaddingException
300: * (decryption only) if padding is expected but not found at the
301: * end of the data.
302: * @throws IllegalBlockSizeException
303: * if no padding is specified and the input data is not a multiple
304: * of the blocksize.
305: */
306: protected final byte[] engineDoFinal(byte[] input, int inputOffset,
307: int inputLen) throws IllegalBlockSizeException,
308: BadPaddingException {
309: try {
310: byte[] tmp = new byte[this .engineGetOutputSize(inputLen)];
311: int i = this .engineDoFinal(input, inputOffset, inputLen,
312: tmp, 0);
313: if (i != tmp.length) {
314: byte[] t = new byte[i];
315: System.arraycopy(tmp, 0, t, 0, i);
316: tmp = t;
317: }
318:
319: return tmp;
320: } catch (ShortBufferException e) {
321: throw new RuntimeException(
322: "PANIC: Unreachable code reached.");
323: }
324: }
325:
326: // Abstract BPI methods
327: //
328: // The abstract methods are overridden by the actual cipher implementations
329: // The core* methods are called from within the Mode* classes
330: //.............................................................................
331:
332: abstract void coreInit(Key key, boolean decrypt)
333: throws InvalidKeyException;
334:
335: /**
336: * Encrypt a given buffer. in and out can point to the same buffer if
337: * (outOffset == inOffset) || (outOffset >= (inOffset+coreGetBlockSize))
338: * That is: the buffers may not partially overlap...
339: */
340: abstract void coreCrypt(byte[] in, int inOffset, byte[] out,
341: int outOffset);
342:
343: int coreGetBlockSize() {
344: return BLOCK_SIZE;
345: }
346: }
|