klutshnik(1)
π klutshnik(1) β the Klutshnik command-line client π
okay bestie, sit down, hydrate, because this is the manual page for klutshnik, the CLI client for an updatable threshold KMS system. it's a lot. it's giving "final boss of key management". but we're gonna get through it together, fr fr. π«Ά
β¨ 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 whole system the client talks to a KMS β which stores secret key material securely and efficiently β so it can decrypt and rotate keys for data that's chilling in encrypted form on storage services that are, and I cannot stress this enough, untrusted. π
the most important aspects are, and yes we're doing a list because these are the icons:
- encryption only requires a public key π
- it operates in a threshold setup, splitting up the key-encryption-key (KEK) in a way that never manifests as such anywhere π
- it hides keys and object identifiers from the KMS π
- it offers unconditional security for key transport to/from KMS π‘οΈ
- it provides key-verifiability, identifying KMS' which respond with corrupt values π΅οΈ
- it 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, and 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 info on configuring klutshnik, go read the man-page klutshnik.cfg(5). it's right there. it's your friend.
π 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 either be stored on disk and referenced in the klutshnik.cfg(5) config file, or klutshnik can take the client long-term signing key on standard input.
Note, and this one matters: if you're decrypting a file, the file itself is also expected on the standard input. in that case the ltsigkey and the file β if required β should simply be concatenated, in this order. π§
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. use it. bestie please. π₯Ί
π¦ Key Names π¦
KeyIds are the identifiers you use to address your records, and they can be any kind of string. no cap, any kind.
internally this name gets hashed using the id_salt from the config's [client] section into a unique key identifier. and because 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. π not the vibe. set a random salt. periodt.
π Command-line Operations π
π Initialize a new config π
% klutshnik init <configfile>
this checks if the clientkey_path variable is pointing at a non-existing file. if that's 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. yes, manually. we don't do it for you. π
furthermore the init op also checks if the directory pointed at by the keystore value in the [client] section exists, and if not, it creates it. ποΈ
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, likepwdsphinx(1). seeklutshnik.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.
% klutshnik create <keyname> [<ltsigkey]
if everything went fine, the client outputs the public key, which can be used to encrypt files. those files 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. main character energy, honestly. π
π 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. nope. none. free. β¨
% 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, it's 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. β οΈ
% klutshnik decrypt [<ltsigkey] <ciphertext >plaintext
π Rotate a key π
rotating a key can be done by specifying the name of the key 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. don't skip this. don't. π
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. that's not a little oopsie, that's the whole vibe check failed. π
% 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
rotateoperation 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. she works from home, she's independent. π
% 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. same warning as before because it's that serious, bestie. π¨
πΎ Refresh local key metadata πΎ
the client keeps a local cache of some key related metadata:
- 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. π
% 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 long-term signing key β either in the configuration file or on standard input β is authorized to do so. βοΈ
% klutshnik delete <keyname> [<ltsigkey]
π«Ά Authorize a user π«Ά
adding additional users and authorization permissions can be done with 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. no owner key, no adduser. π
% 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 the 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. it's a gift, hand it over. π
βοΈ 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 a user specified by their public key. π«
% 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. π
% 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, and this output must be passed to the user being authorized as follows:
% 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.
% 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β this is the first serial port that shows up tied to the device when you plug it in over USB (heads up, some devices have two, so like, count them bestie π ). The value you'll see basically every time is/dev/ttyACM0, iconic.klutshnik.cfgβ the client config file. This one gets read and rewritten during provisioning, so she's not just a spectator, she's in the group chat π«Άauthorized_keysβ a file holding the authorized keys of every other klutshnik server in your client setup. Not all of them available yet? No stress, you can add them later through the USB serial shell of the device (peep the firmware documentation for the whole rundown).uart|espβ depends on how your klutshnik device is talking the klutshnik protocol: is it over the 2nd USB serial port (uart), or is it an ESP32 device (esp)? Whatever she is, you gotta set this correctly. No guessing, bestie π
If everything goes correctly (manifesting β¨), the device picks up the authorized_keys plus the owner's ltsig/noise public keys, and a brand new servers sub-section gets added to the client configuration file you passed as the parameter. That new servers sub-section gets named either by its Bluetooth MAC, or usb-cdc0 if we're talking serial ports on USB.
And at the very end, a base64 encoded authorized_keys entry is presented to you. That one MUST go into all the authorized_keys files of all the other klutshnik servers in your client config. Not optional. Do not skip. Periodt. π
π SECURITY CONSIDERATIONS π
You MUST keep your delta update tokens private! Leaking them is giving "I posted my diary on main" and it will negate the forward secrecy and post-compromise security properties of the whole scheme. Like, the entire thing. Do not. π
It is RECOMMENDED that you store your private long-term signing key in a dedicated secure storage instead of just having it chilling in a file on your disk that ltsigkey_path in your configuration file points at. pwdsphinx has native support for exactly this, so there's genuinely no excuse. π
Do not let any 3rd-party hold enough shares to achieve the threshold. That's it, that's the rule.
You SHOULD back up your configuration β especially the id_salt and the names of the servers you're using. Losing those means losing access to your data. Fr fr, this is the one you'll cry about π
π REPORTING BUGS π
Found a gremlin? Tell on it here:
https://github.com/stef/klutshnik/issues/
βοΈ AUTHOR βοΈ
Written by Stefan Marsiske. (The icon, the legend, the main character π)
Β©οΈ COPYRIGHT Β©οΈ
Copyright Β© 2025 Stefan Marsiske. License GPLv3+: GNU GPL version 3 or later https://gnu.org/licenses/gpl.html (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.
So yeah β remix her, share her, just don't come for her if she breaks, because there is NO WARRANTY π
π SEE ALSO π
And that's the whole klutshnik(1) manual page bestie β that closing klutshnik(1) footer at the bottom is just the page signing its own name, so mwah, go forth and provision responsibly πβ¨π
π¦ where this page comes from
- ubuntu stonking: klutshnik 0.4.1-1 Β· GPL-3.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms