A Go implementation of the Secure Remote Password Protocol (SRP)
This package implements SRP as defined in RFC 2945 and RFC 5054.
RFC 2945: The SRP Authentication and Key Exchange System
RFC 5054: Using the Secure Remote Password (SRP) Protocol for TLS Authentication
This package exposes several methods defined in AuthClient
and AuthServer
interfaces
to complete the authentication flow. It offers a default Client and Server set to use
SHA256 as the hashing algorithm and the 4096 prime value group from RFC 5054 Section 3.2.
c, _ := NewDefaultClient("username", "password")
s, _ := NewDefaultServer()
You can pass your own hashing algorithm or prime value group as well.
g, _ := NewGroup(Group8192)
c, _ := NewClient(crypto.SHA512, g, "username", "password")
s, _ := NewServer(crypto.SHA512, g)
This package provides the tooling to enroll and validate a user. Using this library however will still require you to:
- Securely store client submitted credentials during registration. This includes username, salt, verifier
- Retreive user salt and verifier during authentication.
A detailed overview on authentication can be found on RFC 2945 Page 3. In general, we implement the following flow where:
- a, A: Client ephemeral private and public key (*big.Int)
- b, B: Server ephemeral private and public key (*big.Int)
- K: PremasterKey (A shared key generated by both Client and Server (*big.Int)
- M1: Client proof of K generation (*big.Int)
- M2: Server proof of K generation (*big.Int)
Client Server
---------- ----------
Calculate a, A
I, A --------->
Calculate b, B
<--------- B, s
Calculate K, M1
M1 ---------> Calculate K, M2
Confirm M2
<--------- M2
Confirm M2
At each stage of the auth flow, client/server will receive/return several credentails (ex. salt, verifier, proof, public keys) to move forward with the premasterkey calculation.
- Client generates username, salt, verifier
uname, salt, verifier, err := c.Enroll()
- Server accepts credentials. Persisting this data is outside the scope of this package. The verifier value acts as the server's long term secret value for the user. It is never transmitted back after this.
isEnrolled := s.ProcessEnroll(uname, salt, verifier)
- Client generates a new public key and username used during enrollment
uname, cPubKey := c.Auth()
- Server receives credentials from the client. On success, it will generate its own public key and return the salt used during registration.
# You will need to implement this
salt, verifier := RetrieveThisFromSomeStorage()
# On success we will receive the salt and ephemeral public key for the client
sPubKey, salt, err := s.ProcessAuth(uname, salt, cPubKey, verifier)
- Client receives salt and ephemeral public key from server. It then generates proof of its identity to send back to the server.
cProof, err := c.ProveIdentity(sPubKey, salt)
- Server receives the client's proof of identity. If valid, it will return it's own proof for the client.
sProof, err := s.ProcessProof(cProof)
- If the server successfully validated the client proof, it will generate it's own proof that the client may validate.
isServerValid := c.IsProofValid(sProof)
Validation of both the server and client proof ensures that they both calculated
the same PremasterKey
. At this point you may authenticate the user or use the
shared key as part of your authentication protocol.
Tests rely on testify's assert library. It should install automatically if this project is stored outside of your GOPATH. If it is inside GOPATH, you first need to enable module support.
export GO111MODULE=on
Run tests
make test
golangci-lint is used for linting. To install (OSX)
brew install golangci/tap/golangci-lint
Run linter
make lint