From 33423e8e822165045f0506101763ff527cce9d22 Mon Sep 17 00:00:00 2001 From: siddharth Date: Wed, 6 Apr 2022 00:41:55 -0400 Subject: lib: flesh out SRPUser --- lib/srp.go | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/srp_test.go | 69 +++++++++++++++++++++++++++++ 2 files changed, 202 insertions(+) create mode 100644 lib/srp.go create mode 100644 lib/srp_test.go diff --git a/lib/srp.go b/lib/srp.go new file mode 100644 index 0000000..20208a6 --- /dev/null +++ b/lib/srp.go @@ -0,0 +1,133 @@ +// Copyright © 2022 siddharth +// SPDX-License-Identifier: ISC + +package lib + +import "math/big" + +// SRP - implementation. +// Reference http://srp.stanford.edu/design.html + +// SRP Client UI - Spec +// +// > register s@ricketyspace.net +// Enter password +// > ****** +// Registering with server...registered! +// > login s@ricketyspace.net +// Enter password +// > ****** +// Logging in...in! +// s@ricketyspace.net> +// s@ricketyspace.net> login s@ricketyspace.net +// login command not allowed when logged in +// s@ricketyspace.net> register rsd@gnu.org +// register command not allowed when logged in +// s@ricketyspace.net> logout +// Logging out..out! +// > register s@ricketyspace.net +// Already registered! + +// SRP Server. +type SRPServer struct { + users []SRPUser +} + +// Registered user on the SRP server. +type SRPUser struct { + // Large safe prime. Server and client agree upon the value of + // N. + n *big.Int + // Generator modulo N. Server and client agree upon the value + // of N. + g *big.Int + // Multipier parameter. Server and client agree upon the value + // of N. + k *big.Int + // Hashing object for H() function. + h Sha256 + // User's email address + ident string + // Salt. Randomly generator by the server. + salt []byte + // Private key derived from salt and user's pass. + x *big.Int + // Scrambling parameter. + u *big.Int + // Secret ephemeral value. + b *big.Int + // Password verifier. + v *big.Int + // Session key. + sk []byte +} + +// SRP client. +type SRPClient struct { + session SRPClientSession +} + +// User session on the SRP client. +type SRPClientSession struct { + // Large safe prime. Client and server agree upon the value of + // N. + n *big.Int + // Generator modulo N. Client and server agree upon the value + // of N. + g *big.Int + // Multipier parameter. Client and server agree upon the value + // of N. + k *big.Int + // User's email address + ident string + // Scrambling parameter. + u *big.Int + // Secret ephemeral value. + a *big.Int + // Session key. + sk []byte +} + +func NewSRPUser(n, g, k, ident, pass string) (*SRPUser, error) { + var err error + var ok bool + + user := new(SRPUser) + user.n, ok = new(big.Int).SetString(StripSpaceChars(n), 16) + if !ok { + return nil, CPError{"n is invalid"} + } + user.g, ok = new(big.Int).SetString(StripSpaceChars(g), 16) + if !ok { + return nil, CPError{"g is invalid"} + } + user.k, ok = new(big.Int).SetString(StripSpaceChars(k), 16) + if !ok { + return nil, CPError{"k is invalid"} + } + user.ident = ident + user.x = big.NewInt(0) + user.v = big.NewInt(0) + + // Initialize hashing object. + user.h = Sha256{} + user.h.Init([]uint32{}) + + // Generate salt. + user.salt, err = RandomBytes(8) + if err != nil { + return nil, err + } + + // Generate private key `x` from salt+pass + m := make([]byte, 0) + copy(m, user.salt) + m = append(m, StrToBytes(pass)...) + user.h.Message(m) + user.x.SetBytes(user.h.Hash()) + + // Generate password verifier `v` + user.v.Exp(user.g, user.x, user.n) + + return user, nil +} diff --git a/lib/srp_test.go b/lib/srp_test.go new file mode 100644 index 0000000..d7e3b0d --- /dev/null +++ b/lib/srp_test.go @@ -0,0 +1,69 @@ +// Copyright © 2022 siddharth +// SPDX-License-Identifier: ISC + +package lib + +import ( + "math/big" + "testing" +) + +func TestNewSRPUser(t *testing.T) { + n := StripSpaceChars( + `ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024 + e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd + 3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec + 6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f + 24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361 + c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552 + bb9ed529077096966d670c354e4abc9804f1746c08ca237327fff + fffffffffffff`) + g := "2" + k := "3" + ident := "s@ricketyspace.net" + pass := "d59d6c93af0f37f272d924979" + user, err := NewSRPUser(n, g, k, ident, pass) + if err != nil { + t.Errorf("Error: %v\n", err) + return + } + + // Check n. + bigN, _ := new(big.Int).SetString(StripSpaceChars(n), 16) + if user.n.Cmp(bigN) != 0 { + t.Error("Error: n not set correctly\n") + return + } + // Check g. + bigG, _ := new(big.Int).SetString(StripSpaceChars(g), 16) + if user.g.Cmp(bigG) != 0 { + t.Error("Error: g not set correctly\n") + return + } + // Check k. + bigK, _ := new(big.Int).SetString(StripSpaceChars(k), 16) + if user.k.Cmp(bigK) != 0 { + t.Error("Error: k not set correctly\n") + return + } + // Check ident. + if user.ident != ident { + t.Error("Error: user not set correctly\n") + return + } + // Check salt. + if len(user.salt) < 8 { + t.Error("Error: salt not set correctly\n") + return + } + // Check x. + if user.x.Cmp(big.NewInt(1)) < 0 { + t.Error("Error: x not set correctly\n") + return + } + // Check v. + if user.v.Cmp(big.NewInt(1)) < 0 { + t.Error("Error: v not set correctly\n") + return + } +} -- cgit v1.2.3