Add cli_utils.d

This commit is contained in:
Andrew Lalis 2023-03-21 12:53:18 +01:00
parent f2df5a48d2
commit 6fd042f594
2 changed files with 123 additions and 104 deletions

View File

@ -11,6 +11,7 @@ import botan.hash.hash : HashFunction;
import botan.hash.sha2_32 : SHA256; import botan.hash.sha2_32 : SHA256;
import cipher_utils; import cipher_utils;
import cli_utils;
int main(string[] args) { int main(string[] args) {
Params params; Params params;
@ -20,10 +21,9 @@ int main(string[] args) {
return result; return result;
} }
BlockCipher cipher = null; BlockCipher cipher = null;
// TODO: Use args to determine block cipher. // TODO: Use args to determine block cipher.
writeln("Enter a password:"); writeln("Enter a passphrase:");
string password = readPassphrase(); string password = readPassphrase();
if (password is null) { if (password is null) {
return 2; return 2;
@ -54,108 +54,6 @@ int main(string[] args) {
return 0; return 0;
} }
enum Action {
ENCRYPT,
DECRYPT
}
struct Params {
Action action = Action.ENCRYPT;
string target = ".";
bool recursive = false;
bool verbose = false;
}
int parseParams(string[] args, ref Params params) {
getopt(
args,
"recursive|r", &params.recursive,
"verbose|v", &params.verbose
);
if (args.length < 2) {
stderr.writeln("Missing required action.");
return 1;
}
string action = args[1].strip();
if (action != "encrypt" && action != "decrypt") {
stderr.writeln("Invalid action.");
return 1;
}
if (action == "encrypt") {
params.action = Action.ENCRYPT;
} else if (action == "decrypt") {
params.action = Action.DECRYPT;
}
if (args.length >= 3) {
params.target = args[2];
if (!exists(params.target)) {
stderr.writefln!"Target \"%s\" doesn't exist."(params.target);
return 1;
}
}
return 0;
}
string readPassphrase() {
version(Posix) {
import core.sys.posix.termios : termios, tcgetattr, tcsetattr, ECHO;
import core.sys.posix.stdio;
termios term;
tcgetattr(0, &term);
term.c_lflag &= ~ECHO;
tcsetattr(0, 0, &term);
string passphrase = readln().strip();
term.c_lflag |= ECHO;
tcsetattr(0, 0, &term);
return passphrase;
} else version(Windows) {
import core.sys.windows.windows;
DWORD con_mode;
DWORD dwRead;
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(hIn, &con_mode);
SetConsoleMode(hIn, con_mode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));
string password = "";
char BACKSPACE = 8;
char RETURN = 13;
char ch = 0;
while (ReadConsoleA(hIn, &ch, 1, &dwRead, NULL) && ch != RETURN) {
if (ch == BACKSPACE) {
if (password.length > 0) {
password = password[0 .. $ - 1];
}
} else {
password ~= ch;
}
}
return password;
} else {
stderr.writeln("Unsupported password reading.");
return null;
}
}
void printUsage() {
writeln(q"HELP
Usage: scrambler <encrypt|decrypt> [target] [options]
Scramber is a command-line tool for "scrambling", or encrypting files with a
passphrase so they can only be read after they're decrypted using the same
passphrase.
Provide either the "encrypt" or "decrypt" command, followed by a target that's
either a directory, or an individual file. By default, the target is the
directory that Scrambler was invoked from.
The following options are available:
-r | --recursive Recursively encrypt/decrypt nested directories.
-v | --verbose Show verbose output during runtime.
HELP");
}
void encryptAndRemoveFile(string filename, BlockCipher cipher, ref ubyte[] buffer) { void encryptAndRemoveFile(string filename, BlockCipher cipher, ref ubyte[] buffer) {
string encryptedFilename = filename ~ ".enc"; string encryptedFilename = filename ~ ".enc";

121
source/cli_utils.d Normal file
View File

@ -0,0 +1,121 @@
module cli_utils;
enum Action {
ENCRYPT,
DECRYPT
}
struct Params {
Action action = Action.ENCRYPT;
string target = ".";
bool recursive = false;
bool verbose = false;
}
int parseParams(string[] args, ref Params params) {
import std.getopt;
import std.stdio;
import std.file : exists;
import std.string : strip;
bool isEncrypting;
bool isDecrypting;
getopt(
args,
"recursive|r", &params.recursive,
"verbose|v", &params.verbose,
"encrypt|e", &isEncrypting,
"decrypt|d", &isDecrypting
);
if (isEncrypting && isDecrypting) {
stderr.writeln("Invalid arguments: Cannot specify both the --encrypt and --decrypt flags.");
}
if (isEncrypting) {
params.action = Action.ENCRYPT;
} else if (isDecrypting) {
params.action = Action.DECRYPT;
} else {
writeln("Determining if we should encrypt or decrypt");
params.action = Action.ENCRYPT;
}
if (args.length > 1) {
params.target = args[1];
if (!exists(params.target)) {
stderr.writefln!"Target \"%s\" doesn't exist."(params.target);
return 1;
}
}
return 0;
}
void printUsage() {
import std.stdio : writeln;
writeln(q"HELP
Usage: scrambler [target] [options]
Scramber is a command-line tool for encrypting and decrypting files or entire
directories using a passphrase.
The following options are available:
-e | --encrypt Do an encryption operation on the target file or
directory.
-d | --decrypt Do a decryption operation on the target file or
directory.
-r | --recursive Recursively encrypt/decrypt nested directories.
-v | --verbose Show verbose output during runtime.
-s | --no-suffix Do not add the ".enc" suffix to files.
Encrypted files are suffixed with ".enc" to indicate that they're encrypted and
cannot be read as usual. If neither --encrypt nor --decrypt flags are provided,
Scrambler will try to determine which operation to do based on the presence of
".enc" file(s) at the target location. It's recommended that you always do
provide an explicit --encrypt or --decrypt flag.
HELP");
}
string readPassphrase() {
import std.stdio;
import std.string : strip;
version(Posix) {
import core.sys.posix.termios : termios, tcgetattr, tcsetattr, ECHO;
import core.sys.posix.stdio;
termios term;
tcgetattr(0, &term);
term.c_lflag &= ~ECHO;
tcsetattr(0, 0, &term);
string passphrase = readln().strip();
term.c_lflag |= ECHO;
tcsetattr(0, 0, &term);
return passphrase;
} else version(Windows) {
import core.sys.windows.windows;
DWORD prev_con_mode;
DWORD con_mode;
DWORD dwRead;
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(hIn, &con_mode);
GetConsoleMode(hIn, &prev_con_mode);
SetConsoleMode(hIn, con_mode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));
string password = "";
char BACKSPACE = 8;
char RETURN = 13;
char ch = 0;
while (ReadConsoleA(hIn, &ch, 1, &dwRead, NULL) && ch != RETURN) {
if (ch == BACKSPACE) {
if (password.length > 0) {
password = password[0 .. $ - 1];
}
} else {
password ~= ch;
}
}
SetConsoleMode(hIn, prev_con_mode);
return password;
} else {
stderr.writeln("Cannot securely read password from terminal.");
return null;
}
}