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 * @author Yuri A. Kropachev
19 * @version $Revision$
20 */
21 
22 
23 package org.apache.harmony.security.provider.crypto;
24 
25 import static org.apache.harmony.security.provider.crypto.SHA1Constants.*;
26 
27 /**
28  * This class contains methods providing SHA-1 functionality to use in classes. <BR>
29  * The methods support the algorithm described in "SECURE HASH STANDARD", FIPS PUB 180-2, <BR>
30  * "http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf"      <BR>
31  * <BR>
32  * The class contains two package level access methods, -
33  * "void updateHash(int[], byte[], int, int)" and "void computeHash(int[])", -
34  * performing the following operations. <BR>
35  * <BR>
36  * The "updateHash(..)" method appends new bytes to existing ones
37  * within limit of a frame of 64 bytes (16 words).
38  * Once a length of accumulated bytes reaches the limit
39  * the "computeHash(int[])" method is invoked on the frame to compute updated hash,
40  * and the number of bytes in the frame is set to 0.
41  * Thus, after appending all bytes, the frame contain only those bytes
42  * that were not used in computing final hash value yet. <BR>
43  * <BR>
44  * The "computeHash(..)" method generates a 160 bit hash value using
45  * a 512 bit message stored in first 16 words of int[] array argument and
46  * current hash value stored in five words, beginning HASH_OFFSET, of the array argument.
47  * Computation is done according to SHA-1 algorithm. <BR>
48  * <BR>
49  * The resulting hash value replaces the previous hash value in the array;
50  * original bits of the message are not preserved.
51  */
52 public class SHA1Impl {
53 
54 
55     /**
56      * The method generates a 160 bit hash value using
57      * a 512 bit message stored in first 16 words of int[] array argument and
58      * current hash value stored in five words, beginning OFFSET+1, of the array argument.
59      * Computation is done according to SHA-1 algorithm.
60      *
61      * The resulting hash value replaces the previous hash value in the array;
62      * original bits of the message are not preserved.
63      *
64      * No checks on argument supplied, that is,
65      * a calling method is responsible for such checks.
66      * In case of incorrect array passed to the method
67      * either NPE or IndexOutOfBoundException gets thrown by JVM.
68      *
69      * @params
70      *        arrW - integer array; arrW.length >= (BYTES_OFFSET+6); <BR>
71      *               only first (BYTES_OFFSET+6) words are used
72      */
computeHash(int[] arrW)73     static void computeHash(int[] arrW) {
74 
75         int  a = arrW[HASH_OFFSET   ];
76         int  b = arrW[HASH_OFFSET +1];
77         int  c = arrW[HASH_OFFSET +2];
78         int  d = arrW[HASH_OFFSET +3];
79         int  e = arrW[HASH_OFFSET +4];
80 
81         int temp;
82 
83         // In this implementation the "d. For t = 0 to 79 do" loop
84         // is split into four loops. The following constants:
85         //     K = 5A827999   0 <= t <= 19
86         //     K = 6ED9EBA1  20 <= t <= 39
87         //     K = 8F1BBCDC  40 <= t <= 59
88         //     K = CA62C1D6  60 <= t <= 79
89         // are hex literals in the loops.
90 
91         for ( int t = 16; t < 80 ; t++ ) {
92 
93             temp  = arrW[t-3] ^ arrW[t-8] ^ arrW[t-14] ^ arrW[t-16];
94             arrW[t] = ( temp<<1 ) | ( temp>>>31 );
95         }
96 
97         for ( int t = 0 ; t < 20 ; t++ ) {
98 
99             temp = ( ( a<<5 ) | ( a>>>27 )   ) +
100                    ( ( b & c) | ((~b) & d)   ) +
101                    ( e + arrW[t] + 0x5A827999 ) ;
102             e = d;
103             d = c;
104             c = ( b<<30 ) | ( b>>>2 ) ;
105             b = a;
106             a = temp;
107         }
108         for ( int t = 20 ; t < 40 ; t++ ) {
109 
110             temp = ((( a<<5 ) | ( a>>>27 ))) + (b ^ c ^ d) + (e + arrW[t] + 0x6ED9EBA1) ;
111             e = d;
112             d = c;
113             c = ( b<<30 ) | ( b>>>2 ) ;
114             b = a;
115             a = temp;
116         }
117         for ( int t = 40 ; t < 60 ; t++ ) {
118 
119             temp = (( a<<5 ) | ( a>>>27 )) + ((b & c) | (b & d) | (c & d)) +
120                                                              (e + arrW[t] + 0x8F1BBCDC) ;
121             e = d;
122             d = c;
123             c = ( b<<30 ) | ( b>>>2 ) ;
124             b = a;
125             a = temp;
126         }
127         for ( int t = 60 ; t < 80 ; t++ ) {
128 
129             temp = ((( a<<5 ) | ( a>>>27 ))) + (b ^ c ^ d) + (e + arrW[t] + 0xCA62C1D6) ;
130             e = d;
131             d = c;
132             c = ( b<<30 ) | ( b>>>2 ) ;
133             b = a;
134             a = temp;
135         }
136 
137         arrW[HASH_OFFSET   ] += a;
138         arrW[HASH_OFFSET +1] += b;
139         arrW[HASH_OFFSET +2] += c;
140         arrW[HASH_OFFSET +3] += d;
141         arrW[HASH_OFFSET +4] += e;
142     }
143 
144     /**
145      * The method appends new bytes to existing ones
146      * within limit of a frame of 64 bytes (16 words).
147      *
148      * Once a length of accumulated bytes reaches the limit
149      * the "computeHash(int[])" method is invoked on the array to compute updated hash,
150      * and the number of bytes in the frame is set to 0.
151      * Thus, after appending all bytes, the array contain only those bytes
152      * that were not used in computing final hash value yet.
153      *
154      * No checks on arguments passed to the method, that is,
155      * a calling method is responsible for such checks.
156      *
157      * @params
158      *        intArray  - int array containing bytes to which to append;
159      *                    intArray.length >= (BYTES_OFFSET+6)
160      * @params
161      *        byteInput - array of bytes to use for the update
162      * @params
163      *        from      - the offset to start in the "byteInput" array
164      * @params
165      *        to        - a number of the last byte in the input array to use,
166      *                that is, for first byte "to"==0, for last byte "to"==input.length-1
167      */
updateHash(int[] intArray, byte[] byteInput, int fromByte, int toByte)168     static void updateHash(int[] intArray, byte[] byteInput, int fromByte, int toByte) {
169 
170         // As intArray contains a packed bytes
171         // the buffer's index is in the intArray[BYTES_OFFSET] element
172 
173         int index = intArray[BYTES_OFFSET];
174         int i = fromByte;
175         int maxWord;
176         int nBytes;
177 
178         int wordIndex = index >>2;
179         int byteIndex = index & 0x03;
180 
181         intArray[BYTES_OFFSET] = ( index + toByte - fromByte + 1 ) & 077 ;
182 
183         // In general case there are 3 stages :
184         // - appending bytes to non-full word,
185         // - writing 4 bytes into empty words,
186         // - writing less than 4 bytes in last word
187 
188         if ( byteIndex != 0 ) {       // appending bytes in non-full word (as if)
189 
190             for ( ; ( i <= toByte ) && ( byteIndex < 4 ) ; i++ ) {
191                 intArray[wordIndex] |= ( byteInput[i] & 0xFF ) << ((3 - byteIndex)<<3) ;
192                 byteIndex++;
193             }
194             if ( byteIndex == 4 ) {
195                 wordIndex++;
196                 if ( wordIndex == 16 ) {          // intArray is full, computing hash
197 
198                     computeHash(intArray);
199                     wordIndex = 0;
200                 }
201             }
202             if ( i > toByte ) {                 // all input bytes appended
203                 return ;
204             }
205         }
206 
207         // writing full words
208 
209         maxWord = (toByte - i + 1) >> 2;           // # of remaining full words, may be "0"
210         for ( int k = 0; k < maxWord ; k++ ) {
211 
212             intArray[wordIndex] = ( ((int) byteInput[i   ] & 0xFF) <<24 ) |
213                                   ( ((int) byteInput[i +1] & 0xFF) <<16 ) |
214                                   ( ((int) byteInput[i +2] & 0xFF) <<8  ) |
215                                   ( ((int) byteInput[i +3] & 0xFF)      )  ;
216             i += 4;
217             wordIndex++;
218 
219             if ( wordIndex < 16 ) {     // buffer is not full yet
220                 continue;
221             }
222             computeHash(intArray);      // buffer is full, computing hash
223             wordIndex = 0;
224         }
225 
226         // writing last incomplete word
227         // after writing free byte positions are set to "0"s
228 
229         nBytes = toByte - i +1;
230         if ( nBytes != 0 ) {
231 
232             int w =  ((int) byteInput[i] & 0xFF) <<24 ;
233 
234             if ( nBytes != 1 ) {
235                 w |= ((int) byteInput[i +1] & 0xFF) <<16 ;
236                 if ( nBytes != 2) {
237                     w |= ((int) byteInput[i +2] & 0xFF) <<8 ;
238                 }
239             }
240             intArray[wordIndex] = w;
241         }
242 
243         return ;
244     }
245 
246 }
247