Make it possible to set number of threads in the front-end + updated the README file.

This commit is contained in:
LoRd_MuldeR 2022-03-23 22:33:45 +01:00
parent a4aec9f3fe
commit d0be7ad5a5
Signed by: mulder
GPG Key ID: 2B5913365F57E03F
11 changed files with 221 additions and 165 deletions

View File

@ -119,7 +119,10 @@ The following environment variables may be used:
Passing the passphrase via environment variable is considered more secure, because environment variables are not normally visible to other (unprivileged) users.
- **`SLUNK_KEEP_INCOMPLETE`**:
If set to a *non-zero* value, incomplete or corrupted output files will **not** be deleted automatically. Default is `0`.
If set to a *non-zero* value, incomplete or corrupted output files will **not** be deleted automatically. By default, the files will be deleted.
- **`SLUNK_THREADS`**:
Specifies the number of worker threads to use. By default, SlunkCrypt detects the number of available processors and creates one thread for each processor.
Examples
--------
@ -247,7 +250,7 @@ Here is a simple example on how to use the SlunkCrypt [**`Decryptor`**](#decrypt
{
/* Open input and output files here */
uint8_t buffer[BUFF_SIZE];
slunkcrypt::Decryptor slunk_decrypt(nonce, passphrase);
slunkcrypt::Decryptor slunk_decrypt(passphrase, nonce);
while (input.good())
{
input.read(reinterpret_cast<char*>(buffer), BUFF_SIZE);
@ -276,16 +279,20 @@ Class for *encrypting* data using the SlunkCrypt library.
Create and initialize a new **``Encryptor``** instance. Also generated a new, random nonce.
Encryptor::Encryptor(
const std::string &passwd
const std::string &passwd,
const size_t thread_count = 0U
);
***Parameters:***
* `passwd`
The password to "protect" the message. The password is given as an `std::string`, e.g. UTF-8 encoded characters. The same password **may** be used to encrypt *multiple* messages. Also, the same password **must** be used for both, encryption *and* decryption; it will *only* be possible decrypt the ciphertext, if the "correct" password is known. The password must be kept confidential under all circumstances!
*Note:* In order to thwart *brute force* attacks, it is recommended to choose a "random" password that is at least 12 characters in length and that consists of upper-case characters, lower-case characters, digits as well as other "special" characters.
* `thread_count`
Specifies the number of worker threads to use (optional). By default, SlunkCrypt detects the number of available processors and creates one thread for each processor.
***Exceptions:***
* Throws `std::runtime_error`, if the nonce could not be generated, or if the SlunkCrypt context could not be allocated.
@ -403,21 +410,25 @@ Class for *decrypting* data using the SlunkCrypt library.
Create and initialize a new **``Decryptor``** instance.
Decryptor::Decryptor(
const std::string &passwd,
const uint64_t nonce,
const std::string &passwd
const size_t thread_count = 0U
);
***Parameters:***
* `passwd`
The password to "protect" the message. The password is given as an `std::string`, e.g. UTF-8 encoded characters. The same password **may** be used to encrypt *multiple* messages. Also, the same password **must** be used for both, encryption *and* decryption; it will *only* be possible decrypt the ciphertext, if the "correct" password is known. The password must be kept confidential under all circumstances!
*Note:* In order to thwart *brute force* attacks, it is recommended to choose a "random" password that is at least 12 characters in length and that consists of upper-case characters, lower-case characters, digits as well as other "special" characters.
* `nonce`
The *nonce* (number used once) to be used for the decryption process. The purpose of the nonce is to ensure that each message will be encrypted differently, even when the same password is used to encrypt *multiple* (possibly identical) messages. Therefore, a new *random* nonce **must** be chosen for each message! It is *not* necessary to keep the nonce confidential, but the same nonce **must** be used for both, encryption *and* decryption. Typically, the nonce is stored/transmitted alongside the ciphertext.
*Note:* The `Encryptor` class automatically generates a new, random nonce for each message to be encrypted. Use `Encryptor::get_nonce()` to retrieve that nonce, so that it can be passed to `Decryptor` for decryption later.
* `passwd`
The password to "protect" the message. The password is given as an `std::string`, e.g. UTF-8 encoded characters. The same password **may** be used to encrypt *multiple* messages. Also, the same password **must** be used for both, encryption *and* decryption; it will *only* be possible decrypt the ciphertext, if the "correct" password is known. The password must be kept confidential under all circumstances!
*Note:* In order to thwart *brute force* attacks, it is recommended to choose a "random" password that is at least 12 characters in length and that consists of upper-case characters, lower-case characters, digits as well as other "special" characters.
* `thread_count`
Specifies the number of worker threads to use (optional). By default, SlunkCrypt detects the number of available processors and creates one thread for each processor.
***Exceptions:***
@ -559,6 +570,45 @@ Allocate and initialize a new SlunkCrypt encryption/decryption context.
*Note:* Applications **should** treat `slunkcrypt_t` as an *opaque* handle type. Also, as soon as the SlunkCrypt context is *not* needed anymore, the application **shall** call [`slunkcrypt_free()`](#slunkcrypt_free) in order to "erase" and de-allocate that context. If a SlunkCrypt context is *not* de-allocated properly, it will result in a memory leak!
#### slunkcrypt_alloc_ext()
Allocate and initialize a new SlunkCrypt encryption/decryption context with additional parameters.
slunkcrypt_t slunkcrypt_alloc_ext(
const uint64_t nonce,
const uint8_t *const passwd,
const size_t passwd_len,
const int mode,
const slunkparam_t *const param
);
***Parameters:***
* `nonce`
The *nonce* (number used once) to be used for the encryption/decryption process. The purpose of the nonce is to ensure that each message will be encrypted differently, even when the same password is used to encrypt *multiple* (possibly identical) messages. Therefore, a new *random* nonce **must** be chosen for each message to be encrypted! It is *not* necessary to keep the nonce confidential, but the same nonce **must** be used for both, encryption *and* decryption. Typically, the nonce is stored/transmitted alongside the ciphertext.
*Note:* It is recommended to generate a random nonce via the [`slunkcrypt_generate_nonce()`](#slunkcrypt_generate_nonce) function for each message!
* `passwd`
The password to "protect" the message. The password is given as a byte array (`uint8_t`), e.g. UTF-8 encoded characters; a terminating NULL character is *not* required, as the length of the password is specified explicitly. The same password **may** be used to encrypt *multiple* messages. Also, the same password **must** be used for both, encryption *and* decryption; it will *only* be possible decrypt the ciphertext, if the "correct" password is known. The password must be kept confidential under all circumstances!
*Note:* In order to thwart *brute force* attacks, it is recommended to choose a "random" password that is at least 12 characters in length and that consists of upper-case characters, lower-case characters, digits as well as other "special" characters.
* `passwd_len`
The length of password given by the `passwd` parameter, in bytes, **not** counting a terminating NULL character. The minimum/maximum length of the password are given by the `SLUNKCRYPT_PWDLEN_MIN` and `SLUNKCRYPT_PWDLEN_MAX` constants, respectively.
* `mode`
The mode of operation. Use `SLUNKCRYPT_ENCRYPT` in order to set up this context for *encryption*, or use `SLUNKCRYPT_DECRYPT` in order to set up this context for *decryption*.
* `param`
Additional parameters used to initialize the SlunkCrypt context, given as a pointer to a [`slunkparam_t`](#slunkcrypt-parameters) struct. The memory for the struct must be allocated by the caller and SlunkCrypt does **not** take owner ship of this memory; it will *copy* the relevant fields. The caller is responsible to free the struct; it can be allocated with automatic storage duration.
***Return value:***
* If successful, a handle to the new SlunkCrypt context is return; otherwise `SLUNKCRYPT_NULL` is returned.
*Note:* Applications **should** treat `slunkcrypt_t` as an *opaque* handle type. Also, as soon as the SlunkCrypt context is *not* needed anymore, the application **shall** call [`slunkcrypt_free()`](#slunkcrypt_free) in order to "erase" and de-allocate that context. If a SlunkCrypt context is *not* de-allocated properly, it will result in a memory leak!
#### slunkcrypt_reset()
Re-initialize an existing SlunkCrypt encryption/decryption context.
@ -724,6 +774,15 @@ Erase the contents of a byte array, by overwriting it with *zero* bytes. Compile
* `length`
The size of the buffer to be erased, in bytes.
### Types
#### SlunkCrypt parameters
The `slunkparam_t` struct is used to pass additional parameters that will be used for initializing the SlunkCrypt context. It contains the following fields:
* `version` &ndash; The version of the parameter struct; **must** be set to *`SLUNKCRYPT_PARAM_VERSION`*.
* `thread_count` &ndash; The number of worker threads to use. If this parameter is set to **0**, which is the *default* value, then SlunkCrypt automatically detects the number of available (logical) processors and creates one thread for each processor. Also, the number of threads is capped to a maximum of `MAX_THREADS` (currently defined as **16**).
### Global variables
The SlunkCypt library defines the following global variables:

View File

@ -52,14 +52,22 @@ static int open_files(FILE **const file_in, FILE **const file_out, const CHR *co
return EXIT_SUCCESS;
}
static void init_slunk_param(slunkparam_t *const param, const crypt_options_t *const options)
{
slunkcrypt_bzero(param, sizeof(slunkparam_t));
param->version = SLUNKCRYPT_PARAM_VERSION;
param->thread_count = options->thread_count;
}
// ==========================================================================
// Encrypt
// ==========================================================================
int encrypt(const char *const passphrase, const CHR *const input_path, const CHR *const output_path, const int keep_incomplete)
int encrypt(const char *const passphrase, const CHR *const input_path, const CHR *const output_path, const crypt_options_t *const options)
{
slunkcrypt_t ctx = SLUNKCRYPT_NULL;
FILE* file_in = NULL, * file_out = NULL;
slunkparam_t param;
FILE *file_in = NULL, *file_out = NULL;
int result = EXIT_FAILURE, status;
if (open_files(&file_in, &file_out, input_path, output_path) != EXIT_SUCCESS)
@ -89,7 +97,8 @@ int encrypt(const char *const passphrase, const CHR *const input_path, const CHR
goto clean_up;
}
ctx = slunkcrypt_alloc(nonce, (const uint8_t*)passphrase, strlen(passphrase), SLUNKCRYPT_ENCRYPT);
init_slunk_param(&param, options);
ctx = slunkcrypt_alloc_ext(nonce, (const uint8_t*)passphrase, strlen(passphrase), SLUNKCRYPT_ENCRYPT, &param);
if (!ctx)
{
FPUTS(g_slunkcrypt_abort_flag ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to initialize encryption!\n\n"), stderr);
@ -215,7 +224,7 @@ clean_up:
if (file_out)
{
fclose(file_out);
if ((result != EXIT_SUCCESS) && (!keep_incomplete))
if ((result != EXIT_SUCCESS) && (!options->keep_incomplete))
{
if (REMOVE(output_path))
{
@ -241,10 +250,11 @@ clean_up:
// Decrypt
// ==========================================================================
int decrypt(const char *const passphrase, const CHR *const input_path, const CHR *const output_path, const int keep_incomplete)
int decrypt(const char *const passphrase, const CHR *const input_path, const CHR *const output_path, const crypt_options_t *const options)
{
slunkcrypt_t ctx = SLUNKCRYPT_NULL;
FILE* file_in = NULL, * file_out = NULL;
slunkparam_t param;
FILE *file_in = NULL, *file_out = NULL;
int result = EXIT_FAILURE, status;
if (open_files(&file_in, &file_out, input_path, output_path) != EXIT_SUCCESS)
@ -278,7 +288,8 @@ int decrypt(const char *const passphrase, const CHR *const input_path, const CHR
goto clean_up;
}
ctx = slunkcrypt_alloc(nonce ^ MAGIC_NUMBER, (const uint8_t*)passphrase, strlen(passphrase), SLUNKCRYPT_DECRYPT);
init_slunk_param(&param, options);
ctx = slunkcrypt_alloc_ext(nonce ^ MAGIC_NUMBER, (const uint8_t*)passphrase, strlen(passphrase), SLUNKCRYPT_DECRYPT, &param);
if (!ctx)
{
FPUTS(g_slunkcrypt_abort_flag ? T("\n\nProcess interrupted!\n\n") : T("\n\nSlunkCrypt error: Failed to initialize decryption!\n\n"), stderr);
@ -411,7 +422,7 @@ clean_up:
if (file_out)
{
fclose(file_out);
if ((result != EXIT_SUCCESS) && (!keep_incomplete))
if ((result != EXIT_SUCCESS) && (!options->keep_incomplete))
{
if (REMOVE(output_path))
{

View File

@ -9,7 +9,14 @@
#include "platform.h"
#include <stdint.h>
int encrypt(const char *const passphrase, const CHR *const input_path, const CHR *const output_path, const int keep_incomplete);
int decrypt(const char *const passphrase, const CHR *const input_path, const CHR *const output_path, const int keep_incomplete);
typedef struct
{
int keep_incomplete;
size_t thread_count;
}
crypt_options_t;
int encrypt(const char *const passphrase, const CHR *const input_path, const CHR *const output_path, const crypt_options_t *const options);
int decrypt(const char *const passphrase, const CHR *const input_path, const CHR *const output_path, const crypt_options_t *const options);
#endif

View File

@ -39,6 +39,7 @@ static const size_t DFLT_PWDLEN_LENGTH = 24U;
static const CHR* const ENV_PASSWORD = T("SLUNK_PASSPHRASE");
static const CHR* const ENV_KEEPFILE = T("SLUNK_KEEP_INCOMPLETE");
static const CHR* const ENV_NTHREADS = T("SLUNK_THREADS");
static const CHR* const PREFIX_PASS = T("pass:");
static const CHR* const PREFIX_FILE = T("file:");
@ -111,14 +112,19 @@ static char *copy_passphrase(const CHR *const passphrase)
return buffer;
}
static int keep_incomplete_files(void)
static uint32_t environ_get_uint(const CHR *const name)
{
const CHR *const keep_files = GETENV(ENV_KEEPFILE);
if (keep_files)
const CHR *const value = GETENV(name);
if (value)
{
return BOOLIFY(STRTOUL(keep_files));
return (uint32_t) STRTOUL(value);
}
return 0;
return 0U;
}
static int environ_get_flag(const CHR *const name)
{
return (environ_get_uint(name) != 0);
}
static void check_excess_arguments(const int argc, int maximum)
@ -284,15 +290,15 @@ int MAIN(const int argc, CHR *const argv[])
/* ----------------------------------------------------- */
const uint64_t clk_start = clock_read();
const int keep_incomplete = keep_incomplete_files();
const crypt_options_t options = { environ_get_flag(ENV_KEEPFILE), environ_get_uint(ENV_NTHREADS) };
switch (slunk_mode)
{
case MODE_ENCR:
result = encrypt(passphrase_buffer, input_file, output_file, keep_incomplete);
result = encrypt(passphrase_buffer, input_file, output_file, &options);
break;
case MODE_DECR:
result = decrypt(passphrase_buffer, input_file, output_file, keep_incomplete);
result = decrypt(passphrase_buffer, input_file, output_file, &options);
break;
default:
FPUTS(T("Unexpected mode encountered!\n\n"), stderr);

View File

@ -31,7 +31,6 @@ 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 BOOLIFY(X) (!!(X))
#define BOUND(MIN,VAL,MAX) (((VAL) < (MIN)) ? (MIN) : (((VAL) > (MAX)) ? (MAX) : (VAL)))
#define STARTS_WITH(X,Y) (!STRNICMP((X), (Y), STRLEN((Y))))
#define GET_LOWBITS(X) ((X) & 0x07)

View File

@ -84,7 +84,7 @@ typedef struct
uint16_t version; /* Must set to SLUNKCRYPT_PARAM_VERSION */
size_t thread_count; /* Number of threads, set to 0 for auto-detection */
}
slunk_param_t;
slunkparam_t;
/*
* Version info
@ -112,7 +112,7 @@ SLUNKCRYPT_API int slunkcrypt_generate_nonce(uint64_t *const nonce);
* Allocate, reset or free state
*/
SLUNKCRYPT_API slunkcrypt_t slunkcrypt_alloc(const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode);
SLUNKCRYPT_API slunkcrypt_t slunkcrypt_alloc_ext(const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode, const slunk_param_t *const param);
SLUNKCRYPT_API slunkcrypt_t slunkcrypt_alloc_ext(const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode, const slunkparam_t *const param);
SLUNKCRYPT_API int slunkcrypt_reset(const slunkcrypt_t context, const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode);
SLUNKCRYPT_API void slunkcrypt_free(const slunkcrypt_t context);

View File

@ -1,4 +1,4 @@
/******************************************************************************/
/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
@ -20,6 +20,7 @@
#include <string>
#include <vector>
#include <stdexcept>
#include <cstring>
/*
* Namespace
@ -32,11 +33,20 @@ namespace slunkcrypt
class SlunkBase
{
public:
SlunkBase(const size_t thread_count)
{
std::memset(&m_param, 0, sizeof(m_param));
m_param.version = ::SLUNKCRYPT_PARAM_VERSION;
m_param.thread_count = thread_count;
}
virtual bool process(const uint8_t *const input, uint8_t *const output, size_t length) = 0;
virtual bool process(const std::vector<uint8_t> &input, std::vector<uint8_t> &output) = 0;
virtual bool inplace(uint8_t *const buffer, size_t length) = 0;
virtual bool inplace(std::vector<uint8_t> &buffer) = 0;
protected:
::slunkparam_t m_param;
::slunkcrypt_t m_instance;
};
@ -46,26 +56,18 @@ namespace slunkcrypt
class Encryptor : public SlunkBase
{
public:
Encryptor(const std::string &passwd)
Encryptor(const std::string &passwd, const size_t thread_count = 0U) : SlunkBase(thread_count)
{
if (::slunkcrypt_generate_nonce(&m_nonce) != SLUNKCRYPT_SUCCESS)
{
throw std::runtime_error("SlunkCryptEncr: Failed to generate the seed value!");
}
if ((m_instance = ::slunkcrypt_alloc(m_nonce, (const uint8_t*)passwd.c_str(), passwd.length(), SLUNKCRYPT_ENCRYPT)) == SLUNKCRYPT_NULL)
if ((m_instance = ::slunkcrypt_alloc_ext(m_nonce, (const uint8_t*)passwd.c_str(), passwd.length(), SLUNKCRYPT_ENCRYPT, &m_param)) == SLUNKCRYPT_NULL)
{
throw std::runtime_error("SlunkCryptEncr: Failed to create encoder instance!");
}
}
Encryptor(Encryptor &&other) noexcept
{
this->m_instance = other.m_instance;
this->m_nonce = other.m_nonce;
other.m_instance = SLUNKCRYPT_NULL;
other.m_nonce = (uint64_t)(-1);
}
~Encryptor(void)
{
if (m_instance != SLUNKCRYPT_NULL)
@ -115,20 +117,14 @@ namespace slunkcrypt
class Decryptor : public SlunkBase
{
public:
Decryptor(const uint64_t nonce, const std::string &passwd)
Decryptor(const std::string &passwd, const uint64_t nonce, const size_t thread_count = 0U) : SlunkBase(thread_count)
{
if ((m_instance = ::slunkcrypt_alloc(nonce, (const uint8_t*)passwd.c_str(), passwd.length(), SLUNKCRYPT_DECRYPT)) == SLUNKCRYPT_NULL)
if ((m_instance = ::slunkcrypt_alloc_ext(nonce, (const uint8_t*)passwd.c_str(), passwd.length(), SLUNKCRYPT_DECRYPT, &m_param)) == SLUNKCRYPT_NULL)
{
throw std::runtime_error("SlunkCryptDecr: Failed to create decoder instance!");
}
}
Decryptor(Decryptor &&other) noexcept
{
this->m_instance = other.m_instance;
other.m_instance = SLUNKCRYPT_NULL;
}
~Decryptor(void)
{
if (m_instance != SLUNKCRYPT_NULL)

View File

@ -4,10 +4,10 @@
/******************************************************************************/
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN 1
# define _CRT_SECURE_NO_WARNINGS 1
# define WIN32_LEAN_AND_MEAN 1
# define _CRT_SECURE_NO_WARNINGS 1
#else
# define _GNU_SOURCE 1
# define _GNU_SOURCE 1
#endif
/* Internal */
@ -19,6 +19,12 @@
#include <fcntl.h>
#include <limits.h>
/* PThread */
#if defined(_MSC_VER) && !defined(_DLL)
# define PTW32_STATIC_LIB 1
#endif
#include <pthread.h>
/* Utils */
static INLINE size_t MIN_SIZE(const size_t a, const size_t b) { return (a > b) ? b : a; }
@ -27,62 +33,31 @@ static INLINE size_t MIN_SIZE(const size_t a, const size_t b) { return (a > b) ?
// ==========================================================================
#ifdef _WIN32
# include <Windows.h>
# include <io.h>
# include <Windows.h>
# include <io.h>
#else
# include <unistd.h>
# include <pthread.h>
# include <unistd.h>
# include <pthread.h>
#endif
/* detect destructor support */
#undef ATTRIB_DESTRUCTOR
#if defined(__GNUC__) || defined(__clang__)
# define ATTRIB_DESTRUCTOR __attribute__((destructor))
# define ATTRIB_DESTRUCTOR __attribute__((destructor))
#endif
/* detect getentropy() support */
#undef GETENTROPY
#if (defined(__linux__) && (__linux__ >= 1)) || (defined(__FreeBSD__) && (__FreeBSD__ >= 12)) || (defined(__OpenBSD__) && (__OpenBSD__ >= 1))
# define GETENTROPY getentropy
# define GETENTROPY getentropy
#endif
/* detect explicit_bzero() support */
#undef EXPLICIT_BZERO
#if defined(_WIN32) && (_WIN32 >= 1) && defined(SecureZeroMemory)
# define EXPLICIT_BZERO SecureZeroMemory
# define EXPLICIT_BZERO SecureZeroMemory
#elif (defined(__linux__) && (__linux__ >= 1)) || (defined(__FreeBSD__) && (__FreeBSD__ >= 11)) || (defined(__OpenBSD__) && (__OpenBSD__ >= 1))
# define EXPLICIT_BZERO explicit_bzero
#endif
// ==========================================================================
// Call once support
// ==========================================================================
#ifdef _WIN32
# define CALL_ONCE win32_call_once
# define CALL_ONCE_TYPE volatile LONG
# define CALL_ONCE_INIT 0L
#else
# define CALL_ONCE pthread_once
# define CALL_ONCE_TYPE pthread_once_t
# define CALL_ONCE_INIT PTHREAD_ONCE_INIT
#endif
#ifdef _WIN32
static void win32_call_once(CALL_ONCE_TYPE *const control, void (*init_routine)(void))
{
LONG status;
while ((status = InterlockedCompareExchange(control, -1L, 0L)) != 0L)
{
if(status > 0L)
{
return; /*already initialized*/
}
SwitchToThread();
}
init_routine();
InterlockedExchange(control, 1L);
}
# define EXPLICIT_BZERO explicit_bzero
#endif
// ==========================================================================
@ -92,7 +67,7 @@ static void win32_call_once(CALL_ONCE_TYPE *const control, void (*init_routine)(
#define MAX_COUNT 1048576U
/* Global state */
static CALL_ONCE_TYPE s_random_is_initialized = CALL_ONCE_INIT;
static pthread_once_t s_random_is_initialized = PTHREAD_ONCE_INIT;
#if defined(_WIN32)
typedef BOOLEAN(WINAPI *ptr_genrandom_t)(void *buffer, ULONG length);
static HMODULE s_advapi32 = NULL;
@ -155,10 +130,10 @@ init_completed: ;
}
/* Generate random bytes */
size_t slunkcrypt_random_bytes(uint8_t* const buffer, const size_t length)
size_t slunkcrypt_random_bytes(uint8_t *const buffer, const size_t length)
{
size_t offset;
CALL_ONCE(&s_random_is_initialized, init_random_source);
pthread_once(&s_random_is_initialized, init_random_source);
#ifdef _WIN32
if (s_genrandom)
{

View File

@ -22,6 +22,7 @@ const char *const SLUNKCRYPT_BUILD = __DATE__ ", " __TIME__;
/* Utilities */
#define BOOLIFY(X) (!!(X))
#define THREAD_COUNT(X) (((X)->thread_pool != THRDPL_NULL) ? slunkcrypt_thrdpl_count((X)->thread_pool) : 1U)
// ==========================================================================
// Data structures
@ -117,7 +118,7 @@ static INLINE void random_skip(rand_state_t *const state, const size_t skip_coun
size_t i;
for (i = 0U; i < skip_count; ++i)
{
/* UNUSED volatile uint32_t q = */ random_next(state);
UNUSED /*volatile*/ uint32_t q = random_next(state);
}
}
@ -251,16 +252,20 @@ static INLINE void update_index(thread_state_t *const state, const size_t thread
}
}
static void thread_worker(const size_t thread_count, void *const context, const uint8_t *const input, uint8_t *const output, const size_t length)
static void thread_worker(const size_t thread_count, void *const context, uint8_t *const buffer, const size_t length)
{
thread_state_t *const state = (thread_state_t*) context;
size_t i;
for (i = state->index_off; i < length; i += thread_count)
{
output[i] = process_next_symbol(state, input[i]);
buffer[i] = process_next_symbol(state, buffer[i]);
state->counter += (uint32_t)thread_count;
random_skip(&state->random, 63U * (thread_count - 1U));
CHECK_ABORTED();
}
aborted:
update_index(state, thread_count, length);
}
@ -287,11 +292,11 @@ int slunkcrypt_generate_nonce(uint64_t *const nonce)
slunkcrypt_t slunkcrypt_alloc(const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode)
{
slunk_param_t param = { SLUNKCRYPT_PARAM_VERSION, 0U };
slunkparam_t param = { SLUNKCRYPT_PARAM_VERSION, 0U };
return slunkcrypt_alloc_ext(nonce, passwd, passwd_len, mode, &param);
}
slunkcrypt_t slunkcrypt_alloc_ext(const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode, const slunk_param_t *const param)
slunkcrypt_t slunkcrypt_alloc_ext(const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode, const slunkparam_t *const param)
{
crypt_state_t* state = NULL;
@ -306,22 +311,15 @@ slunkcrypt_t slunkcrypt_alloc_ext(const uint64_t nonce, const uint8_t *const pas
return SLUNKCRYPT_NULL;
}
if ((state->thread_pool = slunkcrypt_thrdpl_create(param->thread_count)) == THRDPL_NULL)
state->thread_pool = slunkcrypt_thrdpl_create(param->thread_count);
if (initialize_state(&state->data, THREAD_COUNT(state), nonce, passwd, passwd_len, mode) == SLUNKCRYPT_SUCCESS)
{
free(state);
return SLUNKCRYPT_NULL;
return (slunkcrypt_t)state;
}
if (initialize_state(&state->data, slunkcrypt_thrdpl_count(state->thread_pool), nonce, passwd, passwd_len, mode) == SLUNKCRYPT_SUCCESS)
{
return ((slunkcrypt_t)state);
}
else
{
slunkcrypt_thrdpl_destroy(state->thread_pool);
slunkcrypt_bzero(state, sizeof(crypt_state_t));
return SLUNKCRYPT_NULL;
}
slunkcrypt_free((slunkcrypt_t)state);
return SLUNKCRYPT_NULL;
}
int slunkcrypt_reset(const slunkcrypt_t context, const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode)
@ -342,8 +340,7 @@ int slunkcrypt_reset(const slunkcrypt_t context, const uint64_t nonce, const uin
int slunkcrypt_process(const slunkcrypt_t context, const uint8_t *const input, uint8_t *const output, size_t length)
{
size_t i;
crypt_state_t *const state = (crypt_state_t*) context;
crypt_state_t *const state = (crypt_state_t*)context;
if (!state)
{
return SLUNKCRYPT_FAILURE;
@ -351,27 +348,16 @@ int slunkcrypt_process(const slunkcrypt_t context, const uint8_t *const input, u
if (length > 0U)
{
const size_t thread_count = slunkcrypt_thrdpl_count(state->thread_pool);
for (i = 0; i < thread_count; ++i)
{
slunkcrypt_thrdpl_exec(state->thread_pool, i, thread_worker, &state->data.thread_data[i], input, output, length);
}
slunkcrypt_thrdpl_await(state->thread_pool);
memcpy(output, input, length);
return slunkcrypt_inplace(context, output, length);
}
CHECK_ABORTED();
return SLUNKCRYPT_SUCCESS;
aborted:
slunkcrypt_thrdpl_await(state->thread_pool);
slunkcrypt_bzero(&state->data, sizeof(crypt_data_t));
return SLUNKCRYPT_ABORTED;
}
int slunkcrypt_inplace(const slunkcrypt_t context, uint8_t *const buffer, size_t length)
{
size_t i;
crypt_state_t *const state = (crypt_state_t*) context;
crypt_state_t *const state = (crypt_state_t*)context;
if (!state)
{
return SLUNKCRYPT_FAILURE;
@ -379,19 +365,27 @@ int slunkcrypt_inplace(const slunkcrypt_t context, uint8_t *const buffer, size_t
if (length > 0U)
{
const size_t thread_count = slunkcrypt_thrdpl_count(state->thread_pool);
for (i = 0; i < thread_count; ++i)
const size_t thread_count = THREAD_COUNT(state);
if (thread_count > 1U)
{
slunkcrypt_thrdpl_exec(state->thread_pool, i, thread_worker, &state->data.thread_data[i], buffer, buffer, length);
size_t i;
for (i = 0U; i < thread_count; ++i)
{
slunkcrypt_thrdpl_exec(state->thread_pool, i, thread_worker, &state->data.thread_data[i], buffer, length);
}
slunkcrypt_thrdpl_await(state->thread_pool);
}
else
{
thread_worker(1U, &state->data.thread_data[0U], buffer, length);
}
slunkcrypt_thrdpl_await(state->thread_pool);
}
CHECK_ABORTED();
return SLUNKCRYPT_SUCCESS;
aborted:
slunkcrypt_thrdpl_await(state->thread_pool);
slunkcrypt_bzero(buffer, length);
slunkcrypt_bzero(&state->data, sizeof(crypt_data_t));
return SLUNKCRYPT_ABORTED;
}
@ -401,7 +395,10 @@ void slunkcrypt_free(const slunkcrypt_t context)
crypt_state_t *const state = (crypt_state_t*) context;
if (state)
{
slunkcrypt_thrdpl_destroy(state->thread_pool);
if (state->thread_pool != THRDPL_NULL)
{
slunkcrypt_thrdpl_destroy(state->thread_pool);
}
slunkcrypt_bzero(state, sizeof(crypt_state_t));
free(state);
}

View File

@ -3,21 +3,23 @@
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
#if defined(_MSC_VER) && !defined(_DLL)
#define PTW32_STATIC_LIB 1
#endif
/* Internal */
#include "slunkcrypt.h"
#include "thread.h"
#include "slunkcrypt.h"
#include "compiler.h"
/* CRT */
#include <stdlib.h>
/* PThread */
#if defined(_MSC_VER) && !defined(_DLL)
# define PTW32_STATIC_LIB 1
#endif
#include <pthread.h>
/* System info */
#ifdef __unix__
#include <sys/sysinfo.h>
# include <sys/sysinfo.h>
#endif
/* States */
@ -34,8 +36,7 @@ typedef struct
thrdpl_worker_t worker;
void *context;
size_t length;
const uint8_t *input;
uint8_t *output;
uint8_t *buffer;
}
thrdpl_task_t;
@ -58,15 +59,13 @@ typedef struct
thrdpl_data_t;
// ==========================================================================
// Helper macros
// Utilities
// ==========================================================================
#define BOUND(MIN, VAL, MAX) \
{ \
if ((VAL) > (MAX)) { VAL = (MAX); } \
if ((VAL) < (MIN)) { VAL = (MIN); } \
} \
while (0)
static INLINE size_t bound(const size_t min, const size_t value, const size_t max)
{
return (value < min) ? min : ((value > max) ? max : value);
}
#define PTHRD_MUTEX_LOCK(X) do \
{ \
@ -140,7 +139,7 @@ static void *worker_thread_main(void *const arg)
task = &data->task;
PTHRD_MUTEX_UNLOCK(&data->mutex);
task->worker(*data->count, task->context, task->input, task->output, task->length);
task->worker(*data->count, task->context, task->buffer, task->length);
PTHRD_MUTEX_LOCK(&data->mutex);
CHECK_IF_CANCELLED();
@ -151,19 +150,19 @@ static void *worker_thread_main(void *const arg)
}
// ==========================================================================
// Manage threads
// System info
// ==========================================================================
#if defined(__unix__)
# define GET_NPROCS_FUNCTION() get_nprocs()
# define NUM_PROCESSORS_FUNC get_nprocs
#elif defined(PTW32_VERSION)
# define GET_NPROCS_FUNCTION() pthread_num_processors_np()
# define NUM_PROCESSORS_FUNC pthread_num_processors_np
#endif
static size_t detect_cpu_count(void)
{
#ifdef GET_NPROCS_FUNCTION
const int cpu_count = GET_NPROCS_FUNCTION();
#ifdef NUM_PROCESSORS_FUNC
const int cpu_count = NUM_PROCESSORS_FUNC();
if (cpu_count > 0)
{
return (size_t) cpu_count;
@ -172,6 +171,10 @@ static size_t detect_cpu_count(void)
return 1U;
}
// ==========================================================================
// Manage threads
// ==========================================================================
static int create_worker_thread(thrdpl_thread_t *const thread_data, const size_t *const count)
{
thread_data->count = count;
@ -221,14 +224,19 @@ thrdpl_t slunkcrypt_thrdpl_create(const size_t count)
size_t i, j;
thrdpl_data_t *pool = NULL;
if (!(pool = (thrdpl_data_t*) malloc(sizeof(thrdpl_data_t))))
const size_t cpu_count = bound(1U, (count > 0U) ? count : detect_cpu_count(), MAX_THREADS);
if (cpu_count < 2U)
{
return THRDPL_NULL;
}
if (!(pool = (thrdpl_data_t*)malloc(sizeof(thrdpl_data_t))))
{
return THRDPL_NULL;
}
slunkcrypt_bzero(pool, sizeof(thrdpl_data_t));
pool->thread_count = (count > 0U) ? count : detect_cpu_count();
BOUND(MIN_THREADS, pool->thread_count, MAX_THREADS);
pool->thread_count = cpu_count;
for (i = 0U; i < pool->thread_count; ++i)
{
@ -255,7 +263,7 @@ size_t slunkcrypt_thrdpl_count(const thrdpl_t thrdpl)
return pool->thread_count;
}
void slunkcrypt_thrdpl_exec(const thrdpl_t thrdpl, const size_t index, const thrdpl_worker_t worker, void *const context, const uint8_t *const input, uint8_t *const output, const size_t length)
void slunkcrypt_thrdpl_exec(const thrdpl_t thrdpl, const size_t index, const thrdpl_worker_t worker, void *const context, uint8_t *const buffer, const size_t length)
{
thrdpl_data_t *const pool = (thrdpl_data_t*) thrdpl;
thrdpl_thread_t *const thread = &pool->thread_data[index];
@ -277,8 +285,7 @@ void slunkcrypt_thrdpl_exec(const thrdpl_t thrdpl, const size_t index, const thr
thread->task.worker = worker;
thread->task.context = context;
thread->task.input = input;
thread->task.output = output;
thread->task.buffer = buffer;
thread->task.length = length;
thread->state = THRD_STATE_WORK;

View File

@ -9,16 +9,15 @@
#include <stdlib.h>
#include <stdint.h>
#define MIN_THREADS 1U
#define MAX_THREADS 16U
#define THRDPL_NULL ((thrdpl_t)NULL)
typedef void (*thrdpl_worker_t)(const size_t thread_count, void *const context, const uint8_t *const input, uint8_t *const output, const size_t length);
typedef void (*thrdpl_worker_t)(const size_t thread_count, void *const context, uint8_t *const buffer, const size_t length);
typedef uintptr_t thrdpl_t;
thrdpl_t slunkcrypt_thrdpl_create(const size_t count);
size_t slunkcrypt_thrdpl_count(const thrdpl_t thrdpl);
void slunkcrypt_thrdpl_exec(const thrdpl_t thrdpl, const size_t index, const thrdpl_worker_t worker, void *const context, const uint8_t *const input, uint8_t *const output, const size_t length);
void slunkcrypt_thrdpl_exec(const thrdpl_t thrdpl, const size_t index, const thrdpl_worker_t worker, void *const context, uint8_t *const buffer, const size_t length);
void slunkcrypt_thrdpl_await(const thrdpl_t thrdpl);
void slunkcrypt_thrdpl_destroy(const thrdpl_t thrdpl);