OSDN Git Service

GUI: Added new background pattern.
[slunkcrypt/SlunkCrypt.git] / README.md
1 ---
2 title: "![SlunkCrypt](etc/img/SlunkCrypt-Logo.png)"
3 ---
4
5
6 Introduction
7 ============
8
9 SlunkCrypt is an experimental cross-platform cryptography library and command-line tool. A fully-featured GUI is provided for the Windows platform.
10
11 Please refer to the section [*encryption algorithm*](#encryption-algorithm) for more details!
12
13
14 Legal Warning
15 =============
16
17 Use of SlunkCrypt may be illegal in countries where encryption is outlawed. We believe it is legal to use SlunkCrypt in many countries all around the world, but we are not lawyers, and so if in doubt you should seek legal advice before downloading it. You may find useful information at [cryptolaw.org](http://www.cryptolaw.org/), which collects information on cryptography laws in many countries.
18
19
20 System Requirements
21 ===================
22
23 The SlunkCrypt library and the command-line application currently run on the following platforms:
24
25 * **Microsoft Windows** (Windows XP SP-3, or later) — i686, x86-64 and ARM64
26 * **Linux** (kernel version 3.17, or later) — i686, x86-64, ARM64 and MIPS
27 * **Various BSD flavors** (tested on NetBSD 9.2, FreeBSD 13.0 and OpenBSD 7.0) — i686 and x86-64
28 * **Solaris** (tested on Solaris 11.4 and OmniOS/illumos) — i686 and x86-64
29 * **GNU/Hurd** (tested on Debian GNU/Hurd 0.9) — i686
30 * **Haiku** (tested on Haiku R1/b3) — i686 and x86-64
31 * **Mac OS X** (tested on “Big Sur”) — x86-64 and ARM64
32
33 The SlunkCrypt GUI application currently runs on the following platforms:
34
35 * **Microsoft Windows** with .NET Framework 4.7.2 — can be installed on Windows 7 SP1, or later
36
37
38 GUI Usage
39 =========
40
41 This is how the graphical user interface (GUI) for SlunkCrypt looks on [Windows 11](https://i.pinimg.com/736x/0f/57/4c/0f574c445b497cc4748a9e1ab7491582--taps-funny-stuff.jpg):
42
43 ![](etc/img/SlunkCrypt-GUI.jpg)
44
45 Prerequisites
46 -------------
47
48 Please be sure to install the **.NET Framework 4.7.2**, or any later *.NET Framework 4.x* version, before running the SlunkCrypt **Windows GUI** application:  
49 <https://dotnet.microsoft.com/download/dotnet-framework>
50
51 ***Note:*** If you are running Windows 8.1 or later, then almost certainly a suitable version of the .NET Framework is already installed &#128526;
52
53 Settings
54 --------
55
56 The following settings can be adjusted in the `slunkcrypt-gui.exe.config` configuration file:
57
58 - **`DisableBusyIndicator`:**  
59   If set to `true`, the “busy indicator” animation will be *disabled* on application startup &mdash; default value: `false`.
60
61 - **`ThreadCount`:**  
62   Specifies the number of worker threads to use &mdash; default value: `0` (i.e. detect the number of available processors and create one thread for each processor).
63
64 - **`KeepIncompleteFiles`:**  
65   If set to `true`, incomplete or corrupted output files will *not* be deleted &mdash; default value: `false`.
66
67 Command-line Usage
68 ==================
69
70 This section describes the SlunkCypt command-line application.
71
72 Synopsis
73 --------
74
75 The SlunkCypt command-line program is invoked as follows:
76
77     slunkcrypt --encrypt [pass:<pass>|file:<file>] <input.txt> <output.enc>
78     slunkcrypt --decrypt [pass:<pass>|file:<file>] <input.enc> <output.txt>
79     slunkcrypt --make-pw [<length>]
80
81 Commands
82 --------
83
84 One of the following commands **must** be chosen:
85
86 - **`--encrypt` (`-e`):**  
87   Run application in ***encrypt*** mode. Reads the given *plaintext* and generates *ciphertext*.
88 - **`--decrypt` (`-d`):**  
89   Run application in ***decrypt*** mode. Reads the given *ciphertext* and restores *plaintext*.
90 - **`--make-pw` (`-p`):**  
91   Generate a "strong" random passphrase, suitable for use with SlunkCrypt.
92 - **`--self-test` (`-t`):**  
93   Run the application in ***self-test*** mode. Program will exit after all test are completed.
94
95 Options
96 -------
97
98 The following command-line options are available:
99
100 - **`pass:<pass>`**:  
101   * Specifies the "secret" passphrase directly on the command-line. This is considered *insecure*.
102 - **`file:<file>`**:  
103   * Specifies a file to read the passphrase from. Only the *first* line of the file will be read!
104   * *Note:* It is also possible to specify **`-`** in order to read the passphrase from the *stdin*.
105 - **`<input>`**:  
106   * In ***encrypt*** mode &ndash; specifies the *plaintext* file (unencrypted information) that is to be encrypted.
107   * In ***decrypt*** mode &ndash; specifies the *ciphertext* file (result of encryption) that is to be decrypted.
108 - **`<output>`**:  
109   * In ***encrypt*** mode &ndash; specifies the file where the *ciphertext* (result of encryption) will be stored.
110   * In ***decrypt*** mode &ndash; specifies the file where the *plaintext* (unencrypted information) will be stored.
111 - **`<length>`**:  
112   * Specifies the length of the passphrase to be generated. If *not* specified, defaults to 24.
113
114 ### Remarks {.unlisted}
115
116 - The same passphrase must be used for both, ***encrypt*** and ***decrypt*** mode. The decryption of the ciphertext will only be possible, if the "correct" passphrase is known. It is recommended to choose a "random" password that is at least 12 characters in length and consists of a mix of upper-case characters, lower-case characters, digits as well as special characters.
117
118 - Passing the passphrase directly on the command-line is insecure, because the full command-line may be visible to other users!
119
120 Environment
121 -----------
122
123 The following environment variables may be used:
124
125 - **`SLUNK_PASSPHRASE`**:  
126   Specifies the "secret" passphrase. This environment variables is only evaluated, if the passphrase was **not** specified on the command-line.  
127   Passing the passphrase via environment variable is considered more secure, because environment variables are not normally visible to other (unprivileged) users.
128
129 - **`SLUNK_KEEP_INCOMPLETE`**:  
130   If set to a *non-zero* value, incomplete or corrupted output files will **not** be deleted automatically. By default, the files will be deleted.
131
132 - **`SLUNK_THREADS`**:  
133   Specifies the number of worker threads to use. By default, SlunkCrypt detects the number of available processors and creates one thread for each processor.
134
135 - **`SLUNK_LEGACY_COMPAT`**:  
136   If set to a *non-zero* value, enables "legacy" compatibility-mode, required to decrypt files encrypted with SlunkCrypt version 1.2.x or older.
137
138 - **`SLUNK_DEBUG_LOGGING`**:  
139   If set to a *non-zero* value, enables additional logging output to the syslog (Unix-like) or to the debugger (Windows). This is intended for debugging purposes only!
140
141 Examples
142 --------
143
144 Here are some examples on how to use the SlunkCrypt command-line application:
145
146 ### Example #1 {.unlisted}
147
148 1. Let's generate a new random (secure) password first:
149
150        slunkcrypt --make-pw
151
152    *Example output:*
153
154        cdG2=fh<C=3[SSCzf[)iDjIV
155
156 2. Now, encrypt the plaintext message, using the generated password:
157
158        slunkcrypt --encrypt pass:"cdG2=fh<C=3[SSCzf[)iDjIV" plaintext.txt ciphertext.enc
159
160    Optionally, let's have a look at the ciphertext:
161
162        hexdump -C ciphertext.enc
163
164 3. Finally, decrypt the ciphertext, using the same password as before:
165
166        slunkcrypt --decrypt pass:"cdG2=fh<C=3[SSCzf[)iDjIV" ciphertext.enc plaintext.out
167
168    Optionally, verify that the decrypted file is identical to the original:
169
170        sha256sum -b plaintext.txt plaintext.out
171
172 ### Example #2 {.unlisted}
173
174 1. Generate a new password and store it to a text file:
175
176        slunkcrypt --make-pw > passwd.txt
177
178    Optionally, output the generated password to the terminal:
179
180        cat passwd.txt
181
182 2. Encrypt file by reading the password from the text file:
183
184        slunkcrypt --encrypt file:passwd.txt plaintext.txt ciphertext.enc
185
186 ### Example #3 {.unlisted}
187
188 1. Generate a new password directly to an environment variable:
189
190        MY_PASSWD="$(slunkcrypt --make-pw)"
191
192    Optionally, output the generated password to the terminal:
193
194        echo "${MY_PASSWD}"
195
196 2. Encrypt file by reading the password from the *stdin*:
197
198        slunkcrypt --encrypt - plaintext.txt ciphertext.enc <<< "${MY_PASSWD}"
199
200
201 Encryption algorithm
202 ====================
203
204 SlunkCrypt is based on concepts of the well-known [**Enigma**](https://en.wikipedia.org/wiki/Enigma_machine) machine, but with numerous "modern" improvements, largely inspired by [***“A Modern Rotor Machine”***](https://rdcu.be/cBo8y):
205
206 - The original Enigma machine had only *three* (or, in some models, *four*) rotors, plus a static "reflector" wheel. In SlunkCrypt, we uses **256** simulated rotors for an improved security. Furthermore, the original Enigma machine supported only 26 distinct symbols, i.e. the letters `A` to `Z`. In SlunkCrypt, we use **256** distinct symbols, i.e. the byte values `0x00` to `0xFF`, which allows the encryption (and decryption) of arbitrary streams of bytes, rather than just plain text. Of course, SlunkCrypt can encrypt (and decrypt) text files as well.
207
208 - In the original Enigma machine, the signal passes through the rotors *twice*, once in forward direction and then again in backwards direction &ndash; thus the "reflector" wheel. This way, the Enigma's encryption was made *involutory*, i.e. encryption and decryption were the same operation. While this was highly convenient, it also severely weakened the cryptographic strength of the Enigma machine, because the number of possible permutations was reduced drastically! This is one of the main reasons why the Enigma machine eventually was defeated. In SlunkCrypt, the signal passes through the simulated rotors just *once*, in order to maximize the number of possible permutations. This eliminates the most important known weakness of the Enigma machine. Obviously, in SlunkCrypt, separate "modes" for encryption and decryption need to be provided, since encryption and decryption *no* longer are the same operation.
209
210 - In the original Enigma machine, the rightmost rotor was moved, by one step, after every symbol. Meanwhile, all other rotors were moved, by one step, *only* when their right-hand neighbor had completed a full turn &ndash; much like the odometer in a car. The fact that most of the rotors remained in the same "static" position most of the time was an important weakness of the Enigma machine. Also, the sequence of the Enigma's rotor positions started to repeat after only 16,900 characters. SlunkCrypt employs an improved stepping algorithm, based on a ***linear-feedback shift register* (LSFR)**, ensuring that *all* rotors move frequently and in a "randomized" unpredictable pattern. The rotor positions of SlunkCrypt practically *never* repeat.
211
212 - The internal wiring of each of the original Enigma machine's rotors was *fixed*. Each rotor "type" came with a different internal wiring (i.e. permutation). Some models had up to eight rotor "types" to choose from, but only three or four rotors were used at a time. Nonetheless, the internal wiring (i.e. permutation) of each of the supplied rotors was **not** modifiable. This severely restricted the key space of the Enigma machine, as far as the rotors are concerned, because *only* the order of the rotors and the initial position of each rotor could be varied. In SlunkCrypt, a fully *randomized* wiring (i.e. permutation) is generated from the password for each of the 256 simulated rotors. The initial rotor positions are *randomized* as well.
213
214 - SlunkCrypt does **not** currently implement the *plugboard* (“Steckerbrett”) of the original Enigma machine. That is because, even though the plugboard has a large key space, it is just a *fixed* substitution cipher that does *not* contribute much to the cryptographic strength of the Enigma machine. In fact, the plugboard could be "erased" by Welchman's [diagonal board](https://en.wikipedia.org/wiki/Bombe#Stecker_values).
215
216 Details
217 -------
218
219 This section explains some implementation details of the SlunkCrypt library:
220
221 * **DRBG:** The *deterministic random bit generator* (DRBG) employed by SlunkCrypt is called [*Xorwow*](https://en.wikipedia.org/wiki/Xorshift#xorwow), an enhanced variant of *Xorshift* , i.e. a form of *linear-feedback shift registers (LSFR)*.
222
223 * **Initialization (key schedule):** In the initialization phase, the *pseudo-random* internal wiring (i.e. permutation) is generated &ndash; separately for each of the 256 rotors. For this purpose, the initial state of the DRBG is set up in a way that depends on the given *passphrase*, a message-specific *nonce* as well as the current *rotor index*. More specifically, the initial state of the DRBG is derived from a combination of all input parameters, by applying a <u>large</u> number of iterations of the *FNV&#8209;1a 128-Bit* hash function. The permutation for the current rotor is then created by the ***Fisher&#8209;Yates*** shuffle algorithm, using the DRBG as its randomness source. This produces a distinct "randomized" internal rotor wiring for each message to be encrypted. 
224
225 * **Message processing:** During the encryption or decryption process, the individual offsets (positions) of the first 8 rotors are controlled by a 64-Bit counter, whereas the offsets of the remaining 248 rotors are continuously "randomized" by the DRBG. The initial counter value as well as the initial state of the DRBG are set up in a way that depends on the given *passphrase* and a message-specific *nonce*. Also, after each symbol that was processed, the counter is incremented by one and new *pseudo-random* offsets (rotor positions) are drawn.
226
227 * **Checksum:** The message-length is padded to a multiple of 8 bytes and a 64-Bit [BLAKE2s](https://www.blake2.net/) hash is appended, *before* encryption. This "checksum" can be used to detect decryption errors.
228
229
230 Programming Interface (API)
231 ===========================
232
233 This section describes the SlunkCypt library interface for software developers.
234
235 Getting started
236 ---------------
237
238 In order to use the SlunkCypt library in your C++ code, include **`<slunkcrypt.hpp>`** header and instantiate the appropriate SlunkCypt classes:
239
240 ### Example #1 {.unlisted}
241
242 Here is a simple example on how to use the SlunkCrypt [**`Encryptor`**](#encryptor) class:
243
244     #include <slunkcrypt.hpp>
245     #include <fstream>
246     #include <iostream>
247
248     int main()
249     {
250         /* Open input and output files here */
251         uint8_t buffer[BUFF_SIZE];
252         slunkcrypt::Encryptor slunk_encrypt(passphrase);
253         while (input.good())
254         {
255             input.read(reinterpret_cast<char*>(buffer), BUFF_SIZE);
256             if ((!input.bad()) && (input.gcount() > 0))
257             {
258                 if (!slunk_encrypt.inplace(buffer, (size_t)input.gcount()))
259                 {
260                     /* Implement error handling here */
261                 }
262                 output.write(reinterpret_cast<char*>(buffer), count);
263             }
264         }
265         std::cout << std::hex << slunk_encrypt.get_nonce() << std::endl;
266     }
267
268 ### Example #2 {.unlisted}
269
270 Here is a simple example on how to use the SlunkCrypt [**`Decryptor`**](#decryptor) class:
271
272     #include <slunkcrypt.hpp>
273     #include <fstream>
274     #include <iostream>
275
276     int main()
277     {
278         /* Open input and output files here */
279         uint8_t buffer[BUFF_SIZE];
280         slunkcrypt::Decryptor slunk_decrypt(passphrase, nonce);
281         while (input.good())
282         {
283             input.read(reinterpret_cast<char*>(buffer), BUFF_SIZE);
284             if ((!input.bad()) && (input.gcount() > 0))
285             {
286                 if (!slunk_decrypt.inplace(buffer, (size_t)input.gcount()))
287                 {
288                     /* Implement error handling here */
289                 }
290                 output.write(reinterpret_cast<char*>(buffer), count);
291             }
292         }
293     }
294
295 C++11 API
296 ---------
297
298 This section describes the "high-level" C++11 API of the SlunkCrypt library. All SlunkCrypt classes live in the **`slunkcrypt`** namespace.
299
300 ### Encryptor
301
302 Class for *encrypting* data using the SlunkCrypt library.
303
304 #### Constructor
305
306 Create and initialize a new **``Encryptor``** instance. Also generated a new, random nonce.
307
308     Encryptor::Encryptor(
309       const std::string &passwd,
310       const size_t thread_count = 0U,
311       const bool legacy_compat = false,
312       const bool debug_logging = false
313     );
314
315 ***Parameters:***
316
317   * `passwd`  
318     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!
319      
320     *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.
321
322   * `thread_count`  
323     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.
324
325   * `legacy_compat`  
326     Enables "legacy" compatibility-mode; required to encrypt messages in a way that allows decryption with SlunkCrypt version 1.2.x or earlier. Option is disabled by default.
327
328   * `debug_logging`  
329     Enables additional debug logging. Messages are written to the syslog (Unix-like) or to the debugger (Windows). Option is disabled by default.
330
331 ***Exceptions:***
332
333   * Throws `std::runtime_error`, if the nonce could not be generated, or if the SlunkCrypt context could not be allocated.
334
335 #### Encryptor::process() [1]
336
337 Encrypt the next message chunk, using separate input/output buffers.
338
339     bool process(
340       const uint8_t *const input,
341       uint8_t *const output,
342       size_t length
343     );
344
345 ***Parameters:***
346
347  * `input`  
348     A pointer to the *input* buffer containing the next chunk of the plaintext to be encrypted. The plaintext is given as a byte array (`uint8_t`). This can be arbitrary binary data, e.g. UTF-8 encoded text. NULL bytes are **not** treated specially.
349     
350     The *input* buffer must contain *at least* `length` bytes of data. If the buffer is longer than `length` bytes, then only the first `length` bytes will be processed and the remainder is ignored!
351
352  * `output`  
353     A pointer to the *output* buffer where the ciphertext chunk that corresponds to the given plaintext chunk will be stored. The ciphertext is stored as a byte array (`uint8_t`); it has the same length as the plaintext data.
354     
355     The *output* buffer must provide sufficient space for storing *at least* `length` bytes of encrypted data. If the buffer is longer than `length` bytes, then only the first `length` bytes of the buffer will be filled with encrypted data!
356
357  * `length`  
358    The length of the plaintext chunk contained in the *input* buffer given by the `input` parameter, in bytes. At the same time, this determines the minimum required size of the *output* buffer given by the `output` parameters, in bytes.
359
360    *Note:* It is recommended to process chunks of at least &sim;64 KB each, in order to take full advantage of multi-threading.
361
362 ***Return value:***
363
364   * If successful, `true` is returned; otherwise `false` is returned.
365
366 #### Encryptor::process() [2]
367
368 Encrypt the next message chunk, using separate input/output containers (`std::vector`).
369
370     bool process(
371       const std::vector<uint8_t> &input,
372       std::vector<uint8_t> &output
373     );
374
375 ***Parameters:***
376
377  * `input`  
378     A reference to the `std::vector<uint8_t>` instance containing the next chunk of the plaintext to be encrypted. This can be arbitrary binary data, e.g. UTF-8 encoded text. NULL bytes are **not** treated specially.
379
380  * `output`  
381     A reference to the `std::vector<uint8_t>` instance where the ciphertext that corresponds to the given plaintext will be stored.
382     
383     The `output.size()` must be *greater than or equal* to `input.size()`. If the `output.size()` is larger than the `input.size()`, then only the first `input.size()` elements of `output` will be filled with encrypted data!
384
385 ***Return value:***
386
387   * If successful, `true` is returned; otherwise `false` is returned. The function fails, if the *output* `std::vector` is too small.
388
389 #### Encryptor::inplace() [1]
390
391 Encrypt the next message chunk, using a single buffer.
392
393     bool inplace(
394       uint8_t *const buffer,
395       size_t length
396     );
397
398 ***Parameters:***
399
400  * `buffer`  
401     A pointer to the buffer initially containing the next chunk of the plaintext to be encrypted. The plaintext is given as a byte array (`uint8_t`). This can be arbitrary binary data, e.g. UTF-8 encoded text. NULL bytes are **not** treated specially. The ciphertext chunk that corresponds to the given plaintext chunk will be stored to the *same* buffer, thus replacing the plaintext data.
402     
403     The buffer must initially contain *at least* `length` bytes of input data; the first `length` bytes of the buffer will be overwritten with the encrypted data. If the buffer is longer than `length` bytes, then only the first `length` bytes will be processed and overwritten.
404
405  * `length`  
406    The length of the plaintext chunk initially contained in the input/output buffer given by the `buffer` parameter, in bytes. At the same time, this determines the portion of the input/output buffer that will be overwritten with encrypted data, in bytes.
407
408    *Note:* It is recommended to process chunks of at least &sim;64 KB each, in order to take full advantage of multi-threading.
409
410 ***Return value:***
411
412   * If successful, `true` is returned; otherwise `false` is returned.
413
414 #### Encryptor::inplace() [2]
415
416 Encrypt the next message chunk, using a single container (`std::vector`).
417
418     bool inplace(
419       std::vector<uint8_t> &buffer
420     );
421
422 ***Parameters:***
423
424  * `buffer`  
425     A reference to the `std::vector<uint8_t>` initially containing the next chunk of the plaintext to be encrypted. This can be arbitrary binary data, e.g. UTF-8 encoded text. NULL bytes are **not** treated specially. The ciphertext chunk that corresponds to the given plaintext chunk will be stored to the *same* `std::vector<uint8_t>`, thus replacing all the plaintext data.
426
427 ***Return value:***
428
429   * If successful, `true` is returned; otherwise `false` is returned.
430
431 #### Encryptor::get_nonce()
432
433 Retrieve the random nonce that is used to encrypt the message.
434
435     uint64_t get_nonce();
436
437 ***Return value:***
438
439   * Returns the nonce that is used to encrypt the message. 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.
440     
441     *Note:* The `Encryptor` class automatically generates a new, random nonce for each message to be encrypted. Use *this* function to retrieve that nonce, so that it can be passed to `Decryptor` for decryption later.
442
443 ### Decryptor
444
445 Class for *decrypting* data using the SlunkCrypt library.
446
447 #### Constructor
448
449 Create and initialize a new **``Decryptor``** instance.
450
451     Decryptor::Decryptor(
452       const std::string &passwd,
453       const uint64_t nonce,
454       const size_t thread_count = 0U,
455       const bool legacy_compat = false,
456       const bool debug_logging = false
457     );
458
459 ***Parameters:***
460
461   * `passwd`  
462     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!
463     
464     *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.
465
466   * `nonce`  
467     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.
468     
469     *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.
470
471   * `thread_count`  
472     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.
473
474   * `legacy_compat`  
475     Enables "legacy" compatibility-mode; required to decrypt messages that were encrypted with SlunkCrypt version 1.2.x or earlier. Option is disabled by default.
476
477   * `debug_logging`  
478     Enables additional debug logging. Messages are written to the syslog (Unix-like) or to the debugger (Windows). Option is disabled by default.
479
480 ***Exceptions:***
481
482   * Throws `std::runtime_error`, if the SlunkCrypt context could not be allocated.
483
484 #### Decryptor::process() [1]
485
486 Decrypt the next message chunk, using separate input/output buffers.
487
488     bool process(
489       const uint8_t *const input,
490       uint8_t *const output,
491       size_t length
492     );
493
494 ***Parameters:***
495
496  * `input`  
497     A pointer to the *input* buffer containing the next chunk of the ciphertext to be decrypted. The ciphertext is given as a byte array (`uint8_t`).
498     
499     The *input* buffer must contain *at least* `length` bytes of data. If the buffer is longer than `length` bytes, then only the first `length` bytes will be processed and the remainder is ignored!
500
501  * `output`  
502     A pointer to the *output* buffer where the plaintext chunk that corresponds to the given ciphertext chunk will be stored. The plaintext is stored as a byte array (`uint8_t`); it has the same length as the ciphertext data.
503     
504     The *output* buffer must provide sufficient space for storing *at least* `length` bytes of decrypted data. If the buffer is longer than `length` bytes, then only the first `length` bytes of the buffer will be filled with decrypted data!
505
506  * `length`  
507    The length of the ciphertext chunk contained in the *input* buffer given by the `input` parameter, in bytes. At the same time, this determines the minimum required size of the *output* buffer given by the `output` parameters, in bytes.
508
509    *Note:* It is recommended to process chunks of at least &sim;64 KB each, in order to take full advantage of multi-threading.
510
511 ***Return value:***
512
513   * If successful, `true` is returned; otherwise `false` is returned.
514
515 #### Decryptor::process() [2]
516
517 Decrypt the next message chunk, using separate input/output containers (`std::vector`).
518
519     bool process(
520       const std::vector<uint8_t> &input,
521       std::vector<uint8_t> &output
522     );
523
524 ***Parameters:***
525
526  * `input`  
527     A reference to the `std::vector<uint8_t>` instance containing the next chunk of the ciphertext to be decrypted.
528
529  * `output`  
530     A reference to the `std::vector<uint8_t>` instance where the plaintext that corresponds to the given ciphertext will be stored.
531     
532     The `output.size()` must be *greater than or equal* to `input.size()`. If the `output.size()` is greater than the `input.size()`, then only the first `input.size()` elements of `output` will be filled with decrypted data!
533
534 ***Return value:***
535
536   * If successful, `true` is returned; otherwise `false` is returned. The function fails, if the *output* `std::vector` is too small.
537
538 #### Decryptor::inplace() [1]
539
540 Decrypt the next message chunk, using a single buffer.
541
542     bool inplace(
543       uint8_t *const buffer,
544       size_t length
545     );
546
547 ***Parameters:***
548
549  * `buffer`  
550     A pointer to the buffer initially containing the next chunk of the ciphertext to be decrypted. The ciphertext is given as a byte array (`uint8_t`). The plaintext that corresponds to the given ciphertext will be stored to the *same* buffer, replacing the plaintext data.
551     
552     The buffer must initially contain *at least* `length` bytes of input data; the first `length` bytes of the buffer will be overwritten with the encrypted data. If the buffer is longer than `length` bytes, then only the first `length` bytes will be processed and overwritten.
553
554  * `length`  
555    The length of the ciphertext chunk initially contained in the input/output buffer given by the `buffer` parameter, in bytes. At the same time, this determines the portion of the input/output buffer that will be overwritten with decrypted data, in bytes.
556
557    *Note:* It is recommended to process chunks of at least &sim;64 KB each, in order to take full advantage of multi-threading.
558
559 ***Return value:***
560
561   * If successful, `true` is returned; otherwise `false` is returned.
562
563 #### Decryptor::inplace() [2]
564
565 Decrypt the next message chunk, using a single container (`std::vector`).
566
567     bool inplace(
568       std::vector<uint8_t> &buffer
569     );
570
571 ***Parameters:***
572
573  * `buffer`  
574     A reference to the `std::vector<uint8_t>` initially containing the next chunk of the ciphertext to be decrypted. The plaintext that corresponds to the given ciphertext will be stored to the *same* `std::vector<uint8_t>`, replacing all the ciphertext data.
575
576 ***Return value:***
577
578   * If successful, `true` is returned; otherwise `false` is returned.
579
580 C99 API
581 -------
582
583 This section describes the "low-level" C99 API of the SlunkCypt library.
584
585 ### Functions
586
587 The SlunkCypt library defines the following functions:
588
589 #### slunkcrypt_alloc()
590
591 Allocate and initialize a new SlunkCrypt encryption/decryption context.
592
593     slunkcrypt_t slunkcrypt_alloc(
594         const uint64_t nonce,
595         const uint8_t *const passwd,
596         const size_t passwd_len,
597         const int mode
598     );
599
600 ***Parameters:***
601
602   * `nonce`  
603     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.
604     
605     *Note:* It is recommended to generate a random nonce via the [`slunkcrypt_generate_nonce()`](#slunkcrypt_generate_nonce) function for each message!
606   
607   * `passwd`  
608     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!
609     
610     *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.
611   
612   * `passwd_len`  
613     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.
614
615   * `mode`  
616     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*.
617
618 ***Return value:***
619
620   * If successful, a handle to the new SlunkCrypt context is return; otherwise `SLUNKCRYPT_NULL` is returned.
621     
622     *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!
623
624 #### slunkcrypt_alloc_ext()
625
626 Allocate and initialize a new SlunkCrypt encryption/decryption context with additional parameters.
627
628     slunkcrypt_t slunkcrypt_alloc_ext(
629         const uint64_t nonce,
630         const uint8_t *const passwd,
631         const size_t passwd_len,
632         const int mode,
633         const slunkparam_t *const param
634     );
635
636 ***Parameters:***
637
638   * `nonce`  
639     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.
640     
641     *Note:* It is recommended to generate a random nonce via the [`slunkcrypt_generate_nonce()`](#slunkcrypt_generate_nonce) function for each message!
642   
643   * `passwd`  
644     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!
645     
646     *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.
647   
648   * `passwd_len`  
649     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.
650
651   * `mode`  
652     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*.
653
654   * `param`  
655     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.
656
657 ***Return value:***
658
659   * If successful, a handle to the new SlunkCrypt context is return; otherwise `SLUNKCRYPT_NULL` is returned.
660     
661     *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!
662
663 #### slunkcrypt_reset()
664   
665 Re-initialize an existing SlunkCrypt encryption/decryption context.
666
667     int slunkcrypt_reset(
668         const slunkcrypt_t context,
669         const uint64_t nonce,
670         const uint8_t *const passwd,
671         const size_t passwd_len,
672         const int mode
673     );
674
675 ***Parameters:***
676
677   * `context`  
678     The existing SlunkCrypt context to be re-initialized. This must be a valid handle that was returned by a previous invocation of the [`slunkcrypt_alloc()`](#slunkcrypt_alloc) function.
679
680   * *other parameters*:  
681     Please refer to the [`slunkcrypt_alloc()`](#slunkcrypt_alloc) function for details!
682
683 ***Return value:***
684
685   * If successful, `SLUNKCRYPT_SUCCESS` is returned; otherwise `SLUNKCRYPT_FAILURE` or `SLUNKCRYPT_ABORTED` is returned.
686
687 #### slunkcrypt_free()
688
689 De-allocate an existing SlunkCrypt encryption/decryption context. This will "clear" and release any memory occupied by the context.
690
691     void slunkcrypt_free(
692         const slunkcrypt_t context
693     );
694
695 ***Parameters:***
696
697  * `context`  
698     The existing SlunkCrypt context to be de-allocated. This must be a valid handle that was returned by a previous invocation of the [`slunkcrypt_alloc()`](#slunkcrypt_alloc) function.
699     
700     *Note:* Once a handle has been passed to this function, that handle is *invalidated* and **must not** be used again!
701
702 #### slunkcrypt_generate_nonce()
703
704 Generate a new random *nonce* (number used once), using the system's "cryptographically secure" entropy source.
705
706     int slunkcrypt_generate_nonce(
707       int64_t *const nonce
708     );
709
710 ***Parameters:***
711
712  * `nonce`  
713    A pointer to a variable of type `int64_t` that receives the new random nonce.
714
715 ***Return value:***
716
717   * If successful, `SLUNKCRYPT_SUCCESS` is returned; otherwise `SLUNKCRYPT_FAILURE` or `SLUNKCRYPT_ABORTED` is returned.
718
719 #### slunkcrypt_process()
720
721 Encrypt or decrypt the next message chunk, using separate input/output buffers.
722
723     int slunkcrypt_process(
724         const slunkcrypt_t context,
725         const uint8_t *const input,
726         uint8_t *const output,
727         size_t length
728     );
729
730 ***Parameters:***
731
732  * `context`  
733     The existing SlunkCrypt context to be used for processing the message chunk. This context will be updated.
734
735     *Note:* This function operates either in "encryption" mode or in "decryption" mode, depending on how the given SlunkCrypt context has been [initialized](#slunkcrypt_alloc) or [re-initialized](#slunkcrypt_reset).
736
737  * `input`  
738     A pointer to the *input* buffer containing the next chunk of the plaintext to be encrypted (*encryption* mode), or the next chunk of the ciphertext to be decrypted (*decryption* mode). The input data is given as a byte array (`uint8_t`). This can be arbitrary binary data, e.g. UTF-8 encoded text. NULL bytes are **not** treated specially by this function.
739     
740     The *input* buffer must contain *at least* `length` bytes of data. If the buffer is longer than `length` bytes, then only the first `length` bytes will be processed; the remainder is ignored!
741
742  * `output`  
743     A pointer to the *output* buffer where the ciphertext that corresponds to the given plaintext chunk (*encryption* mode), or the plaintext that corresponds to the given ciphertext chunk (*decryption* mode) will be stored. The output data is stored as a byte array (`uint8_t`) and it always has the same length as the input data.
744     
745     The *output* buffer **must** provide sufficient space for storing *at least* `length` bytes. If the buffer is longer than `length` bytes, then only the first `length` bytes will be filled!
746
747  * `length`  
748    The length of the given plaintext chunk (*encryption* mode), or the length of the given ciphertext chunk (*decryption* mode) in the `input` buffer, in bytes. At the same time, this parameter determines the minimum required size of the `output` buffer, in bytes. If this parameter is set to *zero*, the function does nothing; this is *not* considered an error.
749
750    *Note:* It is recommended to process chunks of at least &sim;64 KB each, in order to take full advantage of multi-threading.
751
752 ***Return value:***
753
754   * If successful, `SLUNKCRYPT_SUCCESS` is returned; otherwise `SLUNKCRYPT_FAILURE` or `SLUNKCRYPT_ABORTED` is returned.
755
756 #### slunkcrypt_inplace()
757
758 Encrypt or decrypt the next message chunk, using a *single* input/output buffer.
759
760     int slunkcrypt_inplace(
761         const slunkcrypt_t context,
762         uint8_t *const buffer,
763         size_t length
764     );
765
766 ***Parameters:***
767
768  * `context`  
769     The existing SlunkCrypt context to be used for processing the message chunk. This context will be updated.
770
771     *Note:* This function operates either in "encryption" mode or in "decryption" mode, depending on how the given SlunkCrypt context has been [initialized](#slunkcrypt_alloc) or [re-initialized](#slunkcrypt_reset).
772
773  * `buffer`  
774     A pointer to the buffer containing the next chunk of the plaintext to be encrypted (*encryption* mode), or the next chunk of the ciphertext to be decrypted (*decryption* mode). The input data is given as a byte array (`uint8_t`). This can be arbitrary binary data, e.g. UTF-8 encoded text. NULL bytes are **not** treated specially by this function. The ciphertext that corresponds to the given plaintext chunk (*encryption* mode), or the plaintext that corresponds to the given ciphertext chunk (*decryption* mode) will be stored to the ***same*** buffer.
775     
776     The given buffer **must** initially contain *at least* `length` bytes of input data. The first `length` bytes in the buffer will be processed and will be *overwritten* with the corresponding output data. If the buffer is longer than `length` bytes, then only the first `length` bytes in the buffer will be processed; the remainder is ignored!
777
778  * `length`  
779    The length of the plaintext chunk (*encryption* mode), or the length of the ciphertext chunk (*decryption* mode) initially contained in the input/output buffer, in bytes.
780
781    *Note:* It is recommended to process chunks of at least &sim;64 KB each, in order to take full advantage of multi-threading.
782
783 ***Return value:***
784
785   * If successful, `SLUNKCRYPT_SUCCESS` is returned; otherwise `SLUNKCRYPT_FAILURE` or `SLUNKCRYPT_ABORTED` is returned.
786
787 #### slunkcrypt_random_bytes()
788
789 Generate a sequence of random bytes, using the system's "cryptographically secure" entropy source.
790
791     size_t slunkcrypt_random_bytes(
792       uint8_t *const buffer,
793       const size_t length
794     );
795
796 ***Parameters:***
797
798  * `buffer`  
799    A pointer to the *output* buffer where the random bytes will be stored.
800
801    The *output* buffer **must** provide sufficient space for storing *at least* `length` bytes of random data. *At most* the first `length` bytes of the buffer will be filled with random data!
802
803  * `length`  
804    The number of random bytes to be generated. At the same time, this parameter determines the minimum required size of the `output` buffer, in bytes.
805
806 ***Return value:***
807
808   * The number of random bytes that have been generated and that have been stored to the `output` buffer buffer is returned.
809     
810     The number of generated random bytes can be *at most* `length`. Less than `length` random bytes will be generated, if and only if the the system's "cryptographically secure" entropy source could *not* provide the requested number of bytes at this time &ndash; in that case, you can try again later. The number of generated bytes can be as low as **0**.
811
812
813 #### slunkcrypt_bzero()
814
815 Erase the contents of a byte array, by overwriting it with *zero* bytes. Compiler optimizations will **not** remove the erase operation.
816
817     void slunkcrypt_bzero(
818       void *const buffer,
819       const size_t length
820     );
821
822 ***Parameters:***
823
824  * `buffer`  
825    A pointer to the buffer whose content is to be erased.
826
827    The buffer **must** be *at least* `length` bytes in size. If the buffer is longer than `length` bytes, then *only* the first `length` bytes of the buffer will be erased!
828
829  * `length`  
830    The size of the buffer to be erased, in bytes.
831
832 ### Types
833
834 #### SlunkCrypt parameters
835
836 The `slunkparam_t` struct is used to pass additional parameters that will be used for initializing the SlunkCrypt context. It contains the following fields:
837
838 * `version` &ndash; The version of the parameter struct; **must** be set to *`SLUNKCRYPT_PARAM_VERSION`*.
839 * `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 **32**).
840 * `legacy_compat` &ndash; If set to *`SLUNKCRYPT_TRUE`*, enables "legacy" compatibility-mode; required to decrypt messages that were encrypted with SlunkCrypt version 1.2.x or earlier.
841 * `debug_logging` &ndash; If set to *`SLUNKCRYPT_TRUE`*, enables additional debug logging; messages are written to the syslog (Unix-like) or to the debugger (Windows).
842
843 ### Global variables
844
845 The SlunkCypt library defines the following global variables:
846
847 #### Version information
848
849 These variables can be used to determine the version of the SlunkCrypt library at runtime, using the [semantic versioning](https://semver.org/spec/v2.0.0.html) scheme:
850
851 * `const uint16_t SLUNKCRYPT_VERSION_MAJOR` &ndash; The current *major* version.
852 * `const uint16_t SLUNKCRYPT_VERSION_MINOR` &ndash; The current *minor* version.
853 * `const uint16_t SLUNKCRYPT_VERSION_PATCH` &ndash; The current *patch* version.
854 * `const char *SLUNKCRYPT_BUILD` &ndash; The build date and time, as a C string, in the *`"mmm dd yyyy, hh:mm:ss"`* format.
855
856 #### Abort request
857
858 If this flag is set to a non-zero value by the application, any ongoing SlunkCypt library invocation will be aborted as quickly as possible:
859
860 * `volatile int g_slunkcrypt_abort_flag` &ndash; The global abort flag.
861
862   *Note:* Applications may set this flag in their signal handler, e.g. when a `SIGINT` is received, in order to "gracefully" shut down the SlunkCypt library. All long-running library functions will return `SLUNKCRYPT_ABORTED`, if the invocation was interrupted. The application still is responsible for [free](#slunkcrypt_free)'ing any SlunkCypt contexts that it allocated successfully!
863
864 ### Constants
865
866 The SlunkCypt library defines the following constants:
867
868 #### Mode of operation
869
870 The SlunkCypt library supports the following modes of operation:
871
872 * `SLUNKCRYPT_ENCRYPT` &ndash; Run library in *encryption* mode, i.e. consume plaintext and produce ciphertext.
873 * `SLUNKCRYPT_DECRYPT` &ndash; Run library in *decryption* mode, i.e. consume ciphertext and produce plaintext.
874
875 #### Limits
876
877 The following limits are defined for the SlunkCypt library:
878
879 * `SLUNKCRYPT_PWDLEN_MIN` &ndash; The *minimum* required length of a password, currently **8** bytes.
880 * `SLUNKCRYPT_PWDLEN_MAX` &ndash; The *maximum* allowed length of a password, currently **256** bytes.
881
882 #### Error codes
883
884 SlunkCypt library functions that return an error code may return one of the following constants:
885
886 * `SLUNKCRYPT_SUCCESS` &ndash; The operation completed successfully.
887 * `SLUNKCRYPT_FAILURE` &ndash; The operation has failed.
888 * `SLUNKCRYPT_ABORTED` &ndash; The operation was aborted before completion, as requested by the application.
889
890 Thread safety
891 -------------
892
893 The following functions are fully "thread-safe" and thus may safely be called by *any* thread at *any* time ***without*** the need for synchronization:
894
895 * `slunkcrypt_alloc()`
896 * `slunkcrypt_generate_nonce()`
897 * `slunkcrypt_random_bytes()`
898 * `slunkcrypt_bzero()`
899 * `Encryptor::Encryptor()`
900 * `Decryptor::Decryptor()`
901
902 The following functions are "reentrant" and thus may safely be called by *any* thread at *any* time ***without*** the need for synchronization &ndash; provided that each instance of `slunkcrypt_t`, `Encryptor` or `Decryptor` is "owned" by a *single* thread **and** that each instance will *exclusively* be access by its respective "owner" thread:
903
904 * `slunkcrypt_reset()`
905 * `slunkcrypt_free()`
906 * `slunkcrypt_process()`
907 * `slunkcrypt_inplace()`
908 * `Encryptor::process()`
909 * `Encryptor::inplace()`
910 * `Encryptor::get_nonce()`
911 * `Decryptor::process()`
912 * `Decryptor::inplace()`
913
914 ***Note:*** If the same `slunkcrypt_t`, `Encryptor` or `Decryptor` instance needs to be shared across *multiple* threads (i.e. the same instance is accessed by *concurrent* threads), then the application **must** *serialize* any invocation of the above functions on that shared instance, by using a suitable synchronization mechanism! This can be achieved by using a [*mutex*](https://linux.die.net/man/3/pthread_mutex_lock).
915
916
917 Source Code
918 ===========
919
920 The latest SlunkCrypt source code is available from the official Git mirrors at:
921
922 * <https://osdn.net/projects/slunkcrypt/scm/git/SlunkCrypt/>
923 * <https://gitlab.com/lord_mulder/slunkcrypt/>
924 * <https://bitbucket.org/muldersoft/slunkcrypt/>
925 * <https://repo.or.cz/slunkcrypt.git>
926 * <https://punkindrublic.mooo.com:3000/Muldersoft/SlunkCrypt>
927
928
929 Build Instructions
930 ==================
931
932 SlunkCrypt can be built from the sources on Microsoft Windows or any POSIX-compatible platform, using a C-compiler that supports the C99 standard.
933
934 * **Microsoft Windows:**  
935   Project/solution files for [Visual Studio](https://visualstudio.microsoft.com/) are provided. These should work “out of the box” with Visual Studio 2017 or any later version.  
936   Just open the solution, select the “Release” configuration, choose the “x86” or “x64” platform, and finally press `F5`.  
937   Visual Studio also is the only way to build the SlunkCrypt GUI, which is based on Microsoft.NET and Windows Presentation Foundation (WPF).
938
939   Alternatively, SlunkCrypt can built using [Mingw-w64](https://www.mingw-w64.org/) (available via [MSYS2](https://www.msys2.org/)) or even [Cygwin](https://www.cygwin.com/) &ndash; see Linux instructions for details!
940
941 * **Linux:**  
942   Please make sure that the *C compiler* (GCC or Clang) as well as *Make* are installed. Then simply run **`make -B`** from the project's base directory!
943
944   If not already installed, the required build tools can usually be installed via your distribution's package manager.  
945   For example, on Debian-based distributions, the command **`sudo apt install build-essential`** installs all the required build tools at once.
946
947   In order to create a *fully-static* binary of SlunkCrypt that runs on ***any*** Linux distribution from the last decade, you can use [musl libc](https://musl.libc.org/):  
948   `make -B CC=musl-gcc STATIC=1`
949
950 * **BSD and Solaris:**  
951   SlunkCrypt can be built on various BSD flavors and Solaris, but the command **`gmake -B`** needs to be used here, since the native `make` doesn't work!  
952   GNU Make can be installed from the package manager. For example, use **`pkg install gmake`** on FreeBSD or **`pkg_add gmake`** on OpenBSD.
953
954 * **Mac OS X:**  
955   Once you have managed to find a terminal (or even better, connect via SSH), Mac OS X almost works like a proper operating system.  
956   The Xcode command-line tools can be installed with the command **`xcode-select --install`**, if not present yet. Then just type **`make -B`** to build!
957
958   *Hint:* If you want to build with GCC, which produces faster code than Apple's Xcode compiler, you may install it on Mac OS X via [Homebrew](https://formulae.brew.sh/formula/gcc).
959
960
961 License
962 =======
963
964 This work has been released under the **CC0 1.0 Universal** license.
965
966 For details, please refer to:  
967 <https://creativecommons.org/publicdomain/zero/1.0/legalcode>
968
969 Acknowledgement
970 ---------------
971
972 SlunkCrypt incorporates code from the following *third-party* software projects:
973
974 * The "checksum" algorithm used by the SlunkCrypt command-line application was adapted from the **BLAKE2** reference C implementation.  
975   ```
976    BLAKE2 reference source code package - reference C implementations
977    Copyright 2012, Samuel Neves <sneves@dei.uc.pt>.  You may use this under the
978    terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
979    your option.  The terms of these licenses can be found at:
980    - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
981    - OpenSSL license   : https://www.openssl.org/source/license.html
982    - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
983
984    More information about the BLAKE2 hash function can be found at
985    https://blake2.net.
986    ```
987
988 * ***Windows only:*** Builds of SlunkCypt that have multi-threading enabled use the **POSIX Threads for Windows (pthreads4w)** library.  
989   ```
990   Pthreads4w - POSIX Threads for Windows
991   Copyright 1998 John E. Bossom
992   Copyright 1999-2018, Pthreads4w contributors
993
994   Homepage: https://sourceforge.net/projects/pthreads4w/
995  
996   Licensed under the Apache License, Version 2.0 (the "License");
997   you may not use this file except in compliance with the License.
998   You may obtain a copy of the License at
999
1000       http://www.apache.org/licenses/LICENSE-2.0
1001
1002   Unless required by applicable law or agreed to in writing, software
1003   distributed under the License is distributed on an "AS IS" BASIS,
1004   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1005   See the License for the specific language governing permissions and
1006   limitations under the License.
1007   ```
1008
1009
1010 &marker;