Files
angelc2/full/Angel-payload/angel/utils/cryptography/utils.d
2025-12-22 16:23:48 +01:00

109 lines
2.1 KiB
D

module angel.utils.cryptography.utils;
import core.vararg;
import std.traits;
import std.algorithm;
/// TODO: neat variadic implementation of `wipe()`
/// Clears data in memory.
@safe @nogc nothrow
void wipe(T)(ref T t) {
static if(is(typeof(cast (ubyte[]) t))) {
ubyte[] bytes = cast(ubyte[]) t;
bytes[] = 0;
if(!all!"a == 0"(bytes[])) {
// This should not get optimized away.
assert(false, "Wiping failed.");
}
} else static if ( is(typeof( {T a = T.init;} ))) {
t = T.init;
if(t != T.init) {
// This should not get optimized away.
assert(false, "Wiping failed.");
}
} else {
static assert(false, "Type not supported for wiping: " ~ T.stringof);
}
}
@safe @nogc nothrow
void wipe(T...)(ref T ts) {
foreach(ref t; ts) {
wipe(t);
}
}
// test static arrays
unittest {
ubyte[4] buf1 = [1,2,3,4];
uint[4] buf2 = [1,2,3,4];
size_t[4] buf3 = [1,2,3,4];
wipe(buf1);
wipe(buf2);
wipe(buf3);
assert(all!"a == 0"(buf1[]), "Failed to wipe ubyte[].");
assert(all!"a == 0"(buf2[]), "Failed to wipe ubyte[].");
assert(all!"a == 0"(buf3[]), "Failed to wipe ubyte[].");
}
// test dynamic arrays
unittest {
ubyte[] buf1 = [1,2,3,4];
uint[] buf2 = [1,2,3,4];
size_t[] buf3 = [1,2,3,4];
wipe(buf1, buf2, buf3);
assert(all!"a == 0"(buf1), "Failed to wipe ubyte[].");
assert(all!"a == 0"(buf2), "Failed to wipe ubyte[].");
assert(all!"a == 0"(buf3), "Failed to wipe ubyte[].");
}
unittest {
int a = 42;
int b = 84;
ubyte c = 1;
wipe(a, b, c);
assert(a == 0 && b == 0 && c == 0, "Wiping integer failed!");
}
/// Compares a and b in constant time.
///
/// Returns: 0 if a == b, some other value if a != b.
bool crypto_equals(T)(in T[] a, in T[] b) pure nothrow @safe @nogc
in {
assert(a.length == b.length, "Unequal length.");
} body {
T result = 0;
size_t i = 0;
while(i < a.length) {
result |= a[i] ^ b[i];
++i;
}
if(i != a.length) {
// Just to be sure that the compiler optimization does not destroy const time.
assert(false);
}
return result == 0;
}
// test crypto_equals
unittest {
ubyte[32] f = 0;
immutable ubyte[32] zero = 0;
assert(crypto_equals(f[], zero[]));
f[8] = 1;
assert(!crypto_equals(f[], zero[]));
}