1 module dcrypt.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.random.fortuna.entropysource;
9 import dcrypt.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 @safe
18 public class RebootEntropySource: EntropySource
19 {
20 
21 	private string seedFile;
22 	private Fortuna rng;
23 	private uint blockCounter = 0;
24 	private uint delay = 1;
25 
26 	/// Params:
27 	/// seedFile = The file to load the seed from and to store new seed.
28 	this(string seedFile) nothrow
29 	{
30 		this.seedFile = seedFile;
31 	}
32 
33 	/// Read entropy from file.
34 	@trusted
35 	override public void collectEntropy() nothrow {
36 
37 		delay = 0; // one shot
38 
39 		if(exists(seedFile)) {
40 			try {
41 				// read whole file and send it to the accumulator
42 				File inputFile = File(seedFile, "rb");
43 
44 				scope(exit) {
45 					inputFile.close();
46 				}
47 
48 				foreach(ubyte[] c; inputFile.chunks(32)) {
49 					sendEntropyEvent(c);
50 				}
51 
52 
53 			} catch (Exception e) {
54 				
55 				// TODO
56 				assert(false, "error opening entropy file");
57 			}
58 		}
59 	}
60 
61 	@nogc @property nothrow
62 	override public string name() {
63 		return "RebootSource";
64 	}
65 
66 	@safe @nogc nothrow
67 	override uint scheduleNext() {
68 		return delay;
69 	}
70 
71 	/// Get random data from Fortuna and store it to a file for use at next program start.
72 	@trusted
73 	private void storeEntropy() nothrow {
74 		try {
75 			ubyte[32] buf;
76 
77 			File f = File(seedFile, "wb");
78 
79 			//f.seek(blockSize*blockCounter, SEEK_SET); // FIXME seek does not work as intended
80 
81 			foreach(i; 0..32) {
82 				rng.nextBytes(buf);
83 				f.rawWrite(buf);
84 			}
85 
86 			blockCounter++;
87 			blockCounter %= blocksPerFile;
88 
89 		}catch (Exception e) {
90 			version(assert) {
91 				assert(false, "'reboot' entropy source: could not store entropy to file!");
92 			}
93 			// TODO use a logger
94 		}
95 	}
96 
97 	~this() {
98 		storeEntropy();
99 	}
100 }
101