{"id":15395436,"url":"https://github.com/stef/klutshnik","last_synced_at":"2025-06-11T01:06:26.632Z","repository":{"id":149313348,"uuid":"619987345","full_name":"stef/klutshnik","owner":"stef","description":"data-at-rest encryption KMS server and client","archived":false,"fork":false,"pushed_at":"2025-05-14T22:55:50.000Z","size":257,"stargazers_count":11,"open_issues_count":1,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-05-14T23:30:41.293Z","etag":null,"topics":["crypto","danger","data-at-rest","encryption","experimental","oprf","threshold"],"latest_commit_sha":null,"homepage":"https://klutshnik.info","language":"Zig","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stef.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-03-27T20:06:31.000Z","updated_at":"2025-05-14T22:55:54.000Z","dependencies_parsed_at":null,"dependency_job_id":"31c1a798-0667-4802-bee9-cbcc8bbd0976","html_url":"https://github.com/stef/klutshnik","commit_stats":{"total_commits":71,"total_committers":2,"mean_commits":35.5,"dds":"0.014084507042253502","last_synced_commit":"e001e2ab17bc4a9c7cf7af701491690329ea9a09"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Fklutshnik","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Fklutshnik/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Fklutshnik/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Fklutshnik/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stef","download_url":"https://codeload.github.com/stef/klutshnik/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Fklutshnik/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259178486,"owners_count":22817386,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crypto","danger","data-at-rest","encryption","experimental","oprf","threshold"],"created_at":"2024-10-01T15:28:21.094Z","updated_at":"2025-06-11T01:06:26.620Z","avatar_url":"https://github.com/stef.png","language":"Zig","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GNU Klutshnik\n\nHello my name is Klyoovtuokmshnik, Styepanovich Klyoovtuokmshnik - but\nmy friends call me \"klutshnik\" (Narrator: let me interject for a\nmoment, What you are referring to as Klutshnik, is in fact,\nGNU/Klutshnik, or as I've recently taken to calling it, GNU plus\nKlutshnik)\n\n## Also on Radicle\n\nTo clone this repo on [Radicle](https://radicle.xyz), simply run:\n\n  `rad clone rad:zogkw4qiTrH7rKVa89BrKo8z5miA`\n\n# WARNING\n\nWARNING! this is very early alpha-grade proof of concept, it is\nintended for interested parties to poke at and play with it. It is not\nintended for any even half-serious use yet.\n\n# Verifiable Threshold Updatable Oblivious Key Management for Storage Systems\n\nThis is a PoC implementing the full VTUOKMS from\n\nhttps://eprint.iacr.org/2019/1275\n\"Updatable Oblivious Key Management for Storage Systems\"\nby Stanislaw Jarecki, Hugo Krawczyk, and Jason Resch\n\nOK, tl;dr, wth is a vtuokms???5? To quote the above paper's abstract:\n\n\u003e [...] system, that builds on Oblivious Pseudorandom Functions\n\u003e (OPRF), hides keys and object identifiers from the KMS, offers\n\u003e unconditional security for key transport, provides key\n\u003e verifiability, reduces storage, and more. Further, we show how to\n\u003e provide all these features in a distributed threshold implementation\n\u003e that enhances protection against server compromise.\n\n\u003e We extend this system with updatable encryption capability that\n\u003e supports key updates (known as key rotation) so that upon the\n\u003e periodic change of OPRF keys by the KMS server, a very efficient\n\u003e update procedure allows a client of the KMS service to\n\u003e non-interactively update all its encrypted data to be decryptable\n\u003e only by the new key. This enhances security with forward and\n\u003e post-compromise security, namely, security against future and past\n\u003e compromises, respectively, of the client’s OPRF keys held by the\n\u003e KMS. Additionally, and in contrast to traditional KMS, our solution\n\u003e supports public key encryption and dispenses with any interaction\n\u003e with the KMS for data encryption (only decryption by the client\n\u003e requires such communication).\n\nOne thing that is missing from the above, is the \"V\" in \"VTUOKMS\"\nwhich:\n\n\u003e provides verifiability, namely, the ability of KMS to prove to C\n\u003e that the [calculated en/decryption key] is indeed the value that\n\u003e results from computing the OPRF on the client-provided object\n\u003e identifier. This prevents data loss that occurs if the [calculated\n\u003e en/decryption key] is wrong (either due to computing error or to\n\u003e adversarial action)\n\n# Dependencies\n\nThis code depends on liboprf[1], libsodium[2], pysodium[3]\n\n[1] https://github.com/stef/liboprf/\n[2] https://github.com/jedisct1/libsodium\n[2] https://github.com/stef/pysodium\n\n# Building\n\nYou need to install zig, libsodium-dev, liboprf, pyoprf and pysodium, with\nwhatever tools your OS provides you with.\n\n## liboprf\n\nInstall libsodium with development files from your favorite package repository.\n\n```\n# in directory $buildroot\ngit clone https://github.com/stef/liboprf/\ncd liboprf\n# you can use the PREFIX environment variable to set the install location to a writable directory\nexport PREFIX=/path/preferred/oprf/location\nmake install\n# ldconfig\n# go back to $buildroot\ncd ..\n\npip install pyoprf\n```\n\n## build Klutshnik\n\n```\n# in directory $buildroot\ngit clone https://github.com/stef/klutshnik\ncd klutshnik\nmake\nsudo PREFIX=/usr make install\ncd server\nzig build\n```\n\n## testing\n\nIn order to test also the update of keys, a minimum of\n`2*(threshold-1)+1` shares is necessary. Hence the minimum setup\nrequires 5 servers. If you don't have that many devices to run\nklutshnik servers on, just run a couple of them on the same device.\n\nIn the `test` directory there is a fully configured client/server (3-out-of-5)\nsetup. If you have installed libklutshnik and the python cli client, and built\nthe zig server, the following should work (and give you an idea how to use\nthis):\n\n```sh\n% cd test/servers\n% ./start-servers.sh\n\n# switch to a different terminal and go to klutshnik/test\n# create the key\n% klutshnik create \"keyid1\"\nKLCPK-XhIO9gsXc0EJGlFFgLxlpsVE39pk3gRgzKkPg4gbgg0AAAAA9MxKACsmwEEfbMdS4tf8KrYM5h/w2FRcAZ0/4pRK0GQ=\n\n# encrypt a message (this one only needs the public key from above)\n% echo \"attack at dawn\" | klutshnik encrypt KLCPK-XhIO9gsXc0EJGlFFgLxlpsVE39pk3gRgzKkPg4gbgg0AAAAA9MxKACsmwEEfbMdS4tf8KrYM5h/w2FRcAZ0/4pRK0GQ= \u003e/tmp/klutshniked\n\n# decrypt the message (this one needs the key from the klutshnik server)\n% klutshnik decrypt \u003c/tmp/klutshniked\n\n# update the key on the klutshnik server\n% klutshnik rotate \"keyid1\"\nKLCPK-XhIO9gsXc0EJGlFFgLxlpsVE39pk3gRgzKkPg4gbgg0AAAABkD+jW5DoYBln2WJQ74gySEWhtM4bxbyJkeDgTcpNLVA=\nKLCDELTA-XhIO9gsXc0EJGlFFgLxlpsVE39pk3gRgzKkPg4gbgg0AAAABk4hPN4VKb6lxeZO0hXEx1e/iGWQvYAIXQvu2pbIrQQQ=\n\n# update the encryption on the encrypted file\n% { echo \"KLCDELTA-XhIO9gsXc0EJGlFFgLxlpsVE39pk3gRgzKkPg4gbgg0AAAABk4hPN4VKb6lxeZO0hXEx1e/iGWQvYAIXQvu2pbIrQQQ=\"; \\\n    echo \"/tmp/klutshniked\" } | klutshnik update\n\n# decrypt with the new key\n% klutshnik decrypt \u003c/tmp/klutshniked\n\n# list who is authorized to operate on this key\n% klutshnik listusers \"keyid1\"\n\n# add a user that can update keys, but nothing else\n% klutshnik adduser keyid1 13lty/jQszJ1Xn5krTC2kltvPJDMqb4bqk3jgZxR430= update\nthe newly authorized client must run:\nklutshnik import \"some-keyname\" KLTCFG-\u003clong base64 string\u003e\n\n# check that this user has been added\n% klutshnik listusers \"keyid1\"\n\n# remove this user again\n% klutshnik deluser keyid1 13lty/jQszJ1Xn5krTC2kltvPJDMqb4bqk3jgZxR430=\n\n# check that user has been removed\n% klutshnik listusers \"keyid1\"\n\n# delete the key\n% klutshnik delete \"keyid1\"\n\n# fail to decrypt the file without a key.\n% klutshnik decrypt \u003c/tmp/klutshniked\n\n# switch to the other console running the servers and quit them by pressing ^c\n```\n\n# example session\n\n```\n% klutshnik create keyid1\nKLCPK-XhIO9gsXc0EJGlFFgLxlpsVE39pk3gRgzKkPg4gbgg0AAAAAUjWZfmo4B3a3i+Ii+KMS7L5d/vMyxpMUEvUMjJPWAQM=\n% echo \"HELLO world\" | klutshnik encrypt KLCPK-XhIO9gsXc0EJGlFFgLxlpsVE39pk3gRgzKkPg4gbgg0AAAAAUjWZfmo4B3a3i+Ii+KMS7L5d/vMyxpMUEvUMjJPWAQM= \u003e/tmp/encrypted\n% xxd /tmp/encrypted\n00000000: 5e12 0ef6 0b17 7341 091a 5145 80bc 65a6  ^.....sA..QE..e.\n00000010: c544 dfda 64de 0460 cca9 0f83 881b 820d  .D..d..`........\n00000020: 0000 0000 fc2f 2e5b e52f 341f 0874 6771  ...../.[./4..tgq\n00000030: 0174 aba4 b489 44ff dd0e f291 5502 5ee6  .t....D.....U.^.\n00000040: 3de7 a93b 63f2 22c7 886d 816b b26a 8447  =..;c.\"..m.k.j.G\n00000050: 1aa7 2b81 36e1 3329 f517 2658 3ad1 7100  ..+.6.3)..\u0026X:.q.\n00000060: e5c1 8560 395b 1957 3c00 7176            ...`9[.W\u003c.qv\n\n% klutshnik decrypt \u003c/tmp/encrypted\nHELLO world\n% klutshnik rotate \"keyid1\"\nKLCPK-XhIO9gsXc0EJGlFFgLxlpsVE39pk3gRgzKkPg4gbgg0AAAABkD+jW5DoYBln2WJQ74gySEWhtM4bxbyJkeDgTcpNLVA=\nKLCDELTA-XhIO9gsXc0EJGlFFgLxlpsVE39pk3gRgzKkPg4gbgg0AAAABk4hPN4VKb6lxeZO0hXEx1e/iGWQvYAIXQvu2pbIrQQQ=\n% printf \"KLCDELTA-XhIO9gsXc0EJGlFFgLxlpsVE39pk3gRgzKkPg4gbgg0AAAABk4hPN4VKb6lxeZO0hXEx1e/iGWQvYAIXQvu2pbIrQQQ=\\n/tmp/encrypted\" | klutshnik update keyid1\n% xxd /tmp/encrypted\n00000000: 5e12 0ef6 0b17 7341 091a 5145 80bc 65a6  ^.....sA..QE..e.\n00000010: c544 dfda 64de 0460 cca9 0f83 881b 820d  .D..d..`........\n00000020: 0000 0001 bc9b 0104 283b 7aa8 2939 d0f5  ........(;z.)9..\n00000030: 89a8 eda3 f665 995f 499b d895 04da 9238  .....e._I......8\n00000040: 5db1 8d05 63f2 22c7 886d 816b b26a 8447  ]...c.\"..m.k.j.G\n00000050: 1aa7 2b81 36e1 3329 f517 2658 3ad1 7100  ..+.6.3)..\u0026X:.q.\n00000060: e5c1 8560 395b 1957 3c00 7176            ...`9[.W\u003c.qv\n\n% klutshnik decrypt \u003c/tmp/encrypted\nHELLO world\n```\n\n# File formats\n\nEncrypted files have the following structure:\n\n```\n16 bytes keyid\n4  bytes epoch\n32 bytes w value\n12 byte nonce-half\nevery 64KB\n    64 kBytes ciphertext (chacha20)\n    16 bytes MAC (poly1305)\n```\nYou can see in the above example session, that after key-update only\nthe w value is changed, nothing else.\n\n# References\n\nThe main functionality is based on the UOKMS construction of the\nhttps://eprint.iacr.org/2019/1275\n\n    \"Updatable Oblivious Key Management for Storage Systems\"\n    by Stanislaw Jarecki, Hugo Krawczyk, and Jason Resch\n\nThe Threshold OPRF is based on: https://eprint.iacr.org/2017/363\n\n    \"TOPPSS: Cost-minimal Password-Protected Secret Sharing based on Threshold OPRF\"\n    by Stanislaw Jarecki, Aggelos Kiayias, Hugo Krawczyk, and Jiayu Xu\n\nWithin this, the DKG is based on\n\n    R. Gennaro, M. O. Rabin, and T. Rabin. \"Simplified VSS and fact-track\n    multiparty computations with applications to threshold cryptography\" In B.\n    A. Coan and Y. Afek, editors, 17th ACM PODC, pages 101–111. ACM, June /\n    July 1998 and is fully specified in liboprf/docs/stp-dkg.txt\n\nThe key-update is based on:\n\n    Fig. 2 from \"Simplified VSS and fact-track multiparty computations with\n    applications to threshold cryptography\" by R. Gennaro, M. O. Rabin, and T.\n    Rabin. This is fully specified in liboprf/docs/stp-update.txt\n\nThe files are encrypted using `crypto_secretbox()` by libsodium\nhttps://github.com/jedisct1/libsodium, using the STREAM construction\nhttps://eprint.iacr.org/2015/189:\n\n    \"Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance\"\n    by Viet Tung Hoang, Reza Reyhanitabar, Phillip Rogaway, and Damian Vizár\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstef%2Fklutshnik","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstef%2Fklutshnik","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstef%2Fklutshnik/lists"}