| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| |
| package org.apache.harmony.security.provider.crypto; |
| |
| |
| import java.security.DigestException; |
| import java.security.MessageDigestSpi; |
| import java.util.Arrays; |
| |
| |
| /** |
| * This class extends the MessageDigestSpi class implementing all its abstract methods; |
| * it overrides the "Object clone()" and "int engineGetDigestLength()" methods. <BR> |
| * The class implements the Cloneable interface. |
| */ |
| |
| |
| public class SHA1_MessageDigestImpl extends MessageDigestSpi implements Cloneable, SHA1_Data { |
| private int[] buffer; // buffer has the following structure: |
| // - 0-16 - frame for accumulating a message |
| // - 17-79 - for SHA1Impl methods |
| // - 80 - unused |
| // - 81 - to store length of the message |
| // - 82-86 - frame for current message digest |
| |
| private byte[] oneByte; // one byte buffer needed to use in engineUpdate(byte) |
| // having buffer as private field is just optimization |
| |
| private long messageLength; // total length of bytes supplied by user |
| |
| |
| /** |
| * The constructor creates needed buffers and sets the engine at initial state |
| */ |
| public SHA1_MessageDigestImpl() { |
| |
| // BYTES_OFFSET +6 is minimal length required by methods in SHA1Impl |
| buffer = new int[BYTES_OFFSET +6]; |
| |
| oneByte = new byte[1]; |
| |
| engineReset(); |
| } |
| |
| |
| /** |
| * The method performs final actions and invokes the "computeHash(int[])" method. |
| * In case if there is no enough words in current frame |
| * after processing its data, extra frame is prepared and |
| * the "computeHash(int[])" method is invoked second time. <BR> |
| * |
| * After processing, the method resets engine's state |
| * |
| * @param |
| * digest - byte array |
| * @param |
| * offset - offset in digest |
| */ |
| private void processDigest(byte[] digest, int offset) { |
| |
| int i, j; // implementation variables |
| int lastWord; // |
| |
| long nBits = messageLength <<3 ; // length has to be calculated before padding |
| |
| engineUpdate( (byte) 0x80 ); // beginning byte in padding |
| |
| i = 0; // i contains number of beginning word for following loop |
| |
| lastWord = (buffer[BYTES_OFFSET] + 3)>>2 ; // computing of # of full words by shifting |
| // # of bytes |
| |
| // possible cases: |
| // |
| // - buffer[BYTES_OFFSET] == 0 - buffer frame is empty, |
| // padding byte was 64th in previous frame |
| // current frame should contain only message's length |
| // |
| // - lastWord < 14 - two last, these are 14 & 15, words in 16 word frame are free; |
| // no extra frame needed |
| // - lastWord = 14 - only one last, namely 15-th, word in frame doesn't contain bytes; |
| // extra frame is needed |
| // - lastWord > 14 - last word in frame is not full; |
| // extra frame is needed |
| |
| if ( buffer[BYTES_OFFSET] != 0 ) { |
| |
| if ( lastWord < 15 ) { |
| i = lastWord; |
| } else { |
| if ( lastWord == 15 ) { |
| buffer[15] = 0; // last word in frame is set to "0" |
| } |
| SHA1Impl.computeHash(buffer); |
| i = 0; |
| } |
| } |
| Arrays.fill(buffer, i, 14, 0); |
| |
| buffer[14] = (int)( nBits >>>32 ); |
| buffer[15] = (int)( nBits & 0xFFFFFFFF ); |
| SHA1Impl.computeHash(buffer); |
| |
| // converting 5-word frame into 20 bytes |
| j = offset; |
| for ( i = HASH_OFFSET; i < HASH_OFFSET +5; i++ ) { |
| int k = buffer[i]; |
| digest[j ] = (byte) ( k >>>24 ); // getting first byte from left |
| digest[j+1] = (byte) ( k >>>16 ); // getting second byte from left |
| digest[j+2] = (byte) ( k >>> 8 ); // getting third byte from left |
| digest[j+3] = (byte) ( k ); // getting fourth byte from left |
| j += 4; |
| } |
| |
| engineReset(); |
| } |
| |
| // methods specified in java.security.MessageDigestSpi |
| |
| /** |
| * Returns a "deep" copy of this SHA1MDImpl object. <BR> |
| * |
| * The method overrides "clone()" in class Object. <BR> |
| * |
| * @return |
| * a clone of this object |
| */ |
| public Object clone() throws CloneNotSupportedException { |
| SHA1_MessageDigestImpl cloneObj = (SHA1_MessageDigestImpl) super.clone(); |
| cloneObj.buffer = buffer.clone(); |
| cloneObj.oneByte = oneByte.clone(); |
| return cloneObj; |
| } |
| |
| |
| /** |
| * Computes a message digest value. <BR> |
| * |
| * The method resets the engine. <BR> |
| * |
| * The method overrides "engineDigest()" in class MessageDigestSpi. <BR> |
| * |
| * @return |
| * byte array containing message digest value |
| */ |
| protected byte[] engineDigest() { |
| byte[] hash = new byte[DIGEST_LENGTH]; |
| processDigest(hash, 0); |
| return hash; |
| } |
| |
| |
| /** |
| * Computes message digest value. |
| * Upon return, the value is stored in "buf" buffer beginning "offset" byte. <BR> |
| * |
| * The method resets the engine. <BR> |
| * |
| * The method overrides "engineDigest(byte[],int,int) in class MessageDigestSpi. |
| * |
| * @param |
| * buf byte array to store a message digest returned |
| * @param |
| * offset a position in the array for first byte of the message digest |
| * @param |
| * len number of bytes within buffer allotted for the message digest; |
| * as this implementation doesn't provide partial digests, |
| * len should be >= 20, DigestException is thrown otherwise |
| * @return |
| * the length of the message digest stored in the "buf" buffer; |
| * in this implementation the length=20 |
| * |
| * @throws IllegalArgumentException |
| * if null is passed to the "buf" argument <BR> |
| * if offset + len > buf.length <BR> |
| * if offset > buf.length or len > buf.length |
| * |
| * @throws DigestException |
| * if len < 20 |
| * |
| * @throws ArrayIndexOutOfBoundsException |
| * if offset < 0 |
| */ |
| protected int engineDigest(byte[] buf, int offset, int len) throws DigestException { |
| if (buf == null) { |
| throw new IllegalArgumentException("buf == null"); |
| } |
| if (offset > buf.length || len > buf.length || (len + offset) > buf.length) { |
| throw new IllegalArgumentException(); |
| } |
| if (len < DIGEST_LENGTH) { |
| throw new DigestException("len < DIGEST_LENGTH"); |
| } |
| if (offset < 0) { |
| throw new ArrayIndexOutOfBoundsException(offset); |
| } |
| |
| processDigest(buf, offset); |
| |
| return DIGEST_LENGTH; |
| } |
| |
| |
| /** |
| * Returns a message digest length. <BR> |
| * |
| * The method overrides "engineGetDigestLength()" in class MessageDigestSpi. <BR> |
| * |
| * @return |
| * total length of current message digest as an int value |
| */ |
| protected int engineGetDigestLength() { |
| return DIGEST_LENGTH; |
| } |
| |
| |
| /** |
| * Resets the engine. <BR> |
| * |
| * The method overrides "engineReset()" in class MessageDigestSpi. <BR> |
| */ |
| protected void engineReset() { |
| |
| messageLength = 0; |
| |
| buffer[BYTES_OFFSET] = 0; |
| buffer[HASH_OFFSET ] = H0; |
| buffer[HASH_OFFSET +1] = H1; |
| buffer[HASH_OFFSET +2] = H2; |
| buffer[HASH_OFFSET +3] = H3; |
| buffer[HASH_OFFSET +4] = H4; |
| } |
| |
| |
| /** |
| * Supplements a byte to current message. <BR> |
| * |
| * The method overrides "engineUpdate(byte)" in class MessageDigestSpi. <BR> |
| * |
| * @param |
| * input byte to add to current message |
| */ |
| protected void engineUpdate(byte input) { |
| |
| oneByte[0] = input; |
| SHA1Impl.updateHash( buffer, oneByte, 0, 0 ); |
| messageLength++; |
| } |
| |
| |
| /** |
| * Updates current message. <BR> |
| * |
| * The method overrides "engineUpdate(byte[],int,int)" in class MessageDigestSpi. <BR> |
| * |
| * The method silently returns if "len" <= 0. |
| * |
| * @param |
| * input a byte array |
| * @param |
| * offset a number of first byte in the "input" array to use for updating |
| * @param |
| * len a number of bytes to use |
| * |
| * @throws NullPointerException |
| * if null is passed to the "buf" argument |
| * |
| * @throws IllegalArgumentException |
| * if offset > buf.length or len > buf.length or |
| * (len + offset) > buf.length |
| * @throws ArrayIndexOutOfBoundsException |
| * offset < 0 |
| */ |
| protected void engineUpdate(byte[] input, int offset, int len) { |
| if (input == null) { |
| throw new IllegalArgumentException("input == null"); |
| } |
| if (len <= 0) { |
| return; |
| } |
| if (offset < 0) { |
| throw new ArrayIndexOutOfBoundsException(offset); |
| } |
| if (offset > input.length || len > input.length || (len + offset) > input.length) { |
| throw new IllegalArgumentException(); |
| } |
| |
| SHA1Impl.updateHash(buffer, input, offset, offset + len -1 ); |
| messageLength += len; |
| } |
| |
| } |