-
Notifications
You must be signed in to change notification settings - Fork 2
/
ecc_key.go
125 lines (100 loc) · 3.32 KB
/
ecc_key.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
package pgp
import (
"bytes"
"crypto/ed25519"
"crypto/sha1"
"crypto/sha256"
"encoding/binary"
"math/big"
"time"
)
// ellipticCurveKey is used to abstract away the the common encoding of elliptic curve
// private and public keys in OpenPGP format.
type ellipticCurveKey struct {
PrivateSerialized []byte
PublicSerialized []byte
PrivateSigning ed25519.PrivateKey
PublicSigning ed25519.PublicKey
Creation time.Time
Algorithm byte
CurveOID []byte
ExtraPublicData []byte
}
// encodePublic encodes the public key into a serialized payload suitable for
// use in a packet payload.
func (key *ellipticCurveKey) encodePublic() []byte {
buf := new(bytes.Buffer)
// Packet version
buf.WriteByte(keyPacketVersion)
// Specify key creation time
binary.Write(buf, binary.BigEndian, uint32(key.Creation.Unix()))
// Describe use purpose of public key
buf.WriteByte(key.Algorithm)
// Specify which curve the key uses
buf.WriteByte(byte(len(key.CurveOID)))
buf.Write(key.CurveOID)
// MPI-encoding of public key point
publicKeyMPI := EncodeMPI(
new(big.Int).SetBytes(append([]byte{mpiPrefixEddsaPoint}, key.PublicSerialized...)),
)
buf.Write(publicKeyMPI)
if key.ExtraPublicData != nil {
buf.Write(key.ExtraPublicData)
}
return buf.Bytes()
}
// encodePrivate encodes the private key into a serialized payload suitable for
// use in a packet payload.
func (key *ellipticCurveKey) encodePrivate(password []byte) ([]byte, error) {
buf := new(bytes.Buffer)
// First include public key in the packet.
buf.Write(key.encodePublic())
if len(password) > 0 {
encrypted, err := EncryptS2K(DefaultStringToKeyHashFunc, key.PrivateSerialized, password)
if err != nil {
return nil, err
}
buf.Write(encrypted)
} else {
// Specify string-to-key usage byte as unencrypted.
buf.WriteByte(0)
// MPI-encoded secret key.
mpiEncodedKey := EncodeMPI(new(big.Int).SetBytes(key.PrivateSerialized))
buf.Write(mpiEncodedKey)
buf.Write(checksumMPI(mpiEncodedKey))
}
return buf.Bytes(), nil
}
// encodePrivateDummy encodes the private key into a serialized private key stub,
// payload suitable for use in a packet payload.
func (key *ellipticCurveKey) encodePrivateDummy() []byte {
buf := new(bytes.Buffer)
// First include public key in the packet.
buf.Write(key.encodePublic())
// Specify string-to-key usage as gnu-dummy.
buf.WriteByte(stringToKeySpecifierPrefix)
buf.WriteByte(0) // No cipher algorithm, because no encryption
buf.WriteByte(s2kExtensionGNUDummy)
buf.WriteByte(0) // No hash algorithm, because no encryption
buf.Write([]byte(s2kGNUExtensionID))
buf.WriteByte(s2kExtensionGNUDummy - 100) // 1
return buf.Bytes()
}
// FingerprintV4 returns the 20-byte SHA1 hash of the serialized public key.
func (key *ellipticCurveKey) FingerprintV4() []byte {
publicKeyPayload := key.encodePublic()
h := sha1.New()
h.Write([]byte{publicKeyPrefixV4})
binary.Write(h, binary.BigEndian, uint16(len(publicKeyPayload)))
h.Write(publicKeyPayload)
return h.Sum(nil)
}
// FingerprintV5 returns the 32-byte SHA256 hash of the serialized public key.
func (key *ellipticCurveKey) FingerprintV5() []byte {
publicKeyPayload := key.encodePublic()
h := sha256.New()
h.Write([]byte{publicKeyPrefixV5})
binary.Write(h, binary.BigEndian, uint32(len(publicKeyPayload)))
h.Write(publicKeyPayload)
return h.Sum(nil)
}