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.security.provider.crypto;
019:
020: import java.security.MessageDigestSpi;
021: import java.security.DigestException;
022:
023: import java.util.Arrays;
024:
025: import org.apache.harmony.security.internal.nls.Messages;
026: import org.apache.harmony.security.provider.crypto.SHA1_Data;
027: import org.apache.harmony.security.provider.crypto.SHA1Impl;
028:
029: /**
030: * This class extends the MessageDigestSpi class implementing all its abstract methods;
031: * it overrides the "Object clone()" and "int engineGetDigestLength()" methods. <BR>
032: * The class implements the Cloneable interface.
033: */
034:
035: public class SHA1_MessageDigestImpl extends MessageDigestSpi implements
036: Cloneable, SHA1_Data {
037:
038: private int buffer[]; // buffer has the following structure:
039: // - 0-16 - frame for accumulating a message
040: // - 17-79 - for SHA1Impl methods
041: // - 80 - unused
042: // - 81 - to store length of the message
043: // - 82-86 - frame for current message digest
044:
045: private byte oneByte[]; // one byte buffer needed to use in engineUpdate(byte)
046: // having buffer as private field is just optimization
047:
048: private int messageLength; // total length of bytes supplied by user
049:
050: /**
051: * The constructor creates needed buffers and sets the engine at initial state
052: */
053: public SHA1_MessageDigestImpl() {
054:
055: // BYTES_OFFSET +6 is minimal length required by methods in SHA1Impl
056: buffer = new int[BYTES_OFFSET + 6];
057:
058: oneByte = new byte[1];
059:
060: engineReset();
061: }
062:
063: /**
064: * The method performs final actions and invokes the "computeHash(int[])" method.
065: * In case if there is no enough words in current frame
066: * after processing its data, extra frame is prepared and
067: * the "computeHash(int[])" method is invoked second time. <BR>
068: *
069: * After processing, the method resets engine's state
070: *
071: * @param
072: * digest - byte array
073: * @param
074: * offset - offset in digest
075: */
076: private void processDigest(byte[] digest, int offset) {
077:
078: int i, j; // implementation variables
079: int lastWord; //
080:
081: long nBits = messageLength << 3; // length has to be calculated before padding
082:
083: engineUpdate((byte) 0x80); // beginning byte in padding
084:
085: i = 0; // i contains number of beginning word for following loop
086:
087: lastWord = (buffer[BYTES_OFFSET] + 3) >> 2; // computing of # of full words by shifting
088: // # of bytes
089:
090: // possible cases:
091: //
092: // - buffer[BYTES_OFFSET] == 0 - buffer frame is empty,
093: // padding byte was 64th in previous frame
094: // current frame should contain only message's length
095: //
096: // - lastWord < 14 - two last, these are 14 & 15, words in 16 word frame are free;
097: // no extra frame needed
098: // - lastWord = 14 - only one last, namely 15-th, word in frame doesn't contain bytes;
099: // extra frame is needed
100: // - lastWord > 14 - last word in frame is not full;
101: // extra frame is needed
102:
103: if (buffer[BYTES_OFFSET] != 0) {
104:
105: if (lastWord < 15) {
106: i = lastWord;
107: } else {
108: if (lastWord == 15) {
109: buffer[15] = 0; // last word in frame is set to "0"
110: }
111: SHA1Impl.computeHash(buffer);
112: i = 0;
113: }
114: }
115: Arrays.fill(buffer, i, 14, 0);
116:
117: buffer[14] = (int) (nBits >>> 32);
118: buffer[15] = (int) (nBits & 0xFFFFFFFF);
119: SHA1Impl.computeHash(buffer);
120:
121: // converting 5-word frame into 20 bytes
122: j = offset;
123: for (i = HASH_OFFSET; i < HASH_OFFSET + 5; i++) {
124: int k = buffer[i];
125: digest[j] = (byte) (k >>> 24); // getting first byte from left
126: digest[j + 1] = (byte) (k >>> 16); // getting second byte from left
127: digest[j + 2] = (byte) (k >>> 8); // getting third byte from left
128: digest[j + 3] = (byte) (k); // getting fourth byte from left
129: j += 4;
130: }
131:
132: engineReset();
133: }
134:
135: // methods specified in java.security.MessageDigestSpi
136:
137: /**
138: * Returns a "deep" copy of this SHA1MDImpl object. <BR>
139: *
140: * The method overrides "clone()" in class Object. <BR>
141: *
142: * @return
143: * a clone of this object
144: */
145: public Object clone() throws CloneNotSupportedException {
146:
147: SHA1_MessageDigestImpl cloneObj = (SHA1_MessageDigestImpl) super
148: .clone();
149:
150: cloneObj.buffer = (int[]) buffer.clone();
151: cloneObj.oneByte = (byte[]) oneByte.clone();
152:
153: return cloneObj;
154: }
155:
156: /**
157: * Computes a message digest value. <BR>
158: *
159: * The method resets the engine. <BR>
160: *
161: * The method overrides "engineDigest()" in class MessageDigestSpi. <BR>
162: *
163: * @return
164: * byte array containing message digest value
165: */
166: protected byte[] engineDigest() {
167:
168: byte[] hash = new byte[DIGEST_LENGTH];
169:
170: processDigest(hash, 0);
171: return hash;
172: }
173:
174: /**
175: * Computes message digest value.
176: * Upon return, the value is stored in "buf" buffer beginning "offset" byte. <BR>
177: *
178: * The method resets the engine. <BR>
179: *
180: * The method overrides "engineDigest(byte[],int,int) in class MessageDigestSpi.
181: *
182: * @param
183: * buf byte array to store a message digest returned
184: * @param
185: * offset a position in the array for first byte of the message digest
186: * @param
187: * len number of bytes within buffer allotted for the message digest;
188: * as this implementation doesn't provide partial digests,
189: * len should be >= 20, DigestException is thrown otherwise
190: * @return
191: * the length of the message digest stored in the "buf" buffer;
192: * in this implementation the length=20
193: *
194: * @throws IllegalArgumentException
195: * if null is passed to the "buf" argument <BR>
196: * if offset + len > buf.length <BR>
197: * if offset > buf.length or len > buf.length
198: *
199: * @throws DigestException
200: * if len < 20
201: *
202: * @throws ArrayIndexOutOfBoundsException
203: * if offset < 0
204: */
205: protected int engineDigest(byte[] buf, int offset, int len)
206: throws DigestException {
207:
208: if (buf == null) {
209: throw new IllegalArgumentException(Messages
210: .getString("security.162")); //$NON-NLS-1$
211: }
212: if (offset > buf.length || len > buf.length
213: || (len + offset) > buf.length) {
214: throw new IllegalArgumentException(Messages
215: .getString("security.163")); //$NON-NLS-1$
216: }
217: if (len < DIGEST_LENGTH) {
218: throw new DigestException(Messages
219: .getString("security.164")); //$NON-NLS-1$
220: }
221: if (offset < 0) {
222: throw new ArrayIndexOutOfBoundsException(Messages
223: .getString("security.165", offset)); //$NON-NLS-1$
224: }
225:
226: processDigest(buf, offset);
227:
228: return DIGEST_LENGTH;
229: }
230:
231: /**
232: * Returns a message digest length. <BR>
233: *
234: * The method overrides "engineGetDigestLength()" in class MessageDigestSpi. <BR>
235: *
236: * @return
237: * total length of current message digest as an int value
238: */
239: protected int engineGetDigestLength() {
240: return DIGEST_LENGTH;
241: }
242:
243: /**
244: * Resets the engine. <BR>
245: *
246: * The method overrides "engineReset()" in class MessageDigestSpi. <BR>
247: */
248: protected void engineReset() {
249:
250: messageLength = 0;
251:
252: buffer[BYTES_OFFSET] = 0;
253: buffer[HASH_OFFSET] = H0;
254: buffer[HASH_OFFSET + 1] = H1;
255: buffer[HASH_OFFSET + 2] = H2;
256: buffer[HASH_OFFSET + 3] = H3;
257: buffer[HASH_OFFSET + 4] = H4;
258: }
259:
260: /**
261: * Supplements a byte to current message. <BR>
262: *
263: * The method overrides "engineUpdate(byte)" in class MessageDigestSpi. <BR>
264: *
265: * @param
266: * input byte to add to current message
267: */
268: protected void engineUpdate(byte input) {
269:
270: oneByte[0] = input;
271: SHA1Impl.updateHash(buffer, oneByte, 0, 0);
272: messageLength++;
273: }
274:
275: /**
276: * Updates current message. <BR>
277: *
278: * The method overrides "engineUpdate(byte[],int,int)" in class MessageDigestSpi. <BR>
279: *
280: * The method silently returns if "len" <= 0.
281: *
282: * @param
283: * input a byte array
284: * @param
285: * offset a number of first byte in the "input" array to use for updating
286: * @param
287: * len a number of bytes to use
288: *
289: * @throws NullPointerException
290: * if null is passed to the "buf" argument
291: *
292: * @throws IllegalArgumentException
293: * if offset > buf.length or len > buf.length or
294: * (len + offset) > buf.length
295: * @throws ArrayIndexOutOfBoundsException
296: * offset < 0
297: */
298: protected void engineUpdate(byte[] input, int offset, int len) {
299:
300: if (input == null) {
301: throw new IllegalArgumentException(Messages
302: .getString("security.166")); //$NON-NLS-1$
303: }
304: if (len <= 0) {
305: return;
306: }
307: if (offset < 0) {
308: throw new ArrayIndexOutOfBoundsException(Messages
309: .getString("security.165", offset)); //$NON-NLS-1$
310: }
311: if (offset > input.length || len > input.length
312: || (len + offset) > input.length) {
313: throw new IllegalArgumentException(Messages
314: .getString("security.167")); //$NON-NLS-1$
315: }
316:
317: SHA1Impl.updateHash(buffer, input, offset, offset + len - 1);
318: messageLength += len;
319: }
320:
321: }
|