1 /******************************************************************************/
2 /* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
3 /* This work has been released under the CC0 1.0 Universal license! */
4 /******************************************************************************/
13 #include <slunkcrypt.h>
22 // ==========================================================================
24 // ==========================================================================
33 static const size_t RCMD_PWDLEN_LENGTH = 12U;
34 static const size_t DFLT_PWDLEN_LENGTH = 24U;
36 static const CHR* const ENV_PASSWORD = T("SLUNK_PASSPHRASE");
37 static const CHR* const ENV_KEEPFILE = T("SLUNK_KEEP_INCOMPLETE");
38 static const CHR* const ENV_NTHREADS = T("SLUNK_THREADS");
39 static const CHR* const ENV_LGCYCMPT = T("SLUNK_LEGACY_COMPAT");
41 static const CHR* const PREFIX_PASS = T("pass:");
42 static const CHR* const PREFIX_FILE = T("file:");
44 // ==========================================================================
45 // Auxiliary functions
46 // ==========================================================================
48 #define PW_FROM_ENV (!(argc > 4))
50 static int parse_slunk_mode(const CHR* const command)
52 if ((!STRICMP(command, T("-h"))) || (!STRICMP(command, T("/?"))) || (!STRICMP(command, T("--help"))))
56 else if ((!STRICMP(command, T("-v"))) || (!STRICMP(command, T("--version"))))
60 else if ((!STRICMP(command, T("-e"))) || (!STRICMP(command, T("--encrypt"))))
64 else if ((!STRICMP(command, T("-d"))) || (!STRICMP(command, T("--decrypt"))))
68 else if ((!STRICMP(command, T("-p"))) || (!STRICMP(command, T("--make-pw"))))
72 else if ((!STRICMP(command, T("-t"))) || (!STRICMP(command, T("--self-test"))))
78 return -1; /*invalid command*/
82 static void print_manpage(const CHR *const program)
84 FPUTS(T("====================================================================\n"), stderr);
85 FPUTS(T("This software has been released under the CC0 1.0 Universal license:\n"), stderr);
86 FPUTS(T("https://creativecommons.org/publicdomain/zero/1.0/legalcode\n"), stderr);
87 FPUTS(T("====================================================================\n\n"), stderr);
88 FPUTS(T("Usage:\n"), stderr);
89 FPRINTF(stderr, T(" %") T(PRISTR) T(" --encrypt [pass:<pass>|file:<file>] <input.txt> <output.enc>\n"), program);
90 FPRINTF(stderr, T(" %") T(PRISTR) T(" --decrypt [pass:<pass>|file:<file>] <input.enc> <output.txt>\n"), program);
91 FPRINTF(stderr, T(" %") T(PRISTR) T(" --make-pw [<length>]\n\n"), program);
92 FPRINTF(stderr, T("Optionally, reads passphrase from the %") T(PRISTR) T(" environment variable.\n\n"), ENV_PASSWORD);
95 static char *copy_passphrase(const CHR *const passphrase)
97 if ((!passphrase) || (!passphrase[0U]))
99 FPUTS(T("Error: The passphrase input string must not be empty!\n\n"), stderr);
103 char *const buffer = CHR_to_utf8(passphrase);
106 FPUTS(T("Error: Failed to allocate the string buffer!\n\n"), stderr);
112 static uint32_t environ_get_uint(const CHR *const name)
114 const CHR *const value = GETENV(name);
117 return (uint32_t) STRTOUL(value);
122 static int environ_get_flag(const CHR *const name)
124 return (environ_get_uint(name) != 0U) ? SLUNKCRYPT_TRUE : SLUNKCRYPT_FALSE;
127 static void check_excess_arguments(const int argc, int maximum)
131 FPUTS(T("Warning: Excess command-line argument(s) will be ignored!\n\n"), stderr);
136 static void sigint_handler(const int sig)
140 g_slunkcrypt_abort_flag = 1;
144 // ==========================================================================
146 // ==========================================================================
148 int MAIN(const int argc, CHR *const argv[])
150 int result = EXIT_FAILURE;
151 const CHR *input_file = NULL, *output_file = NULL;
152 char *passphrase_buffer = NULL;
155 setup_signal_handler(SIGINT, sigint_handler);
157 FPRINTF(stderr, T("SlunkCrypt Utility (%") T(PRIstr) T("-%") T(PRIstr) T("), by LoRd_MuldeR <MuldeR2@GMX.de>\n"), OS_TYPE_NAME, CPU_ARCH);
158 FPRINTF(stderr, T("Using libSlunkCrypt-%") T(PRIstr) T(" v%u.%u.%u [%") T(PRIstr) T("]\n\n"),
159 SLUNKCRYPT_HAVE_THREADS ? "MT" : "ST", SLUNKCRYPT_VERSION_MAJOR, SLUNKCRYPT_VERSION_MINOR, SLUNKCRYPT_VERSION_PATCH, SLUNKCRYPT_BUILD);
163 /* ----------------------------------------------------- */
164 /* Parse arguments */
165 /* ----------------------------------------------------- */
167 if ((argc < 1) || (!argv[0]))
169 FPUTS(T("Error: Argument array is empty. The program was called incorrectly!\n\n"), stderr);
175 FPRINTF(stderr, T("Error: Nothing to do. Please type '%") T(PRISTR) T(" --help' for details!\n\n"), get_file_name(argv[0U]));
179 const int slunk_mode = parse_slunk_mode(argv[1U]);
183 print_manpage(get_file_name(argv[0U]));
185 result = EXIT_SUCCESS;
189 break; /*fallthrough*/
191 check_excess_arguments(argc, 3);
192 result = generate_passphrase((argc > 2) ? STRTOUL(argv[2U]) : DFLT_PWDLEN_LENGTH);
195 check_excess_arguments(argc, 2);
196 result = run_selftest_routine(environ_get_uint(ENV_NTHREADS));
199 FPRINTF(stderr, T("Error: The specified command \"%") T(PRISTR) T("\" is unknown!\n\n"), argv[1U]);
205 FPRINTF(stderr, T("Error: Required argument is missing. Please type '%") T(PRISTR) T(" --help' for details!\n\n"), get_file_name(argv[0U]));
209 check_excess_arguments(argc, 5);
211 const CHR *const passphrase = PW_FROM_ENV ? GETENV(ENV_PASSWORD) : argv[2U];
212 if ((!passphrase) || (!passphrase[0U]))
214 FPUTS(T("Error: The passphrase must be specified, directly or indirectly!\n\n"), stderr);
218 if ((!PW_FROM_ENV) && STRICMP(passphrase, T("-")))
220 if ((!STARTS_WITH(passphrase, PREFIX_PASS)) && (!STARTS_WITH(passphrase, PREFIX_FILE)))
222 FPRINTF(stderr, T("Error: The passphrase must start with a '%") T(PRISTR) T("' or '%") T(PRISTR) T("' prefix!\n\n"), PREFIX_PASS, PREFIX_FILE);
227 input_file = argv[PW_FROM_ENV ? 2U : 3U];
230 FPUTS(T("Error: The specified input file name must not be empty!\n\n"), stderr);
234 output_file = argv[PW_FROM_ENV ? 3U : 4U];
235 if (!output_file[0U])
237 FPUTS(T("Error: The specified output file name must not be empty!\n\n"), stderr);
241 if (same_file(input_file, output_file) > 0)
243 FPUTS(T("Error: The input and output files must not be the same!\n\n"), stderr);
247 /* ----------------------------------------------------- */
248 /* Initialize passphrase */
249 /* ----------------------------------------------------- */
251 if (!(passphrase_buffer = PW_FROM_ENV ? copy_passphrase(passphrase) :
252 (STARTS_WITH(passphrase, PREFIX_PASS) ? copy_passphrase(passphrase + STRLEN(PREFIX_PASS)) :
253 (STARTS_WITH(passphrase, PREFIX_FILE) ? read_passphrase(passphrase + STRLEN(PREFIX_FILE)) : read_passphrase(T("-"))))))
258 slunkcrypt_bzero((CHR*)passphrase, STRLEN(passphrase) * sizeof(CHR));
260 const size_t passphrase_len = strlen(passphrase_buffer);
261 if (passphrase_len < SLUNKCRYPT_PWDLEN_MIN)
263 FPRINTF(stderr, T("Error: Passphrase must be at least %u characters in length!\n\n"), (unsigned)SLUNKCRYPT_PWDLEN_MIN);
266 else if (passphrase_len > SLUNKCRYPT_PWDLEN_MAX)
268 FPRINTF(stderr, T("Error: Passphrase must be at most %u characters in length!\n\n"), (unsigned)SLUNKCRYPT_PWDLEN_MAX);
272 if (slunk_mode == MODE_ENCR)
274 if (passphrase_len < RCMD_PWDLEN_LENGTH)
276 FPRINTF(stderr, T("Warning: Using a *short* passphrase; a length of %u characters or more is recommended!\n\n"), (unsigned)RCMD_PWDLEN_LENGTH);
278 else if (weak_passphrase(passphrase_buffer))
280 FPUTS(T("Warning: Using a *weak* passphrase; a mix of upper-case letters, lower-case letters, digits and other characters is recommended!\n\n"), stderr);
286 /* ----------------------------------------------------- */
287 /* Encrypt or decrypt */
288 /* ----------------------------------------------------- */
290 const uint64_t clk_start = clock_read();
291 const crypt_options_t options = { environ_get_flag(ENV_KEEPFILE), environ_get_flag(ENV_LGCYCMPT), environ_get_uint(ENV_NTHREADS) };
296 result = encrypt(passphrase_buffer, input_file, output_file, &options);
299 result = decrypt(passphrase_buffer, input_file, output_file, &options);
302 FPUTS(T("Unexpected mode encountered!\n\n"), stderr);
305 if (!g_slunkcrypt_abort_flag)
307 FPRINTF(stderr, T("--------\n\nOperation completed after %.1f seconds.\n\n"), (clock_read() - clk_start) / ((double)clock_freq()));
310 /* ----------------------------------------------------- */
312 /* ----------------------------------------------------- */
318 if (passphrase_buffer)
320 slunkcrypt_bzero(passphrase_buffer, strlen(passphrase_buffer));
321 free(passphrase_buffer);
327 #if defined(_WIN32) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
328 void __wgetmainargs(int*, wchar_t***, wchar_t***, int, int*);
331 wchar_t** enpv, ** argv;
333 __wgetmainargs(&argc, &argv, &enpv, 1, &si);
334 return wmain(argc, argv);