{"id":13781517,"url":"https://github.com/olastor/age-plugin-sss","last_synced_at":"2026-01-16T23:57:05.058Z","repository":{"id":215946847,"uuid":"734850418","full_name":"olastor/age-plugin-sss","owner":"olastor","description":"Age plugin to split keys and wrap them with different recipients using Shamir's Secret Sharing.","archived":false,"fork":false,"pushed_at":"2025-12-30T20:14:26.000Z","size":88,"stargazers_count":48,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-03T18:26:15.808Z","etag":null,"topics":["age","age-encryption","age-plugin","plugin","shamir"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/olastor.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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-12-22T20:02:33.000Z","updated_at":"2026-01-01T19:52:21.000Z","dependencies_parsed_at":"2025-12-28T16:05:57.676Z","dependency_job_id":null,"html_url":"https://github.com/olastor/age-plugin-sss","commit_stats":null,"previous_names":["olastor/age-plugin-sss"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/olastor/age-plugin-sss","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olastor%2Fage-plugin-sss","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olastor%2Fage-plugin-sss/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olastor%2Fage-plugin-sss/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olastor%2Fage-plugin-sss/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/olastor","download_url":"https://codeload.github.com/olastor/age-plugin-sss/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olastor%2Fage-plugin-sss/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28489472,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T23:55:29.509Z","status":"ssl_error","status_checked_at":"2026-01-16T23:55:29.108Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["age","age-encryption","age-plugin","plugin","shamir"],"created_at":"2024-08-03T18:01:26.678Z","updated_at":"2026-01-16T23:57:05.053Z","avatar_url":"https://github.com/olastor.png","language":"Go","funding_links":[],"categories":["Plugins","Go"],"sub_categories":[],"readme":"# age-plugin-sss\n\n\u003e [!WARNING]\n\u003e Consider this plugin to be experimental until the version v1.0.0 is published! Open for feedback and improvements.\n\n---\n\n:scissors: Split encryption keys and encrypt key shares with different [age](https://github.com/FiloSottile/age) (licensed BSD 3-Clause) recipients.\n\n:passport_control: Create (complex) policies about which combinations of identites can decrypt the file.\n\n:pushpin: Uses Hashicorp Vault's [implementation](https://github.com/hashicorp/vault/blob/main/shamir/shamir.go) of Shamir's Secret Sharing (licensed MPL-2.0).\n\n:memo: See [SPEC.md](https://github.com/olastor/age-plugin-sss/blob/main/SPEC.md) for more details.\n\n---\n\n## Installation\n\n### Requirements\n\n- [age](https://github.com/FiloSottile/age) (\u003e= 1.1.0) or [rage](https://github.com/str4d/rage)\n\n### Download/Install Binary\n\nDownload a the latest binary from the [release page](https://github.com/olastor/age-plugin-sss/releases). Copy the binary to your `$PATH` (preferably in `$(which age)`) and make sure it's executable.\n\nYou can also use the following script for installation:\n\n- Installs binary to `~/.local/bin/age-plugin-sss` (change to your preferred directory)\n- Make sure to adjust `OS` and `ARCH` if needed (`OS=darwin ARCH=arm64` for Apple Silicon, `OS=darwin ARCH=amd64` for older Macs)\n\n```bash\ncd \"$(mktemp -d)\"\nVERSION=v0.3.1 OS=linux ARCH=amd64; curl -L \"https://github.com/olastor/age-plugin-sss/releases/download/$VERSION/age-plugin-sss-$VERSION-$OS-$ARCH.tar.gz\" -o age-plugin-sss.tar.gz\ntar -xzf age-plugin-sss.tar.gz\nmv age-plugin-sss/age-plugin-sss ~/.local/bin\n```\n\nPlease note that Windows builds are currently not enabled, but if you need them please open a new issue and I'll try to look into it.\n\n### Build from source\n\nAlternatively the plugin can be built from source. Simply run\n\n```bash\nmake build\n```\nand copy the binary `age-plugin-sss` to a directory of your `$PATH`.\n\n## Usage\n\n### Basic Usage\n\n#### Encryption\n\nFirst, define a policy in YAML format:\n\n```yaml\nthreshold: 2\nshares:\n  - age1t7cexdfjmkk4fgsf6pgzhn0skk0qewxr9y7tdu3l639fdmptcaxqv3nznt\n  - age1jcq99v6f74gwstqhg2vsll5s3rckdys8ttr2nnrzpegxu0y533vqnf7d2u\n  - age1zunvd6ztdeljcxzhe70370cx5q54czyhy2qjgsnju9rsyjaexqqqfrxg2w\n```\n\nIn this case, the file key will be split into three shares, each of which will be encrypted with one of the three recipients in the `shares` array. The `threshold` specifies how many of the shares are required to decrypt the file again. For our example, any two identities that correspond to a recipient in the list will suffice.\n\nYou can not only use native age recipients (see below how to handle passwords), but also plugin or SSH recipients.\n\nNext, generate a new recipient from this policy file:\n\n```bash\n$ age-plugin-sss --generate-recipient policy.yaml\nage1sss1r79ssqqqqqqqqq8l2nxy6m5yyq2qpc9mkz0q2pv4uf2e5tsv0urpec5rqupvdwmhm8xqt05mypvanzmyktldcfy3j4kvul9p2znxn67ly9xdvedmn3hwey0xzq5f32e9myz74s50s496hhe842k5ret3gsjvl6ul7y92ftytzkfmkvkzaevvm3e3v709f5pa0u3jv9nrr2nhrtws8ee4ug2659vljczx392j7qa48x7x5cehsfeyz4vmvx0df6rmvls9mr47ez2thh6vqvqfhxnrzauha8alqqqqplll80huf5hzqqqqq3csvcr\n```\n\nAs you can see, recipients for this plugin can be quite long because they contain multiple other recipients used for encrypting key shares.\n\nNow you can use this recipient to encrypt anything, e.g.\n\n```bash\necho \"it works\" | age -r age1sss1r79ssqqqqqqqqq8l2nxy6m5yyq2qpc9mkz0q2pv4uf2e5tsv0urpec5rqupvdwmhm8xqt05mypvanzmyktldcfy3j4kvul9p2znxn67ly9xdvedmn3hwey0xzq5f32e9myz74s50s496hhe842k5ret3gsjvl6ul7y92ftytzkfmkvkzaevvm3e3v709f5pa0u3jv9nrr2nhrtws8ee4ug2659vljczx392j7qa48x7x5cehsfeyz4vmvx0df6rmvls9mr47ez2thh6vqvqfhxnrzauha8alqqqqplll80huf5hzqqqqq3csvcr -o testing.enc\n```\n\n#### Decryption\n\nFirst, define a new YAML file containing the identities to use for decryption with the following structure:\n\n```yaml\nidentities:\n  - AGE-SECRET-KEY-1XUR5...\n  - AGE-SECRET-KEY-17FXT...\n```\n\nThis file only contains a flat list of identities. The structure of the policy (or order of shares) is not replicated here and thresholds or other information do not need to be included. There must be enough valid identities to meet the secret splitting threshold, though.\n\nNext, generate an identity from the YAML file (similarly as done for recipients):\n\n```bash\nage-plugin-sss --generate-identity example-id.yaml \u003e id.txt\n```\n\nFinally, the encrypted file can be decrypted with the generated identity:\n\n```bash\n$ age -d -i id.txt testing.enc\nit works\n```\n\n### Advanced Usage\n\n#### (More) Complex Policies\n\nLet's say you want to encrypt a file so that in addition to your X25519 identity you also need one of two fido2 keys for decryption. This can be achived by adding a nested policy in one of the shares as such:\n\n```yaml\nthreshold: 2\nshares:\n  - age1t7cexdfjmkk4fgsf6pgzhn0skk0qewxr9y7tdu3l639fdmptcaxqv3nznt\n  - threshold: 1\n    shares:\n      - age1fido2-hmac1qqa...\n      - age1fido2-hmac1qqb...\n```\n\nYou can add as many nested level as you want. Please notice, however, that for decryption the (sss-)plugin might ask you which share to decrypt in the case of plugin recipients/identities interactively and that the recipient string encoding the policy will be rather long.\n\n#### Pinning identities to a specific share\n\nYou can bypass the user interaction for selecting the share if the plugin is unsure about which one to choose by specifying a `share_id` in your identity file. To find out which share in the policy tree you want to target, you can inspect the policy of the encrypted file with the following command:\n\n```\n$ age-plugin-sss --inspect test.enc\nsss (t=2)\n ├─ x25519 [id=1]\n └─ sss (t=1)\n     ├─ fido2-hmac [id=2]\n     └─ fido2-hmac [id=3]\n```\n\nFor example, you may only want to use one of your fido2 tokens for decryption because the other one is only a backup. In your identity YAML file, simply pin the `share_id` to the correct one:\n\n```yaml\nidentities:\n  - AGE-SECRET-KEY-1XUR5...\n  - share_id: 3\n    identity: AGE-PLUGIN-FIDO2-HMAC-1VE5KGMEJ945X6CTRM2TF76\n```\n\n#### SSH Recipients/Identities\n\nIt's also possible to include an SSH public key in a policy and an SSH private key in an identity. Make sure to use YAML's multi-line string formatting for the identity.\n\n**Example:**\n\n```yaml\n# recipient.yaml\nthreshold: 1\nshares:\n  - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL84xOFSWXIcAeQK8CJ0qvHojdFZDuLGRe5FPg4aM3kY testing@local\n```\n\n```yaml\n# identity.yaml\nidentities:\n  - |\n    -----BEGIN OPENSSH PRIVATE KEY-----\n    b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n    QyNTUxOQAAACC/OMThUllyHAHkCvAidKrx6I3RWQ7ixkXuRT4OGjN5GAAAAKCxGCybsRgs\n    mwAAAAtzc2gtZWQyNTUxOQAAACC/OMThUllyHAHkCvAidKrx6I3RWQ7ixkXuRT4OGjN5GA\n    AAAEBqlzBxbT+cd7xs19UN6ZFKG2bb4vtoR6/7FHt7yJ4DZ784xOFSWXIcAeQK8CJ0qvHo\n    jdFZDuLGRe5FPg4aM3kYAAAAGnNlYmFzdGlhbkBmZWRvcmEuZnJpdHouYm94AQID\n    -----END OPENSSH PRIVATE KEY-----\n```\n\nIf the private key is passphrase-protected, you will be prompted for the password, **but only if the encrypted private key contains the public key**. Otherwise, you'll need to create a version of your private key that is not passphrase encrypted (see [here](https://stackoverflow.com/a/112409)). This issue is tracked in [#3](https://github.com/olastor/age-plugin-sss/issues/3).\n\n#### Passwords\n\nLet's say you want to split the encryption key into shares wrapped by different passwords. As there is no recipient string you can generate, you must provide a special keyword of the form `password-\u003cname-or-slug\u003e`, e.g.\n\n```yaml\nthreshold: 3\nshares:\n  - password-alice\n  - password-bob\n  - password-chris\n```\n\nThe plugin will ask you for each password upon encryption. Please notice that\n\n- the name/slug is required, but it is not persisted in the encrypted file. It's only there for you to not confuse passwords when interacting with the cli.\n- the name/slug is mandatory for encryption, but optional for decryption (as the plugin will try all password stanzas until it finds the correct one). So having one or multiple identities named `password` is fine.\n\n#### Converting recipients/identities back to YAML\n\nYou can always decode a recipient or identity with the `--decode` flag by passing the string via STDIN:\n\n```bash\n$ cat recipient.txt | age-plugin-sss --decode\nthreshold: 2\nshares:\n    - recipient: age1t7cexdfjmkk4fgsf6pgzhn0skk0qewxr9y7tdu3l639fdmptcaxqv3nznt\n    - recipient: age1jcq99v6f74gwstqhg2vsll5s3rckdys8ttr2nnrzpegxu0y533vqnf7d2u\n    - recipient: age1zunvd6ztdeljcxzhe70370cx5q54czyhy2qjgsnju9rsyjaexqqqfrxg2w\n```\n\n#### Using the same recipient multiple times\n\nIt's totally valid to define the same recipient more than once anywhere inside a policy. However, when decrypting you must list the same identity multiple times, as well. This is because with the current design the plugin assumes that one identity only unwraps one share. For plugin identities, you may also consider specifying the `share_id` in your identity YAML file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folastor%2Fage-plugin-sss","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Folastor%2Fage-plugin-sss","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folastor%2Fage-plugin-sss/lists"}