001: /*
002: * @(#)RC4.java 1.9 01/08/21
003: *
004: * Copyright (c) 2000-2001 Sun Microsystems, Inc., 901 San Antonio Road,
005: * Palo Alto, CA 94303, U.S.A. All Rights Reserved.
006: *
007: * Sun Microsystems, Inc. has intellectual property rights relating
008: * to the technology embodied in this software. In particular, and
009: * without limitation, these intellectual property rights may include
010: * one or more U.S. patents, foreign patents, or pending
011: * applications. Sun, Sun Microsystems, the Sun logo, Java, KJava,
012: * and all Sun-based and Java-based marks are trademarks or
013: * registered trademarks of Sun Microsystems, Inc. in the United
014: * States and other countries.
015: *
016: * This software is distributed under licenses restricting its use,
017: * copying, distribution, and decompilation. No part of this
018: * software may be reproduced in any form by any means without prior
019: * written authorization of Sun and its licensors, if any.
020: *
021: * FEDERAL ACQUISITIONS: Commercial Software -- Government Users
022: * Subject to Standard License Terms and Conditions
023: */
024: package com.sun.portal.kssl;
025:
026: import com.sun.portal.ksecurity.Key;
027: import com.sun.portal.ksecurity.SecretKey;
028: import com.sun.portal.ksecurity.KeyBuilder;
029: import com.sun.portal.ksecurity.CryptoException;
030:
031: /**
032: * This class implements the ARCfour stream cipher
033: */
034: final class RC4 extends Cipher {
035: /** Current cipher type. */
036: private byte type;
037: /** Current cipher mode. */
038: private byte mode;
039: /** Local certificate key. */
040: private Key ckey = null;
041: /** Seed array. */
042: private byte[] S = null;
043: /** First intermediate result array. */
044: private int ii;
045: /** Second intermediate result array. */
046: private int jj;
047:
048: /**
049: * Constructor for algorithm 3 (ALG_ARCFOUR)
050: */
051: public void RC4() {
052: type = Cipher.ALG_ARCFOUR;
053: mode = Cipher.MODE_UNKNOWN;
054: S = null;
055: ii = 0;
056: jj = 0;
057: }
058:
059: /**
060: * Get the alorithm (ALG_ARCFOUR).
061: * @return algorithm 3 code
062: */
063: public byte getAlgorithm() {
064: return Cipher.ALG_ARCFOUR;
065: }
066:
067: /**
068: * Initialize the alorithm with initial data. (Not supported)
069: * @param theKey public key
070: * @param theMode mode of operation
071: * @param b buffer of data
072: * @param off offset in the provided buffer
073: * @param len length of data to be processed
074: * @exception CryptoException is thrown, because the method
075: * is not supported.
076: */
077: public void init(Key theKey, byte theMode, byte[] b, int off,
078: int len) throws CryptoException {
079: // ARCfour does not require additional parameters (IV, for example)
080: throw new CryptoException(CryptoException.ILLEGAL_USE);
081: }
082:
083: /**
084: * Initializes the cipher's S-boxes based on the key.
085: * This code is based on the cipher's description in
086: * Bruce Schenier's "Applied Cryptography", Second Edition, pp 397-398,
087: * ISBN 0-471-11709-9
088: * @param theKey public key
089: * @param theMode mode of operation
090: * @exception CryptoException is thrown, if there is an error
091: * in the arguments.
092: */
093: public void init(Key theKey, byte theMode) throws CryptoException {
094: if ((theKey.getType() != KeyBuilder.TYPE_ARCFOUR)
095: || ((theMode != Cipher.MODE_ENCRYPT) && (theMode != Cipher.MODE_DECRYPT))) {
096: throw new CryptoException(CryptoException.ILLEGAL_VALUE);
097: }
098:
099: mode = theMode;
100: ckey = theKey;
101:
102: // Initialize the counters
103: ii = 0;
104: jj = 0;
105:
106: S = new byte[256];
107: byte[] key = new byte[(theKey.getSize() + 7) >>> 3];
108: ((SecretKey) theKey).getKey(key, (short) 0);
109:
110: // Initialize S
111: for (int i = 0; i < 256; i++)
112: S[i] = (byte) i;
113:
114: // Initilaize K based on the key
115: byte[] K = new byte[256];
116: int index = 0;
117: while (index < 256) {
118: for (int i = 0; (i < key.length) && (index < 256); i++) {
119: K[index++] = key[i];
120: }
121: }
122:
123: // Populate the 8*8 S-box
124: int j = 0;
125: byte temp;
126: for (int i = 0; i < 256; i++) {
127: j = (j + ((S[i] + K[i]) & 0xff)) & 0xff;
128: temp = S[i];
129: S[i] = S[j];
130: S[j] = temp;
131: }
132: }
133:
134: /**
135: * Native function to transform a buffer.
136: * @param S array of S box values
137: * @param X first set intermediate results
138: * @param Y second set of intermediate results
139: * @param inbuf input buffer of data
140: * @param inoff offset in the provided input buffer
141: * @param inlen length of data to be processed
142: * @param outbuf output buffer of data
143: * @param outoff offset in the provided output buffer
144: private static native void nativetx(byte[] S, int[] X, int[] Y,
145: byte[] inbuf, int inoff, int inlen,
146: byte[] outbuf, int outoff);
147: */
148:
149: /**
150: * Transform a buffer of data,
151: * @param inBuf input buffer of data
152: * @param inOff offset in the provided input buffer
153: * @param inLen length of data to be processed
154: * @param outBuf output buffer of data
155: * @param outOff offset in the provided output buffer
156: * @return number of bytes copied to output buffer
157: */
158:
159: public int transform(byte[] inBuf, int inOff, int inLen,
160: byte[] outBuf, int outOff) {
161: byte tmp;
162: int t;
163: byte kt;
164:
165: // We don't use loop unrolling since a typical processor for
166: // the Kjava platform is unlikely to benefit from it. Conserving
167: // memory is likely to be more important
168: for (int i = 0; i < inLen; i++) {
169: ii = (ii + 1) & 0xff;
170: tmp = S[ii];
171: jj = (jj + (tmp & 0xff)) & 0xff;
172: S[ii] = S[jj];
173: S[jj] = tmp;
174: t = (S[ii] + tmp) & 0xff;
175: kt = S[t];
176: outBuf[outOff + i] = (byte) (inBuf[inOff + i] ^ kt);
177: }
178:
179: return inLen;
180: }
181:
182: // private int transform(byte[] inBuf, int inOff, int inLen,
183: // byte[] outBuf, int outOff) {
184: /*
185: * Normally, we would use something like:
186: * int test = inBuf[inOff] + inBuf[inLen - 1] +
187: * inBuf[inOff + inLen - 1] +
188: * outBuf[outOff] + outBuf[outOff + inLen - 1];
189: * to force an array bounds check that might otherwise crash
190: * the VM. However, since we have such checks in the update
191: * method, we do not need them here.
192: */
193: //nativetx(S, ii, jj, inBuf, inOff, inLen, outBuf, outOff);
194: // return inLen;
195: // }
196:
197: /**
198: * Update the current data record.
199: *
200: * @param inBuf input buffer of data
201: * @param inOff offset in the provided input buffer
202: * @param inLen length of data to be processed
203: * @param outBuf output buffer of data
204: * @param outOff offset in the provided output buffer
205: * @return number of bytes copied to output buffer
206: * @exception CryptoException is thrown, if there are errors in the arguments
207: */
208: public int update(byte[] inBuf, int inOff, int inLen,
209: byte[] outBuf, int outOff) throws CryptoException {
210: if ((inLen < 0) || (inOff + inLen > inBuf.length)
211: || (outOff + inLen > outBuf.length)) {
212: throw new CryptoException(CryptoException.ILLEGAL_USE);
213: }
214:
215: if (mode == Cipher.MODE_UNKNOWN) {
216: throw new CryptoException(CryptoException.INVALID_INIT);
217: }
218:
219: if (inLen == 0) {
220: return 0;
221: }
222:
223: return transform(inBuf, inOff, inLen, outBuf, outOff);
224: }
225:
226: /**
227: * Process the final data record.
228: *
229: * @param inBuf input buffer of data
230: * @param inOff offset in the provided input buffer
231: * @param inLen length of data to be processed
232: * @param outBuf output buffer of data
233: * @param outOff offset in the provided output buffer
234: * @return number of bytes copied to output buffer
235: * @exception CryptoException is thrown, if there are errors
236: * in the arguments
237: */
238: public int doFinal(byte[] inBuf, int inOff, int inLen,
239: byte[] outBuf, int outOff) throws CryptoException {
240: int val = update(inBuf, inOff, inLen, outBuf, outOff);
241: init(ckey, mode);
242: return val;
243: }
244: }
|