Skip to content

Commit 3e1d27f

Browse files
committed
Added documentation and adjusted API
1 parent 3ae12f4 commit 3e1d27f

File tree

5 files changed

+86
-51
lines changed

5 files changed

+86
-51
lines changed

Diff for: client.go

+21-24
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,29 @@ import (
77
)
88

99
type SRPClient struct {
10-
// Set in constructor
1110
Params *SRPParams
1211
Secret1 *big.Int
1312
Multiplier *big.Int
1413
A *big.Int
1514
X *big.Int
16-
17-
// Set in SetB
18-
M1 []byte
19-
M2 []byte
20-
K []byte
21-
22-
// Private (for tests)
23-
U *big.Int
24-
S *big.Int
15+
M1 []byte
16+
M2 []byte
17+
K []byte
18+
u *big.Int
19+
s *big.Int
2520
}
2621

27-
func NewClient(params *SRPParams, salt, identity, password, S1b []byte) *SRPClient {
22+
func NewClient(params *SRPParams, salt, identity, password, secret1 []byte) *SRPClient {
2823
multiplier := getMultiplier(params)
29-
secret1 := intFromBytes(S1b)
30-
Ab := getA(params, secret1)
24+
secret1Int := intFromBytes(secret1)
25+
Ab := getA(params, secret1Int)
3126
A := intFromBytes(Ab)
3227
x := getx(params, salt, identity, password)
3328

3429
return &SRPClient{
3530
Params: params,
3631
Multiplier: multiplier,
37-
Secret1: secret1,
32+
Secret1: secret1Int,
3833
A: A,
3934
X: x,
4035
}
@@ -44,6 +39,16 @@ func (c *SRPClient) ComputeA() []byte {
4439
return intToBytes(c.A)
4540
}
4641

42+
// ComputeVerifier returns a verifier that is calculated as described in
43+
// Section 3 of [SRP-RFC]
44+
func ComputeVerifier(params *SRPParams, salt, I, P []byte) []byte {
45+
x := getx(params, salt, I, P)
46+
vNum := new(big.Int)
47+
vNum.Exp(params.G, x, params.N)
48+
49+
return padToN(vNum, params)
50+
}
51+
4752
func (c *SRPClient) SetB(Bb []byte) {
4853
B := intFromBytes(Bb)
4954
u := getu(c.Params, c.A, B)
@@ -53,8 +58,8 @@ func (c *SRPClient) SetB(Bb []byte) {
5358
c.M1 = getM1(c.Params, intToBytes(c.A), Bb, S)
5459
c.M2 = getM2(c.Params, intToBytes(c.A), c.M1, c.K)
5560

56-
c.U = u // Only for tests
57-
c.S = intFromBytes(S) // Only for tests
61+
c.u = u // Only for tests
62+
c.s = intFromBytes(S) // Only for tests
5863
}
5964

6065
func (c *SRPClient) ComputeM1() []byte {
@@ -129,11 +134,3 @@ func getx(params *SRPParams, salt, I, P []byte) *big.Int {
129134

130135
return hashToInt(hashX)
131136
}
132-
133-
func ComputeVerifier(params *SRPParams, salt, I, P []byte) []byte {
134-
x := getx(params, salt, I, P)
135-
vNum := new(big.Int)
136-
vNum.Exp(params.G, x, params.N)
137-
138-
return padToN(vNum, params)
139-
}

Diff for: params.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func createParams(G int64, nBitLength int, hash crypto.Hash, NHex string) *SRPPa
2929
return &p
3030
}
3131

32-
func Params(G int) *SRPParams {
32+
func GetParams(G int) *SRPParams {
3333
params := knownGroups[G]
3434
if params == nil {
3535
panic(fmt.Sprintf("Params don't exist for %v", G))

Diff for: server.go

+7-12
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,15 @@ import (
77
)
88

99
type SRPServer struct {
10-
// Set in constructor
1110
Params *SRPParams
1211
Verifier *big.Int
1312
Secret2 *big.Int
1413
B *big.Int
15-
16-
// Set in SetA
17-
M1 []byte
18-
M2 []byte
19-
K []byte
20-
21-
// Private (for tests)
22-
U *big.Int
23-
S *big.Int
14+
M1 []byte
15+
M2 []byte
16+
K []byte
17+
u *big.Int
18+
s *big.Int
2419
}
2520

2621
func NewServer(params *SRPParams, Vb []byte, S2b []byte) *SRPServer {
@@ -52,8 +47,8 @@ func (s *SRPServer) SetA(A []byte) {
5247
s.M1 = getM1(s.Params, A, intToBytes(s.B), S)
5348
s.M2 = getM2(s.Params, A, s.M1, s.K)
5449

55-
s.U = U // only for tests
56-
s.S = intFromBytes(S) // only for tests
50+
s.u = U // only for tests
51+
s.s = intFromBytes(S) // only for tests
5752
}
5853

5954
func (s *SRPServer) CheckM1(M1 []byte) ([]byte, error) {

Diff for: srp.go

+45-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,46 @@
1+
// Package srp is port of node-srp to Go.
2+
//
3+
//
4+
// To use SRP, first decide on they parameters you will use. Both client and server must
5+
// use the same set.
6+
// params := srp.GetParams(4096)
7+
//
8+
// From the client... generate a new secret key, initialize the client, and compute A.
9+
// Once you have A, you can send A to the server.
10+
// secret1 := srp.GenKey()
11+
// client := NewClient(params, salt, identity, secret, a)
12+
// srpA := client.computeA()
13+
//
14+
// sendToServer(srpA)
15+
//
16+
// From the server... generate another secret key, initialize the server, and compute B.
17+
// Once you have B, you can send B to the client.
18+
// secret2 := srp.GenKey()
19+
// server := NewServer(params, verifier, secret2)
20+
// srpB := client.computeB()
21+
//
22+
// sendToClient(srpB)
23+
//
24+
// Once the client received B from the server, it can compute M1 based on A and B.
25+
// Once you have M1, send M1 to the server.
26+
// client.setB(srpB)
27+
// srpM1 := client.ComputeM1()
28+
// sendM1ToServer(srpM1)
29+
//
30+
// Once the server receives M1, it can verify that it is correct. If checkM1() returns
31+
// an error, authentication failed. If it succeeds it should be sent to the client.
32+
// srpM2, err := server.checkM1(srpM1)
33+
//
34+
// Once the client receives M2, it can verify that it is correct, and know that authentication
35+
// was successful.
36+
// err = client.CheckM2(serverM2)
37+
//
38+
// Now that both client and server have completed a successful authentication, they can
39+
// both compute K independently. K can now be used as either a key to encrypt communication
40+
// or as a session ID.
41+
// clientK := client.ComputeK()
42+
// serverK := server.ComputeK()
43+
//
144
package srp
245

346
import (
@@ -6,8 +49,8 @@ import (
649
"math/big"
750
)
851

9-
func GenKey(numBytes int) []byte {
10-
bytes := make([]byte, numBytes)
52+
func GenKey() []byte {
53+
bytes := make([]byte, 32)
1154
_, err := io.ReadFull(rand.Reader, bytes)
1255
if err != nil {
1356
panic("Random source is broken!")

Diff for: srp_test.go

+12-12
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ var identity = []byte("alice")
1111
var password = []byte("password123")
1212

1313
func getAAndB() ([]byte, []byte) {
14-
a := GenKey(64)
15-
b := GenKey(32)
14+
a := GenKey()
15+
b := GenKey()
1616
return a, b
1717
}
1818

@@ -41,13 +41,13 @@ func getVerifier() []byte {
4141
}
4242

4343
func TestCreateVerifier(t *testing.T) {
44-
verifier := ComputeVerifier(Params(4096), salt, identity, password)
44+
verifier := ComputeVerifier(GetParams(4096), salt, identity, password)
4545
expected := getVerifier()
4646
assert.Equal(t, expected, verifier, "Verifier did not match")
4747
}
4848

4949
func TestUseAAndB(t *testing.T) {
50-
params := Params(4096)
50+
params := GetParams(4096)
5151
a, b := getAAndB()
5252

5353
// Create client
@@ -91,7 +91,7 @@ func TestUseAAndB(t *testing.T) {
9191

9292
func TestServerRejectsWrongM1(t *testing.T) {
9393
a, b := getAAndB()
94-
params := Params(4096)
94+
params := GetParams(4096)
9595
badClient := NewClient(params, salt, identity, []byte("Bad"), a)
9696
server := NewServer(params, getVerifier(), b)
9797
badClient.SetB(server.ComputeB())
@@ -105,7 +105,7 @@ func TestServerRejectsBadA(t *testing.T) {
105105
// number itself is examined.
106106

107107
_, b := getAAndB()
108-
params := Params(4096)
108+
params := GetParams(4096)
109109
server := NewServer(params, getVerifier(), b)
110110

111111
assert.Panics(t, func() {
@@ -126,7 +126,7 @@ func TestServerRejectsBadA(t *testing.T) {
126126
func TestClientRejectsBadB(t *testing.T) {
127127
// server's "B" must be 1..N-1 . Reject 0 and N and N+1
128128
a, _ := getAAndB()
129-
params := Params(4096)
129+
params := GetParams(4096)
130130
client := NewClient(params, salt, identity, password, a)
131131

132132
assert.Panics(t, func() {
@@ -146,7 +146,7 @@ func TestClientRejectsBadB(t *testing.T) {
146146

147147
func TestClientRejectsBadM2(t *testing.T) {
148148
a, b := getAAndB()
149-
params := Params(4096)
149+
params := GetParams(4096)
150150
client := NewClient(params, salt, identity, password, a)
151151

152152
// Client produces A
@@ -183,7 +183,7 @@ func TestClientRejectsBadM2(t *testing.T) {
183183
}
184184

185185
func TestRFC5054(t *testing.T) {
186-
params := Params(1024)
186+
params := GetParams(1024)
187187
I := []byte("alice")
188188
P := []byte("password123")
189189
s := bytesFromHexString("beb25379d1a8581eb5a727673a2441ee")
@@ -238,10 +238,10 @@ func TestRFC5054(t *testing.T) {
238238

239239
// u and S client
240240
client.SetB(BExpected)
241-
assert.Equal(t, uExpected, intToBytes(client.U), "u should match")
242-
assert.Equal(t, SExpected, intToBytes(client.S), "S should match")
241+
assert.Equal(t, uExpected, intToBytes(client.u), "u should match")
242+
assert.Equal(t, SExpected, intToBytes(client.s), "S should match")
243243

244244
// S server
245245
server.SetA(AExpected)
246-
assert.Equal(t, SExpected, intToBytes(server.S), "S should match")
246+
assert.Equal(t, SExpected, intToBytes(server.s), "S should match")
247247
}

0 commit comments

Comments
 (0)