forked from emersion/neutron
/
keys.go
127 lines (103 loc) · 2.53 KB
/
keys.go
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package backend
import (
"bytes"
"errors"
"strings"
"io"
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/armor"
)
type KeysBackend interface {
// Get a public key for a user.
// If no key is available, an empty string and no error must be returned.
GetPublicKey(email string) (string, error)
// Get a keypair for a user. Contains public & private key.
GetKeypair(email string) (*Keypair, error)
// Create a new keypair.
InsertKeypair(email string, keypair *Keypair) (*Keypair, error)
// Update a user's private key.
// PublicKey must be updated only if it isn't empty.
UpdateKeypair(email string, keypair *Keypair) (*Keypair, error)
}
const PgpMessageType = "PGP MESSAGE"
// Encode a PGP message armor.
func ArmorMessage(w io.Writer) (io.WriteCloser, error) {
return armor.Encode(w, PgpMessageType, map[string]string{})
}
// A keypair contains a private and a public key.
type Keypair struct {
ID string
PublicKey string
PrivateKey string
Fingerprint string // TODO: populate this field
}
func (kp *Keypair) getPrivateKey() (entity *openpgp.Entity, err error) {
entitiesList, err := openpgp.ReadArmoredKeyRing(strings.NewReader(kp.PrivateKey))
if err != nil {
return
}
if len(entitiesList) == 0 {
err = errors.New("Key ring does not contain any key")
return
}
entity = entitiesList[0]
return
}
// Encrypt a message to the keypair's owner.
func (kp *Keypair) Encrypt(data string) (encrypted string, err error) {
entity, err := kp.getPrivateKey()
if err != nil {
return
}
var b bytes.Buffer
armorWriter, err := ArmorMessage(&b)
if err != nil {
return
}
w, err := openpgp.Encrypt(armorWriter, []*openpgp.Entity{entity}, nil, nil, nil)
if err != nil {
return
}
w.Write([]byte(data))
w.Close()
armorWriter.Close()
encrypted = b.String()
return
}
// Read public key from private key
func (kp *Keypair) readPublicKey() (err error) {
entity, err := kp.getPrivateKey()
if err != nil {
return
}
var b bytes.Buffer
w, err := armor.Encode(&b, openpgp.PublicKeyType, nil)
if err != nil {
return
}
err = entity.Serialize(w)
if err != nil {
return
}
w.Close()
kp.PublicKey = b.String()
return
}
// Create a new keypair.
func NewKeypair(pub, priv string) *Keypair {
kp := &Keypair{
PublicKey: pub,
PrivateKey: priv,
}
if kp.PublicKey == "" {
err := kp.readPublicKey()
if err != nil {
panic(err)
}
}
return kp
}
// Check if a string contains an encrypted message.
func IsEncrypted(data string) bool {
return strings.Contains(data, "-----BEGIN " + PgpMessageType + "-----")
}