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