The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1 | /* |
| 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 | |
| 19 | package org.apache.harmony.security.provider.crypto; |
| 20 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 21 | import java.security.DigestException; |
Jesse Wilson | 7365de1 | 2010-08-11 15:21:19 -0700 | [diff] [blame] | 22 | import java.security.MessageDigestSpi; |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 23 | import java.util.Arrays; |
| 24 | |
Elliott Hughes | b2da4ac | 2013-04-24 14:58:26 -0700 | [diff] [blame] | 25 | import static org.apache.harmony.security.provider.crypto.SHA1Constants.*; |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 26 | |
| 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 Hughes | b2da4ac | 2013-04-24 14:58:26 -0700 | [diff] [blame] | 32 | public class SHA1_MessageDigestImpl extends MessageDigestSpi implements Cloneable { |
Elliott Hughes | 171dc20 | 2010-09-02 11:06:55 -0700 | [diff] [blame] | 33 | private int[] buffer; // buffer has the following structure: |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 34 | // - 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 Hughes | 171dc20 | 2010-09-02 11:06:55 -0700 | [diff] [blame] | 40 | private byte[] oneByte; // one byte buffer needed to use in engineUpdate(byte) |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 41 | // having buffer as private field is just optimization |
| 42 | |
Brian Carlstrom | cbec51f | 2011-05-30 20:49:29 -0700 | [diff] [blame] | 43 | private long messageLength; // total length of bytes supplied by user |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 44 | |
| 45 | |
| 46 | /** |
| 47 | * The constructor creates needed buffers and sets the engine at initial state |
Elliott Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 48 | */ |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 49 | 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 Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 63 | * after processing its data, extra frame is prepared and |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 64 | * 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 Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 89 | // - buffer[BYTES_OFFSET] == 0 - buffer frame is empty, |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 90 | // 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 Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 97 | // - lastWord > 14 - last word in frame is not full; |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 98 | // 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 Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 143 | SHA1_MessageDigestImpl cloneObj = (SHA1_MessageDigestImpl) super.clone(); |
Elliott Hughes | 866e7ae | 2010-12-08 19:19:13 -0800 | [diff] [blame] | 144 | cloneObj.buffer = buffer.clone(); |
| 145 | cloneObj.oneByte = oneByte.clone(); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 146 | 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 Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 161 | byte[] hash = new byte[DIGEST_LENGTH]; |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 162 | 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 Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 173 | * The method overrides "engineDigest(byte[],int,int) in class MessageDigestSpi. |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 174 | * |
| 175 | * @param |
Elliott Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 176 | * buf byte array to store a message digest returned |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 177 | * @param |
Elliott Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 178 | * 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 Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 183 | * @return |
Elliott Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 184 | * the length of the message digest stored in the "buf" buffer; |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 185 | * in this implementation the length=20 |
| 186 | * |
Elliott Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 187 | * @throws IllegalArgumentException |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 188 | * 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 Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 192 | * @throws DigestException |
| 193 | * if len < 20 |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 194 | * |
Elliott Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 195 | * @throws ArrayIndexOutOfBoundsException |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 196 | * if offset < 0 |
| 197 | */ |
Elliott Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 198 | protected int engineDigest(byte[] buf, int offset, int len) throws DigestException { |
Elliott Hughes | 897538a | 2010-05-28 20:00:47 -0700 | [diff] [blame] | 199 | if (buf == null) { |
| 200 | throw new IllegalArgumentException("buf == null"); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 201 | } |
Elliott Hughes | 897538a | 2010-05-28 20:00:47 -0700 | [diff] [blame] | 202 | if (offset > buf.length || len > buf.length || (len + offset) > buf.length) { |
| 203 | throw new IllegalArgumentException(); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 204 | } |
Elliott Hughes | 897538a | 2010-05-28 20:00:47 -0700 | [diff] [blame] | 205 | if (len < DIGEST_LENGTH) { |
| 206 | throw new DigestException("len < DIGEST_LENGTH"); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 207 | } |
Elliott Hughes | 897538a | 2010-05-28 20:00:47 -0700 | [diff] [blame] | 208 | if (offset < 0) { |
Elliott Hughes | a160383 | 2010-12-10 18:20:56 -0800 | [diff] [blame] | 209 | throw new ArrayIndexOutOfBoundsException(offset); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 210 | } |
| 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 Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 226 | protected int engineGetDigestLength() { |
| 227 | return DIGEST_LENGTH; |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 228 | } |
Elliott Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 229 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 230 | |
| 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 Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 279 | * @throws NullPointerException |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 280 | * if null is passed to the "buf" argument |
| 281 | * |
Elliott Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 282 | * @throws IllegalArgumentException |
| 283 | * if offset > buf.length or len > buf.length or |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 284 | * (len + offset) > buf.length |
| 285 | * @throws ArrayIndexOutOfBoundsException |
| 286 | * offset < 0 |
| 287 | */ |
| 288 | protected void engineUpdate(byte[] input, int offset, int len) { |
Elliott Hughes | 897538a | 2010-05-28 20:00:47 -0700 | [diff] [blame] | 289 | if (input == null) { |
| 290 | throw new IllegalArgumentException("input == null"); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 291 | } |
Elliott Hughes | 897538a | 2010-05-28 20:00:47 -0700 | [diff] [blame] | 292 | if (len <= 0) { |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 293 | return; |
| 294 | } |
Elliott Hughes | 897538a | 2010-05-28 20:00:47 -0700 | [diff] [blame] | 295 | if (offset < 0) { |
Elliott Hughes | a160383 | 2010-12-10 18:20:56 -0800 | [diff] [blame] | 296 | throw new ArrayIndexOutOfBoundsException(offset); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 297 | } |
Elliott Hughes | 897538a | 2010-05-28 20:00:47 -0700 | [diff] [blame] | 298 | if (offset > input.length || len > input.length || (len + offset) > input.length) { |
| 299 | throw new IllegalArgumentException(); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 300 | } |
| 301 | |
| 302 | SHA1Impl.updateHash(buffer, input, offset, offset + len -1 ); |
| 303 | messageLength += len; |
| 304 | } |
| 305 | |
| 306 | } |