Code Monkey home page Code Monkey logo

age-plugin-tpm's Introduction

TPM plugin for age clients

age-plugin-tpm is a plugin for age clients like age and rage, which enables files to be encrypted to age identities sealed by the TPM.

Features

  • Keys created on the TPM, sealed outside of it
  • PIN support
  • TPM session encryption

Experimental

The identity format and technical details might change between iterations. Consider this plugin experimental.

Instead of utilizing the TPM directly, you can use --swtpm or export AGE_TPM_SWTPM=1 to create a identity backed by swtpm which will be stored under /var/tmp/age-plugin-tpm.

Note that swtpm provides no security properties and should only be used for testing.

Installation

The simplest way of installing this plugin is by running the follow go command.

go install github.com/foxboron/age-plugin-tpm/cmd/age-plugin-tpm@latest

Alternatively download the pre-built binaries.

Usage

# Create identity
$ age-plugin-tpm --generate -o age-identity.txt
$ age-plugin-tpm -y age-identity.txt > age-recipient.txt

# Encrypt / Decrypt something
$ echo "Hack The Planet" | age -R ./age-recipient.txt -o test-decrypt.txt
$ age --decrypt -i ./age-identity.txt -o - test-decrypt.txt
Hack The Planet!

With PIN

# Create identity
$ AGE_TPM_PIN=123 age-plugin-tpm --generate --pin -o age-identity.txt
$ age-plugin-tpm -y age-identity > age-recipient.txt

# Encrypt / Decrypt something
$ echo "Hack The Planet" | age -R ./age-recipient.txt -o test-decrypt.txt
$ AGE_TPM_PIN=123 age --decrypt -i ./age-identity.txt -o - test-decrypt.txt
Hack The Planet!

Commands

An age identity can be created with:

$ age-plugin-tpm --generate -o age-identity.txt
# Created: 2023-07-05 22:38:36.362043774 +0200 CEST m=+0.110154231
# Recipient: age1tpm1qg86fn5esp30u9h6jy6zvu9gcsvnac09vn8jzjxt8s3qtlcv5h2x287wm36

AGE-PLUGIN-TPM-1QYQSQLSQYZJN56KJ4WHGP676AW248W7Z3KE7JRP8HWGGTW98CX955U9NCV4G2QQS828ZMZNQLLC57QU037ELMLA0RR56SM35HLJAFHKY0EH7J62SYJLX3YFULEE7AQJR0DJX7D33HRKWRYHNXFN0TRS45MKUHZGRU3K3EPRUSGSWWV07K2PKTFF79YVACDZSVEKAYY4GEAM6DRNQQPTQQGCQPVQQYQRJQQQQQYQQZQQQXQQSQQSQLFXWNXQX9LSKL2GNGFNS4RZPJ0HPU4JV7G2GEV7ZYP0LPJJAGEGQYQE8GSEC0GWWDVKAFT04QTJWCU3T2KYVXGER35FVMHEY0ZDGEHC4C0EXJ8Y

To display the recipient of a given identity:

$ age-plugin-tpm -y age-identity.txt
age1tpm1qg86fn5esp30u9h6jy6zvu9gcsvnac09vn8jzjxt8s3qtlcv5h2x287wm36

License

Licensed under the MIT license. See LICENSE or http://opensource.org/licenses/MIT

age-plugin-tpm's People

Contributors

cosmicpegasis avatar filosottile avatar foxboron avatar quite avatar stigtsp avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar  avatar

age-plugin-tpm's Issues

Is matrix ?

Hey @Foxboron

want to use this on windows. Mac and Linux.

Any ideas what OS types are supported ? You’re using Google’s tpm package I see .

also planning to build a basic gui with basic query capabilities with gioui

Save the key context outside of the TPM

Since TPM keys are deterministic we can actually save the key context outside of the TPM isntead of a persistent handle. This saves resources on the limited hardware with the downside that the host is storing a blob.

Would need to use tpm2.ContextSave instead of tpm2.EvictControl without key handle. Then we need to use tpm2.ContextLoad before using the key again.

Encrypting with multiple recipients results in an error upon decryption

Test case:

# Generate a key inside of a TPM
$ age-plugin-tpm -g > age-tpm.txt

# Generate a 1KB plaintext and encrypt it
$ dd if=/dev/urandom bs=1024 count=1 | age -a -r "$(age-plugin-tpm -l | tail -n1)" > test.txt.age
1+0 records in
1+0 records out
1024 bytes (1.0 kB, 1.0 KiB) copied, 4.4513e-05 s, 23.0 MB/s

# Try decrypting it
$ cat test.txt.age | age -d -i age-tpm.txt | wc -c
1024

# Generate another 1KB plaintext and try to encrypt it to multiple keys
$ dd if=/dev/urandom bs=1024 count=1 | age -a -r "$(age-plugin-tpm -l | tail -n1)" -r "$(age-keygen 2>/dev/null | age-keygen -y)" > test.txt.age
1+0 records in
1+0 records out
1024 bytes (1.0 kB, 1.0 KiB) copied, 4.2366e-05 s, 24.2 MB/s

# Try to decrypt it... wait, what?!
$ cat test.txt.age | age -d -i age-tpm.txt
age: error: tpm plugin: failed to read line: EOF
age: report unexpected or unhelpful errors at https://filippo.io/age/report

# `rage` also fails:
$ cat test.txt.age | rage -d -i age-tpm.txt
Error: incomplete response

[ Did rage not do what you expected? Could an error be more useful? ]
[ Tell us: https://str4d.xyz/rage/report                            ]

# Interestingly, if a file is encrypted with rage, it is unable to be decrypted at all:
$ dd if=/dev/urandom bs=1024 count=1 | rage -a -r "$(age-plugin-tpm -l | tail -n1)" > test.txt.age
1+0 records in
1+0 records out
1024 bytes (1.0 kB, 1.0 KiB) copied, 4.4326e-05 s, 23.1 MB/s

$ cat test.txt.age | age -d -i age-tpm.txt
age: error: tpm plugin: failed to read line: EOF
age: report unexpected or unhelpful errors at https://filippo.io/age/report

$ cat test.txt.age | rage -d -i age-tpm.txt
Error: incomplete response

[ Did rage not do what you expected? Could an error be more useful? ]
[ Tell us: https://str4d.xyz/rage/report                            ]

Note that in case of multiple keys encrypting a message, other keys decrypt the message successfully, no matter what it's encrypted with.

Implement a key tag

age-plugin-yubikey implements a tag as part of the piv-p256 stanza that is essentially a truncated sha256sum of the key bytes.

I think it's mainly used as a simple canary to ensure the correct key is used?

Support pins for the keys

We should support pins for the key we create. This should be supplyable through -p, --pin or the environment variable AGE_PLUGIN_TPM_KEY_PIN.

Program fails when encrypting when there is no permission to the TPM

On a completely unrelated machine to the one with the actual keys on it; a machine which does not have the TPM configured to be accessible to the user, this happens when I encrypt a file. I don't expect this to happen when I try to encrypt a file, since I only should need the public key and not the actual tpm. Indeed, when I gave myself permission to the tpm, it encrypted fine.

/tmp/recipients.txt:

age1tpm1qgfe8w2vrkrerx9eyc8yjsluelas9l62nm0g72cuzcspxlu8t70a5znvftj
[jade@snowflake:~/.dotfiles/configs/nix]$ AGEDEBUG=plugin rage -R /tmp/recipients.txt -e flake.nix > /tmp/nya
-> add-recipient age1tpm1qgfe8w2vrkrerx9eyc8yjsluelas9l62nm0g72cuzcspxlu8t70a5znvftj

-> wrap-file-key
JfGaksEZOwWERXUhkDd2kw
-> done

Error: open /dev/tpmrm0: permission denied
Usage:
  age-plugin-tpm [flags]

Examples:

  $ age-plugin-tpm --generate -o age-identity.txt
  # Created: 2023-07-10 22:13:57.864450969 +0200 CEST m=+0.475252114
  # Recipient: age1tpm1qt92lcdxj75rjz9e4t9nud7fv6t2cfn8rhzdfnc0z2rnfgv3cqwrqgme4dq

  AGE-PLUGIN-TPM-1QYQQQKQQYVQQKQQZQPEQQQQQZQQPJQQTQQPSQYQQYR92LCDXJ75RJZ9E4T9NUD7[...]

  $ echo "Hello World" | age -r "age1tpm1syqqqpqrtxsnkkqlmu505zzrq439hetls4qwwmyhsv8dgjhks
vtewvx29lxs7s68qy" > secret.age

  $ age --decrypt -i age-identity.txt -o - secret.age
  Hello World

Flags:
  -y, --convert           Convert identities to recipients.
  -o, --output string     Write the result to the file.
  -g, --generate          Generate a identity.
  -p, --pin               Include a pin with the key. Alternatively export AGE_TPM_PIN.
      --log-file string   Logging file for debug output
      --swtpm             Use a software TPM for key storage (Testing only and requires sw
tpm installed)
  -h, --help              help for age-plugin-tpm

2024/02/15 16:56:18 open /dev/tpmrm0: permission denied
Error: 'age-plugin-tpm' unexpectedly died.
If you are developing a plugin, run with AGEDEBUG=plugin for more information.
Warning: this prints private encryption key material to standard error.

[ Did rage not do what you expected? Could an error be more useful? ]
[ Tell us: https://str4d.xyz/rage/report                            ]

Version: 0.2.0 from nixpkgs.

Create ephemeral TPM keys on the recipient side

Currently age-plugin-tpm makes ephemeral NIST P256 key in software when the someone encrypt something with the recipient.

There is probably(?) nothing stopping us from creating an ephemeral key inside the TPM on the remote side and use this for ECDH.

We could make this toggle-able if this is not something the remote end wants.

Sealing keys with PCRs

It would be nice if we could also seal the keys given a set of PCR values.

Even nicer would be support for FAPI policies which could be provided in a JSON file. But I currently see no FAPI support in go-tpm. So its probably quite difficult to implement this without tpm2-tss's Fapi_Import()?

Move prompts to stderr

I think it would be better to print prompts like

pin, err = GetPin("Enter pin for key:")
if err != nil {
return err
}
clearLine(os.Stdin)
confirm, err := GetPin("Confirm pin:")
if err != nil {
return err
}
to stderr, as is common in POSIX applications.

This became problematic for me when I was trying the following:

age-plugin-tpm --generate --pin > test.tpm

And the prompt didn't show

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.