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
14 #include <slunkcrypt.h>
25 // ==========================================================================
27 // ==========================================================================
29 static const uint64_t MAGIC_NUMBER
= 0x243F6A8885A308D3ull
;
31 #define MAX_BUFFER_SIZE 1048576U // 1 MiB
33 // ==========================================================================
34 // Auxiliary functions
35 // ==========================================================================
37 static int open_files(FILE **const file_in
, FILE **const file_out
, const CHR
*const input_path
, const CHR
*const output_path
)
39 if (!(*file_in
= FOPEN(input_path
, "rb")))
41 FPRINTF(stderr
, T("Error: Failed to open input file \"%") T(PRISTR
) T("\" for reading!\n\n%") T(PRISTR
) T("\n\n"), input_path
, STRERROR(errno
));
46 if (!(*file_out
= FOPEN(output_path
, "wb")))
48 FPRINTF(stderr
, T("Error: Failed to open output file \"%") T(PRISTR
) T("\" for writing!\n\n%") T(PRISTR
) T("\n\n"), output_path
, STRERROR(errno
));
52 //setvbuf(*file_in, NULL, _IOFBF, (((8U * BUFFER_SIZE) + (BUFSIZ - 1U)) / BUFSIZ) * BUFSIZ);
53 //setvbuf(*file_out, NULL, _IOFBF, (((8U * BUFFER_SIZE) + (BUFSIZ - 1U)) / BUFSIZ) * BUFSIZ);
58 static size_t get_buffer_size(const uint64_t file_size
)
60 const uint64_t upper_limit
= file_size
/ 101U;
61 size_t pwr2
, result
= 0U;
62 for (pwr2
= 1U; (pwr2
<= MAX_BUFFER_SIZE
) && (pwr2
<= upper_limit
); pwr2
<<= 1)
66 return BOUND(BUFSIZ
, result
, MAX_BUFFER_SIZE
);
69 static void init_slunk_param(slunkparam_t
*const param
, const crypt_options_t
*const options
)
71 slunkcrypt_bzero(param
, sizeof(slunkparam_t
));
72 param
->version
= SLUNKCRYPT_PARAM_VERSION
;
73 param
->thread_count
= options
->thread_count
;
76 #define UPDATE_PROGRESS_INDICATOR(CLK_UPDATE, CURRENT, TOTAL) do \
78 const uint64_t clk_now = clock_read(); \
79 if ((clk_now < (CLK_UPDATE)) || (clk_now - (CLK_UPDATE) > update_interval)) \
81 FPRINTF(stderr, T("\b\b\b\b\b\b\b%5.1f%% "), ((CURRENT) / ((double)(TOTAL))) * 100.0); \
83 CLK_UPDATE = clk_now; \
88 // ==========================================================================
90 // ==========================================================================
92 int encrypt(const char *const passphrase
, const CHR
*const input_path
, const CHR
*const output_path
, const crypt_options_t
*const options
)
94 slunkcrypt_t ctx
= SLUNKCRYPT_NULL
;
96 FILE *file_in
= NULL
, *file_out
= NULL
;
97 uint8_t *buffer
= NULL
;
98 size_t buffer_size
= BUFSIZ
;
99 int result
= EXIT_FAILURE
, status
= -1;
101 if (open_files(&file_in
, &file_out
, input_path
, output_path
) != EXIT_SUCCESS
)
106 const uint64_t file_size
= get_size(file_in
);
107 if (file_size
== UINT64_MAX
)
109 FPUTS(T("I/O error: Failed to determine size of input file!\n\n"), stderr
);
112 else if (file_size
< 1U)
114 FPUTS(T("Error: Input file is empty or an unsupported type!\n\n"), stderr
);
118 if (!(buffer
= malloc((buffer_size
= get_buffer_size(file_size
)) * sizeof(uint8_t))))
120 FPUTS(T("Error: Failed to allocate the I/O buffer!\n\n"), stderr
);
124 FPUTS(T("Encrypting file contents, please be patient... "), stderr
);
128 if (slunkcrypt_generate_nonce(&nonce
) != SLUNKCRYPT_SUCCESS
)
130 FPUTS(T("\n\nSlunkCrypt error: Failed to generate nonce!\n\n"), stderr
);
134 init_slunk_param(¶m
, options
);
135 ctx
= slunkcrypt_alloc_ext(nonce
, (const uint8_t*)passphrase
, strlen(passphrase
), SLUNKCRYPT_ENCRYPT
, ¶m
);
138 FPUTS(g_slunkcrypt_abort_flag
? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to initialize encryption!\n\n"), stderr
);
142 if (fwrite_ui64(nonce
^ MAGIC_NUMBER
, file_out
) < 1U)
144 FPUTS(T("\n\nI/O error: Failed to write nonce value!\n\n"), stderr
);
148 uint64_t bytes_read
= 0U, clk_update
= clock_read();
149 const uint64_t update_interval
= (uint64_t)(clock_freq() * 1.414);
151 blake2s_t blake2s_state
;
152 blake2s_init(&blake2s_state
);
154 FPRINTF(stderr
, T("%5.1f%% "), 0.0);
157 while (bytes_read
< file_size
)
159 const uint64_t bytes_remaining
= file_size
- bytes_read
;
160 const size_t request_len
= (bytes_remaining
< buffer_size
) ? ((size_t)bytes_remaining
) : buffer_size
;
161 const size_t count
= fread(buffer
, sizeof(uint8_t), request_len
, file_in
);
164 blake2s_update(&blake2s_state
, buffer
, count
);
166 if ((status
= slunkcrypt_inplace(ctx
, buffer
, count
)) != SLUNKCRYPT_SUCCESS
)
168 FPUTS((status
== SLUNKCRYPT_ABORTED
) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to encrypt data!\n\n"), stderr
);
171 if (fwrite(buffer
, sizeof(uint8_t), count
, file_out
) < count
)
173 FPUTS(T("\n\nI/O error: Failed to write encrypted data!\n\n"), stderr
);
177 if (count
< request_len
)
181 UPDATE_PROGRESS_INDICATOR(clk_update
, bytes_read
, file_size
);
186 FPUTS(T("\n\nI/O error: Failed to read input data!\n\n"), stderr
);
190 if (bytes_read
!= file_size
)
192 FPUTS(T("\n\nI/O error: Input file could not be fully read!\n\n"), stderr
);
196 const size_t padding
= sizeof(uint64_t) - (file_size
% sizeof(uint64_t));
197 assert(padding
&& (padding
<= sizeof(uint64_t)));
198 if (slunkcrypt_random_bytes(buffer
, padding
) < padding
)
200 FPUTS(T("\n\nSlunkCrypt error: Failed to generate random data!\n\n"), stderr
);
204 SET_LOWBITS(buffer
[padding
- 1U], padding
- 1U);
205 if ((status
= slunkcrypt_inplace(ctx
, buffer
, padding
)) != SLUNKCRYPT_SUCCESS
)
207 FPUTS((status
== SLUNKCRYPT_ABORTED
) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to encrypt data!\n\n"), stderr
);
211 if (fwrite(buffer
, sizeof(uint8_t), padding
, file_out
) < padding
)
213 FPUTS(T("\n\nI/O error: Failed to write padding data!\n\n"), stderr
);
217 uint8_t checksum_buffer
[sizeof(uint64_t)];
218 store_ui64(checksum_buffer
, blake2s_final(&blake2s_state
));
220 if ((status
= slunkcrypt_inplace(ctx
, checksum_buffer
, sizeof(uint64_t))) != SLUNKCRYPT_SUCCESS
)
222 FPUTS((status
== SLUNKCRYPT_ABORTED
) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to encrypt checksum!\n\n"), stderr
);
226 if (fwrite(checksum_buffer
, sizeof(uint8_t), sizeof(uint64_t), file_out
) < sizeof(uint64_t))
228 FPUTS(T("\n\nI/O error: Failed to write the checksum!\n\n"), stderr
);
232 FPRINTF(stderr
, T("\b\b\b\b\b\b\b%5.1f%%\n\n"), 100.0);
234 result
= EXIT_SUCCESS
;
236 FPUTS(T("All is done.\n\n"), stderr
);
241 SLUNKCRYPT_SAFE_FREE(ctx
);
246 if ((result
!= EXIT_SUCCESS
) && (!options
->keep_incomplete
))
248 if (REMOVE(output_path
))
250 FPUTS(T("Warning: Failed to remove incomplete output file!\n\n"), stderr
);
262 slunkcrypt_bzero(buffer
, buffer_size
* sizeof(uint8_t));
266 slunkcrypt_bzero(checksum_buffer
, sizeof(uint64_t));
267 slunkcrypt_bzero(&blake2s_state
, sizeof(blake2s_t
));
268 slunkcrypt_bzero(&nonce
, sizeof(uint64_t));
273 // ==========================================================================
275 // ==========================================================================
277 int decrypt(const char *const passphrase
, const CHR
*const input_path
, const CHR
*const output_path
, const crypt_options_t
*const options
)
279 slunkcrypt_t ctx
= SLUNKCRYPT_NULL
;
281 FILE *file_in
= NULL
, *file_out
= NULL
;
282 uint8_t *buffer
= NULL
;
283 size_t buffer_size
= BUFSIZ
;
284 int result
= EXIT_FAILURE
, status
= -1;
286 if (open_files(&file_in
, &file_out
, input_path
, output_path
) != EXIT_SUCCESS
)
291 const uint64_t file_size
= get_size(file_in
);
292 if (file_size
== UINT64_MAX
)
294 FPUTS(T("I/O error: Failed to determine size of input file!\n\n"), stderr
);
297 else if (file_size
< (3U * sizeof(uint64_t)))
299 FPUTS(T("Error: Input file is too small! Truncated?\n\n"), stderr
);
302 else if ((file_size
% sizeof(uint64_t)) != 0)
304 FPRINTF(stderr
, T("Warning: File size is *not* an integer multiple of %u, ignoring excess bytes!\n\n"), (unsigned)sizeof(uint64_t));
307 if (!(buffer
= malloc((buffer_size
= get_buffer_size(file_size
)) * sizeof(uint8_t))))
309 FPUTS(T("Error: Failed to allocate the I/O buffer!\n\n"), stderr
);
313 FPUTS(T("Decrypting file contents, please be patient... "), stderr
);
317 if (fread_ui64(&nonce
, file_in
) < 1U)
319 FPUTS(T("\n\nI/O error: Failed to read nonce value!\n\n"), stderr
);
323 init_slunk_param(¶m
, options
);
324 ctx
= slunkcrypt_alloc_ext(nonce
^ MAGIC_NUMBER
, (const uint8_t*)passphrase
, strlen(passphrase
), SLUNKCRYPT_DECRYPT
, ¶m
);
327 FPUTS(g_slunkcrypt_abort_flag
? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to initialize decryption!\n\n"), stderr
);
331 uint64_t bytes_read
= sizeof(uint64_t), clk_update
= clock_read();
332 const uint64_t update_interval
= (uint64_t)(clock_freq() * 1.414);
333 const uint64_t read_limit
= round_down(file_size
, sizeof(uint64_t)) - (2U * sizeof(uint64_t));
335 blake2s_t blake2s_state
;
336 blake2s_init(&blake2s_state
);
338 FPRINTF(stderr
, T("%5.1f%% "), 0.0);
341 while (bytes_read
< read_limit
)
343 const uint64_t bytes_remaining
= read_limit
- bytes_read
;
344 const size_t request_len
= (bytes_remaining
< buffer_size
) ? ((size_t)bytes_remaining
) : buffer_size
;
345 const size_t count
= fread(buffer
, sizeof(uint8_t), request_len
, file_in
);
349 if ((status
= slunkcrypt_inplace(ctx
, buffer
, count
)) != SLUNKCRYPT_SUCCESS
)
351 FPUTS((status
== SLUNKCRYPT_ABORTED
) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to decrypt data!\n\n"), stderr
);
354 blake2s_update(&blake2s_state
, buffer
, count
);
355 if (fwrite(buffer
, sizeof(uint8_t), count
, file_out
) < count
)
357 FPUTS(T("failed!\n\nI/O error: Failed to write decrypted data!\n\n"), stderr
);
361 if (count
< request_len
)
365 UPDATE_PROGRESS_INDICATOR(clk_update
, bytes_read
, read_limit
);
370 FPUTS(T("\n\nI/O error: Failed to read input data!\n\n"), stderr
);
374 if (bytes_read
!= read_limit
)
376 FPUTS(T("\n\nI/O error: Input file could not be fully read!\n\n"), stderr
);
380 if (fread(buffer
, sizeof(uint8_t), sizeof(uint64_t), file_in
) < sizeof(uint64_t))
382 FPUTS(T("\n\nI/O error: Failed to read final block!\n\n"), stderr
);
386 if ((status
= slunkcrypt_inplace(ctx
, buffer
, sizeof(uint64_t))) != SLUNKCRYPT_SUCCESS
)
388 FPUTS((status
== SLUNKCRYPT_ABORTED
) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to decrypt data!\n\n"), stderr
);
392 const size_t padding
= GET_LOWBITS(buffer
[sizeof(uint64_t) - 1U]) + 1U;
393 assert(padding
&& (padding
<= sizeof(uint64_t)));
394 if (padding
!= sizeof(uint64_t))
396 const size_t count
= sizeof(uint64_t) - padding
;
397 if (fwrite(buffer
, sizeof(uint8_t), count
, file_out
) < count
)
399 FPUTS(T("failed!\n\nI/O error: Failed to write decrypted data!\n\n"), stderr
);
402 blake2s_update(&blake2s_state
, buffer
, count
);
405 const uint64_t checksum_actual
= blake2s_final(&blake2s_state
);
407 uint8_t checksum_buffer
[sizeof(uint64_t)];
408 if (fread(checksum_buffer
, sizeof(uint8_t), sizeof(uint64_t), file_in
) < sizeof(uint64_t))
410 FPUTS(T("\n\nI/O error: Failed to read the checksum!\n\n"), stderr
);
414 if ((status
= slunkcrypt_inplace(ctx
, checksum_buffer
, sizeof(uint64_t))) != SLUNKCRYPT_SUCCESS
)
416 FPUTS((status
== SLUNKCRYPT_ABORTED
) ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to decrypt checksum!\n\n"), stderr
);
420 FPRINTF(stderr
, T("\b\b\b\b\b\b\b%5.1f%%\n\n"), 100.0);
422 const uint64_t checksum_stored
= load_ui64(checksum_buffer
);
423 if (checksum_actual
!= checksum_stored
)
425 FPRINTF(stderr
, T("Error: Checksum mismatch detected! [expected: 0x%016") T(PRIX64
) T(", actual: 0x%016") T(PRIX64
) T("]\n\n"), checksum_stored
, checksum_actual
);
426 FPUTS(T("Wrong passphrase or corrupted file?\n\n"), stderr
);
430 result
= EXIT_SUCCESS
;
432 FPUTS(T("Checksum is correct.\n\n"), stderr
);
437 SLUNKCRYPT_SAFE_FREE(ctx
);
442 if ((result
!= EXIT_SUCCESS
) && (!options
->keep_incomplete
))
444 if (REMOVE(output_path
))
446 FPUTS(T("Warning: Failed to remove incomplete output file!\n\n"), stderr
);
458 slunkcrypt_bzero(buffer
, buffer_size
* sizeof(uint8_t));
462 slunkcrypt_bzero(checksum_buffer
, sizeof(uint64_t));
463 slunkcrypt_bzero(&blake2s_state
, sizeof(blake2s_t
));
464 slunkcrypt_bzero(&nonce
, sizeof(uint64_t));
465 slunkcrypt_bzero((void*)&checksum_stored
, sizeof(uint64_t));
466 slunkcrypt_bzero((void*)&checksum_actual
, sizeof(uint64_t));