{"id":19388338,"url":"https://github.com/mk-fg/ghg","last_synced_at":"2026-06-12T06:31:25.302Z","repository":{"id":145000858,"uuid":"47614043","full_name":"mk-fg/ghg","owner":"mk-fg","description":"Simple command-line NaCl/libsodium file encryption tool","archived":false,"fork":false,"pushed_at":"2024-02-22T00:37:22.000Z","size":86,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-24T19:58:06.545Z","etag":null,"topics":["cli","cryptography","nacl","ocaml","security","tool"],"latest_commit_sha":null,"homepage":"","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"wtfpl","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mk-fg.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"COPYING","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}},"created_at":"2015-12-08T10:04:58.000Z","updated_at":"2023-10-14T17:39:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"c9c20f5d-5b7e-492c-b8c3-6ee81cd7f6d8","html_url":"https://github.com/mk-fg/ghg","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mk-fg/ghg","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mk-fg%2Fghg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mk-fg%2Fghg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mk-fg%2Fghg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mk-fg%2Fghg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mk-fg","download_url":"https://codeload.github.com/mk-fg/ghg/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mk-fg%2Fghg/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34232789,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-12T02:00:06.859Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["cli","cryptography","nacl","ocaml","security","tool"],"created_at":"2024-11-10T10:12:29.008Z","updated_at":"2026-06-12T06:31:25.282Z","avatar_url":"https://github.com/mk-fg.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"ghg\n===\n\nSimple command-line NaCl/libsodium file encryption tool.\n\nIntended to be a replacement for GnuPG_ file encryption mode (as in command-line\n\"gpg\" tool), based on modern libsodium_ crypto primitives like `NaCl crypto_box`_ and\nsecretstream_xchacha20poly1305, instead of an old/brittle/clunky ElGamal and AES-based stuff.\n\nAllows for an easy and efficient one-way file/pipe encryption from private to public\nkeys, and having lists of these, using any matching local private key(s) for decryption.\n\nUses short base64-encoded ed25519 public/private key strings.\n\nDoesn't require complex key/trust management stuff, which is more direct and manual here,\nthrough options or editing very simple YAML-like text file in ``/etc/ghg.yamlx`` (or path\nspecified via ``-c/--conf`` option).\n\nIt does not have any kind of gpg-agent/ssh-agent like stuff for key passphrases,\nnot intended for email encryption or authentication (signatures), no compression,\n\"web of trust\", signed keys or having images embedded in them - just easy-to-use\nfile encryption between public/private keys and some basic key agility, as mentioned.\n\nSame as with all crypto tools - use at your own risk, manage your trust\ncarefully and check/audit such stuff for basic sanity, at least.\n\nIs it Certified, Peer-Reviewed or blessed-by-EFF-and-Crypto-Jesus-himself? Hell no.\n\n------------\n\nThis tool was originally implemented as a python2 script (started in `mk-fg/fgtk repo`_),\nwhich used slightly different file format (which is still supported for decryption\nwith same keys), actual-YAML config (yuck), and had some extra options like stable encryption,\nparsing/using SSH ed25519 keys, etc, which only ended up being an unnecessary complication\nfor my use-cases.\nThat old script should be accessible via e.g. `commit c010639 here`_ for whatever legacy purposes.\n\n.. contents::\n  :backlinks: none\n\nThis repository URLs:\n\n- https://github.com/mk-fg/ghg\n- https://codeberg.org/mk-fg/ghg\n- https://fraggod.net/code/git/ghg\n\n\n\nUsage\n-----\n\nWith `ghg.example.yamlx \u003cghg.example.yamlx\u003e`_ config like this::\n\n  -keys: link.workstations\n  -keys-dec: link.old-key-2015-12-13 link.old-backup\n\n  workstations:\n    link.desktop\n    link.laptop\n  desktop: sk64.v81IAezQzuzZQ0e9LQk2eaMRNzTAyxFRAfW-qSK-svQ\n  laptop: pk64.mIkC20NfVcFLgKJ5bm5ck93BB55R0XjXTElbtKZ6zSs=\n\n  backup:\n    link.backup.storage-hosts\n    link.backup.offline-keys\n    sk64.M4GuROf3vNLZTAtHcgYPkO7gnC6sPFBSA67-CvV2Fc8=\n\n  backup.storage-hosts: link.backup.hostX link.backup.hostY\n  backup.hostX: pk64.DZqKsImH_Rizt38ariDw-jD-E9pXFbNQ38aoyKIIn2k\n  backup.hostY: pk64.NUcN-SC6rnqLv37d7I3gYnvBZP_Obb5R8ESifuILhe0=\n\n  backup.offline-keys:\n    pk64.PddqJWLx1T-XWD_tnbjb-uWJNgp8muQFK_jHhflGOGo=\n    pk64.QIRv0_7ke5H78A-xQTS4FEZKZ4IGeEfAYLoLeGug0B4\n    pk64.Mm4H27O739v-pB6WiLCnFHZZcoFqdvyNgCwl3nuZemw=\n\n  old-key-2015-12-13: sk64.gXNGcNgy22YxBTDb5wK0Cz8zpRNhjrs-aDLanbj22Fs=\n  old-backup: sk64.VBjFzFE93GtWwUqA4s7s5s_bEy-GW054t9gHPuIevZA=\n\n(`see config file in the repo`_ for comments describing format and all its features)\n\nHere are some usage examples::\n\n  % ghg -h\n  ...\n  ## Should describe how tool works and all supported options\n\n  % ghg -e secret-data.txt\n  % ghg -d secret-data.txt.ghg\n  ## Works same as gpg, replacing source files, but with .ghg suffix\n  ## -e/-d opts can be dropped - auto-detected from first bytes in a file\n\n  % ghg -e -r some-key-on-remote -r offline-backup-key secret-data.txt\n  ## Resulting file will be decryptable only with keys specified with -r\n\n  % ghg -e -r pk64.mIkC20NfVcFLgKJ5bm5ck93BB55R0XjXTElbtKZ6zSs= secret-data.txt\n  ## Public keys are allowed on the command-line, with same format as in config\n\n  % ls -lah /bin/blender\n  -rwxr-xr-x 1 root root 55M Nov  4 17:10 /bin/blender\n  % ghg \u003c/bin/blender \u003eblender.ghg\n  ## Encrypting large files should be fine (chunked), stdin/stdout work too\n  ## With neither -e/-d are specified, direction is auto-detected from file magic\n\n  % ghg -p my-other-key\n  pk64.itMXyr0tmn9HYz95YMPPLNmncE1bXQUnHK4qOco8bRQ\n  ## Print pubkey(s) (in \"pk64.*\" format) for specified/configured private key\n\n  % ghg -g\n  sk64.GfJUQ51_BwWtaqZknIX0Lh129hh_T3eDKzpx3RwV77c=\n  ## Generate and print new private key\n\n  % ghg -x3 somefile.ghg 3\u003c\u003c\u003c secret-argon2id-passphrase\n  ## Decrypt file using a key derived from secret key + extra argon2id passphrase\n\n  % ghg -x3 -k %4 somefile.ghg 3\u003c\u003c\u003c secret-argon2id-passphrase 4\u003c\u003c\u003c sk64.some-key\n  ## Same as above, but provide decryption private key via a file descriptor as well\n\nSome general knowledge about how asymetric crypto works is assumed on the part of the user,\nsuch as understanding of basic concepts like public and private keys, for example.\n\n\n\nInstallation\n------------\n\nThis is a small OCaml_ cli app with C bindings, which can be built using any\nmodern (4.13+) ocamlopt compiler and the usual make tool, with libsodium_ on the system::\n\n  % make\n  % ./ghg --help\n  Usage: ./ghg [opts] [file ...]\n  ...\n\nThat should produce ~1M binary, linked against libsodium (for actual crypto stuff),\nwhich can then be installed and copied between systems normally.\nOCaml compiler is only needed to build the tool, not to run it.\n\n``test.sh`` script (or ``make test``) can be used for a quick sanity-check after code\ntweaks, mostly adapted from an earlier script, with a bunch of leftover redundant tests.\n\n\n\nCrypto details\n--------------\n\nEncryption process in pseudocode::\n\n  file_plaintext = input_data\n  stable = input_stable_option\n  box_dst_pk_list, box_src_sk, box_src_pk = input_keys\n  argon_string, argon_opts = argon_cli_opts\n\n  enc_magic = '¯\\_ʻghgʻ_/¯'\n  enc_ver = '2'\n  enc_header_cap = '-'\n  enc_block_size = 16384\n  argon_salt = 'ghg.argon2id13.1'\n\n  if argon_string:\n    box_src_sk = crypto_pwhash(\n      box_src_sk || argon_string, argon_salt, argon_opts )\n    box_src_pk = crypto_scalarmult_base(box_src_sk)\n\n  sym_key = random(crypto_secretstream_xchacha20poly1305_KEYBYTES)\n\n  header = enc_magic || ' ' || enc_ver || ' ' || enc_header_cap || '\\n'\n  write(header)\n\n  for box_dst_pk in box_dst_pk_list:\n    box_nonce = random(crypto_box_NONCEBYTES)\n    key_slot_ct = crypto_box_easy(sym_key, box_nonce, box_src_sk, box_dst_pk)\n    key_slot = urlsafe_base64(box_src_pk || box_nonce || key_slot_ct)\n    write(key_slot || '\\n')\n\n  write('---\\n')\n\n  for chunk_plaintext in break_into_chunks(file_plaintext, enc_block_size):\n    chunk_ciphertext = crypto_secretstream_xchacha20poly1305(chunk_plaintext, sym_key)\n    write(chunk_ciphertext)\n\nSee libsodium_ docs for info on corresponding primitives there.\n\n\"enc_ver\" is encoded into \"header\" lines in case encryption algorithm might\nchange in the future.\n\nWeird \"enc_magic\" unicode stuff in the \"header\" is an arbitrary magic string to\nbe able to easily and kinda-reliably tell if file is encrypted by the presence\nof that.\n\nWhen decrypting file using bunch of available (configured) keys,\ncrypto_box_open_easy decryption is attempted for each \"key_slot\" line at the top\nusing all specified/configured private keys, until any of them works, or exiting\nwith failure otherwise.\n\ncrypto_secretstream_xchacha20poly1305 AEAD encryption should provide both\nsecrecy and integrity of the plaintext data, with no additional hmac's needed.\n\nOptional Argon2id (1.3) key derivation is performed on the used secret key(s),\nif argon options (fd to read passphrase from and difficulty/memory factors)\nare specified on the command line, which effectively replaces secret key(s)\nbeing used, with one(s) returned from crypto_pwhash().\n\nUnlike gpg, this tool explicitly doesn't do compression, which can be applied\nbefore encryption manually (encypted data is pretty much incompressible),\nbut do keep in mind that it inevitably leaks information about plaintext,\nwhich is especially bad if attacker has control over any part of it\n(see issues with compression in TLS for examples).\n\n\n\nLinks\n-----\n\n- `age \u003chttps://github.com/FiloSottile/age\u003e`_\n\n  More recent tool similar to an older python2 ghg script here, with a lot more\n  features than current ghg.ml, but also a lot more unnecessary junk and dependencies.\n\n  Considered migrating to it (or its `rage \u003chttps://github.com/str4d/rage\u003e`_ rewrite) myself,\n  but couldn't justify extra complexity that involves, and wanted backwards compability with\n  the old format of the script here, but those shouldn't apply to new uses, so check it out.\n\n- `minisign \u003chttps://jedisct1.github.io/minisign/\u003e`_\n\n  Tool for generating signatures for files/data instead of encryption.\n\n- `Earlier python2 ghg script \u003chttps://github.com/mk-fg/ghg/blob/c010639/ghg\u003e`_\n\n  Should only be useful for some legacy purposes.\n\n\n\n.. _GnuPG: https://www.gnupg.org/\n.. _libsodium: https://libsodium.gitbook.io/\n.. _NaCl crypto_box: http://nacl.cr.yp.to/box.html\n.. _mk-fg/fgtk repo: https://github.com/mk-fg/fgtk\n.. _commit c010639 here: https://github.com/mk-fg/ghg/blob/c010639/ghg\n.. _ghg.example.yamlx: ghg.example.yamlx\n.. _see config file in the repo: ghg.example.yamlx\n.. _OCaml: https://ocaml.org/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmk-fg%2Fghg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmk-fg%2Fghg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmk-fg%2Fghg/lists"}