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 19package org.apache.harmony.security.provider.crypto; 20 21 22import java.security.MessageDigestSpi; 23import java.security.DigestException; 24 25import java.util.Arrays; 26 27import org.apache.harmony.security.internal.nls.Messages; 28import org.apache.harmony.security.provider.crypto.SHA1_Data; 29import org.apache.harmony.security.provider.crypto.SHA1Impl; 30 31 32/** 33 * This class extends the MessageDigestSpi class implementing all its abstract methods; 34 * it overrides the "Object clone()" and "int engineGetDigestLength()" methods. <BR> 35 * The class implements the Cloneable interface. 36 */ 37 38 39public class SHA1_MessageDigestImpl extends MessageDigestSpi 40 implements Cloneable, SHA1_Data { 41 42 43 private int buffer[]; // buffer has the following structure: 44 // - 0-16 - frame for accumulating a message 45 // - 17-79 - for SHA1Impl methods 46 // - 80 - unused 47 // - 81 - to store length of the message 48 // - 82-86 - frame for current message digest 49 50 private byte oneByte[]; // one byte buffer needed to use in engineUpdate(byte) 51 // having buffer as private field is just optimization 52 53 private int messageLength; // total length of bytes supplied by user 54 55 56 /** 57 * The constructor creates needed buffers and sets the engine at initial state 58 */ 59 public SHA1_MessageDigestImpl() { 60 61 // BYTES_OFFSET +6 is minimal length required by methods in SHA1Impl 62 buffer = new int[BYTES_OFFSET +6]; 63 64 oneByte = new byte[1]; 65 66 engineReset(); 67 } 68 69 70 /** 71 * The method performs final actions and invokes the "computeHash(int[])" method. 72 * In case if there is no enough words in current frame 73 * after processing its data, extra frame is prepared and 74 * the "computeHash(int[])" method is invoked second time. <BR> 75 * 76 * After processing, the method resets engine's state 77 * 78 * @param 79 * digest - byte array 80 * @param 81 * offset - offset in digest 82 */ 83 private void processDigest(byte[] digest, int offset) { 84 85 int i, j; // implementation variables 86 int lastWord; // 87 88 long nBits = messageLength <<3 ; // length has to be calculated before padding 89 90 engineUpdate( (byte) 0x80 ); // beginning byte in padding 91 92 i = 0; // i contains number of beginning word for following loop 93 94 lastWord = (buffer[BYTES_OFFSET] + 3)>>2 ; // computing of # of full words by shifting 95 // # of bytes 96 97 // possible cases: 98 // 99 // - buffer[BYTES_OFFSET] == 0 - buffer frame is empty, 100 // padding byte was 64th in previous frame 101 // current frame should contain only message's length 102 // 103 // - lastWord < 14 - two last, these are 14 & 15, words in 16 word frame are free; 104 // no extra frame needed 105 // - lastWord = 14 - only one last, namely 15-th, word in frame doesn't contain bytes; 106 // extra frame is needed 107 // - lastWord > 14 - last word in frame is not full; 108 // extra frame is needed 109 110 if ( buffer[BYTES_OFFSET] != 0 ) { 111 112 if ( lastWord < 15 ) { 113 i = lastWord; 114 } else { 115 if ( lastWord == 15 ) { 116 buffer[15] = 0; // last word in frame is set to "0" 117 } 118 SHA1Impl.computeHash(buffer); 119 i = 0; 120 } 121 } 122 Arrays.fill(buffer, i, 14, 0); 123 124 buffer[14] = (int)( nBits >>>32 ); 125 buffer[15] = (int)( nBits & 0xFFFFFFFF ); 126 SHA1Impl.computeHash(buffer); 127 128 // converting 5-word frame into 20 bytes 129 j = offset; 130 for ( i = HASH_OFFSET; i < HASH_OFFSET +5; i++ ) { 131 int k = buffer[i]; 132 digest[j ] = (byte) ( k >>>24 ); // getting first byte from left 133 digest[j+1] = (byte) ( k >>>16 ); // getting second byte from left 134 digest[j+2] = (byte) ( k >>> 8 ); // getting third byte from left 135 digest[j+3] = (byte) ( k ); // getting fourth byte from left 136 j += 4; 137 } 138 139 engineReset(); 140 } 141 142 // methods specified in java.security.MessageDigestSpi 143 144 /** 145 * Returns a "deep" copy of this SHA1MDImpl object. <BR> 146 * 147 * The method overrides "clone()" in class Object. <BR> 148 * 149 * @return 150 * a clone of this object 151 */ 152 public Object clone() throws CloneNotSupportedException { 153 154 SHA1_MessageDigestImpl cloneObj = (SHA1_MessageDigestImpl) super.clone(); 155 156 cloneObj.buffer = ( int[])buffer.clone(); 157 cloneObj.oneByte = (byte[])oneByte.clone(); 158 159 return cloneObj; 160 } 161 162 163 /** 164 * Computes a message digest value. <BR> 165 * 166 * The method resets the engine. <BR> 167 * 168 * The method overrides "engineDigest()" in class MessageDigestSpi. <BR> 169 * 170 * @return 171 * byte array containing message digest value 172 */ 173 protected byte[] engineDigest() { 174 175 byte[] hash = new byte[DIGEST_LENGTH]; 176 177 processDigest(hash, 0); 178 return hash; 179 } 180 181 182 /** 183 * Computes message digest value. 184 * Upon return, the value is stored in "buf" buffer beginning "offset" byte. <BR> 185 * 186 * The method resets the engine. <BR> 187 * 188 * The method overrides "engineDigest(byte[],int,int) in class MessageDigestSpi. 189 * 190 * @param 191 * buf byte array to store a message digest returned 192 * @param 193 * offset a position in the array for first byte of the message digest 194 * @param 195 * len number of bytes within buffer allotted for the message digest; 196 * as this implementation doesn't provide partial digests, 197 * len should be >= 20, DigestException is thrown otherwise 198 * @return 199 * the length of the message digest stored in the "buf" buffer; 200 * in this implementation the length=20 201 * 202 * @throws IllegalArgumentException 203 * if null is passed to the "buf" argument <BR> 204 * if offset + len > buf.length <BR> 205 * if offset > buf.length or len > buf.length 206 * 207 * @throws DigestException 208 * if len < 20 209 * 210 * @throws ArrayIndexOutOfBoundsException 211 * if offset < 0 212 */ 213 protected int engineDigest(byte[] buf, int offset, int len) throws DigestException { 214 215 if ( buf == null ) { 216 throw new IllegalArgumentException(Messages.getString("security.162")); //$NON-NLS-1$ 217 } 218 if ( offset > buf.length || len > buf.length || (len + offset) > buf.length ) { 219 throw new IllegalArgumentException( 220 Messages.getString("security.163")); //$NON-NLS-1$ 221 } 222 if ( len < DIGEST_LENGTH ) { 223 throw new DigestException(Messages.getString("security.164")); //$NON-NLS-1$ 224 } 225 if ( offset < 0 ) { 226 throw new ArrayIndexOutOfBoundsException(Messages.getString("security.165", offset)); //$NON-NLS-1$ 227 } 228 229 processDigest(buf, offset); 230 231 return DIGEST_LENGTH; 232 } 233 234 235 /** 236 * Returns a message digest length. <BR> 237 * 238 * The method overrides "engineGetDigestLength()" in class MessageDigestSpi. <BR> 239 * 240 * @return 241 * total length of current message digest as an int value 242 */ 243 protected int engineGetDigestLength() { 244 return DIGEST_LENGTH; 245 } 246 247 248 /** 249 * Resets the engine. <BR> 250 * 251 * The method overrides "engineReset()" in class MessageDigestSpi. <BR> 252 */ 253 protected void engineReset() { 254 255 messageLength = 0; 256 257 buffer[BYTES_OFFSET] = 0; 258 buffer[HASH_OFFSET ] = H0; 259 buffer[HASH_OFFSET +1] = H1; 260 buffer[HASH_OFFSET +2] = H2; 261 buffer[HASH_OFFSET +3] = H3; 262 buffer[HASH_OFFSET +4] = H4; 263 } 264 265 266 /** 267 * Supplements a byte to current message. <BR> 268 * 269 * The method overrides "engineUpdate(byte)" in class MessageDigestSpi. <BR> 270 * 271 * @param 272 * input byte to add to current message 273 */ 274 protected void engineUpdate(byte input) { 275 276 oneByte[0] = input; 277 SHA1Impl.updateHash( buffer, oneByte, 0, 0 ); 278 messageLength++; 279 } 280 281 282 /** 283 * Updates current message. <BR> 284 * 285 * The method overrides "engineUpdate(byte[],int,int)" in class MessageDigestSpi. <BR> 286 * 287 * The method silently returns if "len" <= 0. 288 * 289 * @param 290 * input a byte array 291 * @param 292 * offset a number of first byte in the "input" array to use for updating 293 * @param 294 * len a number of bytes to use 295 * 296 * @throws NullPointerException 297 * if null is passed to the "buf" argument 298 * 299 * @throws IllegalArgumentException 300 * if offset > buf.length or len > buf.length or 301 * (len + offset) > buf.length 302 * @throws ArrayIndexOutOfBoundsException 303 * offset < 0 304 */ 305 protected void engineUpdate(byte[] input, int offset, int len) { 306 307 if ( input == null ) { 308 throw new IllegalArgumentException(Messages.getString("security.166")); //$NON-NLS-1$ 309 } 310 if ( len <= 0 ) { 311 return; 312 } 313 if ( offset < 0 ) { 314 throw new ArrayIndexOutOfBoundsException(Messages.getString("security.165", offset)); //$NON-NLS-1$ 315 } 316 if ( offset > input.length || len > input.length || (len + offset) > input.length ) { 317 throw new IllegalArgumentException( 318 Messages.getString("security.167")); //$NON-NLS-1$ 319 } 320 321 SHA1Impl.updateHash(buffer, input, offset, offset + len -1 ); 322 messageLength += len; 323 } 324 325} 326