Git Product home page Git Product logo

age-plugin-sss's Introduction

age-plugin-sss

⚠️ Consider this plugin to be experimental until the version v1.0.0 is published! Open for feedback and improvements. Disclaimer: This is my first project in Go. ⚠️


✂️ Split encryption keys and encrypt key shares with different age (licensed BSD 3-Clause) recipients.

🛂 Create (complex) policies about which combinations of identites can decrypt the file.

📌 Uses Hashicorp Vault's implementation of Shamir's Secret Sharing (licensed MPL-2.0).

📝 See SPEC.md for more details.


Installation

Requirements

Download/Install Binary

Download a the latest binary from the release page. Copy the binary to your $PATH (preferably in $(which age)) and make sure it's executable.

You can also use the following script for installation:

  • Installs binary to ~/.local/bin/age-plugin-sss (change to your preferred directory)
  • Make sure to adjust OS and ARCH if needed (OS=darwin ARCH=arm64 for Apple Silicon, OS=darwin ARCH=amd64 for older Macs)
cd "$(mktemp -d)"
VERSION=v0.2.5 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
tar -xzf age-plugin-sss.tar.gz
mv age-plugin-sss/age-plugin-sss ~/.local/bin

Please 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.

Build from source

Alternatively the plugin can be built from source. Simply run

go build -v ./cmd/...

and copy the binary age-plugin-sss to a directory of your $PATH.

Usage

Basic Usage

Encryption

First, define a policy in YAML format:

threshold: 2
shares:
  - age1t7cexdfjmkk4fgsf6pgzhn0skk0qewxr9y7tdu3l639fdmptcaxqv3nznt
  - age1jcq99v6f74gwstqhg2vsll5s3rckdys8ttr2nnrzpegxu0y533vqnf7d2u
  - age1zunvd6ztdeljcxzhe70370cx5q54czyhy2qjgsnju9rsyjaexqqqfrxg2w

In 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.

You can not only use native age recipients (see below how to handle passwords), but also plugin or SSH recipients.

Next, generate a new recipient from this policy file:

$ age-plugin-sss --generate-recipient policy.yaml
age1sss1r79ssqqqqqqqqq8l2nxy6m5yyq2qpc9mkz0q2pv4uf2e5tsv0urpec5rqupvdwmhm8xqt05mypvanzmyktldcfy3j4kvul9p2znxn67ly9xdvedmn3hwey0xzq5f32e9myz74s50s496hhe842k5ret3gsjvl6ul7y92ftytzkfmkvkzaevvm3e3v709f5pa0u3jv9nrr2nhrtws8ee4ug2659vljczx392j7qa48x7x5cehsfeyz4vmvx0df6rmvls9mr47ez2thh6vqvqfhxnrzauha8alqqqqplll80huf5hzqqqqq3csvcr

As you can see, recipients for this plugin can be quite long because they contain multiple other recipients used for encrypting key shares.

Now you can use this recipient to encrypt anything, e.g.

echo "it works" | age -r age1sss1r79ssqqqqqqqqq8l2nxy6m5yyq2qpc9mkz0q2pv4uf2e5tsv0urpec5rqupvdwmhm8xqt05mypvanzmyktldcfy3j4kvul9p2znxn67ly9xdvedmn3hwey0xzq5f32e9myz74s50s496hhe842k5ret3gsjvl6ul7y92ftytzkfmkvkzaevvm3e3v709f5pa0u3jv9nrr2nhrtws8ee4ug2659vljczx392j7qa48x7x5cehsfeyz4vmvx0df6rmvls9mr47ez2thh6vqvqfhxnrzauha8alqqqqplll80huf5hzqqqqq3csvcr -o testing.enc

Decryption

First, define a new YAML file containing the identities to use for decryption with the following structure:

identities:
  - AGE-SECRET-KEY-1XUR5...
  - AGE-SECRET-KEY-17FXT...

This 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.

Next, generate an identity from the YAML file (similarly as done for recipients):

age-plugin-sss --generate-identity example-id.yaml > id.txt

Finally, the encrypted file can be decrypted with the generated identity:

$ age -d -i id.txt testing.enc
it works

Advanced Usage

(More) Complex Policies

Let'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:

threshold: 2
shares:
  - age1t7cexdfjmkk4fgsf6pgzhn0skk0qewxr9y7tdu3l639fdmptcaxqv3nznt
  - threshold: 1
    shares:
      - age1fido2-hmac1qqa...
      - age1fido2-hmac1qqb...

You 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.

Pinning identities to a specific share

You 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:

$ age-plugin-sss --inspect test.enc
sss (t=2)
 ├─ x25519 [id=1]
 └─ sss (t=1)
     ├─ fido2-hmac [id=2]
     └─ fido2-hmac [id=3]

For 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:

identities:
  - AGE-SECRET-KEY-1XUR5...
  - share_id: 3
    identity: AGE-PLUGIN-FIDO2-HMAC-1VE5KGMEJ945X6CTRM2TF76

SSH Recipients/Identities

It'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.

Example:

# recipient.yaml
threshold: 1
shares:
  - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL84xOFSWXIcAeQK8CJ0qvHojdFZDuLGRe5FPg4aM3kY testing@local
# identity.yaml
identities:
  - |
    -----BEGIN OPENSSH PRIVATE KEY-----
    b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
    QyNTUxOQAAACC/OMThUllyHAHkCvAidKrx6I3RWQ7ixkXuRT4OGjN5GAAAAKCxGCybsRgs
    mwAAAAtzc2gtZWQyNTUxOQAAACC/OMThUllyHAHkCvAidKrx6I3RWQ7ixkXuRT4OGjN5GA
    AAAEBqlzBxbT+cd7xs19UN6ZFKG2bb4vtoR6/7FHt7yJ4DZ784xOFSWXIcAeQK8CJ0qvHo
    jdFZDuLGRe5FPg4aM3kYAAAAGnNlYmFzdGlhbkBmZWRvcmEuZnJpdHouYm94AQID
    -----END OPENSSH PRIVATE KEY-----

If 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). This issue is tracked in #3.

Passwords

Let'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-<name-or-slug>, e.g.

threshold: 3
shares:
  - password-alice
  - password-bob
  - password-chris

The plugin will ask you for each password upon encryption. Please notice that

  • 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.
  • 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.

Converting recipients/identities back to YAML

You can always decode a recipient or identity with the --decode flag by passing the string via STDIN:

$ cat recipient.txt | age-plugin-sss --decode
threshold: 2
shares:
    - recipient: age1t7cexdfjmkk4fgsf6pgzhn0skk0qewxr9y7tdu3l639fdmptcaxqv3nznt
    - recipient: age1jcq99v6f74gwstqhg2vsll5s3rckdys8ttr2nnrzpegxu0y533vqnf7d2u
    - recipient: age1zunvd6ztdeljcxzhe70370cx5q54czyhy2qjgsnju9rsyjaexqqqfrxg2w

Using the same recipient multiple times

It'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.

age-plugin-sss's People

Contributors

dependabot[bot] avatar olastor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

age-plugin-sss's Issues

Fix flakey test

testscript -v ./testdata/simple.txt for some mysterious reason randomly gets stuck without printing anything. Seems to be an issue with testscript rather than the plugin code.

SSH Recipients / Identities

SSH recipients / identities are currently not supported, but it would be very nice to include them. The main obstacle seems to be that in the case of encrypted identity files, both the public and private key need to be known. However, at decryption getting the public key is not straight forward and needs further investigation. Maybe one of the following options works:

  • Derive public key from private key (not possible because it's password protected most likely)
  • Find matching public key in stanza (how to match it with the encrypted ssh key?)
  • User must provide both public/private key in SSS identity (worsens UX)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.