-
Notifications
You must be signed in to change notification settings - Fork 0
/
key.go
154 lines (130 loc) · 3.37 KB
/
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package pki
import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"log"
"os"
)
const PKAlgorithmRSA string = "RSA"
const PKAlgorithmECDSA string = "ECDSA"
const PEMBlockTypePK string = "PRIVATE KEY"
var ellipticCurveDetails = []struct {
curve elliptic.Curve
name string
}{
{elliptic.P224(), "P225"},
{elliptic.P256(), "P256"},
{elliptic.P384(), "P384"},
{elliptic.P521(), "P521"},
}
type Key struct {
Private crypto.Signer
Public crypto.PublicKey
}
func CreateKey(publicKeyAlgorithm string, publicKeyCurve string, keyLength int) (*Key, error) {
log.Print("Generating CSR key pair...")
switch publicKeyAlgorithm {
case PKAlgorithmRSA:
log.Print("Creating RSA Private Key...")
privateKey, err := rsa.GenerateKey(rand.Reader, keyLength)
if err != nil {
return nil, err
}
key := &Key{
Private: privateKey,
Public: &privateKey.PublicKey,
}
return key, err
case PKAlgorithmECDSA:
log.Print("Creating ECDSA Private Key...")
curve, err := determineCurve(publicKeyCurve)
if err != nil {
return nil, err
}
privateKey, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
return nil, err
}
key := &Key{
Private: privateKey,
Public: &privateKey.PublicKey,
}
return key, err
}
return nil, errors.New("key pair creation failed, no public key algorithm was available")
}
func LoadKey(fileName string) (*Key, error) {
//Open File
pemBytes, err := os.ReadFile(fileName)
if err != nil {
return nil, fmt.Errorf("unable to open PK file: %s, error: %s", fileName, err)
}
//Convert PEM to DER
pemBlock, _ := pem.Decode(pemBytes)
derBytes := pemBlock.Bytes
//Parse key
keyInterface, err := x509.ParsePKCS8PrivateKey(derBytes)
if err != nil {
return nil, fmt.Errorf("unable to parse PKCS8 key from file: %s, error: %s", fileName, err)
}
//Cast to crypto.Signer
switch privateKey := keyInterface.(type) {
case *rsa.PrivateKey:
key := &Key{
Private: privateKey,
Public: &privateKey.PublicKey,
}
return key, nil
case *ecdsa.PrivateKey:
key := &Key{
Private: privateKey,
Public: &privateKey.PublicKey,
}
return key, nil
default:
return nil, fmt.Errorf("PK not in recognised format, key must be a PKCS8 formatted RSA or ECDSA key")
}
}
func (key *Key) Export(fileName string) error {
log.Print("Converting PK to PEM format...")
//Create PEM
bytes, err := x509.MarshalPKCS8PrivateKey(key.Private)
if err != nil {
return fmt.Errorf("unable to marshal private key to PKCS8 format: %s", err)
}
pemBlock := &pem.Block{
Type: PEMBlockTypePK,
Headers: nil,
Bytes: bytes,
}
//Save PEM to file
log.Printf("Writing PK to file: %s...", fileName)
file, err := os.Create(fileName)
if err != nil {
return fmt.Errorf("unable to create: %s for writing PK: %s", fileName, err)
}
defer file.Close()
if err := pem.Encode(file, pemBlock); err != nil {
return fmt.Errorf("unable to encode PK PEM block: %s", err)
}
return err
}
func determineCurve(publicKeyCurve string) (curve elliptic.Curve, err error) {
log.Printf("converting Curve Name: %s to elliptic curve...", publicKeyCurve)
for _, details := range ellipticCurveDetails {
if details.name == publicKeyCurve {
curve = details.curve
}
}
if curve == nil {
return nil, fmt.Errorf("elliptic curve: %s unrecognised or unsupported", publicKeyCurve)
}
return curve, nil
}