001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.midp.crypto;
028:
029: /**
030: * This class implements the ARCfour stream cipher
031: */
032: public final class ARC4 extends Cipher {
033: /** Current cipher mode. */
034: private int mode;
035: /** Local certificate key. */
036: private SecretKey ckey = null;
037: /** Seed array. */
038: private byte[] S = null;
039: /** First intermediate result array. */
040: private int[] ii = null;
041: /** Second intermediate result array. */
042: private int[] jj = null;
043:
044: /**
045: * Constructor for algorithm 3 (ALG_ARCFOUR)
046: */
047: public void ARC4() {
048: mode = Cipher.MODE_UNINITIALIZED;
049: S = null;
050: ii = null;
051: jj = null;
052: }
053:
054: /**
055: * Called by the factory method to set the mode and padding parameters.
056: * Need because Class.newInstance does not take args.
057: *
058: * @param mode the mode parsed from the transformation parameter of
059: * getInstance and upper cased
060: * @param padding the paddinge parsed from the transformation parameter of
061: * getInstance and upper cased
062: *
063: * @exception NoSuchPaddingException if <code>transformation</code>
064: * contains a padding scheme that is not available
065: * @exception IllegalArgumentException if the mode is invalid for the
066: * cipher
067: */
068: protected void setChainingModeAndPadding(String mode, String padding)
069: throws NoSuchPaddingException {
070:
071: if (!(mode.equals("") || mode.equals("NONE"))) {
072: throw new IllegalArgumentException();
073: }
074:
075: // NOPADDING is not an option.
076: if (!(padding.equals("") || padding.equals("NOPADDING"))) {
077: throw new NoSuchPaddingException();
078: }
079: }
080:
081: /**
082: * Initializes the cipher's S-boxes based on the key.
083: * This code is based on the cipher's description in
084: * Bruce Schenier's "Applied Cryptography", Second Edition, pp 397-398,
085: * ISBN 0-471-11709-9
086: *
087: * @param opmode the operation mode of this cipher (this is one of the
088: * following:
089: * <code>ENCRYPT_MODE</code> or <code>DECRYPT_MODE</code>)
090: * @param key the encryption key
091: * @param params the algorithm parameters
092: *
093: * @exception InvalidKeyException if the given key is inappropriate for
094: * initializing this cipher, or its keysize exceeds the maximum allowable
095: * keysize.
096: * @exception InvalidAlgorithmParameterException if the given algorithm
097: * parameters are inappropriate for this cipher,
098: * or this cipher is being initialized for decryption and requires
099: * algorithm parameters and <code>params</code> is null, or the given
100: * algorithm parameters imply a cryptographic strength that would exceed
101: * the legal limits.
102: * @exception IllegalArgumentException if the opmode is invalid
103: */
104: public void init(int opmode, Key key, CryptoParameter params)
105: throws InvalidKeyException,
106: InvalidAlgorithmParameterException {
107:
108: if (!(key instanceof SecretKey)) {
109: throw new InvalidKeyException();
110: }
111:
112: if (opmode != Cipher.ENCRYPT_MODE
113: && opmode != Cipher.DECRYPT_MODE) {
114: throw new IllegalArgumentException();
115: }
116:
117: mode = opmode;
118: ckey = (SecretKey) key;
119:
120: // Initialize the counters
121: ii = new int[1];
122: ii[0] = 0;
123: jj = new int[1];
124: jj[0] = 0;
125:
126: S = new byte[256];
127:
128: // Initialize S
129: for (int i = 0; i < 256; i++) {
130: S[i] = (byte) i;
131: }
132:
133: // Initilaize K based on the key
134: byte[] K = new byte[256];
135: int index = 0;
136: while (index < 256) {
137: for (int i = 0; (i < ckey.secret.length) && (index < 256); i++) {
138: K[index++] = ckey.secret[i];
139: }
140: }
141:
142: // Populate the 8*8 S-box
143: int j = 0;
144: byte temp;
145: for (int i = 0; i < 256; i++) {
146: j = (j + ((S[i] + K[i]) & 0xff)) & 0xff;
147: temp = S[i];
148: S[i] = S[j];
149: S[j] = temp;
150: }
151: }
152:
153: /**
154: * Native function to transform a buffer.
155: * @param S array of S box values
156: * @param X first set intermediate results
157: * @param Y second set of intermediate results
158: * @param inbuf input buffer of data
159: * @param inoff offset in the provided input buffer
160: * @param inlen length of data to be processed
161: * @param outbuf output buffer of data
162: * @param outoff offset in the provided output buffer
163: */
164: private static native void nativetx(byte[] S, int[] X, int[] Y,
165: byte[] inbuf, int inoff, int inlen, byte[] outbuf,
166: int outoff);
167:
168: /**
169: * Transform a buffer of data,
170: * @param inBuf input buffer of data
171: * @param inOff offset in the provided input buffer
172: * @param inLen length of data to be processed
173: * @param outBuf output buffer of data
174: * @param outOff offset in the provided output buffer
175: * @return number of bytes copied to output buffer
176: */
177: private int transform(byte[] inBuf, int inOff, int inLen,
178: byte[] outBuf, int outOff) {
179: /*
180: * Normally, we would use something like:
181: * int test = inBuf[inOff] + inBuf[inLen - 1] +
182: * inBuf[inOff + inLen - 1] +
183: * outBuf[outOff] + outBuf[outOff + inLen - 1];
184: * to force an array bounds check that might otherwise crash
185: * the VM. However, since we have such checks in the update
186: * method, we do not need them here.
187: */
188: nativetx(S, ii, jj, inBuf, inOff, inLen, outBuf, outOff);
189: return inLen;
190: }
191:
192: /**
193: * Update the current data record.
194: *
195: * @param input the input buffer
196: * @param inputOffset the offset in <code>input</code> where the input
197: * starts
198: * @param inputLen the input length
199: * @param output the buffer for the result
200: * @param outputOffset the offset in <code>output</code> where the result
201: * is stored
202: *
203: * @return the number of bytes stored in <code>output</code>
204: *
205: * @exception IllegalStateException if this cipher is in a wrong state
206: * (e.g., has not been initialized)
207: * @exception ShortBufferException if the given output buffer is too small
208: * to hold the result
209: */
210: public int update(byte[] input, int inputOffset, int inputLen,
211: byte[] output, int outputOffset)
212: throws IllegalStateException, ShortBufferException {
213:
214: Util.checkBounds(input, inputOffset, inputLen, output,
215: outputOffset);
216:
217: if (mode == Cipher.MODE_UNINITIALIZED) {
218: throw new IllegalStateException();
219: }
220:
221: if (inputLen == 0) {
222: return 0;
223: }
224:
225: if (output.length - outputOffset < inputLen) {
226: throw new ShortBufferException();
227: }
228:
229: return transform(input, inputOffset, inputLen, output,
230: outputOffset);
231: }
232:
233: /**
234: * Encrypts or decrypts data in a single-part operation, or finishes a
235: * multiple-part operation. The data is encrypted or decrypted,
236: * depending on how this cipher was initialized.
237: *
238: * <p>The first <code>inputLen</code> bytes in the <code>input</code>
239: * buffer, starting at <code>inputOffset</code> inclusive, and any input
240: * bytes that may have been buffered during a previous
241: * <code>update</code> operation, are processed, with padding
242: * (if requested) being applied.
243: * The result is stored in the <code>output</code> buffer, starting at
244: * <code>outputOffset</code> inclusive.
245: *
246: * <p>If the <code>output</code> buffer is too small to hold the result,
247: * a <code>ShortBufferException</code> is thrown. In this case, repeat this
248: * call with a larger output buffer.
249: *
250: * <p>Upon finishing, this method resets this cipher object to the state
251: * it was in when previously initialized via a call to <code>init</code>.
252: * That is, the object is reset and available to encrypt or decrypt
253: * (depending on the operation mode that was specified in the call to
254: * <code>init</code>) more data.
255: *
256: * <p>Note: if any exception is thrown, this cipher object may need to
257: * be reset before it can be used again.
258: *
259: * <p>Note: this method should be copy-safe, which means the
260: * <code>input</code> and <code>output</code> buffers can reference
261: * the same byte array and no unprocessed input data is overwritten
262: * when the result is copied into the output buffer.
263: *
264: * @param input the input buffer
265: * @param inputOffset the offset in <code>input</code> where the input
266: * starts
267: * @param inputLen the input length
268: * @param output the buffer for the result
269: * @param outputOffset the offset in <code>output</code> where the result
270: * is stored
271: *
272: * @return the number of bytes stored in <code>output</code>
273: *
274: * @exception IllegalStateException if this cipher is in a wrong state
275: * (e.g., has not been initialized)
276: * @exception IllegalBlockSizeException if this cipher is a block cipher,
277: * no padding has been requested (only in encryption mode), and the total
278: * input length of the data processed by this cipher is not a multiple of
279: * block size
280: * @exception ShortBufferException if the given output buffer is too small
281: * to hold the result
282: * @exception BadPaddingException if this cipher is in decryption mode,
283: * and (un)padding has been requested, but the decrypted data is not
284: * bounded by the appropriate padding bytes
285: */
286: public int doFinal(byte[] input, int inputOffset, int inputLen,
287: byte[] output, int outputOffset)
288: throws IllegalStateException, ShortBufferException,
289: IllegalBlockSizeException, BadPaddingException {
290: int val = update(input, inputOffset, inputLen, output,
291: outputOffset);
292:
293: try {
294: init(mode, ckey);
295: } catch (InvalidKeyException ike) {
296: // ignore, the key was already checked
297: }
298:
299: return val;
300: }
301: }
|