blob: 3f41f182be8e4ad3dd70f866f7f2a66a95cb7cee [file] [log] [blame]
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
19package org.apache.harmony.security.provider.crypto;
20
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080021import java.security.DigestException;
Jesse Wilson7365de12010-08-11 15:21:19 -070022import java.security.MessageDigestSpi;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080023import java.util.Arrays;
24
Elliott Hughesb2da4ac2013-04-24 14:58:26 -070025import static org.apache.harmony.security.provider.crypto.SHA1Constants.*;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080026
27/**
28 * This class extends the MessageDigestSpi class implementing all its abstract methods;
29 * it overrides the "Object clone()" and "int engineGetDigestLength()" methods. <BR>
30 * The class implements the Cloneable interface.
31 */
Elliott Hughesb2da4ac2013-04-24 14:58:26 -070032public class SHA1_MessageDigestImpl extends MessageDigestSpi implements Cloneable {
Elliott Hughes171dc202010-09-02 11:06:55 -070033 private int[] buffer; // buffer has the following structure:
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080034 // - 0-16 - frame for accumulating a message
35 // - 17-79 - for SHA1Impl methods
36 // - 80 - unused
37 // - 81 - to store length of the message
38 // - 82-86 - frame for current message digest
39
Elliott Hughes171dc202010-09-02 11:06:55 -070040 private byte[] oneByte; // one byte buffer needed to use in engineUpdate(byte)
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080041 // having buffer as private field is just optimization
42
Brian Carlstromcbec51f2011-05-30 20:49:29 -070043 private long messageLength; // total length of bytes supplied by user
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080044
45
46 /**
47 * The constructor creates needed buffers and sets the engine at initial state
Elliott Hughesf33eae72010-05-13 12:36:25 -070048 */
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080049 public SHA1_MessageDigestImpl() {
50
51 // BYTES_OFFSET +6 is minimal length required by methods in SHA1Impl
52 buffer = new int[BYTES_OFFSET +6];
53
54 oneByte = new byte[1];
55
56 engineReset();
57 }
58
59
60 /**
61 * The method performs final actions and invokes the "computeHash(int[])" method.
62 * In case if there is no enough words in current frame
Elliott Hughesf33eae72010-05-13 12:36:25 -070063 * after processing its data, extra frame is prepared and
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080064 * the "computeHash(int[])" method is invoked second time. <BR>
65 *
66 * After processing, the method resets engine's state
67 *
68 * @param
69 * digest - byte array
70 * @param
71 * offset - offset in digest
72 */
73 private void processDigest(byte[] digest, int offset) {
74
75 int i, j; // implementation variables
76 int lastWord; //
77
78 long nBits = messageLength <<3 ; // length has to be calculated before padding
79
80 engineUpdate( (byte) 0x80 ); // beginning byte in padding
81
82 i = 0; // i contains number of beginning word for following loop
83
84 lastWord = (buffer[BYTES_OFFSET] + 3)>>2 ; // computing of # of full words by shifting
85 // # of bytes
86
87 // possible cases:
88 //
Elliott Hughesf33eae72010-05-13 12:36:25 -070089 // - buffer[BYTES_OFFSET] == 0 - buffer frame is empty,
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080090 // padding byte was 64th in previous frame
91 // current frame should contain only message's length
92 //
93 // - lastWord < 14 - two last, these are 14 & 15, words in 16 word frame are free;
94 // no extra frame needed
95 // - lastWord = 14 - only one last, namely 15-th, word in frame doesn't contain bytes;
96 // extra frame is needed
Elliott Hughesf33eae72010-05-13 12:36:25 -070097 // - lastWord > 14 - last word in frame is not full;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080098 // extra frame is needed
99
100 if ( buffer[BYTES_OFFSET] != 0 ) {
101
102 if ( lastWord < 15 ) {
103 i = lastWord;
104 } else {
105 if ( lastWord == 15 ) {
106 buffer[15] = 0; // last word in frame is set to "0"
107 }
108 SHA1Impl.computeHash(buffer);
109 i = 0;
110 }
111 }
112 Arrays.fill(buffer, i, 14, 0);
113
114 buffer[14] = (int)( nBits >>>32 );
115 buffer[15] = (int)( nBits & 0xFFFFFFFF );
116 SHA1Impl.computeHash(buffer);
117
118 // converting 5-word frame into 20 bytes
119 j = offset;
120 for ( i = HASH_OFFSET; i < HASH_OFFSET +5; i++ ) {
121 int k = buffer[i];
122 digest[j ] = (byte) ( k >>>24 ); // getting first byte from left
123 digest[j+1] = (byte) ( k >>>16 ); // getting second byte from left
124 digest[j+2] = (byte) ( k >>> 8 ); // getting third byte from left
125 digest[j+3] = (byte) ( k ); // getting fourth byte from left
126 j += 4;
127 }
128
129 engineReset();
130 }
131
132 // methods specified in java.security.MessageDigestSpi
133
134 /**
135 * Returns a "deep" copy of this SHA1MDImpl object. <BR>
136 *
137 * The method overrides "clone()" in class Object. <BR>
138 *
139 * @return
140 * a clone of this object
141 */
142 public Object clone() throws CloneNotSupportedException {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800143 SHA1_MessageDigestImpl cloneObj = (SHA1_MessageDigestImpl) super.clone();
Elliott Hughes866e7ae2010-12-08 19:19:13 -0800144 cloneObj.buffer = buffer.clone();
145 cloneObj.oneByte = oneByte.clone();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800146 return cloneObj;
147 }
148
149
150 /**
151 * Computes a message digest value. <BR>
152 *
153 * The method resets the engine. <BR>
154 *
155 * The method overrides "engineDigest()" in class MessageDigestSpi. <BR>
156 *
157 * @return
158 * byte array containing message digest value
159 */
160 protected byte[] engineDigest() {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800161 byte[] hash = new byte[DIGEST_LENGTH];
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800162 processDigest(hash, 0);
163 return hash;
164 }
165
166
167 /**
168 * Computes message digest value.
169 * Upon return, the value is stored in "buf" buffer beginning "offset" byte. <BR>
170 *
171 * The method resets the engine. <BR>
172 *
Elliott Hughesf33eae72010-05-13 12:36:25 -0700173 * The method overrides "engineDigest(byte[],int,int) in class MessageDigestSpi.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800174 *
175 * @param
Elliott Hughesf33eae72010-05-13 12:36:25 -0700176 * buf byte array to store a message digest returned
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800177 * @param
Elliott Hughesf33eae72010-05-13 12:36:25 -0700178 * offset a position in the array for first byte of the message digest
179 * @param
180 * len number of bytes within buffer allotted for the message digest;
181 * as this implementation doesn't provide partial digests,
182 * len should be >= 20, DigestException is thrown otherwise
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800183 * @return
Elliott Hughesf33eae72010-05-13 12:36:25 -0700184 * the length of the message digest stored in the "buf" buffer;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800185 * in this implementation the length=20
186 *
Elliott Hughesf33eae72010-05-13 12:36:25 -0700187 * @throws IllegalArgumentException
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800188 * if null is passed to the "buf" argument <BR>
189 * if offset + len > buf.length <BR>
190 * if offset > buf.length or len > buf.length
191 *
Elliott Hughesf33eae72010-05-13 12:36:25 -0700192 * @throws DigestException
193 * if len < 20
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800194 *
Elliott Hughesf33eae72010-05-13 12:36:25 -0700195 * @throws ArrayIndexOutOfBoundsException
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800196 * if offset < 0
197 */
Elliott Hughesf33eae72010-05-13 12:36:25 -0700198 protected int engineDigest(byte[] buf, int offset, int len) throws DigestException {
Elliott Hughes897538a2010-05-28 20:00:47 -0700199 if (buf == null) {
200 throw new IllegalArgumentException("buf == null");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800201 }
Elliott Hughes897538a2010-05-28 20:00:47 -0700202 if (offset > buf.length || len > buf.length || (len + offset) > buf.length) {
203 throw new IllegalArgumentException();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800204 }
Elliott Hughes897538a2010-05-28 20:00:47 -0700205 if (len < DIGEST_LENGTH) {
206 throw new DigestException("len < DIGEST_LENGTH");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800207 }
Elliott Hughes897538a2010-05-28 20:00:47 -0700208 if (offset < 0) {
Elliott Hughesa1603832010-12-10 18:20:56 -0800209 throw new ArrayIndexOutOfBoundsException(offset);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800210 }
211
212 processDigest(buf, offset);
213
214 return DIGEST_LENGTH;
215 }
216
217
218 /**
219 * Returns a message digest length. <BR>
220 *
221 * The method overrides "engineGetDigestLength()" in class MessageDigestSpi. <BR>
222 *
223 * @return
224 * total length of current message digest as an int value
225 */
Elliott Hughesf33eae72010-05-13 12:36:25 -0700226 protected int engineGetDigestLength() {
227 return DIGEST_LENGTH;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800228 }
Elliott Hughesf33eae72010-05-13 12:36:25 -0700229
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800230
231 /**
232 * Resets the engine. <BR>
233 *
234 * The method overrides "engineReset()" in class MessageDigestSpi. <BR>
235 */
236 protected void engineReset() {
237
238 messageLength = 0;
239
240 buffer[BYTES_OFFSET] = 0;
241 buffer[HASH_OFFSET ] = H0;
242 buffer[HASH_OFFSET +1] = H1;
243 buffer[HASH_OFFSET +2] = H2;
244 buffer[HASH_OFFSET +3] = H3;
245 buffer[HASH_OFFSET +4] = H4;
246 }
247
248
249 /**
250 * Supplements a byte to current message. <BR>
251 *
252 * The method overrides "engineUpdate(byte)" in class MessageDigestSpi. <BR>
253 *
254 * @param
255 * input byte to add to current message
256 */
257 protected void engineUpdate(byte input) {
258
259 oneByte[0] = input;
260 SHA1Impl.updateHash( buffer, oneByte, 0, 0 );
261 messageLength++;
262 }
263
264
265 /**
266 * Updates current message. <BR>
267 *
268 * The method overrides "engineUpdate(byte[],int,int)" in class MessageDigestSpi. <BR>
269 *
270 * The method silently returns if "len" <= 0.
271 *
272 * @param
273 * input a byte array
274 * @param
275 * offset a number of first byte in the "input" array to use for updating
276 * @param
277 * len a number of bytes to use
278 *
Elliott Hughesf33eae72010-05-13 12:36:25 -0700279 * @throws NullPointerException
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800280 * if null is passed to the "buf" argument
281 *
Elliott Hughesf33eae72010-05-13 12:36:25 -0700282 * @throws IllegalArgumentException
283 * if offset > buf.length or len > buf.length or
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800284 * (len + offset) > buf.length
285 * @throws ArrayIndexOutOfBoundsException
286 * offset < 0
287 */
288 protected void engineUpdate(byte[] input, int offset, int len) {
Elliott Hughes897538a2010-05-28 20:00:47 -0700289 if (input == null) {
290 throw new IllegalArgumentException("input == null");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800291 }
Elliott Hughes897538a2010-05-28 20:00:47 -0700292 if (len <= 0) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800293 return;
294 }
Elliott Hughes897538a2010-05-28 20:00:47 -0700295 if (offset < 0) {
Elliott Hughesa1603832010-12-10 18:20:56 -0800296 throw new ArrayIndexOutOfBoundsException(offset);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800297 }
Elliott Hughes897538a2010-05-28 20:00:47 -0700298 if (offset > input.length || len > input.length || (len + offset) > input.length) {
299 throw new IllegalArgumentException();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800300 }
301
302 SHA1Impl.updateHash(buffer, input, offset, offset + len -1 );
303 messageLength += len;
304 }
305
306}