1 module passwd.securewipe; 2 3 @safe: 4 5 import std.traits; 6 7 /** 8 Guarantee value's memory is wiped with zeroes (even with optimisations enabled) 9 10 It's conservative about the types that are allowed. If your type isn't allowed, you should possibly consider using a different one for sensitive data. 11 For example, it won't erase immutable types like strings (use `char[]` instead) or classes (use a plain-old-data struct instead) or anything containing pointers. 12 */ 13 void secureWipe(T)(ref T value) @trusted if (isJustData!T && isMutable!T) 14 { 15 explicit_bzero(&value, T.sizeof); 16 } 17 18 /// ditto 19 void secureWipe(T)(T[] value) @trusted if (isJustData!T && isMutable!T) 20 { 21 // This should be impossible, but @safe is @safe 22 if (value.length > size_t.max / T.sizeof) throw new Error("Array too large to be handled safely"); 23 24 explicit_bzero(value.ptr, T.sizeof * value.length); 25 } 26 27 private: 28 29 extern(C) void explicit_bzero(void*, size_t) @nogc nothrow; 30 31 /** 32 True only for types that are raw data value types with no pointers, etc. 33 34 It's meant to test for types that are safe to wipe. 35 */ 36 template isJustData(T) 37 { 38 static if (isScalarType!T) 39 { 40 enum isJustData = true; 41 } 42 else static if (isStaticArray!T) 43 { 44 enum isJustData = isJustData!(ForeachType!T); 45 } 46 else static if (is(T == struct) || is(T == union)) 47 { 48 enum isJustData = __traits(isPOD, T) && !isNested!T && allFieldsJustData!T; 49 } 50 else 51 { 52 enum isJustData = false; 53 } 54 } 55 56 /** 57 Helper for isJustData 58 59 Required because of D's scoping rules. 60 */ 61 template allFieldsJustData(S) 62 { 63 import std.meta : allSatisfy; 64 enum allFieldsJustData = allSatisfy!(isJustData, Fields!S); 65 }