forked from emersion/go-pgpmail
-
Notifications
You must be signed in to change notification settings - Fork 0
/
local.go
73 lines (59 loc) · 1.5 KB
/
local.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
// Uses the local GPG key store.
package local
import (
"bytes"
"errors"
"os/exec"
"camlistore.org/pkg/misc/pinentry"
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/packet"
)
func Unlock(username, _ string) (openpgp.EntityList, error) {
// Request the password only once as it will be used both to export the
// private key and to decrypt it
req := &pinentry.Request{
Desc: "Please enter the passphrase for your main PGP key.",
}
passphrase, err := req.GetPIN()
if err != nil {
return nil, err
}
// Export private key
cmd := exec.Command("gpg", "--batch", "--pinentry-mode", "loopback", "--passphrase", passphrase, "--export-secret-keys")
b := &bytes.Buffer{}
cmd.Stdout = b
if err := cmd.Run(); err != nil {
return nil, err
}
if b.Len() == 0 {
return nil, errors.New("cannot find any local private key")
}
kr, err := openpgp.ReadKeyRing(b)
if err != nil {
return nil, err
}
// Build a list of keys to decrypt
var keys []*packet.PrivateKey
for _, e := range kr {
// Entity.PrivateKey must be a signing key
if e.PrivateKey != nil {
keys = append(keys, e.PrivateKey)
}
// Entity.Subkeys can be used for encryption
for _, subKey := range e.Subkeys {
if subKey.PrivateKey != nil {
keys = append(keys, subKey.PrivateKey)
}
}
}
// Decrypt all private keys
for _, key := range keys {
if !key.Encrypted {
continue // Key already decrypted
}
if err = key.Decrypt([]byte(passphrase)); err != nil {
return nil, err
}
}
return kr, nil
}