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 }