This repository has been archived by the owner on May 28, 2024. It is now read-only.
generated from findy-network/findy-template-go
-
Notifications
You must be signed in to change notification settings - Fork 2
/
enclave.go
152 lines (126 loc) · 3.88 KB
/
enclave.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
package enclave
import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"encoding/hex"
"math/big"
crpt "github.com/findy-network/findy-common-go/crypto"
"github.com/fxamacker/cbor/v2"
"github.com/go-webauthn/webauthn/protocol/webauthncose"
"github.com/golang/glog"
"github.com/lainio/err2"
"github.com/lainio/err2/assert"
"github.com/lainio/err2/try"
)
type KeyHandle interface {
ID() []byte
CBORPublicKey() ([]byte, error)
Sign(d []byte) ([]byte, error)
Verify(data, sig []byte) (ok bool) // Mainly testing
}
type myHandle struct {
//key []byte
Enclave
id []byte
webauthncose.EC2PublicKeyData
privKey *ecdsa.PrivateKey
}
// ID returns ENCRYPTED presentation of X509 encoded byte slice whole key, which
// means that private key. That means that the whole key pair can be restored
// into this same Enclave (master key is used for the encryption).
func (h *myHandle) ID() []byte {
x509Encoded := try.To1(x509.MarshalECPrivateKey(h.privKey))
if h.id == nil {
h.id = h.Cipher.TryEncrypt(x509Encoded)
}
return h.id
}
// CBORPublicKey returns CBOR marshaled byte slice presentation of the public
// key or error.
func (h *myHandle) CBORPublicKey() (_ []byte, err error) {
return cbor.Marshal(h.EC2PublicKeyData)
}
// Sign signs the byte slice and returns the signature or error.
func (h *myHandle) Sign(d []byte) (_ []byte, err error) {
defer err2.Handle(&err)
hash := crypto.SHA256.New()
try.To1(hash.Write(d))
hashVal := hash.Sum(nil)
sig := try.To1(ecdsa.SignASN1(rand.Reader, h.privKey, hashVal))
return sig, nil
}
// Verify verifies the given data and signature.
func (h *myHandle) Verify(data, sig []byte) (ok bool) {
hash := crypto.SHA256.New()
try.To1(hash.Write(data))
pubKey := &ecdsa.PublicKey{
Curve: elliptic.P256(),
X: big.NewInt(0).SetBytes(h.XCoord),
Y: big.NewInt(0).SetBytes(h.YCoord),
}
return ecdsa.VerifyASN1(pubKey, hash.Sum(nil), sig)
}
// NewKeyHandle creates a new key handle for the Enclave. The Enclave is
// stateless, which means that only the master key is needed. The master key is
// stored to every key handle to maintain statelessness.
func (e Enclave) NewKeyHandle() (_ KeyHandle, err error) {
// new random bytes for EC NewPrivateKey()
defer err2.Handle(&err)
privateKey := try.To1(ecdsa.GenerateKey(elliptic.P256(), rand.Reader))
h := newFromPrivateKey(e, privateKey)
return h, nil
}
// IsKeyHandle tells if given byte slice really is key handle from the current
// Enclave.
func (e Enclave) IsKeyHandle(credID []byte) (ok bool, kh KeyHandle) {
defer err2.Catch(err2.Err(func(err error) {
glog.Errorln("is key handle:", err)
ok, kh = false, nil
}))
pk, err := x509.ParseECPrivateKey(e.Cipher.TryDecrypt(credID))
ok = err == nil
return ok, newFromPrivateKey(e, pk)
}
var (
Store Secure // Store is the default secure enclave created by pkg init.
)
func init() {
const hexKey = "15308490f1e4026284594dd08d31291bc8ef2aeac730d0daf6ff87bb92d4336c"
Store = New(hexKey)
}
// Secure is a secure enclave interface.
type Secure interface {
NewKeyHandle() (kh KeyHandle, err error)
IsKeyHandle(id []byte) (yes bool, kh KeyHandle)
}
// Enclave is secure enclave.
type Enclave struct {
crpt.Cipher
}
// New creates a new Enclave.
func New(hexKey string) *Enclave {
assert.Len(hexKey, 64)
k, err := hex.DecodeString(hexKey)
assert.NoError(err)
theCipher := crpt.NewCipher(k)
return &Enclave{Cipher: *theCipher}
}
// newFromPrivateKey returns instance of our cose.Key where given priKey is in
// ecdsa fmt.
func newFromPrivateKey(e Enclave, priKey *ecdsa.PrivateKey) *myHandle {
return &myHandle{
Enclave: e,
EC2PublicKeyData: webauthncose.EC2PublicKeyData{
PublicKeyData: webauthncose.PublicKeyData{
KeyType: int64(webauthncose.EllipticKey),
Algorithm: int64(webauthncose.AlgES256),
},
Curve: int64(webauthncose.P256),
XCoord: priKey.X.Bytes(),
YCoord: priKey.Y.Bytes(),
},
privKey: priKey}
}