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 import dalvik.system.BlockGuard;
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.IOException;
25 import java.io.ObjectInputStream;
26 import java.io.ObjectOutputStream;
27 import java.io.Serializable;
28 import java.security.InvalidParameterException;
29 import java.security.ProviderException;
30 import java.security.SecureRandomSpi;
31 import libcore.io.Streams;
32 import libcore.util.EmptyArray;
33 
34 import static org.apache.harmony.security.provider.crypto.SHA1Constants.*;
35 
36 /**
37  * This class extends the SecureRandomSpi class implementing all its abstract methods.
38  *
39  * <p>To generate pseudo-random bits, the implementation uses technique described in
40  * the "Random Number Generator (RNG) algorithms" section, Appendix A,
41  * JavaTM Cryptography Architecture, API Specification & Reference.
42  */
43 public class SHA1PRNG_SecureRandomImpl extends SecureRandomSpi implements Serializable {
44 
45     private static final long serialVersionUID = 283736797212159675L;
46 
47     private static FileInputStream devURandom;
48     static {
49         try {
50             devURandom = new FileInputStream(new File("/dev/urandom"));
51         } catch (IOException ex) {
52             throw new RuntimeException(ex);
53         }
54     }
55 
56     // constants to use in expressions operating on bytes in int and long variables:
57     // END_FLAGS - final bytes in words to append to message;
58     //             see "ch.5.1 Padding the Message, FIPS 180-2"
59     // RIGHT1    - shifts to right for left half of long
60     // RIGHT2    - shifts to right for right half of long
61     // LEFT      - shifts to left for bytes
62     // MASK      - mask to select counter's bytes after shift to right
63 
64     private static final int[] END_FLAGS = { 0x80000000, 0x800000, 0x8000, 0x80 };
65 
66     private static final int[] RIGHT1 = { 0, 40, 48, 56 };
67 
68     private static final int[] RIGHT2 = { 0, 8, 16, 24 };
69 
70     private static final int[] LEFT = { 0, 24, 16, 8 };
71 
72     private static final int[] MASK = { 0xFFFFFFFF, 0x00FFFFFF, 0x0000FFFF,
73             0x000000FF };
74 
75     // HASHBYTES_TO_USE defines # of bytes returned by "computeHash(byte[])"
76     // to use to form byte array returning by the "nextBytes(byte[])" method
77     // Note, that this implementation uses more bytes than it is defined
78     // in the above specification.
79     private static final int HASHBYTES_TO_USE = 20;
80 
81     // value of 16 defined in the "SECURE HASH STANDARD", FIPS PUB 180-2
82     private static final int FRAME_LENGTH = 16;
83 
84     // miscellaneous constants defined in this implementation:
85     // COUNTER_BASE - initial value to set to "counter" before computing "nextBytes(..)";
86     //                note, that the exact value is not defined in STANDARD
87     // HASHCOPY_OFFSET   - offset for copy of current hash in "copies" array
88     // EXTRAFRAME_OFFSET - offset for extra frame in "copies" array;
89     //                     as the extra frame follows the current hash frame,
90     //                     EXTRAFRAME_OFFSET is equal to length of current hash frame
91     // FRAME_OFFSET      - offset for frame in "copies" array
92     // MAX_BYTES - maximum # of seed bytes processing which doesn't require extra frame
93     //             see (1) comments on usage of "seed" array below and
94     //             (2) comments in "engineNextBytes(byte[])" method
95     //
96     // UNDEFINED  - three states of engine; initially its state is "UNDEFINED"
97     // SET_SEED     call to "engineSetSeed"  sets up "SET_SEED" state,
98     // NEXT_BYTES   call to "engineNextByte" sets up "NEXT_BYTES" state
99 
100     private static final int COUNTER_BASE = 0;
101 
102     private static final int HASHCOPY_OFFSET = 0;
103 
104     private static final int EXTRAFRAME_OFFSET = 5;
105 
106     private static final int FRAME_OFFSET = 21;
107 
108     private static final int MAX_BYTES = 48;
109 
110     private static final int UNDEFINED = 0;
111 
112     private static final int SET_SEED = 1;
113 
114     private static final int NEXT_BYTES = 2;
115 
116     private static SHA1PRNG_SecureRandomImpl myRandom;
117 
118     // Structure of "seed" array:
119     // -  0-79 - words for computing hash
120     // - 80    - unused
121     // - 81    - # of seed bytes in current seed frame
122     // - 82-86 - 5 words, current seed hash
123     private transient int[] seed;
124 
125     // total length of seed bytes, including all processed
126     private transient long seedLength;
127 
128     // Structure of "copies" array
129     // -  0-4  - 5 words, copy of current seed hash
130     // -  5-20 - extra 16 words frame;
131     //           is used if final padding exceeds 512-bit length
132     // - 21-36 - 16 word frame to store a copy of remaining bytes
133     private transient int[] copies;
134 
135     // ready "next" bytes; needed because words are returned
136     private transient byte[] nextBytes;
137 
138     // index of used bytes in "nextBytes" array
139     private transient int nextBIndex;
140 
141     // variable required according to "SECURE HASH STANDARD"
142     private transient long counter;
143 
144     // contains int value corresponding to engine's current state
145     private transient int state;
146 
147     // The "seed" array is used to compute both "current seed hash" and "next bytes".
148     //
149     // As the "SHA1" algorithm computes a hash of entire seed by splitting it into
150     // a number of the 512-bit length frames (512 bits = 64 bytes = 16 words),
151     // "current seed hash" is a hash (5 words, 20 bytes) for all previous full frames;
152     // remaining bytes are stored in the 0-15 word frame of the "seed" array.
153     //
154     // As for calculating "next bytes",
155     // both remaining bytes and "current seed hash" are used,
156     // to preserve the latter for following "setSeed(..)" commands,
157     // the following technique is used:
158     // - upon getting "nextBytes(byte[])" invoked, single or first in row,
159     //   which requires computing new hash, that is,
160     //   there is no more bytes remaining from previous "next bytes" computation,
161     //   remaining bytes are copied into the 21-36 word frame of the "copies" array;
162     // - upon getting "setSeed(byte[])" invoked, single or first in row,
163     //   remaining bytes are copied back.
164 
165     /**
166      *  Creates object and sets implementation variables to their initial values
167      */
SHA1PRNG_SecureRandomImpl()168     public SHA1PRNG_SecureRandomImpl() {
169 
170         seed = new int[HASH_OFFSET + EXTRAFRAME_OFFSET];
171         seed[HASH_OFFSET] = H0;
172         seed[HASH_OFFSET + 1] = H1;
173         seed[HASH_OFFSET + 2] = H2;
174         seed[HASH_OFFSET + 3] = H3;
175         seed[HASH_OFFSET + 4] = H4;
176 
177         seedLength = 0;
178         copies = new int[2 * FRAME_LENGTH + EXTRAFRAME_OFFSET];
179         nextBytes = new byte[DIGEST_LENGTH];
180         nextBIndex = HASHBYTES_TO_USE;
181         counter = COUNTER_BASE;
182         state = UNDEFINED;
183     }
184 
185     /*
186      * The method invokes the SHA1Impl's "updateHash(..)" method
187      * to update current seed frame and
188      * to compute new intermediate hash value if the frame is full.
189      *
190      * After that it computes a length of whole seed.
191      */
updateSeed(byte[] bytes)192     private void updateSeed(byte[] bytes) {
193 
194         // on call:   "seed" contains current bytes and current hash;
195         // on return: "seed" contains new current bytes and possibly new current hash
196         //            if after adding, seed bytes overfill its buffer
197         SHA1Impl.updateHash(seed, bytes, 0, bytes.length - 1);
198 
199         seedLength += bytes.length;
200     }
201 
202     /**
203      * Changes current seed by supplementing a seed argument to the current seed,
204      * if this already set;
205      * the argument is used as first seed otherwise. <BR>
206      *
207      * The method overrides "engineSetSeed(byte[])" in class SecureRandomSpi.
208      *
209      * @param
210      *       seed - byte array
211      * @throws
212      *       NullPointerException - if null is passed to the "seed" argument
213      */
engineSetSeed(byte[] seed)214     protected synchronized void engineSetSeed(byte[] seed) {
215 
216         if (seed == null) {
217             throw new NullPointerException("seed == null");
218         }
219 
220         if (state == NEXT_BYTES) { // first setSeed after NextBytes; restoring hash
221             System.arraycopy(copies, HASHCOPY_OFFSET, this.seed, HASH_OFFSET,
222                     EXTRAFRAME_OFFSET);
223         }
224         state = SET_SEED;
225 
226         if (seed.length != 0) {
227             updateSeed(seed);
228         }
229     }
230 
231     /**
232      * Returns a required number of random bytes. <BR>
233      *
234      * The method overrides "engineGenerateSeed (int)" in class SecureRandomSpi. <BR>
235      *
236      * @param
237      *       numBytes - number of bytes to return; should be >= 0.
238      * @return
239      *       byte array containing bits in order from left to right
240      * @throws
241      *       InvalidParameterException - if numBytes < 0
242      */
engineGenerateSeed(int numBytes)243     protected synchronized byte[] engineGenerateSeed(int numBytes) {
244 
245         byte[] myBytes; // byte[] for bytes returned by "nextBytes()"
246 
247         if (numBytes < 0) {
248             throw new NegativeArraySizeException(Integer.toString(numBytes));
249         }
250         if (numBytes == 0) {
251             return EmptyArray.BYTE;
252         }
253 
254         if (myRandom == null) {
255             myRandom = new SHA1PRNG_SecureRandomImpl();
256             myRandom.engineSetSeed(getRandomBytes(DIGEST_LENGTH));
257         }
258 
259         myBytes = new byte[numBytes];
260         myRandom.engineNextBytes(myBytes);
261 
262         return myBytes;
263     }
264 
265     /**
266      * Writes random bytes into an array supplied.
267      * Bits in a byte are from left to right. <BR>
268      *
269      * To generate random bytes, the "expansion of source bits" method is used,
270      * that is,
271      * the current seed with a 64-bit counter appended is used to compute new bits.
272      * The counter is incremented by 1 for each 20-byte output. <BR>
273      *
274      * The method overrides engineNextBytes in class SecureRandomSpi.
275      *
276      * @param
277      *       bytes - byte array to be filled in with bytes
278      * @throws
279      *       NullPointerException - if null is passed to the "bytes" argument
280      */
engineNextBytes(byte[] bytes)281     protected synchronized void engineNextBytes(byte[] bytes) {
282 
283         int i, n;
284 
285         long bits; // number of bits required by Secure Hash Standard
286         int nextByteToReturn; // index of ready bytes in "bytes" array
287         int lastWord; // index of last word in frame containing bytes
288         final int extrabytes = 7;// # of bytes to add in order to computer # of 8 byte words
289 
290         if (bytes == null) {
291             throw new NullPointerException("bytes == null");
292         }
293 
294         lastWord = seed[BYTES_OFFSET] == 0 ? 0
295                 : (seed[BYTES_OFFSET] + extrabytes) >> 3 - 1;
296 
297         if (state == UNDEFINED) {
298 
299             // no seed supplied by user, hence it is generated thus randomizing internal state
300             updateSeed(getRandomBytes(DIGEST_LENGTH));
301             nextBIndex = HASHBYTES_TO_USE;
302 
303             // updateSeed(...) updates where the last word of the seed is, so we
304             // have to read it again.
305             lastWord = seed[BYTES_OFFSET] == 0 ? 0
306                     : (seed[BYTES_OFFSET] + extrabytes) >> 3 - 1;
307 
308         } else if (state == SET_SEED) {
309 
310             System.arraycopy(seed, HASH_OFFSET, copies, HASHCOPY_OFFSET,
311                     EXTRAFRAME_OFFSET);
312 
313             // possible cases for 64-byte frame:
314             //
315             // seed bytes < 48      - remaining bytes are enough for all, 8 counter bytes,
316             //                        0x80, and 8 seedLength bytes; no extra frame required
317             // 48 < seed bytes < 56 - remaining 9 bytes are for 0x80 and 8 counter bytes
318             //                        extra frame contains only seedLength value at the end
319             // seed bytes > 55      - extra frame contains both counter's bytes
320             //                        at the beginning and seedLength value at the end;
321             //                        note, that beginning extra bytes are not more than 8,
322             //                        that is, only 2 extra words may be used
323 
324             // no need to set to "0" 3 words after "lastWord" and
325             // more than two words behind frame
326             for (i = lastWord + 3; i < FRAME_LENGTH + 2; i++) {
327                 seed[i] = 0;
328             }
329 
330             bits = (seedLength << 3) + 64; // transforming # of bytes into # of bits
331 
332             // putting # of bits into two last words (14,15) of 16 word frame in
333             // seed or copies array depending on total length after padding
334             if (seed[BYTES_OFFSET] < MAX_BYTES) {
335                 seed[14] = (int) (bits >>> 32);
336                 seed[15] = (int) (bits & 0xFFFFFFFF);
337             } else {
338                 copies[EXTRAFRAME_OFFSET + 14] = (int) (bits >>> 32);
339                 copies[EXTRAFRAME_OFFSET + 15] = (int) (bits & 0xFFFFFFFF);
340             }
341 
342             nextBIndex = HASHBYTES_TO_USE; // skipping remaining random bits
343         }
344         state = NEXT_BYTES;
345 
346         if (bytes.length == 0) {
347             return;
348         }
349 
350         nextByteToReturn = 0;
351 
352         // possibly not all of HASHBYTES_TO_USE bytes were used previous time
353         n = (HASHBYTES_TO_USE - nextBIndex) < (bytes.length - nextByteToReturn) ? HASHBYTES_TO_USE
354                 - nextBIndex
355                 : bytes.length - nextByteToReturn;
356         if (n > 0) {
357             System.arraycopy(nextBytes, nextBIndex, bytes, nextByteToReturn, n);
358             nextBIndex += n;
359             nextByteToReturn += n;
360         }
361 
362         if (nextByteToReturn >= bytes.length) {
363             return; // return because "bytes[]" are filled in
364         }
365 
366         n = seed[BYTES_OFFSET] & 0x03;
367         for (;;) {
368             if (n == 0) {
369 
370                 seed[lastWord] = (int) (counter >>> 32);
371                 seed[lastWord + 1] = (int) (counter & 0xFFFFFFFF);
372                 seed[lastWord + 2] = END_FLAGS[0];
373 
374             } else {
375 
376                 seed[lastWord] |= (int) ((counter >>> RIGHT1[n]) & MASK[n]);
377                 seed[lastWord + 1] = (int) ((counter >>> RIGHT2[n]) & 0xFFFFFFFF);
378                 seed[lastWord + 2] = (int) ((counter << LEFT[n]) | END_FLAGS[n]);
379             }
380             if (seed[BYTES_OFFSET] > MAX_BYTES) {
381                 copies[EXTRAFRAME_OFFSET] = seed[FRAME_LENGTH];
382                 copies[EXTRAFRAME_OFFSET + 1] = seed[FRAME_LENGTH + 1];
383             }
384 
385             SHA1Impl.computeHash(seed);
386 
387             if (seed[BYTES_OFFSET] > MAX_BYTES) {
388 
389                 System.arraycopy(seed, 0, copies, FRAME_OFFSET, FRAME_LENGTH);
390                 System.arraycopy(copies, EXTRAFRAME_OFFSET, seed, 0,
391                         FRAME_LENGTH);
392 
393                 SHA1Impl.computeHash(seed);
394                 System.arraycopy(copies, FRAME_OFFSET, seed, 0, FRAME_LENGTH);
395             }
396             counter++;
397 
398             int j = 0;
399             for (i = 0; i < EXTRAFRAME_OFFSET; i++) {
400                 int k = seed[HASH_OFFSET + i];
401                 nextBytes[j] = (byte) (k >>> 24); // getting first  byte from left
402                 nextBytes[j + 1] = (byte) (k >>> 16); // getting second byte from left
403                 nextBytes[j + 2] = (byte) (k >>> 8); // getting third  byte from left
404                 nextBytes[j + 3] = (byte) (k); // getting fourth byte from left
405                 j += 4;
406             }
407 
408             nextBIndex = 0;
409             j = HASHBYTES_TO_USE < (bytes.length - nextByteToReturn) ? HASHBYTES_TO_USE
410                     : bytes.length - nextByteToReturn;
411 
412             if (j > 0) {
413                 System.arraycopy(nextBytes, 0, bytes, nextByteToReturn, j);
414                 nextByteToReturn += j;
415                 nextBIndex += j;
416             }
417 
418             if (nextByteToReturn >= bytes.length) {
419                 break;
420             }
421         }
422     }
423 
424     private void writeObject(ObjectOutputStream oos) throws IOException {
425 
426         int[] intData = null;
427 
428         final int only_hash = EXTRAFRAME_OFFSET;
429         final int hashes_and_frame = EXTRAFRAME_OFFSET * 2 + FRAME_LENGTH;
430         final int hashes_and_frame_extra = EXTRAFRAME_OFFSET * 2 + FRAME_LENGTH
431                 * 2;
432 
433         oos.writeLong(seedLength);
434         oos.writeLong(counter);
435         oos.writeInt(state);
436         oos.writeInt(seed[BYTES_OFFSET]);
437 
438         int nRemaining = (seed[BYTES_OFFSET] + 3) >> 2; // converting bytes in words
439         // result may be 0
440         if (state != NEXT_BYTES) {
441 
442             // either the state is UNDEFINED or previous method was "setSeed(..)"
443             // so in "seed[]" to serialize are remaining bytes (seed[0-nRemaining]) and
444             // current hash (seed[82-86])
445 
446             intData = new int[only_hash + nRemaining];
447 
448             System.arraycopy(seed, 0, intData, 0, nRemaining);
449             System.arraycopy(seed, HASH_OFFSET, intData, nRemaining,
450                     EXTRAFRAME_OFFSET);
451 
452         } else {
453             // previous method was "nextBytes(..)"
454             // so, data to serialize are all the above (two first are in "copies" array)
455             // and current words in both frame and extra frame (as if)
456 
457             int offset = 0;
458             if (seed[BYTES_OFFSET] < MAX_BYTES) { // no extra frame
459 
460                 intData = new int[hashes_and_frame + nRemaining];
461 
462             } else { // extra frame is used
463 
464                 intData = new int[hashes_and_frame_extra + nRemaining];
465 
466                 intData[offset] = seed[FRAME_LENGTH];
467                 intData[offset + 1] = seed[FRAME_LENGTH + 1];
468                 intData[offset + 2] = seed[FRAME_LENGTH + 14];
469                 intData[offset + 3] = seed[FRAME_LENGTH + 15];
470                 offset += 4;
471             }
472 
473             System.arraycopy(seed, 0, intData, offset, FRAME_LENGTH);
474             offset += FRAME_LENGTH;
475 
476             System.arraycopy(copies, FRAME_LENGTH + EXTRAFRAME_OFFSET, intData,
477                     offset, nRemaining);
478             offset += nRemaining;
479 
480             System.arraycopy(copies, 0, intData, offset, EXTRAFRAME_OFFSET);
481             offset += EXTRAFRAME_OFFSET;
482 
483             System.arraycopy(seed, HASH_OFFSET, intData, offset,
484                     EXTRAFRAME_OFFSET);
485         }
486         for (int i = 0; i < intData.length; i++) {
487             oos.writeInt(intData[i]);
488         }
489 
490         oos.writeInt(nextBIndex);
491         oos.write(nextBytes, nextBIndex, HASHBYTES_TO_USE - nextBIndex);
492     }
493 
494     private void readObject(ObjectInputStream ois) throws IOException,
495             ClassNotFoundException {
496 
497         seed = new int[HASH_OFFSET + EXTRAFRAME_OFFSET];
498         copies = new int[2 * FRAME_LENGTH + EXTRAFRAME_OFFSET];
499         nextBytes = new byte[DIGEST_LENGTH];
500 
501         seedLength = ois.readLong();
502         counter = ois.readLong();
503         state = ois.readInt();
504         seed[BYTES_OFFSET] = ois.readInt();
505 
506         int nRemaining = (seed[BYTES_OFFSET] + 3) >> 2; // converting bytes in words
507 
508         if (state != NEXT_BYTES) {
509 
510             for (int i = 0; i < nRemaining; i++) {
511                 seed[i] = ois.readInt();
512             }
513             for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
514                 seed[HASH_OFFSET + i] = ois.readInt();
515             }
516         } else {
517             if (seed[BYTES_OFFSET] >= MAX_BYTES) {
518 
519                 // reading next bytes in seed extra frame
520                 seed[FRAME_LENGTH] = ois.readInt();
521                 seed[FRAME_LENGTH + 1] = ois.readInt();
522                 seed[FRAME_LENGTH + 14] = ois.readInt();
523                 seed[FRAME_LENGTH + 15] = ois.readInt();
524             }
525             // reading next bytes in seed frame
526             for (int i = 0; i < FRAME_LENGTH; i++) {
527                 seed[i] = ois.readInt();
528             }
529             // reading remaining seed bytes
530             for (int i = 0; i < nRemaining; i++) {
531                 copies[FRAME_LENGTH + EXTRAFRAME_OFFSET + i] = ois.readInt();
532             }
533             // reading copy of current hash
534             for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
535                 copies[i] = ois.readInt();
536             }
537             // reading current hash
538             for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
539                 seed[HASH_OFFSET + i] = ois.readInt();
540             }
541         }
542 
543         nextBIndex = ois.readInt();
544         Streams.readFully(ois, nextBytes, nextBIndex, HASHBYTES_TO_USE - nextBIndex);
545     }
546 
getRandomBytes(int byteCount)547     private static byte[] getRandomBytes(int byteCount) {
548         if (byteCount <= 0) {
549             throw new IllegalArgumentException("Too few bytes requested: " + byteCount);
550         }
551 
552         BlockGuard.Policy originalPolicy = BlockGuard.getThreadPolicy();
553         try {
554             BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY);
555             byte[] result = new byte[byteCount];
556             Streams.readFully(devURandom, result, 0, byteCount);
557             return result;
558         } catch (Exception ex) {
559             throw new ProviderException("Couldn't read " + byteCount + " random bytes", ex);
560         } finally {
561             BlockGuard.setThreadPolicy(originalPolicy);
562         }
563     }
564 }
565