1 module dcrypt.crypto.random.fortuna.sources.reboot; 2 3 /// The reboot entropy source loads entropy from a specified file 4 /// and updates the seed in this file with new random data. 5 /// The goal of this entropy source is to provide good entropy at start of 6 /// the program. This is however not the case when the program is run the first time. 7 8 import dcrypt.crypto.random.fortuna.entropysource; 9 import dcrypt.crypto.random.fortuna.fortuna; 10 11 import std.stdio; 12 import std.file; 13 14 private enum blockSize = 32*32; 15 private enum blocksPerFile = 16; 16 17 version (linux) { 18 unittest { 19 RebootEntropySource rbs = new RebootEntropySource("/tmp/reboot.seed"); 20 rbs.start(); 21 } 22 } 23 24 @safe 25 public class RebootEntropySource: EntropySource 26 { 27 28 private string seedFile; 29 private Fortuna rng; 30 private uint blockCounter = 0; 31 private uint delay = 1; 32 33 /// Params: 34 /// seedFile = The file to load the seed from and to store new seed. 35 this(string seedFile) nothrow 36 { 37 this.seedFile = seedFile; 38 } 39 40 /// Read entropy from file. 41 @trusted 42 override public void collectEntropy() nothrow { 43 44 delay = 0; // one shot 45 46 if(exists(seedFile)) { 47 try { 48 // read whole file and send it to the accumulator 49 File inputFile = File(seedFile, "rb"); 50 51 scope(exit) { 52 inputFile.close(); 53 } 54 55 foreach(ubyte[] c; inputFile.chunks(32)) { 56 sendEntropyEvent(c); 57 } 58 59 60 } catch (Exception e) { 61 62 // TODO 63 assert(false, "error opening entropy file"); 64 } 65 } 66 } 67 68 @nogc @property nothrow 69 override public string name() { 70 return "RebootSource"; 71 } 72 73 @safe @nogc nothrow 74 override uint scheduleNext() { 75 return delay; 76 } 77 78 /// Get random data from Fortuna and store it to a file for use at next program start. 79 @trusted 80 private void storeEntropy() nothrow { 81 try { 82 ubyte[32] buf; 83 84 File f = File(seedFile, "wb"); 85 86 //f.seek(blockSize*blockCounter, SEEK_SET); // FIXME seek does not work as intended 87 88 foreach(i; 0..32) { 89 rng.nextBytes(buf); 90 f.rawWrite(buf); 91 } 92 93 blockCounter++; 94 blockCounter %= blocksPerFile; 95 96 }catch (Exception e) { 97 version(assert) { 98 assert(false, "'reboot' entropy source: could not store entropy to file!"); 99 } 100 // TODO use a logger 101 } 102 } 103 104 ~this() { 105 storeEntropy(); 106 } 107 } 108