- Notifications
You must be signed in to change notification settings - Fork 371
/
Copy pathecdsa.go
134 lines (112 loc) · 3.4 KB
/
ecdsa.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
package jwt
import (
"crypto"
"crypto/ecdsa"
"crypto/rand"
"errors"
"math/big"
)
var (
// Sadly this is missing from crypto/ecdsa compared to crypto/rsa
ErrECDSAVerification=errors.New("crypto/ecdsa: verification error")
)
// SigningMethodECDSA implements the ECDSA family of signing methods.
// Expects *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for verification
typeSigningMethodECDSAstruct {
Namestring
Hash crypto.Hash
KeySizeint
CurveBitsint
}
// Specific instances for EC256 and company
var (
SigningMethodES256*SigningMethodECDSA
SigningMethodES384*SigningMethodECDSA
SigningMethodES512*SigningMethodECDSA
)
funcinit() {
// ES256
SigningMethodES256=&SigningMethodECDSA{"ES256", crypto.SHA256, 32, 256}
RegisterSigningMethod(SigningMethodES256.Alg(), func() SigningMethod {
returnSigningMethodES256
})
// ES384
SigningMethodES384=&SigningMethodECDSA{"ES384", crypto.SHA384, 48, 384}
RegisterSigningMethod(SigningMethodES384.Alg(), func() SigningMethod {
returnSigningMethodES384
})
// ES512
SigningMethodES512=&SigningMethodECDSA{"ES512", crypto.SHA512, 66, 521}
RegisterSigningMethod(SigningMethodES512.Alg(), func() SigningMethod {
returnSigningMethodES512
})
}
func (m*SigningMethodECDSA) Alg() string {
returnm.Name
}
// Verify implements token verification for the SigningMethod.
// For this verify method, key must be an ecdsa.PublicKey struct
func (m*SigningMethodECDSA) Verify(signingStringstring, sig []byte, keyinterface{}) error {
// Get the key
varecdsaKey*ecdsa.PublicKey
switchk:=key.(type) {
case*ecdsa.PublicKey:
ecdsaKey=k
default:
returnnewError("ECDSA verify expects *ecdsa.PublicKey", ErrInvalidKeyType)
}
iflen(sig) !=2*m.KeySize {
returnErrECDSAVerification
}
r:=big.NewInt(0).SetBytes(sig[:m.KeySize])
s:=big.NewInt(0).SetBytes(sig[m.KeySize:])
// Create hasher
if!m.Hash.Available() {
returnErrHashUnavailable
}
hasher:=m.Hash.New()
hasher.Write([]byte(signingString))
// Verify the signature
ifverifystatus:=ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus {
returnnil
}
returnErrECDSAVerification
}
// Sign implements token signing for the SigningMethod.
// For this signing method, key must be an ecdsa.PrivateKey struct
func (m*SigningMethodECDSA) Sign(signingStringstring, keyinterface{}) ([]byte, error) {
// Get the key
varecdsaKey*ecdsa.PrivateKey
switchk:=key.(type) {
case*ecdsa.PrivateKey:
ecdsaKey=k
default:
returnnil, newError("ECDSA sign expects *ecdsa.PrivateKey", ErrInvalidKeyType)
}
// Create the hasher
if!m.Hash.Available() {
returnnil, ErrHashUnavailable
}
hasher:=m.Hash.New()
hasher.Write([]byte(signingString))
// Sign the string and return r, s
ifr, s, err:=ecdsa.Sign(rand.Reader, ecdsaKey, hasher.Sum(nil)); err==nil {
curveBits:=ecdsaKey.Curve.Params().BitSize
ifm.CurveBits!=curveBits {
returnnil, ErrInvalidKey
}
keyBytes:=curveBits/8
ifcurveBits%8>0 {
keyBytes+=1
}
// We serialize the outputs (r and s) into big-endian byte arrays
// padded with zeros on the left to make sure the sizes work out.
// Output must be 2*keyBytes long.
out:=make([]byte, 2*keyBytes)
r.FillBytes(out[0:keyBytes]) // r is assigned to the first half of output.
s.FillBytes(out[keyBytes:]) // s is assigned to the second half of output.
returnout, nil
} else {
returnnil, err
}
}