-
Notifications
You must be signed in to change notification settings - Fork 0
/
pin_uv_auth_protocol_1.go
109 lines (97 loc) · 2.62 KB
/
pin_uv_auth_protocol_1.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
package ctap
import (
"crypto/aes"
"crypto/cipher"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"errors"
"log"
"github.com/veraison/go-cose"
)
type PinUVAuthProtocol1 struct {
KeyAgreementKey *ecdsa.PrivateKey
PinUvAuthToken []byte
}
func (p *PinUVAuthProtocol1) Version() uint {
return 1
}
func (p *PinUVAuthProtocol1) Initialize() {
var err error
p.KeyAgreementKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Panic("Failed to generate KeyAgreementKey: ", err)
}
}
func (p *PinUVAuthProtocol1) getPublicKey() *PinUvAuthProtocolKey {
key, err := cose.NewKeyFromPublic(p.KeyAgreementKey.Public())
if err != nil {
log.Panic("Failed to getPublicKey: ", err)
}
key.Algorithm = cose.Algorithm(-25)
return &PinUvAuthProtocolKey{
Key: key,
}
}
func (p *PinUVAuthProtocol1) Encapsulate(peerCoseKey *PinUvAuthProtocolKey) (*PinUvAuthProtocolKey, []byte, error) {
sharedSecret, err := p.ecdh(peerCoseKey)
return p.getPublicKey(), sharedSecret, err
}
func (p *PinUVAuthProtocol1) Encrypt(key []byte, demPlainText []byte) []byte {
rawCipher, err := aes.NewCipher(key)
if err != nil {
log.Panic("Failed to initialize cipher: ", err)
}
c := cipher.NewCBCEncrypter(rawCipher, make([]byte, rawCipher.BlockSize()))
res := make([]byte, len(demPlainText))
c.CryptBlocks(res, demPlainText)
return res
}
func (p *PinUVAuthProtocol1) Decrypt(key []byte, demCipherText []byte) ([]byte, error) {
rawCipher, err := aes.NewCipher(key)
if err != nil {
log.Panic("Failed to initialize cipher: ", err)
}
c := cipher.NewCBCDecrypter(rawCipher, make([]byte, rawCipher.BlockSize()))
if len(demCipherText)%c.BlockSize() != 0 {
return nil, errors.New("invalid message length")
}
res := make([]byte, len(demCipherText))
c.CryptBlocks(res, demCipherText)
return res, nil
}
func (p *PinUVAuthProtocol1) Authenticate(key []byte, message []byte) []byte {
m := hmac.New(sha256.New, key)
m.Write(message)
return m.Sum(nil)[:16]
}
func (p *PinUVAuthProtocol1) ecdh(peerCoseKey *PinUvAuthProtocolKey) ([]byte, error) {
peerCoseKey.Algorithm = cose.AlgorithmES256
peerKeyParsed, err := peerCoseKey.PublicKey()
if err != nil {
return nil, err
}
peerKey, ok := peerKeyParsed.(*ecdsa.PublicKey)
if !ok {
return nil, ErrProtocolUnsupported
}
ecdhSelf, err := p.KeyAgreementKey.ECDH()
if err != nil {
return nil, err
}
ecdhPeer, err := peerKey.ECDH()
if err != nil {
return nil, err
}
z, err := ecdhSelf.ECDH(ecdhPeer)
if err != nil {
return nil, err
}
return p.kdf(z), nil
}
func (p *PinUVAuthProtocol1) kdf(z []byte) []byte {
sum := sha256.Sum256(z)
return sum[:]
}