Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: mindbright/security/SecureRandom.java


1   /******************************************************************************
2    *
3    * Copyright (C) 1998 Logi Ragnarsson
4    *
5    * Adapted 1999 for use in MindTerm by Mats Andersson (mats@mindbright.se)
6    * This class is the RandomSpinner class of the Cryptonite library found at:
7    *     <http://www.hi.is/~logir/cryptonite/>
8    *
9    * This program is free software; you can redistribute it and/or modify
10   * it under the terms of the GNU General Public License as published by
11   * the Free Software Foundation; either version 2 of the License, or
12   * (at your option) any later version.
13   *
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   *
19   *****************************************************************************
20   * $Author: nallen $
21   * $Date: 2001/11/12 16:31:16 $
22   * $Name:  $
23   *****************************************************************************/
24  package mindbright.security;
25  
26  import java.util.Random;
27  
28  /**
29   * This class uses the scheduler to generate random numbers. It counts the
30   * number of times a loop is repeated before a thread has slept for a specified
31   * number of milliseconds. These numbers are then fed to a hash function to mask
32   * any possible correlations.<p>
33   */
34  public class SecureRandom extends Random {
35  
36      MD5 md5 = new MD5();
37      private int t;
38      public Thread updater;
39  
40      public static int secureLevel = 0;
41  
42      public SecureRandom() {
43          t=Spinner.guessTime(1024);
44  
45    int paranoia = ((secureLevel > 0) ? 2 : 1);
46  
47    for(int i=0; i<paranoia; i++) {
48              // Estimate about 4 bits of entropy per call to spinner
49              for(int j=md5.buffer.length-1; j>=0; j--) {
50                  // Fill the buffer with spin-counts from the Spinner class.
51                  md5.buffer[j] = (byte)Spinner.spin(t);
52      if(secureLevel < 2)
53          md5.buffer[--j] = (byte)System.currentTimeMillis();
54        }
55              md5.transform(md5.buffer, 0);
56    }
57          unused     = new byte[16];
58          unusedPos  = 16;
59    unusedLock = new Object();
60      }
61  
62      public SecureRandom(byte[] seed) {
63    try {
64        MD5 md5 = new MD5();
65        md5.update(seed);
66        this.md5 = md5;
67    } catch (Exception e) {
68        // !!!
69        System.out.println("Can't operate, MD5 not available...");
70    }
71          t = Spinner.guessTime(1024);
72          unused     = new byte[16];
73          unusedPos  = 16;
74    unusedLock = new Object();
75      }
76  
77      /** unused[unusedPos..15] is unused pseudo-random numbers. */
78      byte[] unused;
79      int    unusedPos;
80      Object unusedLock;
81  
82      int poolSweep=0;
83  
84      /** Get new unused bytes. */
85      protected synchronized void update() {
86          // Inject entropy into the pool
87    //
88    if(secureLevel > 1) {
89        md5.buffer[poolSweep++] += Spinner.spin(t) + 1;
90        md5.buffer[poolSweep++] += Spinner.spin(t) + 1;
91    } else {
92        md5.buffer[poolSweep++] += Spinner.bogusSpin();
93        md5.buffer[poolSweep]   += md5.buffer[poolSweep - 1];
94        poolSweep++;
95    }
96  
97          poolSweep %= 64;
98  
99    byte[] newUnused = new byte[16];
100         md5.transform(md5.buffer,0);
101         writeBytes(md5.hash[0], newUnused, 0,4);
102         writeBytes(md5.hash[1], newUnused, 4,4);
103         writeBytes(md5.hash[2], newUnused, 8,4);
104         writeBytes(md5.hash[3], newUnused,12,4);
105 
106   synchronized(unusedLock) {
107       unused    = newUnused;
108       unusedPos = 0;
109   }
110     }
111     
112     /** Generates the next random number. */
113     protected synchronized int next(int bits) {
114         //System.out.println(bits);
115   int r=0;
116   synchronized(unusedLock) {
117       for(int b=0; b<bits; b+=8) {
118     if(unusedPos==16)
119         update();
120     r = (r<<8) + unused[unusedPos++];
121       }
122   }
123         return r;
124     }
125 
126     public synchronized void startUpdater() {
127   if(updater != null)
128       return;
129   updater = (new Thread(new Runnable() {
130       public void run() { 
131     SecureRandom.this.updater.setPriority(SecureRandom.this.updater.getPriority() - 1);
132     while(true) {
133         try {
134       Thread.sleep(10000);
135         } catch (InterruptedException e) {
136       // !!!
137         }
138         SecureRandom.this.update();
139     }
140       }
141   }));
142   updater.start();
143     }
144 
145     public void nextPadBytes(byte[] bytes, int len) {
146   nextPadBytes(bytes, 0, len);
147     }
148 
149     public void nextPadBytes(byte[] bytes, int off, int len) {
150   byte[] ub;
151   int    ui;
152   synchronized(unusedLock) {
153       for(int i = 0; i < len; i++) {
154     unusedPos %= 16;
155     bytes[off + i] = unused[unusedPos++];
156       }
157   }
158     }
159 
160     public static final void writeBytes(long a, byte[] dest, int i, int length) {
161         for (int j=i+length-1; j>=i; j--){
162             dest[j]=(byte)a;
163             a = a >>> 8;
164         }
165     }
166 
167 }