-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathserver.go
155 lines (126 loc) · 3.61 KB
/
server.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
155
package srp
import (
"crypto"
"math/big"
)
// Server represents an SRP Server. Server validates a Client's enrollment
// and authentication.
type Server struct {
SRP
}
// ProcessEnroll acknowledges an enrollment payload from an SRP Client.
// It returns true if valid credentials have been submitted.
func (s *Server) ProcessEnroll(u, sa string, v *big.Int) bool {
if u == "" || sa == "" || v == nil {
return false
}
s.I = u
s.S = sa
s.Secret = v
return true
}
// ProcessAuth ackwnowledges an authentication request from a
// pre-enrolled SRP Client. Credentials should be received from the SRP client.
// Salt and verifier should be retrieved from some secure persisted storage
// prior to this call. Retreival of cr2 is outside the scope of this package.
func (s *Server) ProcessAuth(u, sa string, A, v *big.Int) (*big.Int, string, error) {
s.I = u
s.ephemeralSharedKey = A
s.S = sa
s.Secret = v
pk := big.Int{}
if pk.Mod(A, s.N); pk.Sign() == 0 {
return &big.Int{}, "", ErrPublicKeyModuloZero
}
_, err := s.ephemeralPublic()
if err != nil {
return &big.Int{}, "", err
}
_, err = s.premasterSecret()
if err != nil {
return &big.Int{}, "", err
}
return s.ephemeralPublicKey, s.S, nil
}
// ProcessProof receives and validates proof from an SRP Client.
func (s *Server) ProcessProof(cp *big.Int) (*big.Int, error) {
p, err := s.serverProof(cp, s.ephemeralSharedKey)
if err != nil {
return &big.Int{}, err
}
if !s.IsProofValid(cp) {
return &big.Int{}, ErrBadClientProof
}
return p, nil
}
// IsProofValid validates a SRP Client's proof of session key.
func (s *Server) IsProofValid(i *big.Int) bool {
proof, _ := s.clientProof(s.ephemeralSharedKey, s.ephemeralPublicKey)
isValid := proof.Cmp(i) == 0
return isValid
}
// EphemeralPublic calculate's the server's ephemeral public key B.
// RFC 5054 Defines B as (k*v + g^b) % N
func (s *Server) ephemeralPublic() (*big.Int, error) {
if s.G == nil || s.N == nil {
return nil, ErrNoGroupParams
}
// k*v
kv := &big.Int{}
// g^b
gB := &big.Int{}
B := &big.Int{}
kv.Mul(s.Secret, s.k)
gB.Exp(s.G, s.ephemeralPrivateKey, s.N)
kv.Mod(kv, s.N)
B.Add(kv, gB)
B.Mod(B, s.N)
s.ephemeralPublicKey = B
return B, nil
}
// premasterSecret creates the premaster secret key. If either client/server pair
// fails to calculate the premaster secret, final messages will fail to decrypt.
// RFC 5054 2.6 Defines the server secret as (A * v^u) ^ b % N
func (s *Server) premasterSecret() (*big.Int, error) {
if s.G == nil || s.N == nil {
return nil, ErrNoGroupParams
}
if s.ephemeralPublicKey == nil || s.ephemeralSharedKey == nil {
return nil, ErrNoEphemeralKeys
}
ownKey := big.Int{}
if ownKey.Mod(s.ephemeralPublicKey, s.N); ownKey.Sign() == 0 {
return nil, ErrPublicKeyModuloZero
}
otherKey := big.Int{}
if otherKey.Mod(s.ephemeralSharedKey, s.N); otherKey.Sign() == 0 {
return nil, ErrPublicKeyModuloZero
}
s.scramblingParam(s.ephemeralSharedKey, s.ephemeralPublicKey)
// (A * v^u)
vU := &big.Int{}
vU.Exp(s.Secret, s.u, s.N)
vU.Mul(vU, s.ephemeralSharedKey)
// vU^b % N
k := &big.Int{}
k.Exp(vU, s.ephemeralPrivateKey, s.N)
s.PremasterKey = k
return s.PremasterKey, nil
}
// NewServer returns an SRP Server with user defined hash and group.
func NewServer(h crypto.Hash, g *Group) (*Server, error) {
srp, err := NewSRP(h, g)
if err != nil {
return &Server{}, err
}
server := &Server{
SRP: *srp,
}
return server, nil
}
// NewDefaultServer returns an SRP server preconfigured for parameters
// Group4096 and SHA256 hashing function.
func NewDefaultServer() (*Server, error) {
g, _ := NewGroup(Group4096)
return NewServer(crypto.SHA256, g)
}