2020-10-12 23:10:47 +02:00
|
|
|
/******************************************************************************/
|
|
|
|
/* MCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
|
|
|
|
/* This work has been released under the CC0 1.0 Universal license! */
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
#define _CRT_SECURE_NO_WARNINGS 1
|
|
|
|
|
|
|
|
#include <mcrypt.h>
|
2020-10-13 15:04:59 +02:00
|
|
|
#include "utils.h"
|
|
|
|
#include "crc.h"
|
2020-10-12 23:10:47 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
static void print_string(const char *const text, const size_t length)
|
|
|
|
{
|
|
|
|
fputc('"', stderr);
|
|
|
|
for (size_t i = 0; i < length; ++i)
|
|
|
|
{
|
|
|
|
fputc((text[i] >= 0x20) ? text[i] : '?', stderr);
|
|
|
|
}
|
|
|
|
fputs("\"\n\n", stderr);
|
|
|
|
}
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
static int open_files(FILE** const fin, FILE** const fout, const CHR* const input, const CHR* const output)
|
2020-10-12 23:10:47 +02:00
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
*fin = FOPEN(input, T("rb"));
|
2020-10-13 00:43:57 +02:00
|
|
|
if (!(*fin))
|
2020-10-12 23:10:47 +02:00
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("Error: Failed to open input file for reading!\n\n"), stderr);
|
2020-10-12 23:10:47 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
*fout = FOPEN(output, T("wb"));
|
2020-10-13 00:43:57 +02:00
|
|
|
if (!(*fout))
|
2020-10-12 23:10:47 +02:00
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("Error: Failed to open output file for writing!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
fclose(*fin);
|
2020-10-12 23:10:47 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-10-13 00:43:57 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
static int encrypt(const CHR* const passphrase, const CHR* const input, const CHR* const output)
|
2020-10-13 00:43:57 +02:00
|
|
|
{
|
|
|
|
mcrypt_t ctx = NULL;
|
|
|
|
FILE *fin = NULL, *fout = NULL;
|
|
|
|
int result = -1;
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
if (!passphrase[0U])
|
|
|
|
{
|
|
|
|
FPUTS(T("Error: The given passphrase is empty!\n\n"), stderr);
|
|
|
|
goto clean_up;
|
|
|
|
}
|
|
|
|
|
2020-10-13 00:43:57 +02:00
|
|
|
char *const passphrase_utf8 = utf16_to_bytes(passphrase, CP_UTF8);
|
|
|
|
if (!passphrase_utf8)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("Error: Failed to convert passphrase to UTF-8 format!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (open_files(&fin, &fout, input, output) != 0)
|
|
|
|
{
|
|
|
|
goto clean_up;;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
const uint64_t file_size = get_file_size(fin);
|
|
|
|
if (file_size == UINT64_MAX)
|
|
|
|
{
|
|
|
|
FPUTS(T("I/O error: Failed to determine size of input file!\n\n"), stderr);
|
|
|
|
goto clean_up;
|
|
|
|
}
|
|
|
|
else if (file_size < 1LL)
|
|
|
|
{
|
|
|
|
FPUTS(T("Error: Input file is empty!\n\n"), stderr);
|
|
|
|
goto clean_up;
|
|
|
|
}
|
|
|
|
|
2020-10-12 23:10:47 +02:00
|
|
|
uint64_t seed;
|
|
|
|
if (mcrypt_generate_seed(&seed) != 0)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("MCrypt error: Failed to generate seed!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fwrite(&seed, sizeof(uint64_t), 1U, fout) < 1U)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("I/O error: Failed to write seed value!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 00:43:57 +02:00
|
|
|
ctx = mcrypt_alloc(seed, passphrase_utf8);
|
2020-10-12 23:10:47 +02:00
|
|
|
if (!ctx)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("MCrypt error: Failed to initialize encryption!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
FPRINTF(stderr, T("Encrypting, please be patient... %5.1f%%"), 0.0);
|
2020-10-12 23:10:47 +02:00
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
clock_t clk_now, clk_update = clock();
|
|
|
|
uint64_t crc_actual = CRC_INITIALIZER, bytes_read = sizeof(uint64_t);
|
2020-10-12 23:10:47 +02:00
|
|
|
uint8_t buffer[1024U];
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
while ((!feof(fin)) && (bytes_read < file_size))
|
2020-10-12 23:10:47 +02:00
|
|
|
{
|
|
|
|
const size_t count = fread(buffer, sizeof(uint8_t), 1024U, fin);
|
|
|
|
if (ferror(fin))
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("\n\nI/O error: Failed to read input data!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
if (count > 0U)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
crc_actual = crc64_update(crc_actual, buffer, count);
|
|
|
|
bytes_read += count;
|
2020-10-12 23:10:47 +02:00
|
|
|
if (mcrypt_enc_process_inplace(ctx, buffer, count) != 0)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("\n\nMCrypt error: Failed to encrypt data!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
if (fwrite(buffer, sizeof(uint8_t), count, fout) < count)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("\n\nI/O error: Failed to write encrypted data!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
}
|
2020-10-13 15:04:59 +02:00
|
|
|
if ((clk_now = clock()) - clk_update > CLOCKS_PER_SEC)
|
|
|
|
{
|
|
|
|
FPRINTF(stderr, T("\b\b\b\b\b\b%5.1f%%"), (bytes_read / ((double)file_size)) * 100.0);
|
|
|
|
fflush(stderr);
|
|
|
|
clk_update = clk_now;
|
|
|
|
}
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
crc_actual = crc64_finish(crc_actual);
|
|
|
|
|
|
|
|
if (bytes_read < file_size)
|
|
|
|
{
|
|
|
|
FPUTS(T("\n\nI/O error: Input file could not be fully read!\n\n"), stderr);
|
|
|
|
goto clean_up;
|
|
|
|
}
|
2020-10-12 23:10:47 +02:00
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
FPRINTF(stderr, T("\b\b\b\b\b\b%5.1f%%\n\n"), 100.0);
|
|
|
|
|
2020-10-12 23:10:47 +02:00
|
|
|
if (fwrite(&crc_actual, sizeof(uint64_t), 1U, fout) < 1U)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("I/O error: Failed to write CRC checksum!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = 0;
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("All is done.\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
fflush(stderr);
|
|
|
|
|
|
|
|
clean_up:
|
|
|
|
|
|
|
|
if (ctx)
|
|
|
|
{
|
2020-10-12 23:10:47 +02:00
|
|
|
mcrypt_free(ctx);
|
2020-10-13 00:43:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fout)
|
|
|
|
{
|
2020-10-12 23:10:47 +02:00
|
|
|
fclose(fout);
|
2020-10-13 00:43:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fin)
|
|
|
|
{
|
2020-10-12 23:10:47 +02:00
|
|
|
fclose(fin);
|
|
|
|
}
|
|
|
|
|
2020-10-13 00:43:57 +02:00
|
|
|
if (passphrase_utf8)
|
|
|
|
{
|
|
|
|
erase(passphrase_utf8, strlen(passphrase_utf8));
|
|
|
|
free(passphrase_utf8);
|
|
|
|
}
|
2020-10-12 23:10:47 +02:00
|
|
|
|
2020-10-13 00:43:57 +02:00
|
|
|
return result;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
static int decrypt(const CHR* const passphrase, const CHR* const input, const CHR* const output)
|
2020-10-12 23:10:47 +02:00
|
|
|
{
|
2020-10-13 00:43:57 +02:00
|
|
|
mcrypt_t ctx = NULL;
|
|
|
|
FILE *fin = NULL, *fout = NULL;
|
|
|
|
int result = -1;
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
if (!passphrase[0U])
|
|
|
|
{
|
|
|
|
FPUTS(T("Error: The given passphrase is empty!\n\n"), stderr);
|
|
|
|
goto clean_up;
|
|
|
|
}
|
|
|
|
|
2020-10-13 00:43:57 +02:00
|
|
|
char *const passphrase_utf8 = utf16_to_bytes(passphrase, CP_UTF8);
|
2020-10-12 23:10:47 +02:00
|
|
|
if (!passphrase_utf8)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("Error: Failed to convert passphrase to UTF-8 format!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 00:43:57 +02:00
|
|
|
if (open_files(&fin, &fout, input, output) != 0)
|
2020-10-12 23:10:47 +02:00
|
|
|
{
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 00:43:57 +02:00
|
|
|
const uint64_t file_size = get_file_size(fin);
|
|
|
|
if (file_size == UINT64_MAX)
|
2020-10-12 23:10:47 +02:00
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("I/O error: Failed to determine size of input file!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
2020-10-13 15:04:59 +02:00
|
|
|
else if (file_size < 16LL)
|
2020-10-12 23:10:47 +02:00
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("Error: Input file is too small! Truncated?\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t seed;
|
|
|
|
if (fread(&seed, sizeof(uint64_t), 1U, fin) < 1U)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("I/O error: Failed to read seed value!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 00:43:57 +02:00
|
|
|
ctx = mcrypt_alloc(seed, passphrase_utf8);
|
2020-10-12 23:10:47 +02:00
|
|
|
if (!ctx)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("MCrypt error: Failed to initialize decryption!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
FPRINTF(stderr, T("Decrypting, please be patient... %5.1f%%"), 0.0);
|
2020-10-12 23:10:47 +02:00
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
clock_t clk_now, clk_update = clock();
|
|
|
|
uint64_t crc_actual = CRC_INITIALIZER, bytes_read = sizeof(uint64_t);
|
2020-10-12 23:10:47 +02:00
|
|
|
uint8_t buffer[1024U];
|
2020-10-13 15:04:59 +02:00
|
|
|
const uint64_t read_limit = file_size - sizeof(uint64_t);
|
2020-10-12 23:10:47 +02:00
|
|
|
|
2020-10-13 00:43:57 +02:00
|
|
|
while ((!feof(fin)) && (bytes_read < read_limit))
|
2020-10-12 23:10:47 +02:00
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
const uint64_t bytes_remaining = read_limit - bytes_read;
|
2020-10-12 23:10:47 +02:00
|
|
|
const size_t read_len = (bytes_remaining < 1024U) ? ((size_t)bytes_remaining) : 1024U;
|
|
|
|
const size_t count = fread(buffer, sizeof(uint8_t), read_len, fin);
|
|
|
|
if (ferror(fin))
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("\n\nI/O error: Failed to read encrypted data!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
if (count > 0U)
|
|
|
|
{
|
|
|
|
bytes_read += count;
|
|
|
|
if (mcrypt_dec_process_inplace(ctx, buffer, count) != 0)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("\n\nMCrypt error: Failed to decrypt data!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
2020-10-13 15:04:59 +02:00
|
|
|
crc_actual = crc64_update(crc_actual, buffer, count);
|
2020-10-12 23:10:47 +02:00
|
|
|
if (fwrite(buffer, sizeof(uint8_t), count, fout) < count)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("failed!\n\nI/O error: Failed to write decrypted data!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
}
|
2020-10-13 15:04:59 +02:00
|
|
|
if ((clk_now = clock()) - clk_update > CLOCKS_PER_SEC)
|
|
|
|
{
|
|
|
|
FPRINTF(stderr, T("\b\b\b\b\b\b%5.1f%%"), (bytes_read / ((double)read_limit)) * 100.0);
|
|
|
|
fflush(stderr);
|
|
|
|
clk_update = clk_now;
|
|
|
|
}
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
crc_actual = crc64_finish(crc_actual);
|
2020-10-12 23:10:47 +02:00
|
|
|
|
2020-10-13 00:43:57 +02:00
|
|
|
if (bytes_read < read_limit)
|
2020-10-12 23:10:47 +02:00
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("\n\nI/O error: Input file could not be fully read!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
FPRINTF(stderr, T("\b\b\b\b\b\b%5.1f%%\n\n"), 100.0);
|
|
|
|
|
2020-10-12 23:10:47 +02:00
|
|
|
uint64_t crc_expected;
|
|
|
|
if (fread(&crc_expected, sizeof(uint64_t), 1U, fin) < 1U)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("I/O error: Failed to read CRC checksum!\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (crc_actual != crc_expected)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPRINTF(stderr, T("CRC error: Checksum mismatch detected! [0x%016") FMT_I64X T(" vs. 0x%016") FMT_I64X T("\n\nWrong passphrase?\n\n"), crc_actual, crc_expected);
|
2020-10-13 00:43:57 +02:00
|
|
|
goto clean_up;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = 0;
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("CRC checksum is correct :-)\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
fflush(stderr);
|
|
|
|
|
|
|
|
clean_up:
|
|
|
|
|
|
|
|
if (ctx)
|
|
|
|
{
|
2020-10-12 23:10:47 +02:00
|
|
|
mcrypt_free(ctx);
|
2020-10-13 00:43:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fout)
|
|
|
|
{
|
2020-10-12 23:10:47 +02:00
|
|
|
fclose(fout);
|
2020-10-13 00:43:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fin)
|
|
|
|
{
|
2020-10-12 23:10:47 +02:00
|
|
|
fclose(fin);
|
|
|
|
}
|
|
|
|
|
2020-10-13 00:43:57 +02:00
|
|
|
if (passphrase_utf8)
|
|
|
|
{
|
|
|
|
erase(passphrase_utf8, strlen(passphrase_utf8));
|
|
|
|
free(passphrase_utf8);
|
|
|
|
}
|
2020-10-12 23:10:47 +02:00
|
|
|
|
2020-10-13 00:43:57 +02:00
|
|
|
return result;
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
int MAIN(int argc, CHR* argv[])
|
2020-10-12 23:10:47 +02:00
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPRINTF(stderr, T("MCrypt Utility [%") FMT_char T("]\n"), __DATE__" "__TIME__);
|
|
|
|
FPRINTF(stderr, T("Powered by libMCrypt v%") FMT_char T(" [%") FMT_char T("]\n\n"), LIBMCRYPT_VERSION, LIBMCRYPT_BUILDNO);
|
2020-10-12 23:10:47 +02:00
|
|
|
|
|
|
|
if (argc < 4)
|
|
|
|
{
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("Usage:\n"), stderr);
|
|
|
|
FPRINTF(stderr, T(" %s [--decrypt] <passphrase> <input> <output>\n\n"), argv[0U]);
|
2020-10-12 23:10:47 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int result = -1;
|
|
|
|
const clock_t clk_start = clock();
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
if ((argc > 4) && ((!STRICMP(argv[1U], T("-d"))) || (!STRICMP(argv[1U], T("--decrypt")))))
|
2020-10-12 23:10:47 +02:00
|
|
|
{
|
|
|
|
result = decrypt(argv[2U], argv[3U], argv[4U]);
|
2020-10-13 15:04:59 +02:00
|
|
|
erase(argv[2U], STRLEN(argv[2U]) * sizeof(CHR));
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result = encrypt(argv[1U], argv[2U], argv[3U]);
|
2020-10-13 15:04:59 +02:00
|
|
|
erase(argv[1U], STRLEN(argv[1U]) * sizeof(CHR));
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 15:04:59 +02:00
|
|
|
FPUTS(T("--------\n\n"), stderr);
|
2020-10-13 00:43:57 +02:00
|
|
|
fflush(stderr);
|
|
|
|
|
2020-10-12 23:10:47 +02:00
|
|
|
const clock_t clk_end = clock();
|
2020-10-13 15:04:59 +02:00
|
|
|
FPRINTF(stderr, T("Operation completed after %.1f seconds.\n\n"), (clk_end - clk_start) / ((double)CLOCKS_PER_SEC));
|
2020-10-12 23:10:47 +02:00
|
|
|
}
|