001: /**
002: * Copyright (c) 2003, www.pdfbox.org
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * 1. Redistributions of source code must retain the above copyright notice,
009: * this list of conditions and the following disclaimer.
010: * 2. Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: * 3. Neither the name of pdfbox; nor the names of its
014: * contributors may be used to endorse or promote products derived from this
015: * software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
021: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: *
028: * http://www.pdfbox.org
029: *
030: */package org.pdfbox.encryption;
031:
032: import java.io.IOException;
033: import java.io.InputStream;
034: import java.io.OutputStream;
035:
036: /**
037: * This class is an implementation of the alleged RC4 algorithm.
038: *
039: * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
040: * @version $Revision: 1.8 $
041: */
042: public class ARCFour {
043: private int[] salt;
044: private int b;
045: private int c;
046:
047: /**
048: * Constructor.
049: *
050: */
051: public ARCFour() {
052: salt = new int[256];
053: }
054:
055: /**
056: * This will reset the key to be used.
057: *
058: * @param key The RC4 key used during encryption.
059: */
060: public void setKey(byte[] key) {
061: b = 0;
062: c = 0;
063:
064: if (key.length < 1 || key.length > 32) {
065: throw new IllegalArgumentException(
066: "number of bytes must be between 1 and 32");
067: }
068: for (int i = 0; i < salt.length; i++) {
069: salt[i] = i;
070: }
071:
072: int keyIndex = 0;
073: int saltIndex = 0;
074: for (int i = 0; i < salt.length; i++) {
075: saltIndex = (fixByte(key[keyIndex]) + salt[i] + saltIndex) % 256;
076: swap(salt, i, saltIndex);
077: keyIndex = (keyIndex + 1) % key.length;
078: }
079:
080: }
081:
082: /**
083: * Thie will ensure that the value for a byte >=0.
084: *
085: * @param aByte The byte to test against.
086: *
087: * @return A value >=0 and < 256
088: */
089: private static final int fixByte(byte aByte) {
090: return aByte < 0 ? 256 + aByte : aByte;
091: }
092:
093: /**
094: * This will swap two values in an array.
095: *
096: * @param data The array to swap from.
097: * @param firstIndex The index of the first element to swap.
098: * @param secondIndex The index of the second element to swap.
099: */
100: private static final void swap(int[] data, int firstIndex,
101: int secondIndex) {
102: int tmp = data[firstIndex];
103: data[firstIndex] = data[secondIndex];
104: data[secondIndex] = tmp;
105: }
106:
107: /**
108: * This will encrypt and write the next byte.
109: *
110: * @param aByte The byte to encrypt.
111: * @param output The stream to write to.
112: *
113: * @throws IOException If there is an error writing to the output stream.
114: */
115: public void write(byte aByte, OutputStream output)
116: throws IOException {
117: b = (b + 1) % 256;
118: c = (salt[b] + c) % 256;
119: swap(salt, b, c);
120: int saltIndex = (salt[b] + salt[c]) % 256;
121: output.write(aByte ^ (byte) salt[saltIndex]);
122: }
123:
124: /**
125: * This will encrypt and write the data.
126: *
127: * @param data The data to encrypt.
128: * @param output The stream to write to.
129: *
130: * @throws IOException If there is an error writing to the output stream.
131: */
132: public void write(byte[] data, OutputStream output)
133: throws IOException {
134: for (int i = 0; i < data.length; i++) {
135: write(data[i], output);
136: }
137: }
138:
139: /**
140: * This will encrypt and write the data.
141: *
142: * @param data The data to encrypt.
143: * @param output The stream to write to.
144: *
145: * @throws IOException If there is an error writing to the output stream.
146: */
147: public void write(InputStream data, OutputStream output)
148: throws IOException {
149: byte[] buffer = new byte[1024];
150: int amountRead = 0;
151: while ((amountRead = data.read(buffer)) != -1) {
152: write(buffer, 0, amountRead, output);
153: }
154: }
155:
156: /**
157: * This will encrypt and write the data.
158: *
159: * @param data The data to encrypt.
160: * @param offset The offset into the array to start reading data from.
161: * @param len The number of bytes to attempt to read.
162: * @param output The stream to write to.
163: *
164: * @throws IOException If there is an error writing to the output stream.
165: */
166: public void write(byte[] data, int offset, int len,
167: OutputStream output) throws IOException {
168: for (int i = offset; i < offset + len; i++) {
169: write(data[i], output);
170: }
171: }
172: }
|