-
Notifications
You must be signed in to change notification settings - Fork 1
/
README
137 lines (93 loc) · 4.42 KB
/
README
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
Standalone SRP-6a implementation in go-lang
===========================================
This is a standalone implementation of SRP in golang. It uses the go
standard libraries and has no other external dependencies. This
library can be used by SRP clients or servers.
SRP is a protocol to authenticate a user and derive safe session
keys. It is the latest in the category of "strong authentication
protocols".
SRP is documented here: http://srp.stanford.edu/doc.html
== Setting up the Verifiers on the Server ==
In order to authenticate and derive session keys, verifiers must be
stored in a non-volatile medium on the server. The verifiers are
generated once when a "user" is created on the server.
The Client is the entity where the user enters their password and
wishes to be authenticated with a SRP server. The communication
between client and server can happen in clear text - SRP is immune
to man in the middle attacks.
The client and server need to agree a-priori on the number of bits
to be used for the common "safe prime". It is acceptable to use 2048
or 4096 for this value. Each verifier can have a different number of
safe prime bits - but it must be recorded along with the verifier.
Every authentication attempt must use the same bit-size for the safe
prime previously recorded for that verifier.
Ih, salt, v, err := srp.Verifier(username, password, Safe_prime_bits)
// Now store Ih, salt, v and possibly Safe_prime_bits in non-volatile storage
Note that Ih is the hashed identity string for username.
Authentication attempt from the Client
--------------------------------------
The client performs the following sequence of steps to authenticate and derive session keys::
c, err := srp.NewClient(username, password, Safe_prime_bits)
if err != nil {
panic(err)
}
creds := c.Creds()
// send the credentials to the server. It is already in ASCII string form.
// Receive the server credentials into 'server_creds'
// it is assumed that there is some network communication that happens
// to get this string from the server
// Now, generate a mutual authenticator to be sent to the server
auth, err := c.Generate(server_creds)
if err != nil {
panic(err)
}
// Send the mutual authenticator to the server and receive "proof" that
// the server too computed the same result.
// Verify that we too have derived the same proof of authentication and
// session keys
err = c.ServerOk(proof)
if err != nil {
panic(err)
}
// Generate session key
rawkey := c.RawKey()
Authenticating a Client on the Server
-------------------------------------
On the server, the authentication attempt begins after receiving the
initial user credentials. This is used to lookup the stored verifier
and other bits.
// Assume that we received the user credentials via the network into 'creds'
// Parse the user info and authenticator from the 'creds' string
I, A, err := srp.ServerBegin(creds)
// Use 'I' to lookup the user in some non-volatile DB and obtain
// previously stored verifier 'v' and 'salt' for that user.
// Begin a new client-server SRP session
s, err := srp.NewServer(I, salt, v, A, Safe_prime_bits)
if err != nil {
panic(err)
}
// Generate server credentials to send to the user and wait for the
// mutual authenticator to arrive
s_creds := s.Credentials()
// Now send 's_creds' to the client and receive 'm_auth' from the client
// Authenticate user and generate proof of authentication
proof, err := s.ClientOk(m_auth)
if err != nil {
panic("Authentication failed")
}
// Auth succeeded, derive session key
rawkey := s.RawKey()
Other Notes
-----------
* The client and server both derive the same value for `RawKey()`. This is
the crux of the SRP protocol. Treat this as a "master key".
* It is not advisable to use the RawKey() for encryption purposes. It is
better to derive a separate key for each direction (client->server
and server->client). e.g.,
c2s_k = KDF(rawkey, "C2S", counter)
s2s_k = KDF(rawkey, "S2C", counter)
* KDF above can be a reputable key derivation function such as PBKDF2 or
Scrypt. The "counter" is incremented every time you derive a new key.
* *I am not a cryptographer*. Please consult your favorite crypto book for
deriving encryption keys from a master key.
-- EOF --