1 module dcrypt.random.urandom;
2 
3 import std.stdio;
4 import std.file;
5 import std.exception;
6 import std.conv: text;
7 
8 import dcrypt.random.prng;
9 
10 /// This module wraps the /dev/urandom special file into a dcrypt PRNG.
11 /// Available for Linux only.
12 
13 version(linux) {
14 
15 	/// Test /dev/urandom based PRNG.
16 	unittest {
17 		URandomRNG rng = new URandomRNG;
18 		
19 		ubyte[16] buf;
20 		
21 		assert(rng.isAvailable);
22 		
23 		rng.nextBytes(buf);
24 		
25 		assert(buf != x"000000000000000000000000000000", "failed to get entropy from /dev/urandom");
26 	}
27 
28 }  
29 
30 unittest {
31 	if(URandomRNG.isAvailable) {
32 		PRNG rand = new URandomRNG();
33 		
34 		auto buf1 = new ubyte[64];
35 		auto buf2 = new ubyte[64];
36 		
37 		rand.nextBytes(buf1);
38 		rand.nextBytes(buf2);
39 		
40 		assert(buf1 != buf2, "data is not random");
41 	}
42 }
43 
44 ///
45 ///	URandomRNG provides an interface to the /dev/urandom RNG of
46 ///	most Unix like systems.
47 ///
48 @safe
49 public class URandomRNG: PRNG {
50 
51 	/**
52 	 Throws: exception if /dev/urandom is not available
53 	 */
54 	public this() {
55 		if (isAvailable()) {
56 			urandFile = File(urand , "r");
57 		} else {
58 			throw new Exception(urand~" not available");
59 		}
60 	}
61 	
62 	~this() {
63 		urandFile.close();
64 	}
65 
66 	/// Evaulates at runtime if /dev/urandom is available.
67 	/// Returns: `true` if /dev/urandom PRNG is available.
68 	@property
69 	public static bool isAvailable() nothrow {
70 			return exists(urand);
71 	}
72 
73 	override {
74 
75 		/// Returns: Get the name of this PRNG.
76 		@property
77 		public pure nothrow string name() {
78 			return "/dev/urandom";
79 		}
80 		
81 		@trusted
82 		public void nextBytes(ubyte[] buf) {
83 			try {
84 				urandFile.rawRead(buf);
85 			}catch(Exception e) {
86 				assert(false, text("URandomPRNG failed to get entropy from ",urand));
87 			}
88 		}
89 		
90 		public void addSeed(in ubyte[] seed) {
91 			// dont do anything
92 		}
93 	}
94 
95 	private {
96 		enum urand = "/dev/urandom";
97 		File urandFile;
98 	}
99 	
100 }