1 /******************************************************************************/
2 /* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
3 /* This work has been released under the CC0 1.0 Universal license! */
4 /******************************************************************************/
7 # define _CRT_SECURE_NO_WARNINGS 1
13 #include <slunkcrypt.h>
26 // ==========================================================================
28 // ==========================================================================
37 static const size_t RCMD_PWDLEN_LENGTH
= 12U;
38 static const size_t DFLT_PWDLEN_LENGTH
= 24U;
40 static const CHR
* const ENV_PASSWORD
= T("SLUNK_PASSPHRASE");
41 static const CHR
* const ENV_KEEPFILE
= T("SLUNK_KEEP_INCOMPLETE");
42 static const CHR
* const ENV_NTHREADS
= T("SLUNK_THREADS");
44 static const CHR
* const PREFIX_PASS
= T("pass:");
45 static const CHR
* const PREFIX_FILE
= T("file:");
47 // ==========================================================================
48 // Auxiliary functions
49 // ==========================================================================
51 #define PW_FROM_ENV (!(argc > 4))
53 static int parse_slunk_mode(const CHR
* const command
)
55 if ((!STRICMP(command
, T("-h"))) || (!STRICMP(command
, T("/?"))) || (!STRICMP(command
, T("--help"))))
59 else if ((!STRICMP(command
, T("-v"))) || (!STRICMP(command
, T("--version"))))
63 else if ((!STRICMP(command
, T("-e"))) || (!STRICMP(command
, T("--encrypt"))))
67 else if ((!STRICMP(command
, T("-d"))) || (!STRICMP(command
, T("--decrypt"))))
71 else if ((!STRICMP(command
, T("-p"))) || (!STRICMP(command
, T("--make-pw"))))
75 else if ((!STRICMP(command
, T("-t"))) || (!STRICMP(command
, T("--self-test"))))
81 return -1; /*invalid command*/
85 static void print_manpage(const CHR
*const program
)
87 FPUTS(T("====================================================================\n"), stderr
);
88 FPUTS(T("This software has been released under the CC0 1.0 Universal license:\n"), stderr
);
89 FPUTS(T("https://creativecommons.org/publicdomain/zero/1.0/legalcode\n"), stderr
);
90 FPUTS(T("====================================================================\n\n"), stderr
);
91 FPUTS(T("Usage:\n"), stderr
);
92 FPRINTF(stderr
, T(" %") T(PRISTR
) T(" --encrypt [pass:<pass>|file:<file>] <input.txt> <output.enc>\n"), program
);
93 FPRINTF(stderr
, T(" %") T(PRISTR
) T(" --decrypt [pass:<pass>|file:<file>] <input.enc> <output.txt>\n"), program
);
94 FPRINTF(stderr
, T(" %") T(PRISTR
) T(" --make-pw [<length>]\n\n"), program
);
95 FPRINTF(stderr
, T("Optionally, reads passphrase from the %") T(PRISTR
) T(" environment variable.\n\n"), ENV_PASSWORD
);
98 static char *copy_passphrase(const CHR
*const passphrase
)
100 if ((!passphrase
) || (!passphrase
[0U]))
102 FPUTS(T("Error: The passphrase input string must not be empty!\n\n"), stderr
);
106 char *const buffer
= CHR_to_utf8(passphrase
);
109 FPUTS(T("Error: Failed to allocate the string buffer!\n\n"), stderr
);
115 static uint32_t environ_get_uint(const CHR
*const name
)
117 const CHR
*const value
= GETENV(name
);
120 return (uint32_t) STRTOUL(value
);
125 static int environ_get_flag(const CHR
*const name
)
127 return (environ_get_uint(name
) != 0);
130 static void check_excess_arguments(const int argc
, int maximum
)
134 FPUTS(T("Warning: Excess command-line argument(s) will be ignored!\n\n"), stderr
);
139 static void sigint_handler(const int sig
)
143 g_slunkcrypt_abort_flag
= 1;
147 // ==========================================================================
149 // ==========================================================================
151 int MAIN(const int argc
, CHR
*const argv
[])
153 int result
= EXIT_FAILURE
;
154 const CHR
*input_file
= NULL
, *output_file
= NULL
;
155 char *passphrase_buffer
= NULL
;
158 setup_signal_handler(SIGINT
, sigint_handler
);
160 FPRINTF(stderr
, T("SlunkCrypt Utility (%") T(PRIstr
) T("-%") T(PRIstr
) T("), by LoRd_MuldeR <MuldeR2@GMX.de>\n"), OS_TYPE_NAME
, CPU_ARCH
);
161 FPRINTF(stderr
, T("Using libSlunkCrypt v%u.%u.%u [%") T(PRIstr
) T("]\n\n"), SLUNKCRYPT_VERSION_MAJOR
, SLUNKCRYPT_VERSION_MINOR
, SLUNKCRYPT_VERSION_PATCH
, SLUNKCRYPT_BUILD
);
165 /* ----------------------------------------------------- */
166 /* Parse arguments */
167 /* ----------------------------------------------------- */
169 if ((argc
< 1) || (!argv
[0]))
171 FPUTS(T("Error: Argument array is empty. The program was called incorrectly!\n\n"), stderr
);
177 FPRINTF(stderr
, T("Error: Nothing to do. Please type '%") T(PRISTR
) T(" --help' for details!\n\n"), get_file_name(argv
[0U]));
181 const int slunk_mode
= parse_slunk_mode(argv
[1U]);
185 print_manpage(get_file_name(argv
[0U]));
187 result
= EXIT_SUCCESS
;
191 break; /*fallthrough*/
193 check_excess_arguments(argc
, 3);
194 result
= generate_passphrase((argc
> 2) ? STRTOUL(argv
[2U]) : DFLT_PWDLEN_LENGTH
);
197 check_excess_arguments(argc
, 2);
198 result
= run_selftest_routine(environ_get_uint(ENV_NTHREADS
));
201 FPRINTF(stderr
, T("Error: The specified command \"%") T(PRISTR
) T("\" is unknown!\n\n"), argv
[1U]);
207 FPRINTF(stderr
, T("Error: Required argument is missing. Please type '%") T(PRISTR
) T(" --help' for details!\n\n"), get_file_name(argv
[0U]));
211 check_excess_arguments(argc
, 5);
213 const CHR
*const passphrase
= PW_FROM_ENV
? GETENV(ENV_PASSWORD
) : argv
[2U];
214 if ((!passphrase
) || (!passphrase
[0U]))
216 FPUTS(T("Error: The passphrase must be specified, directly or indirectly!\n\n"), stderr
);
220 if ((!PW_FROM_ENV
) && STRICMP(passphrase
, T("-")))
222 if ((!STARTS_WITH(passphrase
, PREFIX_PASS
)) && (!STARTS_WITH(passphrase
, PREFIX_FILE
)))
224 FPRINTF(stderr
, T("Error: The passphrase must start with a '%") T(PRISTR
) T("' or '%") T(PRISTR
) T("' prefix!\n\n"), PREFIX_PASS
, PREFIX_FILE
);
229 input_file
= argv
[PW_FROM_ENV
? 2U : 3U];
232 FPUTS(T("Error: The specified input file name must not be empty!\n\n"), stderr
);
236 output_file
= argv
[PW_FROM_ENV
? 3U : 4U];
237 if (!output_file
[0U])
239 FPUTS(T("Error: The specified output file name must not be empty!\n\n"), stderr
);
243 if (same_file(input_file
, output_file
) > 0)
245 FPUTS(T("Error: The input and output files must not be the same!\n\n"), stderr
);
249 /* ----------------------------------------------------- */
250 /* Initialize passphrase */
251 /* ----------------------------------------------------- */
253 if (!(passphrase_buffer
= PW_FROM_ENV
? copy_passphrase(passphrase
) :
254 (STARTS_WITH(passphrase
, PREFIX_PASS
) ? copy_passphrase(passphrase
+ STRLEN(PREFIX_PASS
)) :
255 (STARTS_WITH(passphrase
, PREFIX_FILE
) ? read_passphrase(passphrase
+ STRLEN(PREFIX_FILE
)) : read_passphrase(T("-"))))))
260 slunkcrypt_bzero((CHR
*)passphrase
, STRLEN(passphrase
) * sizeof(CHR
));
262 const size_t passphrase_len
= strlen(passphrase_buffer
);
263 if (passphrase_len
< SLUNKCRYPT_PWDLEN_MIN
)
265 FPRINTF(stderr
, T("Error: Passphrase must be at least %u characters in length!\n\n"), (unsigned)SLUNKCRYPT_PWDLEN_MIN
);
268 else if (passphrase_len
> SLUNKCRYPT_PWDLEN_MAX
)
270 FPRINTF(stderr
, T("Error: Passphrase must be at most %u characters in length!\n\n"), (unsigned)SLUNKCRYPT_PWDLEN_MAX
);
274 if (slunk_mode
== MODE_ENCR
)
276 if (passphrase_len
< RCMD_PWDLEN_LENGTH
)
278 FPRINTF(stderr
, T("Warning: Using a *short* passphrase; a length of %u characters or more is recommended!\n\n"), (unsigned)RCMD_PWDLEN_LENGTH
);
280 else if (weak_passphrase(passphrase_buffer
))
282 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
);
288 /* ----------------------------------------------------- */
289 /* Encrypt or decrypt */
290 /* ----------------------------------------------------- */
292 const uint64_t clk_start
= clock_read();
293 const crypt_options_t options
= { environ_get_flag(ENV_KEEPFILE
), environ_get_uint(ENV_NTHREADS
) };
298 result
= encrypt(passphrase_buffer
, input_file
, output_file
, &options
);
301 result
= decrypt(passphrase_buffer
, input_file
, output_file
, &options
);
304 FPUTS(T("Unexpected mode encountered!\n\n"), stderr
);
307 if (!g_slunkcrypt_abort_flag
)
309 FPRINTF(stderr
, T("--------\n\nOperation completed after %.1f seconds.\n\n"), (clock_read() - clk_start
) / ((double)clock_freq()));
312 /* ----------------------------------------------------- */
314 /* ----------------------------------------------------- */
320 if (passphrase_buffer
)
322 slunkcrypt_bzero(passphrase_buffer
, strlen(passphrase_buffer
));
323 free(passphrase_buffer
);
329 #if defined(_WIN32) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
330 void __wgetmainargs(int*, wchar_t***, wchar_t***, int, int*);
333 wchar_t** enpv
, ** argv
;
335 __wgetmainargs(&argc
, &argv
, &enpv
, 1, &si
);
336 return wmain(argc
, argv
);