diff --git a/README.md b/README.md index 9af46b9..2924d8e 100644 --- a/README.md +++ b/README.md @@ -176,7 +176,7 @@ Here is a simple example on how to use the SlunkCrypt [**`Encryptor`**](#encrypt input.read(reinterpret_cast(buffer), BUFF_SIZE); if ((!input.bad()) && (input.gcount() > 0)) { - if (!slunk_encrypt.encrypt_inplace(buffer, (size_t)input.gcount())) + if (!slunk_encrypt.inplace(buffer, (size_t)input.gcount())) { /* Implement error handling here */ } @@ -204,7 +204,7 @@ Here is a simple example on how to use the SlunkCrypt [**`Decryptor`**](#decrypt input.read(reinterpret_cast(buffer), BUFF_SIZE); if ((!input.bad()) && (input.gcount() > 0)) { - if (!slunk_decrypt.decrypt_inplace(buffer, (size_t)input.gcount())) + if (!slunk_decrypt.inplace(buffer, (size_t)input.gcount())) { /* Implement error handling here */ } @@ -241,13 +241,13 @@ Create and initialize a new **``Encryptor``** instance. Also generated a new, ra * Throws `std::runtime_error`, if the nonce could not be generated, or if the SlunkCrypt context could not be allocated. -#### Encryptor::encrypt() [1] +#### Encryptor::process() [1] Encrypt the next message chunk, using separate input/output buffers. - bool encrypt( - const uint8_t* const input, - uint8_t* const output, + bool process( + const uint8_t *const input, + uint8_t *const output, size_t length ); @@ -270,11 +270,11 @@ Encrypt the next message chunk, using separate input/output buffers. * If successful, `true` is returned; otherwise `false` is returned. -#### Encryptor::encrypt() [2] +#### Encryptor::process() [2] Encrypt the next message chunk, using separate input/output containers (`std::vector`). - bool encrypt( + bool process( const std::vector &input, std::vector &output ); @@ -293,12 +293,12 @@ Encrypt the next message chunk, using separate input/output containers (`std::ve * If successful, `true` is returned; otherwise `false` is returned. The function fails, if the *output* `std::vector` is too small. -#### Encryptor::encrypt_inplace() [1] +#### Encryptor::inplace() [1] Encrypt the next message chunk, using a single buffer. - bool encrypt_inplace( - uint8_t* const buffer, + bool inplace( + uint8_t *const buffer, size_t length ); @@ -316,11 +316,11 @@ Encrypt the next message chunk, using a single buffer. * If successful, `true` is returned; otherwise `false` is returned. -#### Encryptor::encrypt_inplace() [2] +#### Encryptor::inplace() [2] Encrypt the next message chunk, using a single container (`std::vector`). - bool encrypt_inplace( + bool inplace( std::vector &buffer ); @@ -355,7 +355,7 @@ Create and initialize a new **``Decryptor``** instance. Decryptor::Decryptor( const uint64_t nonce, - const std::string& passwd + const std::string &passwd ); ***Parameters:*** @@ -374,13 +374,13 @@ Create and initialize a new **``Decryptor``** instance. * Throws `std::runtime_error`, if the SlunkCrypt context could not be allocated. -#### Decryptor::decrypt() [1] +#### Decryptor::process() [1] Decrypt the next message chunk, using separate input/output buffers. - bool decrypt( - const uint8_t* const input, - uint8_t* const output, + bool process( + const uint8_t *const input, + uint8_t *const output, size_t length ); @@ -403,11 +403,11 @@ Decrypt the next message chunk, using separate input/output buffers. * If successful, `true` is returned; otherwise `false` is returned. -#### Decryptor::decrypt() [2] +#### Decryptor::process() [2] Decrypt the next message chunk, using separate input/output containers (`std::vector`). - bool decrypt( + bool process( const std::vector &input, std::vector &output ); @@ -426,12 +426,12 @@ Decrypt the next message chunk, using separate input/output containers (`std::ve * If successful, `true` is returned; otherwise `false` is returned. The function fails, if the *output* `std::vector` is too small. -#### Decryptor::decrypt_inplace() [1] +#### Decryptor::inplace() [1] Decrypt the next message chunk, using a single buffer. - bool decrypt_inplace( - uint8_t* const buffer, + bool inplace( + uint8_t *const buffer, size_t length ); @@ -449,11 +449,11 @@ Decrypt the next message chunk, using a single buffer. * If successful, `true` is returned; otherwise `false` is returned. -#### Decryptor::decrypt_inplace() [2] +#### Decryptor::inplace() [2] Decrypt the next message chunk, using a single container (`std::vector`). - bool decrypt_inplace( + bool inplace( std::vector &buffer ); @@ -471,14 +471,19 @@ C99 API This section describes the "low-level" C99 API of the SlunkCypt library. -### slunkcrypt_alloc() +### Functions + +The SlunkCypt library defines the following functions: + +#### slunkcrypt_alloc() Allocate and initialize a new SlunkCrypt encryption/decryption context. slunkcrypt_t slunkcrypt_alloc( const uint64_t nonce, const uint8_t *const passwd, - const size_t passwd_len + const size_t passwd_len, + const int mode ); ***Parameters:*** @@ -486,7 +491,7 @@ Allocate and initialize a new SlunkCrypt encryption/decryption context. * `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()` function for each message! + *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! @@ -496,13 +501,16 @@ Allocate and initialize a new SlunkCrypt encryption/decryption context. * `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*. + ***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()` in order to "clear" and de-allocate that 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_reset() +#### slunkcrypt_reset() Re-initialize an existing SlunkCrypt encryption/decryption context. @@ -510,28 +518,23 @@ Re-initialize an existing SlunkCrypt encryption/decryption context. const slunkcrypt_t context, const uint64_t nonce, const uint8_t *const passwd, - const size_t passwd_len + const size_t passwd_len, + const int mode ); ***Parameters:*** * `context` - 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()` function. + 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. - * `nonce` - Please refer to the `slunkcrypt_alloc()` function for details! - - * `passwd` - Please refer to the `slunkcrypt_alloc()` function for details! - - * `passwd_len` - Please refer to the `slunkcrypt_alloc()` function for details! + * *other parameters*: + Please refer to the [`slunkcrypt_alloc()`](#slunkcrypt_alloc) function for details! ***Return value:*** * If successful, `SLUNKCRYPT_SUCCESS` is returned; otherwise `SLUNKCRYPT_FAILURE` or `SLUNKCRYPT_ABORTED` is returned. -### slunkcrypt_free() +#### slunkcrypt_free() De-allocate an existing SlunkCrypt encryption/decryption context. This will "clear" and release any memory occupied by the context. @@ -542,16 +545,16 @@ De-allocate an existing SlunkCrypt encryption/decryption context. This will "cle ***Parameters:*** * `context` - 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()` function. + 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. *Note:* Once a handle has been passed to this function, that handle is *invalidated* and **must not** be used again! -### slunkcrypt_generate_nonce() +#### slunkcrypt_generate_nonce() Generate a new random *nonce* (number used once), using the system's "cryptographically secure" entropy source. int slunkcrypt_generate_nonce( - int64_t* const nonce + int64_t *const nonce ); ***Parameters:*** @@ -563,132 +566,76 @@ Generate a new random *nonce* (number used once), using the system's "cryptograp * If successful, `SLUNKCRYPT_SUCCESS` is returned; otherwise `SLUNKCRYPT_FAILURE` or `SLUNKCRYPT_ABORTED` is returned. -### slunkcrypt_encrypt() +#### slunkcrypt_process() -Encrypt the next message chunk, using separate input/output buffers. +Encrypt or decrypt the next message chunk, using separate input/output buffers. - int slunkcrypt_encrypt( + int slunkcrypt_process( const slunkcrypt_t context, const uint8_t *const input, - uint8_t* const output, + uint8_t *const output, size_t length ); ***Parameters:*** * `context` - The existing SlunkCrypt context to be used for encrypting the message chunk. This context will be updated. + The existing SlunkCrypt context to be used for processing the message chunk. This context will be updated. + + *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). * `input` - 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. + 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. - 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! + 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! * `output` - 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. + 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. - 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! + 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! * `length` - 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. + 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. ***Return value:*** * If successful, `SLUNKCRYPT_SUCCESS` is returned; otherwise `SLUNKCRYPT_FAILURE` or `SLUNKCRYPT_ABORTED` is returned. -### slunkcrypt_encrypt_inplace() +#### slunkcrypt_inplace() -Encrypt the next message chunk, using a single buffer. +Encrypt or decrypt the next message chunk, using a *single* input/output buffer. - int slunkcrypt_encrypt_inplace( + int slunkcrypt_inplace( const slunkcrypt_t context, - uint8_t* const buffer, + uint8_t *const buffer, size_t length ); ***Parameters:*** * `context` - The existing SlunkCrypt context to be used for encrypting the message chunk. This context will be updated. + The existing SlunkCrypt context to be used for processing the message chunk. This context will be updated. + + *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). * `buffer` - 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. + 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. - 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. + 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! * `length` - 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. + 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. ***Return value:*** * If successful, `SLUNKCRYPT_SUCCESS` is returned; otherwise `SLUNKCRYPT_FAILURE` or `SLUNKCRYPT_ABORTED` is returned. -### slunkcrypt_decrypt() - -Decrypt the next ciphertext chunk, using separate input/output buffers. - - int slunkcrypt_decrypt( - const slunkcrypt_t context, - const uint8_t *const input, - uint8_t* const output, - size_t length - ); - -***Parameters:*** - - * `context` - The existing SlunkCrypt context to be used for decrypting the ciphertext chunk. This context will be updated. - - * `input` - 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`). - - 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! - - * `output` - 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 plaintext data. - - 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! - - * `length` - 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. - -***Return value:*** - - * If successful, `SLUNKCRYPT_SUCCESS` is returned; otherwise `SLUNKCRYPT_FAILURE` or `SLUNKCRYPT_ABORTED` is returned. - -### slunkcrypt_decrypt_inplace() - -Decrypt the next ciphertext chunk, using a single buffer. - - int slunkcrypt_decrypt_inplace( - const slunkcrypt_t context, - uint8_t* const buffer, - size_t length - ); - -***Parameters:*** - - * `context` - The existing SlunkCrypt context to be used for decrypting the ciphertext chunk. This context will be updated. - - * `buffer` - 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, thus replacing the plaintext data. - - The buffer must initially contain *at least* `length` bytes of input data; the first `length` bytes of the buffer will be overwritten with the decrypted data. If the buffer is longer than `length` bytes, then only the first `length` bytes will be processed and overwritten. - - * `length` - 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. - -***Return value:*** - - * If successful, `SLUNKCRYPT_SUCCESS` is returned; otherwise `SLUNKCRYPT_FAILURE` or `SLUNKCRYPT_ABORTED` is returned. - -### slunkcrypt_random_bytes() +#### slunkcrypt_random_bytes() Generate a sequence of random bytes, using the system's "cryptographically secure" entropy source. size_t slunkcrypt_random_bytes( - uint8_t* const buffer, + uint8_t *const buffer, const size_t length ); @@ -697,24 +644,24 @@ Generate a sequence of random bytes, using the system's "cryptographically secur * `buffer` A pointer to the *output* buffer where the random bytes will be stored. - The *output* buffer must provide sufficient space for storing *at least* `length` bytes of random data. If the buffer is longer than `length` bytes, then *at most* the first `length` bytes of the buffer will be filled with random data! + 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! * `length` - The number of random bytes to be generated. At the same time, this determines the minimum required size of the *output* buffer given by the `output` parameters, in bytes. + 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. ***Return value:*** - * If successful, the number of random bytes that have been generated and stored to the *output* buffer is returned; otherwise `0` is returned. + * The number of random bytes that have been generated and that have been stored to the `output` buffer buffer is returned. - The number of generated bytes can be *at most* `length`. Less than `length` bytes *may* be generated, if the entropy source could **not** provide the requested number of bytes at this time. In that case, you can try again. + 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 – in that case, you can try again later. The number of generated bytes can be as low as **0**. -### slunkcrypt_bzero() +#### slunkcrypt_bzero() Erase the contents of a byte array, by overwriting it with *zero* bytes. Compiler optimizations will **not** remove the erase operation. void slunkcrypt_bzero( - void* const buffer, + void *const buffer, const size_t length ); @@ -723,35 +670,81 @@ Erase the contents of a byte array, by overwriting it with *zero* bytes. Compile * `buffer` A pointer to the buffer whose content is to be erased. - 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; the remainder of the buffer will *not* be modified! + 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! * `length` The size of the buffer to be erased, in bytes. +### Global variables + +The SlunkCypt library defines the following global variables: + +#### Version information + +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: + +* `const uint16_t SLUNKCRYPT_VERSION_MAJOR` – The current *major* version. +* `const uint16_t SLUNKCRYPT_VERSION_MINOR` – The current *minor* version. +* `const uint16_t SLUNKCRYPT_VERSION_PATCH` – The current *patch* version. +* `const char *SLUNKCRYPT_BUILD` – The build date and time, as a C string, in the *"mmm dd yyyy hh:mm:ss"* format. + +#### Abort request + +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: + +* `volatile int g_slunkcrypt_abort_flag` – The global abort flag. + + *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! + +### Constants + +The SlunkCypt library defines the following constants: + +#### Mode of operation + +The SlunkCypt library supports the following modes of operation: + +* `SLUNKCRYPT_ENCRYPT` – Run library in *encryption* mode, i.e. consume plaintext and produce ciphertext. +* `SLUNKCRYPT_DECRYPT` – Run library in *decryption* mode, i.e. consume ciphertext and produce plaintext. + +#### Limits + +The following limits are defined for the SlunkCypt library: + +* `SLUNKCRYPT_PWDLEN_MIN` – The *minimum* required length of a password, currently **8** bytes. +* `SLUNKCRYPT_PWDLEN_MAX` – The *maximum* allowed length of a password, currently **256** bytes. + +#### Error codes + +SlunkCypt library functions that return an error code may return one of the following constants: + +* `SLUNKCRYPT_SUCCESS` – The operation completed successfully. +* `SLUNKCRYPT_FAILURE` – The operation has failed. +* `SLUNKCRYPT_ABORTED` – The operation was aborted before completion, as requested by the application. + Thread safety ------------- The following functions are fully "thread-safe" and thus may safely be called by *any* thread at *any* time ***without*** the need for synchronization: * `slunkcrypt_alloc()` +* `slunkcrypt_generate_nonce()` * `slunkcrypt_random_bytes()` * `slunkcrypt_bzero()` * `Encryptor::Encryptor()` * `Decryptor::Decryptor()` -The following functions are "reentrant" and thus may safely be called by *any* thread at *any* time ***without*** the need for synchronization – provided that each instance of `slunkcrypt_t`, `Encryptor` or `Decryptor` is "owned" by a *single* thread **and** each instance will *exclusively* be access by its respective "owner" thread: +The following functions are "reentrant" and thus may safely be called by *any* thread at *any* time ***without*** the need for synchronization – 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: * `slunkcrypt_reset()` * `slunkcrypt_free()` -* `slunkcrypt_encrypt()` -* `slunkcrypt_encrypt_inplace()` -* `slunkcrypt_decrypt()` -* `slunkcrypt_decrypt_inplace()` -* `Encryptor::encrypt()` -* `Encryptor::encrypt_inplace()` +* `slunkcrypt_process()` +* `slunkcrypt_inplace()` +* `Encryptor::process()` +* `Encryptor::inplace()` * `Encryptor::get_nonce()` -* `Decryptor::decrypt()` -* `Decryptor::decrypt_inplace()` +* `Decryptor::process()` +* `Decryptor::inplace()` ***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). diff --git a/etc/style/gh-pandoc.min.css b/etc/style/gh-pandoc.min.css index 3e5a0e3..0f22b9c 100644 --- a/etc/style/gh-pandoc.min.css +++ b/etc/style/gh-pandoc.min.css @@ -1 +1 @@ -html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.caption{margin-bottom:5em}*{box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:10pt;line-height:1.6;margin:auto;max-width:1184px;min-width:360px;padding:2rem;word-wrap:break-word}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25;margin-bottom:16px;margin-top:24px}h1{padding-bottom:.3em;font-size:2em;border-bottom:1px solid #eee}h2{padding-bottom:.3em;font-size:1.5em;border-bottom:1px solid #eee}h3{font-size:1.25em}h4{font-size:1em}h5{font-size:.875em}h6{font-size:.85em;color:#777}h1 tt,h1 code,h2 tt,h2 code,h3 tt,h3 code,h4 tt,h4 code,h5 tt,h5 code,h6 tt,h6 code{font-size:inherit}body>h2:first-child{margin-top:0;padding-top:0}body>h1:first-child{margin-top:0;padding-top:0}body>h1:first-child+h2{margin-top:0;padding-top:0}body>h3:first-child,body>h4:first-child,body>h5:first-child,body>h6:first-child{margin-top:0;padding-top:0}a:first-child h1,a:first-child h2,a:first-child h3,a:first-child h4,a:first-child h5,a:first-child h6{margin-top:0;padding-top:0}a{color:#4078c0;text-decoration:none}a:active,a:hover{outline:0;text-decoration:underline}sup,sub,a.footnote{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}ol,ul{margin-bottom:16px;margin-top:0;padding-left:2em}p,blockquote,table,pre{margin:15px 0}ul,ol{padding-left:2em}ul.no-list,ol.no-list{padding:0;list-style-type:none}ul ul,ul ol,ol ol,ol ul{margin-top:0;margin-bottom:0}li>p{margin-top:16px}li+li{margin-top:.25em}ol li ul:first-of-type{margin-top:0}hr{background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC) repeat-x 0 0;border:0 none;color:#ccc;height:4px;margin:16px 0;padding:0}h1+p,h2+p,h3+p,h4+p,h5+p,h6+p,ul li>:first-child,ol li>:first-child{margin-top:0}dl{padding:0}dl dt{font-size:1em;font-weight:bold;font-style:italic;padding:0;margin:15px 0 5px}dl dt:first-child{padding:0}dl dt>:first-child{margin-top:0}dl dt>:last-child{margin-bottom:0}dl dd{margin:0 0 15px;padding:0 15px}dl dd>:first-child{margin-top:0}dl dd>:last-child{margin-bottom:0}blockquote{border-left:4px solid #DDD;padding:0 15px;color:#777}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}table{border-collapse:collapse;border-spacing:0;font-size:100%;font:inherit}table th{font-weight:bold;border:1px solid #ccc;padding:6px 13px}table td{border:1px solid #ccc;padding:6px 13px}table td>p:first-child{margin-top:0}table td>p:last-child{margin-bottom:0}table tr{border-top:1px solid #ccc;background-color:#fff}table tr:nth-child(2n){background-color:#f8f8f8}img{max-width:100%}code,tt{padding:0;padding-top:.2em;padding-bottom:.2em;margin:0;font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:10pt;background-color:rgba(0,0,0,0.04);border-radius:3px}pre>code{margin:0;padding:0;white-space:pre;border:0;background:transparent}pre{padding:16px;margin-top:0;margin-bottom:0;background-color:#f8f8f8;font-size:10pt;line-height:19px;overflow:auto;border-radius:3px}pre code,pre tt{background-color:transparent;border:0}code::before,code::after,tt::before,tt::after{letter-spacing:-0.2em;content:"\00a0"}pre code::before,pre code::after,pre tt::before,pre tt::after{content:normal}code>span.kw{color:#a71d5d;font-weight:normal}code>span.dt{color:inherit}code>span.dv{color:#0086b3}code>span.bn{color:#0086b3}code>span.fl{color:#0086b3}code>span.ch{color:#183691}code>span.st{color:#183691}code>span.co{color:#969896;font-style:normal}code>span.ot{color:#a71d5d}code>span.al{color:red}code>span.fu{color:#795da3}code>span.er{color:red;font-weight:bold}code>span.wa{color:#969896;font-weight:bold;font-style:italic}code>span.cn{color:#800}code>span.sc{color:#183691}code>span.vs{color:#183691}code>span.ss{color:#b68}code>span.va{color:#19177c}code>span.cf{color:#a71d5d;font-weight:normal}code>span.op{color:#666}code>span.pp{color:#bc7a00}code>span.at{color:#0086b3}code>span.do{color:#ba2121;font-style:italic}code>span.an{color:#969896;font-weight:bold;font-style:italic}code>span.cv{color:#969896;font-weight:bold;font-style:italic}code>span.in{color:#969896;font-weight:bold;font-style:italic}@media print{body{background:#fff}img,pre,blockquote,table,figure{page-break-inside:avoid}body{background:#fff;border:0}code{background-color:#fff;color:#333 !important;padding:0 .2em;border:1px solid #dedede}pre{background:#fff}pre code{background-color:white !important;overflow:visible}}@media screen{::selection{background:rgba(157,193,200,0.5)}h1::selection{background-color:rgba(45,156,208,0.3)}h2::selection{background-color:rgba(90,182,224,0.3)}h3::selection,h4::selection,h5::selection,h6::selection,li::selection,ol::selection{background-color:rgba(133,201,232,0.3)}code::selection{background-color:rgba(0,0,0,0.7);color:#eee}code span::selection{background-color:rgba(0,0,0,0.7) !important;color:#eee !important}a::selection{background-color:rgba(255,230,102,0.2)}.inverted a::selection{background-color:rgba(255,230,102,0.6)}td::selection,th::selection,caption::selection{background-color:rgba(180,237,95,0.5)}} \ No newline at end of file +html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.caption{margin-bottom:5em}*{box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:10pt;line-height:1.6;margin:auto;max-width:1184px;min-width:360px;padding:2rem;word-wrap:break-word}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25;margin-bottom:16px;margin-top:24px}h1{padding-bottom:.3em;font-size:2em;border-bottom:1px solid #eee}h2{padding-bottom:.3em;font-size:1.5em;border-bottom:1px solid #eee}h3{font-size:1.25em}h4{font-size:1.12em}h5{font-size:.875em}h6{font-size:.85em;color:#777}h1 tt,h1 code,h2 tt,h2 code,h3 tt,h3 code,h4 tt,h4 code,h5 tt,h5 code,h6 tt,h6 code{font-size:inherit}body>h2:first-child{margin-top:0;padding-top:0}body>h1:first-child{margin-top:0;padding-top:0}body>h1:first-child+h2{margin-top:0;padding-top:0}body>h3:first-child,body>h4:first-child,body>h5:first-child,body>h6:first-child{margin-top:0;padding-top:0}a:first-child h1,a:first-child h2,a:first-child h3,a:first-child h4,a:first-child h5,a:first-child h6{margin-top:0;padding-top:0}a{color:#4078c0;text-decoration:none}a:active,a:hover{outline:0;text-decoration:underline}sup,sub,a.footnote{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}ol,ul{margin-bottom:16px;margin-top:0;padding-left:2em}p,blockquote,table,pre{margin:15px 0}ul,ol{padding-left:2em}ul.no-list,ol.no-list{padding:0;list-style-type:none}ul ul,ul ol,ol ol,ol ul{margin-top:0;margin-bottom:0}li>p{margin-top:16px}li+li{margin-top:.25em}ol li ul:first-of-type{margin-top:0}hr{background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC) repeat-x 0 0;border:0 none;color:#ccc;height:4px;margin:16px 0;padding:0}h1+p,h2+p,h3+p,h4+p,h5+p,h6+p,ul li>:first-child,ol li>:first-child{margin-top:0}dl{padding:0}dl dt{font-size:1em;font-weight:bold;font-style:italic;padding:0;margin:15px 0 5px}dl dt:first-child{padding:0}dl dt>:first-child{margin-top:0}dl dt>:last-child{margin-bottom:0}dl dd{margin:0 0 15px;padding:0 15px}dl dd>:first-child{margin-top:0}dl dd>:last-child{margin-bottom:0}blockquote{border-left:4px solid #DDD;padding:0 15px;color:#777}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}table{border-collapse:collapse;border-spacing:0;font-size:100%;font:inherit}table th{font-weight:bold;border:1px solid #ccc;padding:6px 13px}table td{border:1px solid #ccc;padding:6px 13px}table td>p:first-child{margin-top:0}table td>p:last-child{margin-bottom:0}table tr{border-top:1px solid #ccc;background-color:#fff}table tr:nth-child(2n){background-color:#f8f8f8}img{max-width:100%}code,tt{padding:0;padding-top:.2em;padding-bottom:.2em;margin:0;font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:10pt;background-color:rgba(0,0,0,0.04);border-radius:3px}pre>code{margin:0;padding:0;white-space:pre;border:0;background:transparent}pre{padding:16px;margin-top:0;margin-bottom:0;background-color:#f8f8f8;font-size:10pt;line-height:19px;overflow:auto;border-radius:3px}pre code,pre tt{background-color:transparent;border:0}code::before,code::after,tt::before,tt::after{letter-spacing:-0.2em;content:"\00a0"}pre code::before,pre code::after,pre tt::before,pre tt::after{content:normal}code>span.kw{color:#a71d5d;font-weight:normal}code>span.dt{color:inherit}code>span.dv{color:#0086b3}code>span.bn{color:#0086b3}code>span.fl{color:#0086b3}code>span.ch{color:#183691}code>span.st{color:#183691}code>span.co{color:#969896;font-style:normal}code>span.ot{color:#a71d5d}code>span.al{color:red}code>span.fu{color:#795da3}code>span.er{color:red;font-weight:bold}code>span.wa{color:#969896;font-weight:bold;font-style:italic}code>span.cn{color:#800}code>span.sc{color:#183691}code>span.vs{color:#183691}code>span.ss{color:#b68}code>span.va{color:#19177c}code>span.cf{color:#a71d5d;font-weight:normal}code>span.op{color:#666}code>span.pp{color:#bc7a00}code>span.at{color:#0086b3}code>span.do{color:#ba2121;font-style:italic}code>span.an{color:#969896;font-weight:bold;font-style:italic}code>span.cv{color:#969896;font-weight:bold;font-style:italic}code>span.in{color:#969896;font-weight:bold;font-style:italic}@media print{body{background:#fff}img,pre,blockquote,table,figure{page-break-inside:avoid}body{background:#fff;border:0}code{background-color:#fff;color:#333 !important;padding:0 .2em;border:1px solid #dedede}pre{background:#fff}pre code{background-color:white !important;overflow:visible}}@media screen{::selection{background:rgba(157,193,200,0.5)}h1::selection{background-color:rgba(45,156,208,0.3)}h2::selection{background-color:rgba(90,182,224,0.3)}h3::selection,h4::selection,h5::selection,h6::selection,li::selection,ol::selection{background-color:rgba(133,201,232,0.3)}code::selection{background-color:rgba(0,0,0,0.7);color:#eee}code span::selection{background-color:rgba(0,0,0,0.7) !important;color:#eee !important}a::selection{background-color:rgba(255,230,102,0.2)}.inverted a::selection{background-color:rgba(255,230,102,0.6)}td::selection,th::selection,caption::selection{background-color:rgba(180,237,95,0.5)}} \ No newline at end of file diff --git a/mk-docs.cmd b/mk-docs.cmd index 64e7af6..332353b 100644 --- a/mk-docs.cmd +++ b/mk-docs.cmd @@ -5,7 +5,7 @@ if "%PANDODC_PATH%"=="" ( ) echo on -"%PANDODC_PATH%\pandoc.exe" -o "%~dp0\README.html" --self-contained --toc --toc-depth=2 --css etc\style\gh-pandoc.min.css "%~dp0\README.md" +"%PANDODC_PATH%\pandoc.exe" -o "%~dp0\README.html" --self-contained --toc --toc-depth=3 --css etc\style\gh-pandoc.min.css "%~dp0\README.md" @echo off echo. diff --git a/mk-docs.sh b/mk-docs.sh index a1014c3..9805904 100755 --- a/mk-docs.sh +++ b/mk-docs.sh @@ -2,4 +2,4 @@ set -e cd -- "$(dirname -- "${BASH_SOURCE[0]}")" -pandoc -o README.html --self-contained --toc --toc-depth=2 --css etc/style/gh-pandoc.min.css README.md +pandoc -o README.html --self-contained --toc --toc-depth=3 --css etc/style/gh-pandoc.min.css README.md