001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.harmony.security.provider.crypto;
019:
020: import java.security.InvalidParameterException;
021: import java.security.SecureRandomSpi;
022:
023: import org.apache.harmony.security.internal.nls.Messages;
024: import org.apache.harmony.security.provider.crypto.RandomBitsSupplier;
025: import org.apache.harmony.security.provider.crypto.SHA1Impl;
026:
027: import java.io.Serializable;
028: import java.io.ObjectInputStream;
029: import java.io.ObjectOutputStream;
030: import java.io.IOException;
031:
032: /**
033: * This class extends the SecureRandomSpi class implementing all its abstract methods. <BR>
034: * <BR>
035: * To generate pseudo-random bits, the implementation uses technique described in
036: * the "Random Number Generator (RNG) algorithms" section, Appendix A,
037: * JavaTM Cryptography Architecture, API Specification&Reference <BR>
038: * <BR>
039: * The class implements the Serializable interface.
040: */
041:
042: public class SHA1PRNG_SecureRandomImpl extends SecureRandomSpi
043: implements Serializable, SHA1_Data {
044:
045: private static final long serialVersionUID = 283736797212159675L;
046:
047: // constants to use in expressions operating on bytes in int and long variables:
048: // END_FLAGS - final bytes in words to append to message;
049: // see "ch.5.1 Padding the Message, FIPS 180-2"
050: // RIGHT1 - shifts to right for left half of long
051: // RIGHT2 - shifts to right for right half of long
052: // LEFT - shifts to left for bytes
053: // MASK - mask to select counter's bytes after shift to right
054:
055: private static final int[] END_FLAGS = { 0x80000000, 0x800000,
056: 0x8000, 0x80 };
057:
058: private static final int[] RIGHT1 = { 0, 40, 48, 56 };
059:
060: private static final int[] RIGHT2 = { 0, 8, 16, 24 };
061:
062: private static final int[] LEFT = { 0, 24, 16, 8 };
063:
064: private static final int[] MASK = { 0xFFFFFFFF, 0x00FFFFFF,
065: 0x0000FFFF, 0x000000FF };
066:
067: // HASHBYTES_TO_USE defines # of bytes returned by "computeHash(byte[])"
068: // to use to form byte array returning by the "nextBytes(byte[])" method
069: // Note, that this implementation uses more bytes than it is defined
070: // in the above specification.
071: private static final int HASHBYTES_TO_USE = 20;
072:
073: // value of 16 defined in the "SECURE HASH STANDARD", FIPS PUB 180-2
074: private static final int FRAME_LENGTH = 16;
075:
076: // miscellaneous constants defined in this implementation:
077: // COUNTER_BASE - initial value to set to "counter" before computing "nextBytes(..)";
078: // note, that the exact value is not defined in STANDARD
079: // HASHCOPY_OFFSET - offset for copy of current hash in "copies" array
080: // EXTRAFRAME_OFFSET - offset for extra frame in "copies" array;
081: // as the extra frame follows the current hash frame,
082: // EXTRAFRAME_OFFSET is equal to length of current hash frame
083: // FRAME_OFFSET - offset for frame in "copies" array
084: // MAX_BYTES - maximum # of seed bytes processing which doesn't require extra frame
085: // see (1) comments on usage of "seed" array below and
086: // (2) comments in "engineNextBytes(byte[])" method
087: //
088: // UNDEFINED - three states of engine; initially its state is "UNDEFINED"
089: // SET_SEED call to "engineSetSeed" sets up "SET_SEED" state,
090: // NEXT_BYTES call to "engineNextByte" sets up "NEXT_BYTES" state
091:
092: private static final int COUNTER_BASE = 0;
093:
094: private static final int HASHCOPY_OFFSET = 0;
095:
096: private static final int EXTRAFRAME_OFFSET = 5;
097:
098: private static final int FRAME_OFFSET = 21;
099:
100: private static final int MAX_BYTES = 48;
101:
102: private static final int UNDEFINED = 0;
103:
104: private static final int SET_SEED = 1;
105:
106: private static final int NEXT_BYTES = 2;
107:
108: private static SHA1PRNG_SecureRandomImpl myRandom;
109:
110: // Structure of "seed" array:
111: // - 0-79 - words for computing hash
112: // - 80 - unused
113: // - 81 - # of seed bytes in current seed frame
114: // - 82-86 - 5 words, current seed hash
115: private transient int seed[];
116:
117: // total length of seed bytes, including all processed
118: private transient long seedLength;
119:
120: // Structure of "copies" array
121: // - 0-4 - 5 words, copy of current seed hash
122: // - 5-20 - extra 16 words frame;
123: // is used if final padding exceeds 512-bit length
124: // - 21-36 - 16 word frame to store a copy of remaining bytes
125: private transient int copies[];
126:
127: // ready "next" bytes; needed because words are returned
128: private transient byte nextBytes[];
129:
130: // index of used bytes in "nextBytes" array
131: private transient int nextBIndex;
132:
133: // variable required according to "SECURE HASH STANDARD"
134: private transient long counter;
135:
136: // contains int value corresponding to engine's current state
137: private transient int state;
138:
139: // The "seed" array is used to compute both "current seed hash" and "next bytes".
140: //
141: // As the "SHA1" algorithm computes a hash of entire seed by splitting it into
142: // a number of the 512-bit length frames (512 bits = 64 bytes = 16 words),
143: // "current seed hash" is a hash (5 words, 20 bytes) for all previous full frames;
144: // remaining bytes are stored in the 0-15 word frame of the "seed" array.
145: //
146: // As for calculating "next bytes",
147: // both remaining bytes and "current seed hash" are used,
148: // to preserve the latter for following "setSeed(..)" commands,
149: // the following technique is used:
150: // - upon getting "nextBytes(byte[])" invoked, single or first in row,
151: // which requires computing new hash, that is,
152: // there is no more bytes remaining from previous "next bytes" computation,
153: // remaining bytes are copied into the 21-36 word frame of the "copies" array;
154: // - upon getting "setSeed(byte[])" invoked, single or first in row,
155: // remaining bytes are copied back.
156:
157: /**
158: * Creates object and sets implementation variables to their initial values
159: */
160: public SHA1PRNG_SecureRandomImpl() {
161:
162: seed = new int[HASH_OFFSET + EXTRAFRAME_OFFSET];
163: seed[HASH_OFFSET] = H0;
164: seed[HASH_OFFSET + 1] = H1;
165: seed[HASH_OFFSET + 2] = H2;
166: seed[HASH_OFFSET + 3] = H3;
167: seed[HASH_OFFSET + 4] = H4;
168:
169: seedLength = 0;
170: copies = new int[2 * FRAME_LENGTH + EXTRAFRAME_OFFSET];
171: nextBytes = new byte[DIGEST_LENGTH];
172: nextBIndex = HASHBYTES_TO_USE;
173: counter = COUNTER_BASE;
174: state = UNDEFINED;
175: }
176:
177: /*
178: * The method invokes the SHA1Impl's "updateHash(..)" method
179: * to update current seed frame and
180: * to compute new intermediate hash value if the frame is full.
181: *
182: * After that it computes a length of whole seed.
183: */
184: private void updateSeed(byte[] bytes) {
185:
186: // on call: "seed" contains current bytes and current hash;
187: // on return: "seed" contains new current bytes and possibly new current hash
188: // if after adding, seed bytes overfill its buffer
189: SHA1Impl.updateHash(seed, bytes, 0, bytes.length - 1);
190:
191: seedLength += bytes.length;
192: }
193:
194: /**
195: * Changes current seed by supplementing a seed argument to the current seed,
196: * if this already set;
197: * the argument is used as first seed otherwise. <BR>
198: *
199: * The method overrides "engineSetSeed(byte[])" in class SecureRandomSpi.
200: *
201: * @param
202: * seed - byte array
203: * @throws
204: * NullPointerException - if null is passed to the "seed" argument
205: */
206: protected void engineSetSeed(byte[] seed) {
207:
208: if (seed == null) {
209: throw new NullPointerException(Messages.getString(
210: "security.83", "seed")); //$NON-NLS-1$ //$NON-NLS-2$
211: }
212:
213: if (state == NEXT_BYTES) { // first setSeed after NextBytes; restoring hash
214: System.arraycopy(copies, HASHCOPY_OFFSET, this .seed,
215: HASH_OFFSET, EXTRAFRAME_OFFSET);
216: }
217: state = SET_SEED;
218:
219: if (seed.length != 0) {
220: updateSeed(seed);
221: }
222: }
223:
224: /**
225: * Returns a required number of random bytes. <BR>
226: *
227: * The method overrides "engineGenerateSeed (int)" in class SecureRandomSpi. <BR>
228: *
229: * @param
230: * numBytes - number of bytes to return; should be >= 0.
231: * @return
232: * byte array containing bits in order from left to right
233: * @throws
234: * InvalidParameterException - if numBytes < 0
235: */
236: protected byte[] engineGenerateSeed(int numBytes) {
237:
238: byte[] myBytes; // byte[] for bytes returned by "nextBytes()"
239:
240: if (numBytes < 0) {
241: throw new NegativeArraySizeException(Messages.getString(
242: "security.171", numBytes)); //$NON-NLS-1$
243: }
244: if (numBytes == 0) {
245: return new byte[0];
246: }
247:
248: if (myRandom == null) {
249: myRandom = new SHA1PRNG_SecureRandomImpl();
250: myRandom.engineSetSeed(RandomBitsSupplier
251: .getRandomBits(DIGEST_LENGTH));
252: }
253:
254: myBytes = new byte[numBytes];
255: myRandom.engineNextBytes(myBytes);
256:
257: return myBytes;
258: }
259:
260: /**
261: * Writes random bytes into an array supplied.
262: * Bits in a byte are from left to right. <BR>
263: *
264: * To generate random bytes, the "expansion of source bits" method is used,
265: * that is,
266: * the current seed with a 64-bit counter appended is used to compute new bits.
267: * The counter is incremented by 1 for each 20-byte output. <BR>
268: *
269: * The method overrides engineNextBytes in class SecureRandomSpi.
270: *
271: * @param
272: * bytes - byte array to be filled in with bytes
273: * @throws
274: * NullPointerException - if null is passed to the "bytes" argument
275: */
276: protected void engineNextBytes(byte[] bytes) {
277:
278: int i, n;
279:
280: long bits; // number of bits required by Secure Hash Standard
281: int nextByteToReturn; // index of ready bytes in "bytes" array
282: int lastWord; // index of last word in frame containing bytes
283: final int extrabytes = 7;// # of bytes to add in order to computer # of 8 byte words
284:
285: if (bytes == null) {
286: throw new NullPointerException(Messages.getString(
287: "security.83", "bytes")); //$NON-NLS-1$ //$NON-NLS-2$
288: }
289:
290: lastWord = seed[BYTES_OFFSET] == 0 ? 0
291: : (seed[BYTES_OFFSET] + extrabytes) >> 3 - 1;
292:
293: if (state == UNDEFINED) {
294:
295: // no seed supplied by user, hence it is generated thus randomizing internal state
296: updateSeed(RandomBitsSupplier.getRandomBits(DIGEST_LENGTH));
297: nextBIndex = HASHBYTES_TO_USE;
298:
299: } else if (state == SET_SEED) {
300:
301: System.arraycopy(seed, HASH_OFFSET, copies,
302: HASHCOPY_OFFSET, EXTRAFRAME_OFFSET);
303:
304: // possible cases for 64-byte frame:
305: //
306: // seed bytes < 48 - remaining bytes are enough for all, 8 counter bytes,
307: // 0x80, and 8 seedLength bytes; no extra frame required
308: // 48 < seed bytes < 56 - remaining 9 bytes are for 0x80 and 8 counter bytes
309: // extra frame contains only seedLength value at the end
310: // seed bytes > 55 - extra frame contains both counter's bytes
311: // at the beginning and seedLength value at the end;
312: // note, that beginning extra bytes are not more than 8,
313: // that is, only 2 extra words may be used
314:
315: // no need to set to "0" 3 words after "lastWord" and
316: // more than two words behind frame
317: for (i = lastWord + 3; i < FRAME_LENGTH + 2; i++) {
318: seed[i] = 0;
319: }
320:
321: bits = seedLength << 3 + 64; // transforming # of bytes into # of bits
322:
323: // putting # of bits into two last words (14,15) of 16 word frame in
324: // seed or copies array depending on total length after padding
325: if (seed[BYTES_OFFSET] < MAX_BYTES) {
326: seed[14] = (int) (bits >>> 32);
327: seed[15] = (int) (bits & 0xFFFFFFFF);
328: } else {
329: copies[EXTRAFRAME_OFFSET + 14] = (int) (bits >>> 32);
330: copies[EXTRAFRAME_OFFSET + 15] = (int) (bits & 0xFFFFFFFF);
331: }
332:
333: nextBIndex = HASHBYTES_TO_USE; // skipping remaining random bits
334: }
335: state = NEXT_BYTES;
336:
337: if (bytes.length == 0) {
338: return;
339: }
340:
341: nextByteToReturn = 0;
342:
343: // possibly not all of HASHBYTES_TO_USE bytes were used previous time
344: n = (HASHBYTES_TO_USE - nextBIndex) < (bytes.length - nextByteToReturn) ? HASHBYTES_TO_USE
345: - nextBIndex
346: : bytes.length - nextByteToReturn;
347: if (n > 0) {
348: System.arraycopy(nextBytes, nextBIndex, bytes,
349: nextByteToReturn, n);
350: nextBIndex += n;
351: nextByteToReturn += n;
352: }
353:
354: if (nextByteToReturn >= bytes.length) {
355: return; // return because "bytes[]" are filled in
356: }
357:
358: n = seed[BYTES_OFFSET] & 0x03;
359: for (;;) {
360: if (n == 0) {
361:
362: seed[lastWord] = (int) (counter >>> 32);
363: seed[lastWord + 1] = (int) (counter & 0xFFFFFFFF);
364: seed[lastWord + 2] = END_FLAGS[0];
365:
366: } else {
367:
368: seed[lastWord] |= (int) ((counter >>> RIGHT1[n]) & MASK[n]);
369: seed[lastWord + 1] = (int) ((counter >>> RIGHT2[n]) & 0xFFFFFFFF);
370: seed[lastWord + 2] = (int) ((counter << LEFT[n]) | END_FLAGS[n]);
371: }
372: if (seed[BYTES_OFFSET] > MAX_BYTES) {
373: copies[EXTRAFRAME_OFFSET] = seed[FRAME_LENGTH];
374: copies[EXTRAFRAME_OFFSET + 1] = seed[FRAME_LENGTH + 1];
375: }
376:
377: SHA1Impl.computeHash(seed);
378:
379: if (seed[BYTES_OFFSET] > MAX_BYTES) {
380:
381: System.arraycopy(seed, 0, copies, FRAME_OFFSET,
382: FRAME_LENGTH);
383: System.arraycopy(copies, EXTRAFRAME_OFFSET, seed, 0,
384: FRAME_LENGTH);
385:
386: SHA1Impl.computeHash(seed);
387: System.arraycopy(copies, FRAME_OFFSET, seed, 0,
388: FRAME_LENGTH);
389: }
390: counter++;
391:
392: int j = 0;
393: for (i = 0; i < EXTRAFRAME_OFFSET; i++) {
394: int k = seed[HASH_OFFSET + i];
395: nextBytes[j] = (byte) (k >>> 24); // getting first byte from left
396: nextBytes[j + 1] = (byte) (k >>> 16); // getting second byte from left
397: nextBytes[j + 2] = (byte) (k >>> 8); // getting third byte from left
398: nextBytes[j + 3] = (byte) (k); // getting fourth byte from left
399: j += 4;
400: }
401:
402: nextBIndex = 0;
403: j = HASHBYTES_TO_USE < (bytes.length - nextByteToReturn) ? HASHBYTES_TO_USE
404: : bytes.length - nextByteToReturn;
405:
406: if (j > 0) {
407: System.arraycopy(nextBytes, 0, bytes, nextByteToReturn,
408: j);
409: nextByteToReturn += j;
410: nextBIndex += j;
411: }
412:
413: if (nextByteToReturn >= bytes.length) {
414: break;
415: }
416: }
417: }
418:
419: private void writeObject(ObjectOutputStream oos) throws IOException {
420:
421: int[] intData = null;
422:
423: final int only_hash = EXTRAFRAME_OFFSET;
424: final int hashes_and_frame = EXTRAFRAME_OFFSET * 2
425: + FRAME_LENGTH;
426: final int hashes_and_frame_extra = EXTRAFRAME_OFFSET * 2
427: + FRAME_LENGTH * 2;
428:
429: oos.writeLong(seedLength);
430: oos.writeLong(counter);
431: oos.writeInt(state);
432: oos.writeInt(seed[BYTES_OFFSET]);
433:
434: int nRemaining = (seed[BYTES_OFFSET] + 3) >> 2; // converting bytes in words
435: // result may be 0
436: if (state != NEXT_BYTES) {
437:
438: // either the state is UNDEFINED or previous method was "setSeed(..)"
439: // so in "seed[]" to serialize are remaining bytes (seed[0-nRemaining]) and
440: // current hash (seed[82-86])
441:
442: intData = new int[only_hash + nRemaining];
443:
444: System.arraycopy(seed, 0, intData, 0, nRemaining);
445: System.arraycopy(seed, HASH_OFFSET, intData, nRemaining,
446: EXTRAFRAME_OFFSET);
447:
448: } else {
449: // previous method was "nextBytes(..)"
450: // so, data to serialize are all the above (two first are in "copies" array)
451: // and current words in both frame and extra frame (as if)
452:
453: int offset = 0;
454: if (seed[BYTES_OFFSET] < MAX_BYTES) { // no extra frame
455:
456: intData = new int[hashes_and_frame + nRemaining];
457:
458: } else { // extra frame is used
459:
460: intData = new int[hashes_and_frame_extra + nRemaining];
461:
462: intData[offset] = seed[FRAME_LENGTH];
463: intData[offset + 1] = seed[FRAME_LENGTH + 1];
464: intData[offset + 2] = seed[FRAME_LENGTH + 14];
465: intData[offset + 3] = seed[FRAME_LENGTH + 15];
466: offset += 4;
467: }
468:
469: System.arraycopy(seed, 0, intData, offset, FRAME_LENGTH);
470: offset += FRAME_LENGTH;
471:
472: System.arraycopy(copies, FRAME_LENGTH + EXTRAFRAME_OFFSET,
473: intData, offset, nRemaining);
474: offset += nRemaining;
475:
476: System.arraycopy(copies, 0, intData, offset,
477: EXTRAFRAME_OFFSET);
478: offset += EXTRAFRAME_OFFSET;
479:
480: System.arraycopy(seed, HASH_OFFSET, intData, offset,
481: EXTRAFRAME_OFFSET);
482: }
483: for (int i = 0; i < intData.length; i++) {
484: oos.writeInt(intData[i]);
485: }
486:
487: oos.writeInt(nextBIndex);
488: oos.write(nextBytes, nextBIndex, HASHBYTES_TO_USE - nextBIndex);
489: }
490:
491: private void readObject(ObjectInputStream ois) throws IOException,
492: ClassNotFoundException {
493:
494: seed = new int[HASH_OFFSET + EXTRAFRAME_OFFSET];
495: copies = new int[2 * FRAME_LENGTH + EXTRAFRAME_OFFSET];
496: nextBytes = new byte[DIGEST_LENGTH];
497:
498: seedLength = ois.readLong();
499: counter = ois.readLong();
500: state = ois.readInt();
501: seed[BYTES_OFFSET] = ois.readInt();
502:
503: int nRemaining = (seed[BYTES_OFFSET] + 3) >> 2; // converting bytes in words
504:
505: if (state != NEXT_BYTES) {
506:
507: for (int i = 0; i < nRemaining; i++) {
508: seed[i] = ois.readInt();
509: }
510: for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
511: seed[HASH_OFFSET + i] = ois.readInt();
512: }
513: } else {
514: if (seed[BYTES_OFFSET] >= MAX_BYTES) {
515:
516: // reading next bytes in seed extra frame
517: seed[FRAME_LENGTH] = ois.readInt();
518: seed[FRAME_LENGTH + 1] = ois.readInt();
519: seed[FRAME_LENGTH + 14] = ois.readInt();
520: seed[FRAME_LENGTH + 15] = ois.readInt();
521: }
522: // reading next bytes in seed frame
523: for (int i = 0; i < FRAME_LENGTH; i++) {
524: seed[i] = ois.readInt();
525: }
526: // reading remaining seed bytes
527: for (int i = 0; i < nRemaining; i++) {
528: copies[FRAME_LENGTH + EXTRAFRAME_OFFSET + i] = ois
529: .readInt();
530: }
531: // reading copy of current hash
532: for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
533: copies[i] = ois.readInt();
534: }
535: // reading current hash
536: for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
537: seed[HASH_OFFSET + i] = ois.readInt();
538: }
539: }
540:
541: nextBIndex = ois.readInt();
542: ois.read(nextBytes, nextBIndex, HASHBYTES_TO_USE - nextBIndex);
543: }
544:
545: }
|