001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.harmony.luni.util;
019:
020: import java.io.OutputStream;
021:
022: /**
023: * This class implements the Secure Hash Algorithm, SHA-1. The specification can
024: * be found at http://csrc.ncsl.nist.gov/fips/fip180-1.txt
025: */
026: public class SHAOutputStream extends OutputStream implements Cloneable {
027:
028: /* Constants as in the specification */
029:
030: // K in iterations 0..19, from spec
031: private static final int K0_19 = 0x5a827999;
032:
033: // K in iterations 20..39, from spec
034: private static final int K20_39 = 0x6ed9eba1;
035:
036: // K in iterations 40..59, from spec
037: private static final int K40_59 = 0x8f1bbcdc;
038:
039: // K in iterations 60..79, from spec
040: private static final int K60_79 = 0xca62c1d6;
041:
042: // H0, from spec
043: private static final int H0 = 0x67452301;
044:
045: // H1, from spec
046: private static final int H1 = 0xefcdab89;
047:
048: // H2, from spec
049: private static final int H2 = 0x98badcfe;
050:
051: // H3, from spec
052: private static final int H3 = 0x10325476;
053:
054: // H4, from spec
055: private static final int H4 = 0xc3d2e1f0;
056:
057: private static final int HConstantsSize = 5;
058:
059: private static final int HashSizeInBytes = 20;
060:
061: // 16 words
062: private static final int BlockSizeInBytes = 16 * 4;
063:
064: // 80 words
065: private static final int WArraySize = 80;
066:
067: // 5-word Array. Starts with well-known constants, ends with SHA
068: private int[] HConstants;
069:
070: // 80-word Array.
071: private int[] WArray;
072:
073: // 16-word Array. Input bit stream M is divided in chunks of MArray
074: private byte[] MArray;
075:
076: // Number of bytes of input already processed towards SHA result
077: private long bytesProcessed;
078:
079: // Number of bytes in WArray not processed yet
080: private int bytesToProcess;
081:
082: // Optimization, for write
083: private byte[] oneByte = new byte[1];
084:
085: /**
086: * Constructs a new SHAOutputStream.
087: */
088: public SHAOutputStream() {
089: super ();
090: initialize();
091: reset();
092: }
093:
094: /**
095: * Constructs a new MD5OutputStream with the given initial state.
096: *
097: * @param state The initial state of the output stream. This is what will be
098: * returned by getHash() if write() is never called.
099: *
100: * @throws IllegalArgumentException if state.length is less than 16.
101: */
102: public SHAOutputStream(byte[] state) {
103: this ();
104:
105: if (state.length < HashSizeInBytes) {
106: throw new IllegalArgumentException();
107: }
108:
109: for (int i = 0; i < 4; i++) {
110: HConstants[i] = 0;
111: for (int j = 0; j < 4; j++) {
112: HConstants[i] += (state[4 * i + j] & 0xFF) << 8 * (3 - j);
113: }
114: }
115: }
116:
117: /**
118: * Answers a new instance of the same class as the receiver, whose slots
119: * have been filled in with the values in the slots of the receiver.
120: * <p>
121: * Classes which wish to support cloning must specify that they implement
122: * the Cloneable interface, since the native implementation checks for this.
123: *
124: * @return a complete copy of this object
125: * @throws CloneNotSupportedException if the component does not implement
126: * the interface Cloneable
127: */
128: @Override
129: public Object clone() throws CloneNotSupportedException {
130: // Calling super takes care of primitive type slots
131: SHAOutputStream result = (SHAOutputStream) super .clone();
132: result.HConstants = this .HConstants.clone();
133: result.WArray = this .WArray.clone();
134: result.MArray = this .MArray.clone();
135: result.oneByte = this .oneByte.clone();
136: return result;
137: }
138:
139: /**
140: * Copies a byte array into the receiver's internal buffer, making the
141: * adjustments as necessary and keeping the receiver in a consistent state.
142: *
143: * @param buffer byte array representation of the bytes
144: * @param off offset into the source buffer where to start the copying
145: * @param len how many bytes in the source byte array to copy
146: *
147: */
148: private void copyToInternalBuffer(byte[] buffer, int off, int len) {
149: int index;
150: index = off;
151: for (int i = bytesToProcess; i < bytesToProcess + len; i++) {
152: MArray[i] = buffer[index];
153: index++;
154: }
155: bytesToProcess = bytesToProcess + len;
156: }
157:
158: /**
159: * Returns an int array (length = 5) with the SHA value of the bytes written
160: * to the receiver.
161: *
162: * @return The 5 ints that form the SHA value of the bytes written to
163: * the receiver
164: */
165: public int[] getHash() {
166: this .padBuffer();
167: this .processBuffer();
168: int[] result = HConstants.clone();
169: // After the user asks for the hash value, the stream is put back to the
170: // initial state
171: reset();
172: return result;
173: }
174:
175: /**
176: * Returns a byte array (length = 20) with the SHA value of the bytes
177: * written to the receiver.
178: *
179: * @return The bytes that form the SHA value of the bytes written to
180: * the receiver
181: */
182: public byte[] getHashAsBytes() {
183: byte[] hash = new byte[HashSizeInBytes];
184: this .padBuffer();
185: this .processBuffer();
186:
187: // We need to return HConstants (modified by the loop) as an array of
188: // bytes. A memcopy would be the fastest.
189: for (int i = 0; i < (HashSizeInBytes / 4); ++i) {
190: hash[i * 4] = (byte) (HConstants[i] >>> 24 & 0xff);
191: hash[i * 4 + 1] = (byte) (HConstants[i] >>> 16 & 0xff);
192: hash[i * 4 + 2] = (byte) (HConstants[i] >>> 8 & 0xff);
193: hash[i * 4 + 3] = (byte) (HConstants[i] & 0xff);
194: }
195: // After the user asks for the hash value, the stream is put back to the
196: // initial state
197: reset();
198: return hash;
199: }
200:
201: /**
202: * Returns a byte array (length = 20) with the SHA value of the bytes
203: * written to the receiver.
204: *
205: * @return The bytes that form the SHA value of the bytes written to
206: * the receiver
207: */
208: public byte[] getHashAsBytes(boolean pad) {
209: byte[] hash = new byte[HashSizeInBytes];
210: if (pad) {
211: this .padBuffer();
212: this .processBuffer();
213: }
214:
215: // Convert HConstants to an array of bytes
216: for (int i = 0; i < (HashSizeInBytes / 4); i++) {
217: hash[i * 4] = (byte) (HConstants[i] >>> 24 & 0xff);
218: hash[i * 4 + 1] = (byte) (HConstants[i] >>> 16 & 0xff);
219: hash[i * 4 + 2] = (byte) (HConstants[i] >>> 8 & 0xff);
220: hash[i * 4 + 3] = (byte) (HConstants[i] & 0xff);
221: }
222: // After the user asks for the hash value, the stream is put back to the
223: // initial state
224: reset();
225: return hash;
226: }
227:
228: /**
229: * Initializes the receiver.
230: */
231: private void initialize() {
232: HConstants = new int[HConstantsSize];
233: MArray = new byte[BlockSizeInBytes];
234: WArray = new int[WArraySize];
235: }
236:
237: /**
238: * Adds extra bytes to the bit stream as required (see the SHA
239: * specification).
240: */
241: private void padBuffer() {
242: long lengthInBits;
243: MArray[bytesToProcess] = (byte) 0x80;
244: for (int i = bytesToProcess + 1; i < BlockSizeInBytes; i++) {
245: MArray[i] = (byte) 0;
246: }
247: // Get length now because there might be extra padding (length in bits)
248: lengthInBits = (bytesToProcess + bytesProcessed) * 8;
249:
250: // 9 extra bytes are needed: 1 for 1000... and 8 for length (long)
251: if ((bytesToProcess + 9) > BlockSizeInBytes) {
252: // Not enough space to append length. We need another block for
253: // padding
254: // Padding in this buffer only includes 1000000....
255: this .processBuffer();
256: // Now put 0's in all the buffer. memfill would be faster
257: for (int i = 0; i < BlockSizeInBytes; i++) {
258: MArray[i] = (byte) 0;
259: }
260: }
261:
262: for (int i = 1; i < 9; i++) {
263: MArray[BlockSizeInBytes - i] = (byte) (lengthInBits & 0xff);
264: lengthInBits = lengthInBits >>> 8;
265: }
266: }
267:
268: /**
269: * Core SHA code. Processes the receiver's buffer of bits, computing the
270: * values towards the final SHA
271: */
272: private void processBuffer() {
273: int A; // A variable, from spec
274: int B; // B variable, from spec
275: int C; // C variable, from spec
276: int D; // D variable, from spec
277: int E; // E variable, from spec
278: int temp; // TEMP, from spec
279: int t; // t, for iteration, from spec
280:
281: for (t = 0; t <= 15; t++) { // step a, page 7 of spec. Here we convert 4
282: // bytes into 1 word, 16 times
283: WArray[t] = (MArray[4 * t] & 0xff) << 24
284: | ((MArray[4 * t + 1] & 0xff) << 16)
285: | ((MArray[4 * t + 2] & 0xff) << 8)
286: | (MArray[4 * t + 3] & 0xff);
287: }
288: for (t = 16; t <= 79; t++) { // step b, page 7 of spec
289: temp = (WArray[t - 3] ^ WArray[t - 8] ^ WArray[t - 14] ^ WArray[t - 16]);
290: temp = (temp << 1) | (temp >>> (32 - 1)); // element , Circular
291: // Shift Left by 1
292: WArray[t] = temp;
293: }
294:
295: // step c, page 7 of spec
296: A = HConstants[0];
297: B = HConstants[1];
298: C = HConstants[2];
299: D = HConstants[3];
300: E = HConstants[4];
301:
302: // step d, page 8 of spec
303: for (t = 0; t <= 19; t++) {
304: temp = (A << 5) | (A >>> (32 - 5)); // A , Circular Shift Left by 5
305: temp = temp + E + WArray[t] + K0_19;
306: temp = temp + ((B & C) | (~B & D));
307: E = D;
308: D = C;
309: C = (B << 30) | (B >>> (32 - 30)); // B , Circular Shift Left by 30
310: B = A;
311: A = temp;
312: }
313: for (t = 20; t <= 39; t++) {
314: temp = (A << 5) | (A >>> (32 - 5)); // A , Circular Shift Left by 5
315: temp = temp + E + WArray[t] + K20_39;
316: temp = temp + (B ^ C ^ D);
317: E = D;
318: D = C;
319: C = (B << 30) | (B >>> (32 - 30)); // B , Circular Shift Left by 30
320: B = A;
321: A = temp;
322: }
323: for (t = 40; t <= 59; t++) {
324: temp = (A << 5) | (A >>> (32 - 5)); // A , Circular Shift Left by 5
325: temp = temp + E + WArray[t] + K40_59;
326: temp = temp + ((B & C) | (B & D) | (C & D));
327: E = D;
328: D = C;
329: C = (B << 30) | (B >>> (32 - 30)); // B , Circular Shift Left by 30
330: B = A;
331: A = temp;
332: }
333: for (t = 60; t <= 79; t++) {
334: temp = (A << 5) | (A >>> (32 - 5)); // A , Circular Shift Left by 5
335: temp = temp + E + WArray[t] + K60_79;
336: temp = temp + (B ^ C ^ D);
337: E = D;
338: D = C;
339: C = (B << 30) | (B >>> (32 - 30)); // B , Circular Shift Left by 30
340: B = A;
341: A = temp;
342: }
343:
344: // step e, page 8 of spec
345: HConstants[0] = HConstants[0] + A;
346: HConstants[1] = HConstants[1] + B;
347: HConstants[2] = HConstants[2] + C;
348: HConstants[3] = HConstants[3] + D;
349: HConstants[4] = HConstants[4] + E;
350: // Update number of bytes actually processed
351: bytesProcessed = bytesProcessed + BlockSizeInBytes;
352: bytesToProcess = 0; // No pending bytes in the block
353:
354: }
355:
356: /**
357: * Reset this SHAOutputStream to the state it was before any byte was
358: * written to it.
359: */
360: public void reset() {
361: HConstants[0] = H0;
362: HConstants[1] = H1;
363: HConstants[2] = H2;
364: HConstants[3] = H3;
365: HConstants[4] = H4;
366: bytesProcessed = 0;
367: bytesToProcess = 0;
368: }
369:
370: @Override
371: public String toString() {
372: return this .getClass().getName() + ':'
373: + toStringBlock(getHashAsBytes());
374: }
375:
376: /**
377: * Converts a block to a String representation.
378: *
379: * @param block
380: * byte array representation of the bytes
381: */
382: private static String toStringBlock(byte[] block) {
383: return toStringBlock(block, 0, block.length);
384: }
385:
386: /**
387: * Converts a block to a String representation.
388: *
389: * @param block
390: * byte array representation of the bytes
391: * @param off
392: * offset into the block where to start the conversion
393: * @param len
394: * how many bytes in the byte array to convert to a printable
395: * representation
396: */
397: private static String toStringBlock(byte[] block, int off, int len) {
398: String hexdigits = "0123456789ABCDEF";
399: StringBuilder buf = new StringBuilder();
400: buf.append('[');
401: for (int i = off; i < off + len; ++i) {
402: buf.append(hexdigits.charAt((block[i] >>> 4) & 0xf));
403: buf.append(hexdigits.charAt(block[i] & 0xf));
404: }
405: buf.append(']');
406: return buf.toString();
407: }
408:
409: /**
410: * Writes <code>len</code> <code>bytes</code> from this byte array
411: * <code>buffer</code> starting at offset <code>off</code> to the
412: * SHAOutputStream. The internal buffer used to compute SHA is updated, and
413: * the incremental computation of SHA is also performed.
414: *
415: * @param buffer
416: * the buffer to be written
417: * @param off
418: * offset in buffer to get bytes
419: * @param len
420: * number of bytes in buffer to write
421: */
422: @Override
423: public void write(byte[] buffer, int off, int len) {
424: int spaceLeft;
425: int start;
426: int bytesLeft;
427: spaceLeft = BlockSizeInBytes - bytesToProcess;
428: if (len < spaceLeft) { // Extra bytes are not enough to fill buffer
429: this .copyToInternalBuffer(buffer, off, len);
430: return;
431: }
432: // Extra bytes are bigger than space in buffer. Process buffer multiple
433: // times
434: this .copyToInternalBuffer(buffer, off, spaceLeft);
435: bytesLeft = len - spaceLeft;
436: this .processBuffer();
437: start = off + spaceLeft;
438: while (bytesLeft >= BlockSizeInBytes) {
439: this .copyToInternalBuffer(buffer, start, BlockSizeInBytes);
440: bytesLeft = bytesLeft - BlockSizeInBytes;
441: this .processBuffer();
442: start = start + BlockSizeInBytes;
443: }
444: if (bytesLeft > 0) {
445: // Extra bytes at the end, not enough to fill buffer
446: this .copyToInternalBuffer(buffer, start, bytesLeft);
447: }
448: }
449:
450: /**
451: * Writes the specified byte <code>b</code> to this OutputStream. Only the
452: * low order byte of <code>b</code> is written.
453: *
454: * @param b
455: * the byte to be written
456: */
457: @Override
458: public void write(int b) {
459: // Not thread-safe because we use a shared one-byte buffer
460: oneByte[0] = (byte) b;
461: write(oneByte, 0, 1);
462: }
463: }
|