diff --git a/README.md b/README.md index 4f0f51a..ea3d7fb 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Use of SlunkCrypt may be illegal in countries where encryption is outlawed. We b Command-line Usage ================== -This section describes the SlunkCypt command-line front-end. +This section describes the SlunkCypt command-line application. Synopsis -------- @@ -24,6 +24,7 @@ The SlunkCypt command-line program is invoked as follows: slunkcrypt --encrypt [[@][:]] slunkcrypt --decrypt [[@][:]] + slunkcrypt --make-pw [] Commands -------- @@ -34,8 +35,10 @@ One of the following commands must be chosen: Encrypt the plaintext in the given input file. The ciphertext is written to the specified output file. - **`--decrypt` (`-d`):** Decrypt the ciphertext in the given input file. The plaintext is written to the specified output file. +- **`--make-pw` (`-p`):** + Generate and print a random passphrase. An optional length can be specified (default: 24). - **`--self-test` (`-t`):** - Run self-test and exit application. + Run the self-test and exit application. Options ------- diff --git a/frontend/src/main.c b/frontend/src/main.c index 339352f..6ef2858 100644 --- a/frontend/src/main.c +++ b/frontend/src/main.c @@ -30,9 +30,19 @@ #define SLUNK_MODE_VERS 1 #define SLUNK_MODE_ENCR 2 #define SLUNK_MODE_DECR 3 -#define SLUNK_MODE_TEST 4 +#define SLUNK_MODE_PASS 4 +#define SLUNK_MODE_TEST 5 static const CHR *const ENVV_PASSWD_NAME = T("SLUNK_PASSPHRASE"); +static const char PASSWD_SYMBOLS[] = +{ + '!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', + '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', ']', '^', '_', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '}', '~' +}; // ========================================================================== // Auxiliary functions @@ -56,6 +66,10 @@ static int parse_mode(const CHR* const command) { return SLUNK_MODE_DECR; } + else if ((!STRICMP(command, T("-p"))) || (!STRICMP(command, T("--make-pw")))) + { + return SLUNK_MODE_PASS; + } else if ((!STRICMP(command, T("-t"))) || (!STRICMP(command, T("--self-test")))) { return SLUNK_MODE_TEST; @@ -75,7 +89,8 @@ static void print_manpage(const CHR *const program) FPUTS(T("====================================================================\n\n"), stderr); FPUTS(T("Usage:\n"), stderr); FPRINTF(stderr, T(" %") T(PRISTR) T(" --encrypt [[@][:]] \n"), program); - FPRINTF(stderr, T(" %") T(PRISTR) T(" --decrypt [[@][:]] \n\n"), program); + FPRINTF(stderr, T(" %") T(PRISTR) T(" --decrypt [[@][:]] \n"), program); + FPRINTF(stderr, T(" %") T(PRISTR) T(" --make-pw []\n\n"), program); } static char *read_passphrase(const CHR* const file_name) @@ -140,6 +155,49 @@ static int weak_passphrase(const char *str) return !strong; } +static int generate_passphrase(const size_t length) +{ + int result = EXIT_FAILURE; + const size_t passwd_len = BOUND(SLUNKCRYPT_PWDLEN_MIN, length, SLUNKCRYPT_PWDLEN_MAX); + + char *const buffer = (char*) malloc((passwd_len + 1U) * sizeof(char)); + if (!buffer) + { + FPUTS(T("\n\nError: Failed to allocate memory buffer!\n\n"), stderr); + return EXIT_FAILURE; + } + + do + { + for (size_t i = 0U; i < passwd_len; ++i) + { + uint64_t value; + if (slunkcrypt_generate_nonce(&value) != SLUNKCRYPT_SUCCESS) + { + FPUTS(T("\n\nError: Failed to generate next random number!\n\n"), stderr); + goto clean_up; + } + buffer[i] = PASSWD_SYMBOLS[value % ARRAY_SIZE(PASSWD_SYMBOLS)]; + } + buffer[passwd_len] = '\0'; + } + while (weak_passphrase(buffer)); + + FPRINTF(stdout, T("%") T(PRIstr) T("\n\n"), buffer); + fflush(stdout); + result = EXIT_SUCCESS; + +clean_up: + + if (buffer) + { + slunkcrypt_bzero(buffer, passwd_len * sizeof(char)); + free(buffer); + } + + return result; +} + static int open_files(FILE **const file_in, FILE **const file_out, const CHR* const input_path, const CHR* const output_path) { *file_in = FOPEN(input_path, T("rb")); @@ -180,7 +238,7 @@ static int encrypt(const char* const passphrase, const CHR* const input_path, co if (open_files(&file_in, &file_out, input_path, output_path) != EXIT_SUCCESS) { - goto clean_up;; + goto clean_up; } const uint64_t file_size = get_file_size(file_in); @@ -360,7 +418,7 @@ static int decrypt(const char* const passphrase, const CHR* const input_path, co } else if ((file_size % sizeof(uint64_t)) != 0) { - FPRINTF(stderr, T("Warning: File size is *not* an integer multiple of %u, ignoring excess bytes!\n\n"), sizeof(uint64_t)); + FPRINTF(stderr, T("Warning: File size is *not* an integer multiple of %u, ignoring excess bytes!\n\n"), (unsigned int)sizeof(uint64_t)); } FPUTS(T("Decrypting file contents, please be patient... "), stderr); @@ -674,6 +732,9 @@ int MAIN(const int argc, CHR *const argv[]) case SLUNK_MODE_VERS: result = EXIT_SUCCESS; goto clean_up; + case SLUNK_MODE_PASS: + result = generate_passphrase((argc > 2) ? STRTOUL(argv[2U]) : 24U); + goto clean_up; case SLUNK_MODE_TEST: result = run_self_test(); goto clean_up; diff --git a/frontend/src/platform.h b/frontend/src/platform.h index 09908b1..73596e8 100644 --- a/frontend/src/platform.h +++ b/frontend/src/platform.h @@ -56,6 +56,7 @@ # define STRLEN(X) wcslen((X)) # define STRICMP(X,Y) _wcsicmp((X),(Y)) # define STRRCHR(X,Y) wcsrchr((X),(Y)) +# define STRTOUL(X) wcstoul((X), NULL, 0) # define FPUTS(X,Y) fputws((X),(Y)) # define FPRINTF(X,Y,...) fwprintf((X),(Y),__VA_ARGS__) # define FOPEN(X,Y) _wfsopen((X),(Y),_SH_SECURE) @@ -76,6 +77,7 @@ # define STRLEN(X) strlen((X)) # define STRICMP(X,Y) strcasecmp((X),(Y)) # define STRRCHR(X,Y) strrchr((X),(Y)) +# define STRTOUL(X) strtoul((X), NULL, 0) # define FPUTS(X,Y) fputs((X),(Y)) # define FPRINTF(X,Y,...) fprintf((X),(Y),__VA_ARGS__) # define FOPEN(X,Y) fopen((X),(Y)) diff --git a/frontend/src/utils.h b/frontend/src/utils.h index b4556a3..52d316f 100644 --- a/frontend/src/utils.h +++ b/frontend/src/utils.h @@ -19,6 +19,8 @@ uint64_t get_file_size(FILE* const file); const CHR *get_file_name(const CHR *path); uint64_t round_down(const uint64_t value, const uint64_t base); +#define ARRAY_SIZE(X) (sizeof((X)) / sizeof(*(X))) +#define BOUND(MIN,VAL,MAX) (((VAL) < (MIN)) ? (MIN) : (((VAL) > (MAX)) ? (MAX) : (VAL))) #define GET_NIBBLE(X) ((X) & 0x0F) #define SET_NIBBLE(X, Y) do { X = ((X) & 0xF0) | ((Y) & 0x0F); } while(0) diff --git a/mk-profiled.sh b/mk-profiled.sh index 2ef1138..fa7dd9b 100755 --- a/mk-profiled.sh +++ b/mk-profiled.sh @@ -32,10 +32,11 @@ printf "\033[1;36m-------------------------------------------------------------- dd bs=1024 count=102400 < ${RANDOM_SOURCE} > /tmp/${TMP_NAME}.dat printf "\n" +PASSWRD="$(./frontend/bin/slunkcrypt${SUFFIX} --make-pw)" ./frontend/bin/slunkcrypt${SUFFIX} --self-test -./frontend/bin/slunkcrypt${SUFFIX} --encrypt 'q4cmK7FEK7@v' /tmp/${TMP_NAME}.dat /tmp/${TMP_NAME}.enc -./frontend/bin/slunkcrypt${SUFFIX} --decrypt 'q4cmK7FEK7@v' /tmp/${TMP_NAME}.enc /tmp/${TMP_NAME}.out +./frontend/bin/slunkcrypt${SUFFIX} --encrypt "${PASSWRD}" /tmp/${TMP_NAME}.dat /tmp/${TMP_NAME}.enc +./frontend/bin/slunkcrypt${SUFFIX} --decrypt "${PASSWRD}" /tmp/${TMP_NAME}.enc /tmp/${TMP_NAME}.out printf "\033[1;36m\n------------------------------------------------------------------------------\033[0m\n" printf "\033[1;36mRe-compile\n"