-
-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathencode.go
More file actions
137 lines (122 loc) · 3.78 KB
/
encode.go
File metadata and controls
137 lines (122 loc) · 3.78 KB
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
128
129
130
131
132
133
134
135
136
137
package keys
import (
"strings"
"github.com/keys-pub/keys/encoding"
"github.com/pkg/errors"
)
// Encoding is the type of data.
type Encoding string
const (
// UnknownEncoding is unknown.
UnknownEncoding Encoding = ""
// IDEncoding is a key ID string.
IDEncoding Encoding = "id"
// SaltpackEncoding is armored saltpack encoding.
SaltpackEncoding Encoding = "saltpack"
// SaltpackBinaryEncoding is binary saltpack encoding.
// SaltpackBinaryEncoding Encoding = "saltpack-binary"
// SSHEncoding is ssh private key "-----BEGIN OPENSSH PRIVATE..."
// or public key as "ssh-ed25519 AAAAC3Nz..."
SSHEncoding Encoding = "ssh"
)
// EncodeKey encodes the key using the specified encoding.
func EncodeKey(key Key, enc Encoding, password string) (string, error) {
switch enc {
case SaltpackEncoding:
return EncodeSaltpackKey(key, password)
case SSHEncoding:
return EncodeSSHKey(key, password)
default:
return "", errors.Errorf("unrecognized encoding %s", enc)
}
}
// DecodeKey decodes a key using the specified encoding.
// If you don't know the encoding you can try ParseKey instead.
func DecodeKey(s string, enc Encoding, password string) (Key, error) {
switch enc {
case SaltpackEncoding:
return DecodeSaltpackKey(s, password, false)
case SSHEncoding:
if strings.HasPrefix(s, "ssh-ed25519 ") {
if password != "" {
return nil, errors.Errorf("password unsupported for ssh-ed25519 public key")
}
return ParseSSHPublicKey(s)
}
return ParseSSHKey([]byte(s), []byte(password), true)
default:
return nil, errors.Errorf("unsupported encoding %s", enc)
}
}
// EncodeSSHKey encodes key to SSH.
func EncodeSSHKey(key Key, password string) (string, error) {
switch k := key.(type) {
case *EdX25519Key:
out, err := k.EncodeToSSH([]byte(password))
if err != nil {
return "", err
}
return string(out), nil
case *EdX25519PublicKey:
if password != "" {
return "", errors.Errorf("password not supported when exporting public key")
}
return string(k.EncodeToSSHAuthorized()), nil
default:
return "", errors.Errorf("unsupported key type")
}
}
// Brand is saltpack brand.
type Brand string
// EdX25519Brand is saltpack brand for EdX25519 key.
const EdX25519Brand Brand = "EDX25519 KEY"
// X25519Brand is saltpack brand for X25519 key.
const X25519Brand Brand = "X25519 KEY"
// EncodeSaltpackKey encrypts a key to saltpack with password.
func EncodeSaltpackKey(key Key, password string) (string, error) {
if key == nil {
return "", errors.Errorf("no key to encode")
}
var brand Brand
b := key.Bytes()
switch key.Type() {
case EdX25519:
brand = EdX25519Brand
case X25519:
brand = X25519Brand
default:
return "", errors.Errorf("failed to encode to saltpack: unsupported key %s", key.Type())
}
out := EncryptWithPassword(b, password)
return encoding.EncodeSaltpack(out, string(brand)), nil
}
// DecodeSaltpackKey decrypts a saltpack encrypted key.
func DecodeSaltpackKey(msg string, password string, isHTML bool) (Key, error) {
encrypted, brand, err := encoding.DecodeSaltpack(msg, isHTML)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse saltpack")
}
b, err := DecryptWithPassword(encrypted, password)
if err != nil {
return nil, errors.Wrapf(err, "failed to decrypt saltpack encoded key")
}
if brand == "" {
return nil, errors.Errorf("unable to determine key type from saltpack brand")
}
switch brand {
case string(EdX25519Brand):
if len(b) != 64 {
return nil, errors.Errorf("invalid number of bytes for ed25519 seed")
}
sk := NewEdX25519KeyFromPrivateKey(Bytes64(b))
return sk, nil
case string(X25519Brand):
if len(b) != 32 {
return nil, errors.Errorf("invalid number of bytes for x25519 private key")
}
bk := NewX25519KeyFromPrivateKey(Bytes32(b))
return bk, nil
default:
return nil, errors.Errorf("unknown key type %s", brand)
}
}