Added proper password reading.
This commit is contained in:
parent
27979d58e5
commit
f2df5a48d2
155
source/app.d
155
source/app.d
|
@ -3,6 +3,7 @@ import std.path;
|
|||
import std.file;
|
||||
import std.algorithm : endsWith;
|
||||
import std.string : strip;
|
||||
import std.getopt;
|
||||
|
||||
import botan.block.block_cipher : BlockCipher;
|
||||
import botan.block.aes : AES256;
|
||||
|
@ -12,32 +13,21 @@ import botan.hash.sha2_32 : SHA256;
|
|||
import cipher_utils;
|
||||
|
||||
int main(string[] args) {
|
||||
string action = "encrypt";
|
||||
if (args.length >= 2) {
|
||||
string command = args[1];
|
||||
if (command == "encrypt") {
|
||||
action = "encrypt";
|
||||
} else if (command == "decrypt") {
|
||||
action = "decrypt";
|
||||
} else {
|
||||
stderr.writefln!"Invalid action: %s"(command);
|
||||
return 1;
|
||||
}
|
||||
Params params;
|
||||
int result = parseParams(args, params);
|
||||
if (result != 0) {
|
||||
printUsage();
|
||||
return result;
|
||||
}
|
||||
|
||||
string target = ".";
|
||||
if (args.length >= 3) {
|
||||
target = args[2];
|
||||
if (!exists(target)) {
|
||||
stderr.writefln!"Target \"%s\" doesn't exist."(target);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
BlockCipher cipher = null;
|
||||
// TODO: Use args to determine block cipher.
|
||||
writeln("Enter a password:");
|
||||
string password = readln().strip();
|
||||
string password = readPassphrase();
|
||||
if (password is null) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
HashFunction hash = new SHA256();
|
||||
auto secureKeyVector = hash.process(password);
|
||||
|
@ -45,23 +35,17 @@ int main(string[] args) {
|
|||
cipher.setKey(secureKeyVector);
|
||||
|
||||
ubyte[] buffer = new ubyte[cipher.blockSize];
|
||||
if (isDir(target)) {
|
||||
if (action == "encrypt") {
|
||||
encryptDir(target, cipher, buffer, true);
|
||||
} else if (action == "decrypt") {
|
||||
decryptDir(target, cipher, buffer, true);
|
||||
if (isDir(params.target)) {
|
||||
if (params.action == Action.ENCRYPT) {
|
||||
encryptDir(params.target, cipher, buffer, params.recursive);
|
||||
} else {
|
||||
stderr.writefln!"Unsupported action: %s"(action);
|
||||
return 1;
|
||||
decryptDir(params.target, cipher, buffer, params.recursive);
|
||||
}
|
||||
} else if (isFile(target)) {
|
||||
if (action == "encrypt") {
|
||||
encryptAndRemoveFile(target, cipher, buffer);
|
||||
} else if (action == "decrypt") {
|
||||
decryptAndRemoveFile(target, cipher, buffer);
|
||||
} else if (isFile(params.target)) {
|
||||
if (params.action == Action.ENCRYPT) {
|
||||
encryptAndRemoveFile(params.target, cipher, buffer);
|
||||
} else {
|
||||
stderr.writefln!"Unsupported action: %s"(action);
|
||||
return 1;
|
||||
decryptAndRemoveFile(params.target, cipher, buffer);
|
||||
}
|
||||
} else {
|
||||
stderr.writeln("Target is not a directory or file.");
|
||||
|
@ -70,6 +54,109 @@ int main(string[] args) {
|
|||
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", ¶ms.recursive,
|
||||
"verbose|v", ¶ms.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) {
|
||||
string encryptedFilename = filename ~ ".enc";
|
||||
encryptFile(filename, encryptedFilename, cipher, buffer);
|
||||
|
|
Loading…
Reference in New Issue