1 module dcrypt.random.fortuna.entropysource; 2 3 4 import core.thread; 5 6 import dcrypt.random.fortuna.accumulator; 7 8 /// 9 /// This class provides a simple method to pass an entropy event 10 /// to the accumulator of the PRNG algorithm. Namely: sendEntropyEvent() 11 /// 12 /// 13 @safe 14 public abstract class EntropySource 15 { 16 private 17 { 18 static ubyte idCounter = 0; 19 ubyte sourceID; 20 size_t pool = 0; // ID of the pool where the entropy gets sent to. 21 bool calledSendEntropyEvent; /// Used to control wether the source calls sendEntropyEvent or not. 22 Thread worker; 23 24 bool running = true; 25 } 26 27 28 final this() nothrow { 29 this.sourceID = idCounter++; // give each source another ID (as long as there are less than 256 sources) 30 } 31 32 public final void stop() nothrow { 33 running = false; 34 } 35 36 @trusted 37 public final void start() nothrow { 38 try { 39 worker = new Thread(&run); 40 worker.isDaemon = true; 41 worker.start(); 42 } catch(Exception e) { 43 assert(false, e.toString()); 44 } 45 } 46 47 private void run() { 48 49 while(running) { 50 51 calledSendEntropyEvent = false; 52 collectEntropy(); 53 54 assert(calledSendEntropyEvent, name~" did not call sendEntropyEvent()."); 55 56 uint delay = scheduleNext(); // Ask the source when it wants to be invoked. 57 58 if(delay > 0) { 59 trustedSleep!"msecs"(delay); 60 } else { 61 // delay == 0 means the source wants to be closed 62 running = false; 63 } 64 } 65 66 } 67 68 @trusted 69 private static void trustedSleep(string s)(uint i) nothrow { 70 try { 71 Thread.sleep(dur!s(i)); 72 } catch (ThreadError te) { 73 // swallow 74 } 75 } 76 77 /// Collect entropy. 78 /// Note: Implementation must call `sendEntropyEvent(in ubyte[] buf)` to send data to the accumulator. 79 public abstract void collectEntropy(); 80 81 @safe @nogc nothrow 82 public abstract uint scheduleNext(); 83 84 @property @nogc nothrow 85 public abstract string name(); 86 87 /// use this method to send entropy to the accumulator 88 @safe 89 protected final void sendEntropyEvent(in ubyte[] buf) nothrow { 90 import dcrypt.random.fortuna.fortuna: addEntropy; 91 92 calledSendEntropyEvent = true; 93 addEntropy(sourceID, pool, buf); 94 ++pool; 95 } 96 97 } 98