1 module dcrypt.random.fortuna.sources.filesource;
2 
3 /// Read entropy from a file or special file (/dev/urandom).
4 
5 import dcrypt.random.fortuna.entropysource;
6 import dcrypt.random.fortuna.fortuna;
7 
8 import std.stdio;
9 import std.file;
10 
11 //version (linux) {
12 //	/// Get entropy from /dev/urandom
13 //	unittest {
14 //		import std.algorithm: any;
15 //		FileEntropySource fs = new FileEntropySource("/dev/urandom");
16 //
17 //		ubyte[32] buf;
18 //		ubyte[] slice = fs.getEntropy(buf);
19 //
20 //		assert(slice.length == buf.length, "No data read from /dev/urandom");
21 //		assert(any!"a != 0"(slice), "Got only zeros from /dev/urandom");
22 //	}
23 //}
24 
25 @safe
26 public class FileEntropySource: EntropySource
27 {
28 
29 	private string seedFile;
30 	private File inputFile;
31 	private uint delay = 250;
32 
33 	/// Params:
34 	/// seedFile = The file to load the seed from and to store new seed.
35 	/// Throws: `ErrnoException` if the seed file can not be opened for reading.
36 	this(string seedFile)
37 	{
38 		this.seedFile = seedFile;
39 		inputFile = File(seedFile, "rb");
40 	}
41 
42 	/// Read entropy from file.
43 	@trusted
44 	override public void collectEntropy() nothrow {
45 
46 		ubyte[32] buf;
47 		ubyte[] slice = buf[0..0];
48 
49 		if(inputFile.isOpen) {
50 			// get entropy
51 			try {
52 
53 				slice = inputFile.rawRead(buf);
54 
55 				if(slice.length < buf.length) {
56 					// No remaining data in file
57 					// disable scheduling
58 
59 					delay = 0;
60 				}
61 
62 			} catch (Exception e) {
63 				// TODO
64 				assert(false, "error reading entropy file");
65 			}
66 		} else {
67 			delay = 0; // disable scheduling
68 		}
69 
70 		sendEntropyEvent(slice);
71 	}
72 
73 	@nogc @property nothrow
74 	override public string name() {
75 		return "FileSource";
76 	}
77 
78 	@safe @nogc nothrow
79 	override uint scheduleNext() {
80 		return delay;
81 	}
82 
83 	
84 	~this() {
85 		if(inputFile.isOpen) {
86 			inputFile.close();
87 		}
88 	}
89 }
90