kync 0.1.6

KyNc – a generic API for key encapsulation and a Rust interface to KyNc-plugins
Documentation
= Kync v1
:toc:


== General
Kync describes a **K**e**Y**e**NC**apsulation plugin-API for key encapsulation plugins.

Key encapsulation is the process of encrypting an already existing key with another different key. This allows you to
separate your application from the key storage so that the user can specify how the key is stored – e.g.
password-encrypted in a file or in the OS' keychain.


== Plugin API
To achieve a simple and cross-platform compatible API, we use dynamic libraries that expose a C API/ABI.


=== General Rules
These general rules apply to all API functions and *MUST* be respected by any plugin that implement this API:

. Each function that may fail *MUST* return the error type

. No ownership is transferred

. An API-call *MUST NOT* take longer than 90 seconds before returning

. All functions *MUST* be threadsafe as long as their parameters are not shared


=== API Overview
These functions are defined by the API and *MUST* be implemented:

. `source_t` and `sink_t`: The data source/sink types

. `init`: Takes care of the library initialization and returns the implemented API version

. `capsule_format_uid`: Returns the capsule format UID for the implemented format

. `crypto_item_ids`: Gets all available crypto item IDs (for plugins that implement multiple algorithms or have their
  own key storage; e.g. GnuPG)

. `seal`: Seals some key bytes into a capsule

. `open`: Extracts the key bytes from a capsule

. `error_t`: The error type


=== source_t
[source,cpp]
----
typedef struct {
	uint8_t const* data(void* handle, size_t* len);
	void* handle;
} source_t;
----

A simple, callback based data-source.

_Important: If `data` returns `NULL`, this means the source is unavailable – which *MUST NOT* be confused with an empty
source!_

Fields:

. `data`: A function that returns the available bytes in `handle` and adjusts `len` accordingly
** The returned pointer *MAY* be `NULL` in case this source is not available (which *MUST NOT* be confused with an empty
   source!)
** This function *MAY* be called multiple times in which case it *MUST* always return the same result.

. `handle`: An opaque pointer to the data-source handle


=== sink_t
[source,cpp]
----
typedef struct {
	uint8_t* data(void* handle, size_t len);
	void* handle;
} sink_t;
----

A simple, callback based data-sink.

. `data`: A function that returns a pointer to a `len` sized memory-area within `handle` which can be written
** If the returned pointer is `NULL`, an `ENOBUF`-error *MUST* be returned.
** This function *MAY* be called multiple times to allow partial writes in which case it *MUST* return a _new_ pointer
   to an _empty_ (not already written) slice of memory.

. `handle`: An opaque pointer to the data-sink handle


=== init
[source,cpp]
----
uint8_t init(uint8_t log_level);
----

This function initializes the library, sets the `log_level` and returns the API version. It *MUST NOT* fail.

Valid API versions are:

. `0x01`: The API version for this specification

Parameter `log_level`: The logging level the plugin should use (`0` means no logging). _Note: This only applies to
StdErr-logging_


=== capsule_format_uid
[source,cpp]
----
char const* capsule_format_uid();
----

This function returns a const static pointer the plugin's capsule format UID. It *MUST NOT* fail or return `NULL`.

The capsule format UID is a `'\0'`-terminated UTF-8 string which *MUST* map to one format only. To achieve this, we
append a random UUID; e.g. `AES-256-GCM-IETF.v1.B593CCDE-B5C3-433A-ABBA-9087FBF13E60`. If you write a fully compatible
drop-in replacement for an already existing plugin, you *MAY* use the original format UID.


=== crypto_item_ids
[source,cpp]
----
error_t crypto_item_ids(sink_t ids);
----

This function writes all available crypto item IDs as concatenated, `'\0'`-terminated UTF-8 strings into `ids`.

Crypto item IDs identify a specific algorithm or key in case the plugin allows multiple algorithms (e.g. `"AES-128"` vs.
`"AES-256"`) or offers multiple keys from a key store (e.g. GnuPG).

If the plugin does not support multiple crypto items, it *MUST* return an `ENOTFOUND`-error.


=== seal
[source,cpp]
----
error_t seal(sink_t sink, source_t key, source_t crypto_item_id, source_t user_secret);
----

This function seals a `key` and writes the resulting data to `sink`.

Parameters:

. `sink`: The payload destination

. `key`: The slice containing the key bytes to seal

. `crypto_item_id`: The crypto item ID to use (see `crypto_item_id`)
** The source *MUST* be unavailable if the plugin does not support multiple crypto items (if violated an `EINVAL`-error
   *MUST* be returned).
** The source *MAY* be unavailable even if the plugin supports multiple crypto items in which case a reasonable default
   *SHOULD* be selected if possible (if not possible, an `ENOTFOUND`-error *MUST* be returned).

. `user_secret`: A user-provided secret which may have multiple, plugin-dependent purposes; ranging from a
  hardware-token-PIN to the capsule key itself
** The source *MAY* be unavailable in case is not necessary for the call – _if_ it is unavailable, a plugin *MUST NOT*
   perform any authentication attempts that could decrease a retry counter.


=== open
[source,cpp]
----
error_t open(sink_t sink, source_t capsule, source_t user_secret);
----

This function opens a `capsule` and writes the resulting key bytes into `sink`.

Parameters:

. `sink`: The plaintext-key destination

. `capsule`: The capsule data

. `user_secret`: A user-provided secret which may have multiple, plugin-dependent purposes; ranging from a
  hardware-token-PIN to the capsule key itself
** The source *MAY* be unavailable in case is not necessary for the call – _if_ it is unavailable, a plugin *MUST NOT*
   perform any authentication attempts that could decrease a retry counter.


=== error_t
[source,cpp]
----
typedef struct {
	char const* error_type;
	char const* description;
	uint64_t info;
} error_t;
----

The error type.

Fields:

. `error_type`: The error type as `0`-terminated string or a `NULL`-pointer if no error occurred

. `info`: An error-specific info field

. `description`: An error description as `0`-terminated string; *MUST NOT* be `NULL`


==== EPERM
`"EPERM"` indicates that an operation is not permitted (at least without providing authentication data).

`info` indicates if the action requires authentication (`info != 0`) or if the action will always fail (`info == 0`).


==== EACCES
`"EACCES"` indicates an authentication error. `info` indicates the amount of retries left; if there is no retry-limit,
`info` is `UINT64_MAX`.


==== ENOBUF
`"ENOBUF"` indicates insufficient buffer space – this happens if the `sink_t` store the provided data. `info` indicates
the required size.


==== EIO
`"EIO"` indicates an I/O-related error. `info` is unused.


==== EILSEQ
`"EILSEQ"` indicates invalid capsule data. `info` is unused.


==== ENOTFOUND
`"ENOTFOUND"` indicates that there is no matching key available to decrypt the capsule. `info` is unused.


==== EINVAL
"`EINVAL`" indicates an invalid parameter. `info` is the `0`-based index of the parameter.


==== ECANCELED
`"ECANCELED"` indicates that the operation was canceled. `info` is unused.


==== ETIMEDOUT
`"ETIMEDOUT"` indicates that the operation timed out – either because it hit the 90s deadline or because something else
timed out (e.g. hardware token). `info` is unused.


==== EOTHER
`"EOTHER"` indicates that an unspecified fatal error occurred. `info` *MAY* be a plugin-specific error code and *MUST*
be ignored if it's meaning is unknown.