File: recipient.go

package info (click to toggle)
age-plugin-tpm 1.0.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 196 kB
  • sloc: makefile: 23
file content (91 lines) | stat: -rw-r--r-- 2,023 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package plugin

import (
	"crypto/ecdh"
	"crypto/sha256"
	"fmt"
	"io"

	"filippo.io/age"
	"filippo.io/age/plugin"
	"filippo.io/age/tag"
	"filippo.io/nistec"
	"github.com/google/go-tpm/tpm2"
)

func NewTagRecipientFromBytes(s []byte) (*tag.Recipient, error) {
	ecdhKey, err := PublicToECDH(tpm2.BytesAs2B[tpm2.TPMTPublic](s))
	if err != nil {
		return nil, err
	}
	return NewTagRecipient(ecdhKey)
}

func NewTagRecipient(ecc *ecdh.PublicKey) (*tag.Recipient, error) {
	return tag.NewClassicRecipient(MarshalCompressedEC(ecc))
}

type TPMRecipient struct {
	Pubkey *ecdh.PublicKey
	tag    []byte
}

func (r *TPMRecipient) Tag() []byte {
	return r.tag
}

func (r *TPMRecipient) Bytes() []byte {
	p, err := nistec.NewP256Point().SetBytes(r.Pubkey.Bytes())
	if err != nil {
		panic("internal error: invalid P-256 public key")
	}
	return p.BytesCompressed()
}

func (r *TPMRecipient) String() string {
	return plugin.EncodeRecipient(PluginName, r.Bytes())
}

func (r *TPMRecipient) Wrap(fileKey []byte) ([]*age.Stanza, error) {
	wrapped, sessionKey, err := EncryptFileKey(fileKey, r.Pubkey)
	if err != nil {
		return nil, err
	}
	return []*age.Stanza{{
		Type: "tpm-ecc",
		Args: []string{b64Encode(r.Tag()), b64Encode(sessionKey)},
		Body: wrapped,
	}}, nil
}

func NewTPMRecipient(ecc *ecdh.PublicKey) *TPMRecipient {
	sum := sha256.Sum256(ecc.Bytes())
	return &TPMRecipient{
		Pubkey: ecc,
		tag:    sum[:4],
	}
}

func ParseTPMRecipient(s string) (*TPMRecipient, error) {
	name, b, err := plugin.ParseRecipient(s)
	if err != nil {
		return nil, fmt.Errorf("failed to decode recipient: %v", err)
	}
	if name != PluginName {
		return nil, fmt.Errorf("invalid plugin for type %s", name)
	}
	p, err := nistec.NewP256Point().SetBytes(b)
	if err != nil {
		return nil, err
	}
	pubkey, err := ecdh.P256().NewPublicKey(p.Bytes())
	if err != nil {
		return nil, err
	}
	return NewTPMRecipient(pubkey), nil
}

func MarshalRecipient(recipient fmt.Stringer, w io.Writer) error {
	fmt.Fprintf(w, "%s\n", recipient.String())
	return nil
}