1 module dcrypt.util;
2 
3 import core.vararg;
4 import std.traits;
5 import std.algorithm;
6 
7 /// TODO: neat variadic implementation of `wipe()`
8 
9 /// Clears data in memory.
10 @safe @nogc nothrow
11 void wipe(T)(ref T t) {
12 	static if(is(typeof(cast (ubyte[]) t))) {
13 		ubyte[] bytes = cast(ubyte[]) t;
14 
15 		bytes[] = 0;
16 
17 		if(!all!"a == 0"(bytes[])) {
18 			// This should not get optimized away.
19 			assert(false, "Wiping failed.");
20 		}
21 	} else static if ( is(typeof( {T a = T.init;} ))) {
22 		t = T.init;
23 
24 		if(t != T.init) {
25 			// This should not get optimized away.
26 			assert(false, "Wiping failed.");
27 		}
28 	} else {
29 		static assert(false, "Type not supported for wiping: " ~ T.stringof);
30 	}
31 }
32 
33 
34 @safe @nogc nothrow
35 void wipe(T...)(ref T ts) {
36 	foreach(ref t; ts) {
37 		wipe(t);
38 	}
39 }
40 
41 // test static arrays
42 unittest {
43 	ubyte[4] buf1 = [1,2,3,4];
44 	uint[4] buf2 = [1,2,3,4];
45 	size_t[4] buf3 = [1,2,3,4];
46 
47 	wipe(buf1);
48 	wipe(buf2);
49 	wipe(buf3);
50 
51 	assert(all!"a == 0"(buf1[]), "Failed to wipe ubyte[].");
52 	assert(all!"a == 0"(buf2[]), "Failed to wipe ubyte[].");
53 	assert(all!"a == 0"(buf3[]), "Failed to wipe ubyte[].");
54 }
55 
56 // test dynamic arrays
57 unittest {
58 	ubyte[] buf1 = [1,2,3,4];
59 	uint[] buf2 = [1,2,3,4];
60 	size_t[] buf3 = [1,2,3,4];
61 
62 	wipe(buf1, buf2, buf3);
63 	
64 	assert(all!"a == 0"(buf1), "Failed to wipe ubyte[].");
65 	assert(all!"a == 0"(buf2), "Failed to wipe ubyte[].");
66 	assert(all!"a == 0"(buf3), "Failed to wipe ubyte[].");
67 }
68 
69 unittest {
70 	int a = 42;
71 	int b = 84;
72 	ubyte c = 1;
73 
74 	wipe(a, b, c);
75 
76 	assert(a == 0 && b == 0 && c == 0, "Wiping integer failed!");
77 }
78 
79 /// Compares a and b in constant time.
80 /// 
81 /// Returns: 0 if a == b, some other value if a != b.
82 bool crypto_equals(T)(in T[] a, in T[] b) pure nothrow @safe @nogc
83 in {
84 	assert(a.length == b.length, "Unequal length.");
85 } body  {
86 	T result = 0;
87 	size_t i = 0;
88 
89 	while(i < a.length) {
90 		result |= a[i] ^ b[i];
91 		++i;
92 	}
93 
94 	if(i != a.length) {
95 		// Just to be sure that the compiler optimization does not destroy const time.
96 		assert(false);
97 	}
98 
99 	return result == 0;
100 }
101 
102 // test crypto_equals
103 unittest {
104 	ubyte[32] f = 0;
105 	immutable ubyte[32] zero = 0;
106 	assert(crypto_equals(f[], zero[]));
107 	f[8] = 1;
108 	assert(!crypto_equals(f[], zero[]));
109 }