Files
angelc2/vv1/agent/angel/utils/cryptography/cryptography.d
2025-12-22 16:23:48 +01:00

148 lines
4.1 KiB
D

module angel.utils.cryptography.cryptography;
// Internal imports
import angel.utils.logging;
import angel.utils.cryptography.serpent;
import angel.utils.cryptography.threefish;
import angel.utils.cryptography.curve25519;
// External imports
import std.stdio;
import std.random;
import std.format;
class Cryptography {
public {
struct KeyPair {
ubyte[32] clientSecretKey;
ubyte[32] sharedSecret;
}
}
public static KeyPair derive_25519(ubyte[] pk) {
ubyte[32] sk; // generate client secret key
for (int i = 0; i < 32; ++i) {
sk[i] = cast(ubyte)(uniform(0, 256));
}
Logger.log(LogLevel.Debug, "Generated client sk");
ubyte[32] ss = curve25519_scalarmult(sk, pk); // derive shared secret out of pk and sk
Logger.log(LogLevel.Debug, format("Derived shared secret: %s", ss));
return KeyPair(sk, ss);
}
}
class Freefishy {
private Threefish512 cipher;
this(ulong[8] key, ulong[2] tweak) {
cipher = new Threefish512();
cipher.setup(key, tweak);
}
public ubyte[] encrypt(ubyte[] payload) {
ulong[8] plain = [0, 0, 0, 0, 0, 0, 0, 0];
// Pack the ubyte[] into ulong[] by 8 bytes per ulong
foreach (i, c; payload) {
plain[i / 8] |= cast(ulong) c << ((i % 8) * 8);
}
// Encrypt the ulong array
ulong[] encrypted_three = cipher.crypt(plain);
// Convert the encrypted ulong[] back to ubyte[]
ubyte[] encrypted_bytes;
foreach (enc_val; encrypted_three) {
foreach (i; 0..8) {
encrypted_bytes ~= cast(ubyte)((enc_val >> (i * 8)) & 0xFF);
}
}
Logger.log(LogLevel.Debug, format("Threefish Encrypted: %s", encrypted_bytes));
return encrypted_bytes;
}
public ubyte[] decrypt(ubyte[] payload) {
ulong[8] decrypted_buffer;
// Convert the ubyte[] payload back into ulong[] (8 bytes per ulong)
ulong[8] cipher_payload;
foreach (i, val; payload) {
cipher_payload[i / 8] |= cast(ulong) val << ((i % 8) * 8);
}
// Decrypt the ulong[] array
cipher.decrypt(cipher_payload.ptr, decrypted_buffer.ptr);
// Convert the decrypted ulong[] back to ubyte[]
ubyte[] decrypted_bytes;
foreach (dec_val; decrypted_buffer) {
foreach (i; 0..8) {
decrypted_bytes ~= cast(ubyte)((dec_val >> (i * 8)) & 0xFF);
}
}
Logger.log(LogLevel.Debug, format("Threefish Decrypted: %s", decrypted_bytes));
return decrypted_bytes;
}
}
class Serpi {
private Serpent serp;
this(Cryptography.KeyPair keypair) {
auto key = cast(ubyte[]) keypair.sharedSecret.dup;
serp.start(key);
}
public ubyte[] encrypt(ubyte[] payload) {
ubyte padding = cast(ubyte)(16 - (payload.length % 16));
ubyte[] paddingBytes = new ubyte[padding];
foreach (i; 0 .. padding) {
paddingBytes[i] = padding;
}
ubyte[] input = payload ~ paddingBytes;
ubyte[] output = new ubyte[input.length];
serp.encrypt(input, output);
Logger.log(LogLevel.Debug, format("Serpent Encrypted data: %s", output));
return output;
}
public ubyte[] decrypt(ubyte[] payload) {
ubyte[] output = new ubyte[payload.length];
serp.decrypt(payload, output);
if (output.length == 0) {
throw new Exception("Decryption failed: Output length is zero.");
}
ubyte padding = output[$ - 1];
if (padding > 16 || padding == 0) {
throw new Exception("Invalid padding detected");
}
foreach (i; output.length - padding .. output.length) {
if (output[i] != padding) {
throw new Exception("Padding validation failed");
}
}
ubyte[] unpadded = output[0 .. output.length - padding];
Logger.log(LogLevel.Debug, format("Serpent Decrypted data: %s", unpadded));
return unpadded;
}
public void reset() {
serp.reset();
}
}