-
Notifications
You must be signed in to change notification settings - Fork 5
/
rsa.go
140 lines (115 loc) · 3.38 KB
/
rsa.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
package krypto
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha1" //#nosec G505 -- Need compatibility
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io"
)
func RsaEncrypt(key *rsa.PublicKey, secretMessage []byte) ([]byte, error) {
if key == nil {
return nil, errors.New("Cannot encrypt with a nil key")
}
//#nosec G401 -- Need compatibility
return rsa.EncryptOAEP(sha1.New(), rand.Reader, key, secretMessage, nil)
}
func RsaDecrypt(key *rsa.PrivateKey, ciphertext []byte) ([]byte, error) {
if key == nil {
return nil, errors.New("Cannot decrypt with a nil key")
}
//#nosec G401 -- Need compatibility
return rsa.DecryptOAEP(sha1.New(), rand.Reader, key, ciphertext, nil)
}
func RsaSign(key *rsa.PrivateKey, message []byte) ([]byte, error) {
if key == nil {
return nil, errors.New("Cannot sign with a nil key")
}
hasher := sha256.New()
if _, err := hasher.Write(message); err != nil {
return nil, fmt.Errorf("hashing message: %w", err)
}
digest := hasher.Sum(nil)
return rsa.SignPSS(rand.Reader, key, crypto.SHA256, digest, nil)
}
func RsaVerify(key *rsa.PublicKey, message []byte, sig []byte) error {
if key == nil {
return errors.New("Cannot verify with a nil key")
}
hasher := sha256.New()
if _, err := hasher.Write(message); err != nil {
return fmt.Errorf("hashing message: %w", err)
}
digest := hasher.Sum(nil)
return rsa.VerifyPSS(key, crypto.SHA256, digest, sig, nil)
}
// RsaFingerprint returns the SHA256 fingerprint. This is calculated
// by hashing the DER representation of the public key. It is
// analogous to various openssl commands:
// - openssl rsa -in private.pem -pubout -outform DER | openssl sha256 -c
// - openssl pkey -pubin -in public.pem -pubout -outform der | openssl sha256 -c
func RsaFingerprint(keyRaw interface{}) (string, error) {
var pub *rsa.PublicKey
switch key := keyRaw.(type) {
case *rsa.PublicKey:
pub = key
case *rsa.PrivateKey:
if key == nil {
return "", errors.New("no key, cannot fingerprint")
}
pub = key.Public().(*rsa.PublicKey)
default:
return "", errors.New("cannot fingerprint that type")
}
pkix, err := x509.MarshalPKIXPublicKey(pub)
if err != nil {
return "", fmt.Errorf("marshalling to PKIX: %w", err)
}
sum := sha256.Sum256(pkix)
out := ""
for i := 0; i < 32; i++ {
if i > 0 {
out += ":"
}
out += fmt.Sprintf("%02x", sum[i])
}
return out, nil
}
func RsaRandomKey() (*rsa.PrivateKey, error) {
return rsa.GenerateKey(rand.Reader, 2048)
}
func RsaPrivateKeyToPem(key *rsa.PrivateKey, out io.Writer) error {
privASN1 := x509.MarshalPKCS1PrivateKey(key)
return pem.Encode(out, &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privASN1,
})
}
func RsaPublicKeyToPem(key *rsa.PrivateKey, out io.Writer) error {
pubASN1, err := x509.MarshalPKIXPublicKey(&key.PublicKey)
if err != nil {
return fmt.Errorf("pkix marshalling: %w", err)
}
return pem.Encode(out, &pem.Block{
Type: "PUBLIC KEY",
Bytes: pubASN1,
})
}
func KeyFromPem(pemRaw []byte) (interface{}, error) {
// pem.Decode returns pem, and rest. No error here
block, _ := pem.Decode(pemRaw)
if block == nil || block.Type == "" {
return nil, errors.New("got blank data from pem")
}
switch block.Type {
case "RSA PRIVATE KEY":
return x509.ParsePKCS1PrivateKey(block.Bytes)
case "PUBLIC KEY":
return x509.ParsePKIXPublicKey(block.Bytes)
}
return nil, fmt.Errorf("Unknown block type: %s", block.Type)
}