CSPRNG.java 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992
  1. /* CSPRNG.java -- continuously-seeded pseudo-random number generator.
  2. Copyright (C) 2004, 2006, 2010 Free Software Foundation, Inc.
  3. This file is a part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or (at
  7. your option) any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  15. USA
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package gnu.javax.crypto.prng;
  32. import gnu.java.security.Configuration;
  33. import gnu.java.security.Properties;
  34. import gnu.java.security.Registry;
  35. import gnu.java.security.hash.HashFactory;
  36. import gnu.java.security.hash.IMessageDigest;
  37. import gnu.java.security.prng.BasePRNG;
  38. import gnu.java.security.prng.EntropySource;
  39. import gnu.java.security.prng.IRandom;
  40. import gnu.java.security.prng.LimitReachedException;
  41. import gnu.java.security.util.SimpleList;
  42. import gnu.java.security.util.Util;
  43. import gnu.javax.crypto.cipher.CipherFactory;
  44. import gnu.javax.crypto.cipher.IBlockCipher;
  45. import java.io.ByteArrayOutputStream;
  46. import java.io.FileInputStream;
  47. import java.io.InputStream;
  48. import java.io.PrintStream;
  49. import java.net.MalformedURLException;
  50. import java.net.URL;
  51. import java.security.AccessController;
  52. import java.security.InvalidKeyException;
  53. import java.security.PrivilegedAction;
  54. import java.util.Arrays;
  55. import java.util.Collections;
  56. import java.util.HashMap;
  57. import java.util.Iterator;
  58. import java.util.LinkedList;
  59. import java.util.List;
  60. import java.util.Map;
  61. import java.util.StringTokenizer;
  62. import java.util.logging.Level;
  63. import java.util.logging.Logger;
  64. /**
  65. * An entropy pool-based pseudo-random number generator based on the PRNG in
  66. * Peter Gutmann's cryptlib (<a
  67. * href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">http://www.cs.auckland.ac.nz/~pgut001/cryptlib/</a>).
  68. * <p>
  69. * The basic properties of this generator are:
  70. * <ol>
  71. * <li>The internal state cannot be determined by knowledge of the input.</li>
  72. * <li>It is resistant to bias introduced by specific inputs.</li>
  73. * <li>The output does not reveal the state of the generator.</li>
  74. * </ol>
  75. */
  76. public class CSPRNG
  77. extends BasePRNG
  78. {
  79. private static final Logger log = Configuration.DEBUG ?
  80. Logger.getLogger(CSPRNG.class.getName()) : null;
  81. /**
  82. * Property name for the list of files to read for random values. The mapped
  83. * value is a list with the following values:
  84. * <ol>
  85. * <li>A {@link Double}, indicating the suggested <i>quality</i> of this
  86. * source. This value must be between 0 and 100.</li>
  87. * <li>An {@link Integer}, indicating the number of bytes to skip in the
  88. * file before reading bytes. This can be any nonnegative value.</li>
  89. * <li>An {@link Integer}, indicating the number of bytes to read.</li>
  90. * <li>A {@link String}, indicating the path to the file.</li>
  91. * </ol>
  92. *
  93. * @see gnu.java.security.util.SimpleList
  94. */
  95. public static final String FILE_SOURCES = "gnu.crypto.prng.pool.files";
  96. /**
  97. * Property name for the list of URLs to poll for random values. The mapped
  98. * value is a list formatted similarly as in {@link #FILE_SOURCES}, but the
  99. * fourth member is a {@link URL}.
  100. */
  101. public static final String URL_SOURCES = "gnu.crypto.prng.pool.urls";
  102. /**
  103. * Property name for the list of programs to execute, and use the output as
  104. * new random bytes. The mapped property is formatted similarly an in
  105. * {@link #FILE_SOURCES} and {@link #URL_SOURCES}, except the fourth member
  106. * is a {@link String} of the program to execute.
  107. */
  108. public static final String PROGRAM_SOURCES = "gnu.crypto.prng.pool.programs";
  109. /**
  110. * Property name for a list of other sources of entropy. The mapped value must
  111. * be a list of {@link EntropySource} objects.
  112. */
  113. public static final String OTHER_SOURCES = "gnu.crypto.prng.pool.other";
  114. /**
  115. * Property name for whether or not to wait for the slow poll to complete,
  116. * passed as a {@link Boolean}. The default value is true.
  117. */
  118. public static final String BLOCKING = "gnu.crypto.prng.pool.blocking";
  119. private static final String FILES = "gnu.crypto.csprng.file.";
  120. private static final String URLS = "gnu.crypto.csprng.url.";
  121. private static final String PROGS = "gnu.crypto.csprng.program.";
  122. private static final String OTHER = "gnu.crypto.csprng.other.";
  123. private static final String BLOCK = "gnu.crypto.csprng.blocking";
  124. private static final int POOL_SIZE = 256;
  125. private static final int ALLOC_SIZE = 260;
  126. private static final int OUTPUT_SIZE = POOL_SIZE / 2;
  127. private static final int X917_POOL_SIZE = 16;
  128. private static final String HASH_FUNCTION = Registry.SHA160_HASH;
  129. private static final String CIPHER = Registry.AES_CIPHER;
  130. private static final int MIX_COUNT = 10;
  131. private static final int X917_LIFETIME = 8192;
  132. // FIXME this should be configurable.
  133. private static final int SPINNER_COUNT = 8;
  134. /**
  135. * The spinner group singleton. We use this to add a small amount of
  136. * randomness (in addition to the current time and the amount of free memory)
  137. * based on the randomness (if any) present due to system load and thread
  138. * scheduling.
  139. */
  140. private static final Spinner[] SPINNERS = new Spinner[SPINNER_COUNT];
  141. private static final Thread[] SPINNER_THREADS = new Thread[SPINNER_COUNT];
  142. static
  143. {
  144. for (int i = 0; i < SPINNER_COUNT; i++)
  145. {
  146. SPINNER_THREADS[i] = new Thread(SPINNERS[i] = new Spinner(),
  147. "spinner-" + i);
  148. SPINNER_THREADS[i].setDaemon(true);
  149. SPINNER_THREADS[i].setPriority(Thread.MIN_PRIORITY);
  150. SPINNER_THREADS[i].start();
  151. }
  152. }
  153. /** The message digest (SHA-1) used in the mixing function. */
  154. private final IMessageDigest hash;
  155. /** The cipher (AES) used in the output masking function. */
  156. private final IBlockCipher cipher;
  157. /** The number of times the pool has been mixed. */
  158. private int mixCount;
  159. /** The entropy pool. */
  160. private final byte[] pool;
  161. /** The quality of the random pool (percentage). */
  162. private double quality;
  163. /** The index of the next byte in the entropy pool. */
  164. private int index;
  165. /** The pool for the X9.17-like generator. */
  166. private byte[] x917pool;
  167. /** The number of iterations of the X9.17-like generators. */
  168. private int x917count;
  169. /** Whether or not the X9.17-like generator is initialized. */
  170. private boolean x917init;
  171. /** The list of file soures. */
  172. private final List files;
  173. /** The list of URL sources. */
  174. private final List urls;
  175. /** The list of program sources. */
  176. private final List progs;
  177. /** The list of other sources. */
  178. private final List other;
  179. /** Whether or not to wait for the slow poll to complete. */
  180. private boolean blocking;
  181. /** The thread that polls for random data. */
  182. private Poller poller;
  183. private Thread pollerThread;
  184. public CSPRNG()
  185. {
  186. super("CSPRNG");
  187. pool = new byte[ALLOC_SIZE];
  188. x917pool = new byte[X917_POOL_SIZE];
  189. x917count = 0;
  190. x917init = false;
  191. quality = 0.0;
  192. hash = HashFactory.getInstance(HASH_FUNCTION);
  193. cipher = CipherFactory.getInstance(CIPHER);
  194. buffer = new byte[OUTPUT_SIZE];
  195. ndx = 0;
  196. initialised = false;
  197. files = new LinkedList();
  198. urls = new LinkedList();
  199. progs = new LinkedList();
  200. other = new LinkedList();
  201. }
  202. /**
  203. * Create and initialize a CSPRNG instance with the "system" parameters; the
  204. * files, URLs, programs, and {@link EntropySource} sources used by the
  205. * instance are derived from properties set in the system {@link Properties}.
  206. * <p>
  207. * All properties are of the from <i>name</i>.</i>N</i>, where <i>name</i>
  208. * is the name of the source, and <i>N</i> is an integer (staring at 1) that
  209. * indicates the preference number for that source.
  210. * <p>
  211. * The following vales for <i>name</i> are used here:
  212. * <dl>
  213. * <dt>gnu.crypto.csprng.file</dt>
  214. * <dd>
  215. * <p>
  216. * These properties are file sources, passed as the {@link #FILE_SOURCES}
  217. * parameter of the instance. The property value is a 4-tuple formatted as:
  218. * </p>
  219. * <blockquote><i>quality</i> ; <i>offset</i> ; <i>count</i> ; <i>path</i></blockquote>
  220. * <p>
  221. * The parameters are mapped to the parameters defined for {@link
  222. * #FILE_SOURCES}. Leading or trailing spaces on any item are trimmed off.
  223. * </p>
  224. * </dd>
  225. * <dt>gnu.crypto.csprng.url</dt>
  226. * <dd>
  227. * <p>
  228. * These properties are URL sources, passed as the {@link #URL_SOURCES}
  229. * parameter of the instance. The property is formatted the same way as file
  230. * sources, but the <i>path</i> argument must be a valid URL.
  231. * </p>
  232. * </dd>
  233. * <dt>gnu.crypto.csprng.program</dt>
  234. * <dd>
  235. * <p>
  236. * These properties are program sources, passed as the {@link
  237. * #PROGRAM_SOURCES} parameter of the instance. This property is formatted the
  238. * same way as file and URL sources, but the last argument is a program and
  239. * its arguments.
  240. * </p>
  241. * </dd>
  242. * <dt>gnu.crypto.cspring.other</dt>
  243. * <dd>
  244. * <p>
  245. * These properties are other sources, passed as the {@link #OTHER_SOURCES}
  246. * parameter of the instance. The property value must be the full name of a
  247. * class that implements the {@link EntropySource} interface and has a public
  248. * no-argument constructor.
  249. * </p>
  250. * </dd>
  251. * </dl>
  252. * <p>
  253. * Finally, a boolean property "gnu.crypto.csprng.blocking" can be set to the
  254. * desired value of {@link #BLOCKING}.
  255. * <p>
  256. * An example of valid properties would be:
  257. * <pre>
  258. * gnu.crypto.csprng.blocking=true
  259. *
  260. * gnu.crypto.csprng.file.1=75.0;0;256;/dev/random
  261. * gnu.crypto.csprng.file.2=10.0;0;100;/home/user/file
  262. *
  263. * gnu.crypto.csprng.url.1=5.0;0;256;http://www.random.org/cgi-bin/randbyte?nbytes=256
  264. * gnu.crypto.csprng.url.2=0;256;256;http://slashdot.org/
  265. *
  266. * gnu.crypto.csprng.program.1=0.5;0;10;last -n 50
  267. * gnu.crypto.csprng.program.2=0.5;0;10;tcpdump -c 5
  268. *
  269. * gnu.crypto.csprng.other.1=foo.bar.MyEntropySource
  270. * gnu.crypto.csprng.other.2=com.company.OtherEntropySource
  271. * </pre>
  272. */
  273. public static IRandom getSystemInstance() throws ClassNotFoundException,
  274. MalformedURLException, NumberFormatException
  275. {
  276. CSPRNG instance = new CSPRNG();
  277. HashMap attrib = new HashMap();
  278. attrib.put(BLOCKING, Boolean.valueOf(getProperty(BLOCK)));
  279. String s = null;
  280. // Get each file source "gnu.crypto.csprng.file.N".
  281. List l = new LinkedList();
  282. for (int i = 0; (s = getProperty(FILES + i)) != null; i++)
  283. try
  284. {
  285. l.add(parseString(s.trim()));
  286. }
  287. catch (NumberFormatException nfe)
  288. {
  289. }
  290. attrib.put(FILE_SOURCES, l);
  291. l = new LinkedList();
  292. for (int i = 0; (s = getProperty(URLS + i)) != null; i++)
  293. try
  294. {
  295. l.add(parseURL(s.trim()));
  296. }
  297. catch (NumberFormatException nfe)
  298. {
  299. }
  300. catch (MalformedURLException mue)
  301. {
  302. }
  303. attrib.put(URL_SOURCES, l);
  304. l = new LinkedList();
  305. for (int i = 0; (s = getProperty(PROGS + i)) != null; i++)
  306. try
  307. {
  308. l.add(parseString(s.trim()));
  309. }
  310. catch (NumberFormatException nfe)
  311. {
  312. }
  313. attrib.put(PROGRAM_SOURCES, l);
  314. l = new LinkedList();
  315. for (int i = 0; (s = getProperty(OTHER + i)) != null; i++)
  316. {
  317. try
  318. {
  319. l.add((EntropySource)Class.forName(s.trim()).newInstance());
  320. }
  321. catch (ClassNotFoundException cnfe)
  322. {
  323. // ignore
  324. }
  325. catch (InstantiationException ie)
  326. {
  327. // ignore
  328. }
  329. catch (IllegalAccessException iae)
  330. {
  331. // ignore
  332. }
  333. }
  334. attrib.put(OTHER_SOURCES, l);
  335. instance.init(attrib);
  336. return instance;
  337. }
  338. private static String getProperty(final String name)
  339. {
  340. return (String) AccessController.doPrivileged(new PrivilegedAction()
  341. {
  342. public Object run()
  343. {
  344. return Properties.getProperty(name);
  345. }
  346. });
  347. }
  348. private static List parseString(String s) throws NumberFormatException
  349. {
  350. StringTokenizer tok = new StringTokenizer(s, ";");
  351. if (tok.countTokens() != 4)
  352. throw new IllegalArgumentException("malformed property");
  353. Double quality = new Double(tok.nextToken());
  354. Integer offset = new Integer(tok.nextToken());
  355. Integer length = new Integer(tok.nextToken());
  356. String str = tok.nextToken();
  357. return new SimpleList(quality, offset, length, str);
  358. }
  359. private static List parseURL(String s) throws MalformedURLException,
  360. NumberFormatException
  361. {
  362. StringTokenizer tok = new StringTokenizer(s, ";");
  363. if (tok.countTokens() != 4)
  364. throw new IllegalArgumentException("malformed property");
  365. Double quality = new Double(tok.nextToken());
  366. Integer offset = new Integer(tok.nextToken());
  367. Integer length = new Integer(tok.nextToken());
  368. URL url = new URL(tok.nextToken());
  369. return new SimpleList(quality, offset, length, url);
  370. }
  371. public Object clone()
  372. {
  373. return new CSPRNG();
  374. }
  375. public void setup(Map attrib)
  376. {
  377. List list = null;
  378. if (Configuration.DEBUG)
  379. log.fine("attrib=" + String.valueOf(attrib));
  380. try
  381. {
  382. list = (List) attrib.get(FILE_SOURCES);
  383. if (Configuration.DEBUG)
  384. log.fine("list=" + String.valueOf(list));
  385. if (list != null)
  386. {
  387. files.clear();
  388. for (Iterator it = list.iterator(); it.hasNext();)
  389. {
  390. List l = (List) it.next();
  391. if (Configuration.DEBUG)
  392. log.fine("l=" + l);
  393. if (l.size() != 4)
  394. {
  395. if (Configuration.DEBUG)
  396. log.fine("file list too small: " + l.size());
  397. throw new IllegalArgumentException("invalid file list");
  398. }
  399. Double quality = (Double) l.get(0);
  400. Integer offset = (Integer) l.get(1);
  401. Integer length = (Integer) l.get(2);
  402. String source = (String) l.get(3);
  403. files.add(new SimpleList(quality, offset, length, source));
  404. }
  405. }
  406. }
  407. catch (ClassCastException cce)
  408. {
  409. if (Configuration.DEBUG)
  410. log.log(Level.FINE, "bad file list", cce);
  411. throw new IllegalArgumentException("invalid file list");
  412. }
  413. try
  414. {
  415. list = (List) attrib.get(URL_SOURCES);
  416. if (Configuration.DEBUG)
  417. log.fine("list=" + String.valueOf(list));
  418. if (list != null)
  419. {
  420. urls.clear();
  421. for (Iterator it = list.iterator(); it.hasNext();)
  422. {
  423. List l = (List) it.next();
  424. if (Configuration.DEBUG)
  425. log.fine("l=" + l);
  426. if (l.size() != 4)
  427. {
  428. if (Configuration.DEBUG)
  429. log.fine("URL list too small: " + l.size());
  430. throw new IllegalArgumentException("invalid URL list");
  431. }
  432. Double quality = (Double) l.get(0);
  433. Integer offset = (Integer) l.get(1);
  434. Integer length = (Integer) l.get(2);
  435. URL source = (URL) l.get(3);
  436. urls.add(new SimpleList(quality, offset, length, source));
  437. }
  438. }
  439. }
  440. catch (ClassCastException cce)
  441. {
  442. if (Configuration.DEBUG)
  443. log.log(Level.FINE, "bad URL list", cce);
  444. throw new IllegalArgumentException("invalid URL list");
  445. }
  446. try
  447. {
  448. list = (List) attrib.get(PROGRAM_SOURCES);
  449. if (Configuration.DEBUG)
  450. log.fine("list=" + String.valueOf(list));
  451. if (list != null)
  452. {
  453. progs.clear();
  454. for (Iterator it = list.iterator(); it.hasNext();)
  455. {
  456. List l = (List) it.next();
  457. if (Configuration.DEBUG)
  458. log.fine("l=" + l);
  459. if (l.size() != 4)
  460. {
  461. if (Configuration.DEBUG)
  462. log.fine("program list too small: " + l.size());
  463. throw new IllegalArgumentException("invalid program list");
  464. }
  465. Double quality = (Double) l.get(0);
  466. Integer offset = (Integer) l.get(1);
  467. Integer length = (Integer) l.get(2);
  468. String source = (String) l.get(3);
  469. progs.add(new SimpleList(quality, offset, length, source));
  470. }
  471. }
  472. }
  473. catch (ClassCastException cce)
  474. {
  475. if (Configuration.DEBUG)
  476. log.log(Level.FINE, "bad program list", cce);
  477. throw new IllegalArgumentException("invalid program list");
  478. }
  479. try
  480. {
  481. list = (List) attrib.get(OTHER_SOURCES);
  482. if (Configuration.DEBUG)
  483. log.fine("list=" + String.valueOf(list));
  484. if (list != null)
  485. {
  486. other.clear();
  487. for (Iterator it = list.iterator(); it.hasNext();)
  488. {
  489. EntropySource src = (EntropySource) it.next();
  490. if (Configuration.DEBUG)
  491. log.fine("src=" + src);
  492. if (src == null)
  493. throw new NullPointerException("null source in source list");
  494. other.add(src);
  495. }
  496. }
  497. }
  498. catch (ClassCastException cce)
  499. {
  500. throw new IllegalArgumentException("invalid source list");
  501. }
  502. try
  503. {
  504. Boolean block = (Boolean) attrib.get(BLOCKING);
  505. if (block != null)
  506. blocking = block.booleanValue();
  507. else
  508. blocking = true;
  509. }
  510. catch (ClassCastException cce)
  511. {
  512. throw new IllegalArgumentException("invalid blocking parameter");
  513. }
  514. poller = new Poller(files, urls, progs, other, this);
  515. try
  516. {
  517. fillBlock();
  518. }
  519. catch (LimitReachedException lre)
  520. {
  521. throw new RuntimeException("bootstrapping CSPRNG failed");
  522. }
  523. }
  524. public void fillBlock() throws LimitReachedException
  525. {
  526. if (Configuration.DEBUG)
  527. log.fine("fillBlock");
  528. if (getQuality() < 100.0)
  529. {
  530. if (Configuration.DEBUG)
  531. log.fine("doing slow poll");
  532. slowPoll();
  533. }
  534. do
  535. {
  536. fastPoll();
  537. mixRandomPool();
  538. }
  539. while (mixCount < MIX_COUNT);
  540. if (! x917init || x917count >= X917_LIFETIME)
  541. {
  542. mixRandomPool(pool);
  543. Map attr = new HashMap();
  544. byte[] key = new byte[32];
  545. System.arraycopy(pool, 0, key, 0, 32);
  546. cipher.reset();
  547. attr.put(IBlockCipher.KEY_MATERIAL, key);
  548. try
  549. {
  550. cipher.init(attr);
  551. }
  552. catch (InvalidKeyException ike)
  553. {
  554. throw new Error(ike.toString());
  555. }
  556. mixRandomPool(pool);
  557. generateX917(pool);
  558. mixRandomPool(pool);
  559. generateX917(pool);
  560. if (x917init)
  561. quality = 0.0;
  562. x917init = true;
  563. x917count = 0;
  564. }
  565. byte[] export = new byte[ALLOC_SIZE];
  566. for (int i = 0; i < ALLOC_SIZE; i++)
  567. export[i] = (byte)(pool[i] ^ 0xFF);
  568. mixRandomPool();
  569. mixRandomPool(export);
  570. generateX917(export);
  571. for (int i = 0; i < OUTPUT_SIZE; i++)
  572. buffer[i] = (byte)(export[i] ^ export[i + OUTPUT_SIZE]);
  573. Arrays.fill(export, (byte) 0);
  574. }
  575. /**
  576. * Add an array of bytes into the randomness pool. Note that this method will
  577. * <i>not</i> increment the pool's quality counter (this can only be done via
  578. * a source provided to the setup method).
  579. *
  580. * @param buf The byte array.
  581. * @param off The offset from whence to start reading bytes.
  582. * @param len The number of bytes to add.
  583. * @throws ArrayIndexOutOfBoundsException If <i>off</i> or <i>len</i> are
  584. * out of the range of <i>buf</i>.
  585. */
  586. public synchronized void addRandomBytes(byte[] buf, int off, int len)
  587. {
  588. if (off < 0 || len < 0 || off + len > buf.length)
  589. throw new ArrayIndexOutOfBoundsException();
  590. if (Configuration.DEBUG)
  591. {
  592. log.fine("adding random bytes:");
  593. log.fine(Util.toString(buf, off, len));
  594. }
  595. final int count = off + len;
  596. for (int i = off; i < count; i++)
  597. {
  598. pool[index++] ^= buf[i];
  599. if (index == pool.length)
  600. {
  601. mixRandomPool();
  602. index = 0;
  603. }
  604. }
  605. }
  606. /**
  607. * Add a single random byte to the randomness pool. Note that this method will
  608. * <i>not</i> increment the pool's quality counter (this can only be done via
  609. * a source provided to the setup method).
  610. *
  611. * @param b The byte to add.
  612. */
  613. public synchronized void addRandomByte(byte b)
  614. {
  615. if (Configuration.DEBUG)
  616. log.fine("adding byte " + Integer.toHexString(b));
  617. pool[index++] ^= b;
  618. if (index >= pool.length)
  619. {
  620. mixRandomPool();
  621. index = 0;
  622. }
  623. }
  624. synchronized void addQuality(double quality)
  625. {
  626. if (Configuration.DEBUG)
  627. log.fine("adding quality " + quality);
  628. if (this.quality < 100)
  629. this.quality += quality;
  630. if (Configuration.DEBUG)
  631. log.fine("quality now " + this.quality);
  632. }
  633. synchronized double getQuality()
  634. {
  635. return quality;
  636. }
  637. /**
  638. * The mix operation. This method will, for every 20-byte block in the random
  639. * pool, hash that block, the previous 20 bytes, and the next 44 bytes with
  640. * SHA-1, writing the result back into that block.
  641. */
  642. private void mixRandomPool(byte[] buf)
  643. {
  644. int hashSize = hash.hashSize();
  645. for (int i = 0; i < buf.length; i += hashSize)
  646. {
  647. // First update the bytes [p-19..p-1].
  648. if (i == 0)
  649. hash.update(buf, buf.length - hashSize, hashSize);
  650. else
  651. hash.update(buf, i - hashSize, hashSize);
  652. // Now the next 64 bytes.
  653. if (i + 64 < buf.length)
  654. hash.update(buf, i, 64);
  655. else
  656. {
  657. hash.update(buf, i, buf.length - i);
  658. hash.update(buf, 0, 64 - (buf.length - i));
  659. }
  660. byte[] digest = hash.digest();
  661. System.arraycopy(digest, 0, buf, i, hashSize);
  662. }
  663. }
  664. private void mixRandomPool()
  665. {
  666. mixRandomPool(pool);
  667. mixCount++;
  668. }
  669. private void generateX917(byte[] buf)
  670. {
  671. int off = 0;
  672. for (int i = 0; i < buf.length; i += X917_POOL_SIZE)
  673. {
  674. int copy = Math.min(buf.length - i, X917_POOL_SIZE);
  675. for (int j = 0; j < copy; j++)
  676. x917pool[j] ^= pool[off + j];
  677. cipher.encryptBlock(x917pool, 0, x917pool, 0);
  678. System.arraycopy(x917pool, 0, buf, off, copy);
  679. cipher.encryptBlock(x917pool, 0, x917pool, 0);
  680. off += copy;
  681. x917count++;
  682. }
  683. }
  684. /**
  685. * Add random data always immediately available into the random pool, such as
  686. * the values of the eight asynchronous counters, the current time, the
  687. * current memory usage, the calling thread name, and the current stack trace.
  688. * <p>
  689. * This method does not alter the quality counter, and is provided more to
  690. * maintain randomness, not to seriously improve the current random state.
  691. */
  692. private void fastPoll()
  693. {
  694. byte b = 0;
  695. for (int i = 0; i < SPINNER_COUNT; i++)
  696. b ^= SPINNERS[i].counter;
  697. addRandomByte(b);
  698. addRandomByte((byte) System.currentTimeMillis());
  699. addRandomByte((byte) Runtime.getRuntime().freeMemory());
  700. String s = Thread.currentThread().getName();
  701. if (s != null)
  702. {
  703. byte[] buf = s.getBytes();
  704. addRandomBytes(buf, 0, buf.length);
  705. }
  706. ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
  707. PrintStream pout = new PrintStream(bout);
  708. Throwable t = new Throwable();
  709. t.printStackTrace(pout);
  710. pout.flush();
  711. byte[] buf = bout.toByteArray();
  712. addRandomBytes(buf, 0, buf.length);
  713. }
  714. private void slowPoll() throws LimitReachedException
  715. {
  716. if (Configuration.DEBUG)
  717. log.fine("poller is alive? "
  718. + (pollerThread == null ? false : pollerThread.isAlive()));
  719. if (pollerThread == null || ! pollerThread.isAlive())
  720. {
  721. boolean interrupted = false;
  722. pollerThread = new Thread(poller);
  723. pollerThread.setDaemon(true);
  724. pollerThread.setPriority(Thread.NORM_PRIORITY - 1);
  725. pollerThread.start();
  726. if (blocking)
  727. try
  728. {
  729. pollerThread.join();
  730. }
  731. catch (InterruptedException ie)
  732. {
  733. interrupted = true;
  734. }
  735. // If the full slow poll has completed after we waited for it,
  736. // and there in insufficient randomness, throw an exception.
  737. if (! interrupted && blocking && quality < 100.0)
  738. {
  739. if (Configuration.DEBUG)
  740. log.fine("insufficient quality: " + quality);
  741. throw new LimitReachedException("insufficient randomness was polled");
  742. }
  743. }
  744. }
  745. protected void finalize() throws Throwable
  746. {
  747. if (poller != null && pollerThread != null && pollerThread.isAlive())
  748. {
  749. pollerThread.interrupt();
  750. poller.stopUpdating();
  751. pollerThread.interrupt();
  752. }
  753. Arrays.fill(pool, (byte) 0);
  754. Arrays.fill(x917pool, (byte) 0);
  755. Arrays.fill(buffer, (byte) 0);
  756. }
  757. /**
  758. * A simple thread that constantly updates a byte counter. This class is used
  759. * in a group of lowest-priority threads and the values of their counters
  760. * (updated in competition with all other threads) is used as a source of
  761. * entropy bits.
  762. */
  763. private static class Spinner
  764. implements Runnable
  765. {
  766. protected byte counter;
  767. private Spinner()
  768. {
  769. }
  770. public void run()
  771. {
  772. while (true)
  773. {
  774. counter++;
  775. try
  776. {
  777. Thread.sleep(100);
  778. }
  779. catch (InterruptedException ie)
  780. {
  781. }
  782. }
  783. }
  784. }
  785. private final class Poller
  786. implements Runnable
  787. {
  788. private final List files;
  789. private final List urls;
  790. private final List progs;
  791. private final List other;
  792. private final CSPRNG pool;
  793. private boolean running;
  794. Poller(List files, List urls, List progs, List other, CSPRNG pool)
  795. {
  796. super();
  797. this.files = Collections.unmodifiableList(files);
  798. this.urls = Collections.unmodifiableList(urls);
  799. this.progs = Collections.unmodifiableList(progs);
  800. this.other = Collections.unmodifiableList(other);
  801. this.pool = pool;
  802. }
  803. public void run()
  804. {
  805. running = true;
  806. if (Configuration.DEBUG)
  807. {
  808. log.fine("files: " + files);
  809. log.fine("URLs: " + urls);
  810. log.fine("progs: " + progs);
  811. }
  812. Iterator files_it = files.iterator();
  813. Iterator urls_it = urls.iterator();
  814. Iterator prog_it = progs.iterator();
  815. Iterator other_it = other.iterator();
  816. while (files_it.hasNext() || urls_it.hasNext() || prog_it.hasNext()
  817. || other_it.hasNext())
  818. {
  819. // There is enough random data. Go away.
  820. if (pool.getQuality() >= 100.0 || ! running)
  821. return;
  822. if (files_it.hasNext())
  823. try
  824. {
  825. List l = (List) files_it.next();
  826. if (Configuration.DEBUG)
  827. log.fine(l.toString());
  828. double qual = ((Double) l.get(0)).doubleValue();
  829. int offset = ((Integer) l.get(1)).intValue();
  830. int count = ((Integer) l.get(2)).intValue();
  831. String src = (String) l.get(3);
  832. InputStream in = new FileInputStream(src);
  833. byte[] buf = new byte[count];
  834. if (offset > 0)
  835. in.skip(offset);
  836. int len = in.read(buf);
  837. if (len >= 0)
  838. {
  839. pool.addRandomBytes(buf, 0, len);
  840. pool.addQuality(qual * ((double) len / (double) count));
  841. }
  842. if (Configuration.DEBUG)
  843. log.fine("got " + len + " bytes from " + src);
  844. }
  845. catch (Exception x)
  846. {
  847. if (Configuration.DEBUG)
  848. log.throwing(this.getClass().getName(), "run", x);
  849. }
  850. if (pool.getQuality() >= 100.0 || ! running)
  851. return;
  852. if (urls_it.hasNext())
  853. try
  854. {
  855. List l = (List) urls_it.next();
  856. if (Configuration.DEBUG)
  857. log.fine(l.toString());
  858. double qual = ((Double) l.get(0)).doubleValue();
  859. int offset = ((Integer) l.get(1)).intValue();
  860. int count = ((Integer) l.get(2)).intValue();
  861. URL src = (URL) l.get(3);
  862. InputStream in = src.openStream();
  863. byte[] buf = new byte[count];
  864. if (offset > 0)
  865. in.skip(offset);
  866. int len = in.read(buf);
  867. if (len >= 0)
  868. {
  869. pool.addRandomBytes(buf, 0, len);
  870. pool.addQuality(qual * ((double) len / (double) count));
  871. }
  872. if (Configuration.DEBUG)
  873. log.fine("got " + len + " bytes from " + src);
  874. }
  875. catch (Exception x)
  876. {
  877. if (Configuration.DEBUG)
  878. log.throwing(this.getClass().getName(), "run", x);
  879. }
  880. if (pool.getQuality() >= 100.0 || ! running)
  881. return;
  882. Process proc = null;
  883. if (prog_it.hasNext())
  884. try
  885. {
  886. List l = (List) prog_it.next();
  887. if (Configuration.DEBUG)
  888. log.finer(l.toString());
  889. double qual = ((Double) l.get(0)).doubleValue();
  890. int offset = ((Integer) l.get(1)).intValue();
  891. int count = ((Integer) l.get(2)).intValue();
  892. String src = (String) l.get(3);
  893. proc = null;
  894. proc = Runtime.getRuntime().exec(src);
  895. InputStream in = proc.getInputStream();
  896. byte[] buf = new byte[count];
  897. if (offset > 0)
  898. in.skip(offset);
  899. int len = in.read(buf);
  900. if (len >= 0)
  901. {
  902. pool.addRandomBytes(buf, 0, len);
  903. pool.addQuality(qual * ((double) len / (double) count));
  904. }
  905. proc.destroy();
  906. proc.waitFor();
  907. if (Configuration.DEBUG)
  908. log.fine("got " + len + " bytes from " + src);
  909. }
  910. catch (Exception x)
  911. {
  912. if (Configuration.DEBUG)
  913. log.throwing(this.getClass().getName(), "run", x);
  914. try
  915. {
  916. if (proc != null)
  917. {
  918. proc.destroy();
  919. proc.waitFor();
  920. }
  921. }
  922. catch (Exception ignored)
  923. {
  924. }
  925. }
  926. if (pool.getQuality() >= 100.0 || ! running)
  927. return;
  928. if (other_it.hasNext())
  929. try
  930. {
  931. EntropySource src = (EntropySource) other_it.next();
  932. byte[] buf = src.nextBytes();
  933. if (pool == null)
  934. return;
  935. pool.addRandomBytes(buf, 0, buf.length);
  936. pool.addQuality(src.quality());
  937. if (Configuration.DEBUG)
  938. log.fine("got " + buf.length + " bytes from " + src);
  939. }
  940. catch (Exception x)
  941. {
  942. if (Configuration.DEBUG)
  943. log.throwing(this.getClass().getName(), "run", x);
  944. }
  945. }
  946. }
  947. public void stopUpdating()
  948. {
  949. running = false;
  950. }
  951. }
  952. }