Files
infisical/cli/packages/srp/client.go
2022-11-17 17:54:35 -05:00

141 lines
3.0 KiB
Go

package srp
import (
"bytes"
"errors"
"math/big"
)
type SRPClient struct {
Params *SRPParams
Secret1 *big.Int
Multiplier *big.Int
A *big.Int
X *big.Int
M1 []byte
M2 []byte
K []byte
u *big.Int
s *big.Int
}
func NewClient(params *SRPParams, identity, password, secret1 []byte) *SRPClient {
multiplier := getMultiplier(params)
secret1Int := intFromBytes(secret1)
Ab := getA(params, secret1Int)
A := intFromBytes(Ab)
x := getx(params, []byte(""), identity, password) // salt has to be set using SetSalt
return &SRPClient{
Params: params,
Multiplier: multiplier,
Secret1: secret1Int,
A: A,
X: x,
}
}
func (c *SRPClient) ComputeA() []byte {
return intToBytes(c.A)
}
// ComputeVerifier returns a verifier that is calculated as described in
// Section 3 of [SRP-RFC]
func ComputeVerifier(params *SRPParams, salt, identity, password []byte) []byte {
x := getx(params, salt, identity, password)
vNum := new(big.Int)
vNum.Exp(params.G, x, params.N)
return padToN(vNum, params)
}
func (c *SRPClient) SetB(Bb []byte) {
B := intFromBytes(Bb)
u := getu(c.Params, c.A, B)
S := clientGetS(c.Params, c.Multiplier, c.X, c.Secret1, B, u)
c.K = getK(c.Params, S)
c.M1 = getM1(c.Params, intToBytes(c.A), Bb, c.K) // modified S -> c.K
c.M2 = getM2(c.Params, intToBytes(c.A), c.M1, c.K)
c.u = u // Only for tests
c.s = intFromBytes(S) // Only for tests
}
func (c *SRPClient) SetSalt(salt, identity, password []byte) {
c.X = getx(c.Params, salt, identity, password) //Overwrite
}
func (c *SRPClient) ComputeM1() []byte {
if c.M1 == nil {
panic("Incomplete protocol")
}
return c.M1
}
func (c *SRPClient) ComputeK() []byte {
return c.K
}
func (c *SRPClient) CheckM2(M2 []byte) error {
if !bytes.Equal(c.M2, M2) {
return errors.New("M2 didn't check")
} else {
return nil
}
}
func getA(params *SRPParams, a *big.Int) []byte {
ANum := new(big.Int)
ANum.Exp(params.G, a, params.N)
return padToN(ANum, params)
}
func clientGetS(params *SRPParams, k, x, a, B, u *big.Int) []byte {
BLessThan0 := B.Cmp(big.NewInt(0)) <= 0
NLessThanB := params.N.Cmp(B) <= 0
if BLessThan0 || NLessThanB {
panic("invalid server-supplied 'B', must be 1..N-1")
}
result1 := new(big.Int)
result1.Exp(params.G, x, params.N)
result2 := new(big.Int)
result2.Mul(k, result1)
result3 := new(big.Int)
result3.Sub(B, result2)
result4 := new(big.Int)
result4.Mul(u, x)
result5 := new(big.Int)
result5.Add(a, result4)
result6 := new(big.Int)
result6.Exp(result3, result5, params.N)
result7 := new(big.Int)
result7.Mod(result6, params.N)
return padToN(result7, params)
}
func getx(params *SRPParams, salt, I, P []byte) *big.Int {
var ipBytes []byte
ipBytes = append(ipBytes, I...)
ipBytes = append(ipBytes, []byte(":")...)
ipBytes = append(ipBytes, P...)
hashIP := params.Hash.New()
hashIP.Write(ipBytes)
hashX := params.Hash.New()
hashX.Write(salt)
hashX.Write(hashToBytes(hashIP))
return hashToInt(hashX)
}