# NAME

klutshnik - command-line client for an updatable threshold KMS system

# SYNOPSIS

     klutshnik init <configfile>

     klutshnik create  <keyname> [<ltsigkey] >pk

     klutshnik encrypt <pk> <plaintext >ciphertext

     klutshnik decrypt [<ltsigkey] <ciphertext >plaintext

     klutshnik rotate  <keyname> [<ltsigkey] >pk-and-delta

     klutshnik refresh <keyname> [<ltsigkey] >pk

     klutshnik delete  <keyname> [<ltsigkey]

     klutshnik update  <delta  <files2update

     klutshnik adduser <keyname> <b64 pubkey> <owner,decrypt,update,delete> [<ltsigkey]

     klutshnik deluser <keyname> <b64 pubkey> [<ltsigkey]

     klutshnik listusers <keyname> [<ltsigkey]

     klutshnik import <keyid> <KLTCFG-...> [<ltsigkey]

     klutshnik provision <serial port> <klutshnik.cfg> <authorized_keys> <uart|esp> [<ltsigkey]

# DESCRIPTION

klutshnik is a CLI client for an updatable threshold Key Management
Server (KMS) protocol. In this system the `client` interacts with a `KMS` -
which stores securely and efficiently secret key material -, in
order to decrypt and rotate keys for data that is stored in encrypted
form on untrusted `storage services`.

The most important aspects are:

  - encryption only requires a public key,
  - operates in a threshold setup, splitting up the key-encryption-key
    (KEK) in a way that never manifests as such anywhere,
  - hides keys and object identifiers from the KMS,
  - offers unconditional security for key transport to/from KMS,
  - provides key-verifiability, identifying KMS' which respond with
    corrupt values,
  - provides very efficient key-rotation of the KEKs, which does not
    require re-encryption of the encrypted data itself.
  - updating the KEKs can be done even by the untrusted storage, it
    will not learn anything.

Klutshnik is based on https://eprint.iacr.org/2019/1275 "Updatable
Oblivious Key Management for Storage Systems" by Stanislaw Jarecki,
Hugo Krawczyk, and Jason Resch

## Configuration

For information on configuring `klutshnik`, see the man-page
`klutshnik.cfg(5)`.

## Command-line usage and examples

### Long-term signing key

`klutshnik` uses EdDSA long-term signing keys for authentication
towards the KMS servers. This key can be stored on disk and referenced
in the `klutshnik.cfg(5)` config file. Alternatively `klutshnik` can
take the client long-term signing key on the standard input. Note: If
you are decrypting a file, the file itself is also expected on the
standard input. In this case the ltsigkey and the file - if required -
should be simply (in this order) concatenated.

It is warmly recommended to use pwdsphinx
https://github.com/stef/pwdsphinx as a "storage" for the client
long-term signing keys, since it handles keys also in a threshold
setup in a most secure manner.

### Key Names

KeyIds are the identifiers that you use to address your records, they
can be any kind of string. Internally this name is hashed using the
`id_salt` from the configurations `[client]` section into a unique key
identifier. As this salt is necessary to access your records, it is
strongly recommended to set the `id_salt` to some random value and to
back up this value. If you use a commonly used salt (i.e. the default
salt) chances are high that there are collisions for record ids, and
that people can guess your record ids.

## Command-line Operations

### Initialize a new config

```sh
% klutshnik init <configfile>
```

This checks if the `clientkey_path` variable is pointing at a non-existing
file. If this is the case, then the client generates a new client
master key, saves it at the pointed location and prints your long and short
public key on standard output. This long public key value must be manually added
to any klutshnik server `authorized_keys` files that you want to use.

Furthermore the `init` op also checks if the directory pointed at by the
`keystore` value in the `[client]` section exists and if not creates
this.

Note it is recommended to store your client master key in a more
secure location than your disk, if possible store it in a password
manager, like `pwdsphinx(1)`, see `klutshnik.cfg(5)` for more details.

### Create a new key

Creating a new key is as simple as providing a key name and if
`ltsigkey_path` is not configured the long-term signing private key on the
standard input.

```sh
% klutshnik create <keyname> [<ltsigkey]
```

If everything went fine, the client outputs the public key, which can
be used to encrypt files. These can be decrypted by the key referenced
by the key name you provided.

This operation sets the long-term signing public key of the creator as
the owner of the key, giving all permissions to them.

### Encrypt a file

Encrypting a file requires the latest public key as provided by the
`create`, `rotate` and `refresh` operations. Users who have no
authorization to interact with the keyid on the KMS' must rely on any
of the authorized users to provide the public key of the current
epoch. This operation does not require a long-term signing key.

```sh
% klutshnik encrypt <public key> <plaintext >ciphertext
```

### Decrypt a file

Decrypting a file just pipe the ciphertext into the process and get
the plaintext on standard output. If you don't have your long-term
signing key in your configuration, this is expected as a prefix to the
encrypted file. Of course this works on the condition that enough KMS'
are responding correctly and that the file has been updated with the
delta of the current epoch.

```sh
% klutshnik decrypt [<ltsigkey] <ciphertext >plaintext
```

### Rotate a key

Rotating a key can be done by specifying the name of the key that you
want to rotate. Depending on your configuration, you must supply your
long-term signing key on standard input. The output of this operation
is:
 - the new public key, which you should distribute to anyone who is
   expected to encrypt to this key, and
 - your update delta token which is required to update the encryption
   of the files encrypted with this key.

It is essential to run the `update` procedure from the next section on
all files encrypted with the rotated key by applying this update delta
token to them.

Make sure that you keep this update token delta secret, if it leaks,
it will neutralize the forward secrecy and post-compromise security
properties of this protocol for the current and the previous key.

```sh
% klutshnik rotate <keyname> [<ltsigkey] >pubkey-and-delta
```

### Update a file with a rotated key

Files encrypted with the key referenced by the key name can be
bulk-updated by piping:
 - the update delta token from the rotate operation described in the
   previous section, and
 - the list of paths pointing at these files
into the CLI client.

This operation does not require a long-term signing key. Furthermore
this is an offline operation, there is no need for connectivity to the
KMS', In fact this operation can run on the storage server itself.

```sh
% klutshnik update <delta  <files2update
```

Warning: Make sure that you keep the update token delta secret, if it
leaks, it will neutralize the forward secrecy and post-compromise
security properties of this protocol for the current and the previous
key.

### Refresh local key metadata

The client keeps a local cache of some key related metadata:

 - as the public key,
 - the current epoch,
 - the threshold,
 - the owner public key, and
 - the shares that can be combined into the public key.

When a client rotates a key, some of these values change. Other
clients should refresh their own local copy of these by running a
refresh operation.

```sh
% klutshnik refresh <keyname> [<ltsigkey] >pk
```

This operation will output the current public key associated with the
keyname on standard output.

### Delete a key

This operation deletes the shares of the key referenced by the
`keyname` if the provided (either in the configuration file or on
standard input) long-term signing key is authorized to do so.

```sh
% klutshnik delete <keyname> [<ltsigkey]
```

### Authorize a user

Adding additional users and authorization permissions can be done by
using the `adduser` operation. The parameters to this operation are
 - the `keyname` to which a new user is added,
 - the base64 encoded long-term public signing-key,
 - and a list of permissions, separated by commas: owner,decrypt,update,delete

The user executing this operation must be in possession of a long-term
signing-key, which has the `owner` permission.

```sh
% klutshnik adduser <keyname> <b64 pubkey> <owner,decrypt,update,delete> [<ltsigkey]
```

The output of this operation is the base64 encoded serialized setup
related to this key. This data is they keyid, and the `[server]`
section with `ltsigkey` and `ssl_cert` files inlined. This "token"
must be passed to the user who has been authorized, so they can
`import` this into their own configuration.

### Delete a user

A user which has the `owner` permission associated with their
long-term signing key associated with a key referenced by the
`keyname` can delete an user specified by their public key.

```sh
% klutshnik deluser <keyname> <b64 pubkey> [<ltsigkey]
```

### List authorizations of users

A user which has the `owner` permission associated with their
long-term signing key associated with a key referenced by the
`keyname` can list all authorized users and their permissions.

```sh
% klutshnik listusers <keyname> [<ltsigkey]
```

### Import Foreign Key Setup

Non-owner users who have been authorized - unless they have the same
`id_salt` value and the same `[server]` section in their config as the
owner -, must import the setup of the owner into their local
`keystore`. The setup is exported by the owner automatically when
running an `adduser` operation, this output must be passed to the user
being authorized as follows:

```sh
% klutshnik import <keyid> <KLTCFG-...b64...> [<ltsigkey]
```

This command automatically runs internally a `refresh` operation to
query the current epoch and public key related to this key. All this
is stored in the local `keystore` of the user.

### Provisioning Klutshnik Microcontroller Devices

It is possible to run klutshnik servers on microcontrollers like ESP32, or
Cortex-M series ARM devices (see https://github.com/stef/klutshnik-zephyr).
After installing the firmware on these, they need to be configured like regular
servers.

```sh
% klutshnik provision <serial port> <klutshnik.cfg> <authorized_keys> <uart|esp> [<ltsigkey]
```

Warning: if you add a new USB serial-based klutshnik device, make sure that the
existing config has no `servers` subsection with the name `usb-cdc0` as that
will be overwritten during the provisioning. If this happens anyway, a backup
of the original config file is made.

Parameters:

 - `serial port`: is the first (some devices have two) serial port when connected
   via USB associated with the device. A very common value is `/dev/ttyACM0`
 - `klutshnik.cfg`: the client config file which will be consulted and updated
   during the provisioning.
 - `authorized_keys`: a file containing the authorized keys of all the other
   klutshnik servers in the client setup. If they are not all available they
   can be added later using the USB serial shell of the device (see the
   firmware documentation for more details)
 - `uart|esp` depending on whether the klutshnik device is communicating the
   klutshnik protocol over the 2nd USB serial port or is an ESP32 device, this
   must be set correctly.

If everything goes correctly, the device gets the `authorized_keys` and the
owners client ltsig/noise public keys and a new `servers` sub-section is added
to the client configuration file provides as parameter. This new `servers`
sub-section has either with their Bluetooth MAC as a name, or `usb-cdc0` in
case of serial ports on USB. 

At the end a base64 encoded `authorized_keys` entry is presented, which
**MUST** be added to all `authorized_keys` files of all the other klutshnik
servers in the client config.

# SECURITY CONSIDERATIONS

You **MUST** keep your delta update tokens private! Leaking them will
negate the forward secrecy and post-compromise security properties of
the whole scheme.

It is **RECOMMENDED** to store your private long-term signing key in a
dedicated secure storage instead of just having it in a file on your
disk pointed at the `ltsigkey_path` variable in your configuration
file. pwdsphinx provides native support for this.

Do not let any 3rd-party hold enough shares to achieve the threshold.

You **SHOULD** back up your configuration, especially the `id_salt`
and the names of the servers you are using, losing them means losing
access to your data.

# REPORTING BUGS

https://github.com/stef/klutshnik/issues/

# AUTHOR

Written by Stefan Marsiske.

# COPYRIGHT

Copyright © 2025 Stefan Marsiske.  License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.  There is NO WARRANTY, to the extent permitted by law.

# SEE ALSO

`https://klutshnik.info`

`klutshnik.cfg(5)`

`https://sphinx.pm`
