diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/aes.go | 2 | ||||
-rw-r--r-- | lib/b64.go | 2 | ||||
-rw-r--r-- | lib/blocks.go | 2 | ||||
-rw-r--r-- | lib/brute.go | 2 | ||||
-rw-r--r-- | lib/byte.go | 2 | ||||
-rw-r--r-- | lib/cbrt.go | 121 | ||||
-rw-r--r-- | lib/cbrt_test.go | 37 | ||||
-rw-r--r-- | lib/dh.go | 2 | ||||
-rw-r--r-- | lib/dh_test.go | 2 | ||||
-rw-r--r-- | lib/error.go | 2 | ||||
-rw-r--r-- | lib/gf.go | 2 | ||||
-rw-r--r-- | lib/hamming.go | 2 | ||||
-rw-r--r-- | lib/hash.go | 2 | ||||
-rw-r--r-- | lib/hash_test.go | 2 | ||||
-rw-r--r-- | lib/hex.go | 2 | ||||
-rw-r--r-- | lib/md4.go | 2 | ||||
-rw-r--r-- | lib/md4_test.go | 2 | ||||
-rw-r--r-- | lib/rand.go | 2 | ||||
-rw-r--r-- | lib/rng.go | 2 | ||||
-rw-r--r-- | lib/rsa.go | 157 | ||||
-rw-r--r-- | lib/rsa_test.go | 133 | ||||
-rw-r--r-- | lib/sha1.go | 2 | ||||
-rw-r--r-- | lib/sha1_test.go | 2 | ||||
-rw-r--r-- | lib/sha256.go | 2 | ||||
-rw-r--r-- | lib/sha256_test.go | 2 | ||||
-rw-r--r-- | lib/srp.go | 149 | ||||
-rw-r--r-- | lib/srp_test.go | 95 | ||||
-rw-r--r-- | lib/str.go | 2 | ||||
-rw-r--r-- | lib/str_test.go | 2 | ||||
-rw-r--r-- | lib/time.go | 2 | ||||
-rw-r--r-- | lib/xor.go | 2 |
31 files changed, 678 insertions, 64 deletions
@@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/blocks.go b/lib/blocks.go index b157eb3..76f34d3 100644 --- a/lib/blocks.go +++ b/lib/blocks.go @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/brute.go b/lib/brute.go index ca875ed..04727da 100644 --- a/lib/brute.go +++ b/lib/brute.go @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/byte.go b/lib/byte.go index 0544a48..02746ae 100644 --- a/lib/byte.go +++ b/lib/byte.go @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/cbrt.go b/lib/cbrt.go new file mode 100644 index 0000000..07a56cf --- /dev/null +++ b/lib/cbrt.go @@ -0,0 +1,121 @@ +// Copyright © 2022 siddharth ravikumar <s@ricketyspace.net> +// SPDX-License-Identifier: ISC + +package lib + +import ( + "math/big" +) + +// Cube root tolerance. +var bigCubeRootTolerance = big.NewFloat(0.00001) + +// Returns cube root of a. +// +// Uses Newton's method. +// https://en.wikipedia.org/wiki/Newton's_method +func BigCubeRoot(a *big.Float) *big.Float { + // If x^3 = a, then our f(x) is: + // f(x) = x^3 - a + fx := func(x *big.Float) *big.Float { + // x^3 + e := big.NewFloat(0) + e = e.Mul(x, x) + e = e.Mul(e, x) + + // x^3 - a + z := big.NewFloat(0).Sub(e, a) + + return z + } + + // f'(x) is: + // f'(x) = 3 * x^2 + fxPrime := func(x *big.Float) *big.Float { + // x^2 + x2 := big.NewFloat(0).Mul(x, x) + + // 3 * x^2 + z := big.NewFloat(0).Mul(big.NewFloat(3), x2) + + return z + } + + x0 := a // Initial guess. + for i := 0; i < 1000000; i++ { + // f(x0) / f'(x0) + d := fx(x0) + d = d.Quo(d, fxPrime(x0)) + + // x0 - ( f(x0) / f'(x0) ) + x1 := big.NewFloat(0).Set(x0) + x1 = x1.Sub(x1, d) + + // x0 - x1 + df := big.NewFloat(0).Set(x0) + df = df.Sub(df, x1) + df = df.Abs(df) + if df.Cmp(bigCubeRootTolerance) == -1 { + return x1 + } + + x0 = x1 + } + return nil +} + +// Returns cube root of a. +// +// Uses Newton's method. +// https://en.wikipedia.org/wiki/Newton's_method +func BigIntCubeRoot(a *big.Int) *big.Int { + // If x^3 = a, then our f(x) is: + // f(x) = x^3 - a + fx := func(x *big.Int) *big.Int { + // x^3 + e := big.NewInt(0) + e = e.Mul(x, x) + e = e.Mul(e, x) + + // x^3 - a + z := big.NewInt(0).Sub(e, a) + + return z + } + + // f'(x) is: + // f'(x) = 3 * x^2 + fxPrime := func(x *big.Int) *big.Int { + // x^2 + x2 := big.NewInt(0).Mul(x, x) + + // 3 * x^2 + z := big.NewInt(0).Mul(big.NewInt(3), x2) + + return z + } + + x0 := a // Initial guess. + zero := big.NewInt(0) + one := big.NewInt(1) + for i := 0; i < 1000000; i++ { + // f(x0) / f'(x0) + d := fx(x0) + d = d.Div(d, fxPrime(x0)) + + // x0 - ( f(x0) / f'(x0) ) + x1 := big.NewInt(0).Set(x0) + x1 = x1.Sub(x1, d) + + // x0 - x1 + df := big.NewInt(0).Set(x0) + df = df.Sub(df, x1) + df = df.Abs(df) + if df.Cmp(zero) == 0 { + return x1.Sub(x1, one) + } + + x0 = x1 + } + return nil +} diff --git a/lib/cbrt_test.go b/lib/cbrt_test.go new file mode 100644 index 0000000..36bcc79 --- /dev/null +++ b/lib/cbrt_test.go @@ -0,0 +1,37 @@ +// Copyright © 2022 siddharth ravikumar <s@ricketyspace.net> +// SPDX-License-Identifier: ISC + +package lib + +import ( + "math/big" + "testing" +) + +func TestBigCubeRoot(t *testing.T) { + a := big.NewFloat(612) + acr := BigCubeRoot(a) + if acr == nil { + t.Errorf("Could not find cube root of %v\n", a) + return + } + expected := big.NewFloat(8.490184748) + if big.NewFloat(0).Sub(acr, expected).Cmp(bigCubeRootTolerance) != -1 { + t.Errorf("Could not find cube root of %v (%v)\n", a, acr) + return + } +} + +func TestBigIntCubeRoot(t *testing.T) { + a := big.NewInt(19683) + acr := BigIntCubeRoot(a) + if acr == nil { + t.Errorf("Could not find cube root of %v\n", a) + return + } + expected := big.NewInt(27) + if big.NewInt(0).Sub(acr, expected).Cmp(big.NewInt(0)) != 0 { + t.Errorf("Could not find cube root of %v (%v)\n", a, acr) + return + } +} @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/dh_test.go b/lib/dh_test.go index f313d82..c24a517 100644 --- a/lib/dh_test.go +++ b/lib/dh_test.go @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/error.go b/lib/error.go index 5b62ab5..19d9d5d 100644 --- a/lib/error.go +++ b/lib/error.go @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/hamming.go b/lib/hamming.go index 229fb7f..74f9716 100644 --- a/lib/hamming.go +++ b/lib/hamming.go @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/hash.go b/lib/hash.go index b636e17..32c1fe5 100644 --- a/lib/hash.go +++ b/lib/hash.go @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/hash_test.go b/lib/hash_test.go index bde6b3f..5b4ba35 100644 --- a/lib/hash_test.go +++ b/lib/hash_test.go @@ -1,4 +1,4 @@ -// Copyright © 2022 siddharth <s@ricketyspace.net> +// Copyright © 2022 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/md4_test.go b/lib/md4_test.go index 65770d1..d7b412f 100644 --- a/lib/md4_test.go +++ b/lib/md4_test.go @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/rand.go b/lib/rand.go index 5fdade9..41dfe6d 100644 --- a/lib/rand.go +++ b/lib/rand.go @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/rsa.go b/lib/rsa.go new file mode 100644 index 0000000..772b898 --- /dev/null +++ b/lib/rsa.go @@ -0,0 +1,157 @@ +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> +// SPDX-License-Identifier: ISC + +package lib + +import ( + "crypto/rand" + "math/big" +) + +// Represents an RSA key pair. +type RSAPair struct { + Public *RSAPub + Private *RSAPrivate +} + +type RSAPub struct { + e *big.Int + n *big.Int +} + +type RSAPrivate struct { + d *big.Int + n *big.Int +} + +// Copy b to a. +func biCopy(a, b *big.Int) *big.Int { + a.SetBytes(b.Bytes()) + if b.Sign() == -1 { + a.Mul(a, big.NewInt(-1)) + } + return a +} + +func InvMod(a, n *big.Int) (*big.Int, error) { + // Initialize. + t0 := big.NewInt(0) + t1 := big.NewInt(1) + r0 := biCopy(big.NewInt(0), n) + r1 := biCopy(big.NewInt(0), a) + + for r1.Cmp(big.NewInt(0)) != 0 { + q := big.NewInt(0) + q.Div(r0, r1) + + tt := big.NewInt(0) + tt = tt.Mul(q, t1) + tt = tt.Sub(t0, tt) + + biCopy(t0, t1) + biCopy(t1, tt) + + tr := big.NewInt(0) + tr = tr.Mul(q, r1) + tr = tr.Sub(r0, tr) + + biCopy(r0, r1) + biCopy(r1, tr) + } + + if r0.Cmp(big.NewInt(1)) > 0 { + return nil, CPError{"not invertible"} + } + if t0.Cmp(big.NewInt(0)) < 0 { + t0.Add(t0, n) + } + return t0, nil +} + +func RSAGenKey() (*RSAPair, error) { + // Initialize. + e := big.NewInt(3) + d := big.NewInt(0) + n := big.NewInt(0) + + // Compute n and d. + for { + // Generate prime p. + p, err := rand.Prime(rand.Reader, 1024) + if err != nil { + return nil, CPError{"unable to generate p"} + } + + // Generate prime q. + q, err := rand.Prime(rand.Reader, 1024) + if err != nil { + return nil, CPError{"unable to generate q"} + } + + // Calculate n. + n = big.NewInt(0).Mul(p, q) + + // Calculate totient. + p1 := big.NewInt(0).Sub(p, big.NewInt(1)) // p-1 + q1 := big.NewInt(0).Sub(q, big.NewInt(1)) // q-1 + et := big.NewInt(0).Mul(p1, q1) // Totient `et`. + + // Calculate private key `d`. + d, err = InvMod(e, et) + if err != nil { + continue // Inverse does not does. Try again. + } + break + } + if n.Cmp(big.NewInt(0)) <= 0 { + return nil, CPError{"unable to compute n"} + } + if d.Cmp(big.NewInt(0)) <= 0 { + return nil, CPError{"unable to compute d"} + } + + // Make pub key. + pub := new(RSAPub) + pub.e = e + pub.n = biCopy(big.NewInt(0), n) + + // Make private key. + prv := new(RSAPrivate) + prv.d = d + prv.n = biCopy(big.NewInt(0), n) + + // Make key pair. + pair := new(RSAPair) + pair.Public = pub + pair.Private = prv + + return pair, nil +} + +func (r *RSAPub) Encrypt(msg []byte) []byte { + // Convert message to big int. + m := big.NewInt(0).SetBytes(msg) + + // Encrypt. + c := big.NewInt(0).Exp(m, r.e, r.n) + + return c.Bytes() +} + +func (r *RSAPub) E() *big.Int { + return r.e +} + +func (r *RSAPub) N() *big.Int { + return r.n +} + +func (r *RSAPrivate) Decrypt(cipher []byte) []byte { + // Convert cipher to big int. + c := big.NewInt(0).SetBytes(cipher) + + // Decrypt. + m := big.NewInt(0).Exp(c, r.d, r.n) + + return m.Bytes() +} diff --git a/lib/rsa_test.go b/lib/rsa_test.go new file mode 100644 index 0000000..d26ee2c --- /dev/null +++ b/lib/rsa_test.go @@ -0,0 +1,133 @@ +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> +// SPDX-License-Identifier: ISC + +package lib + +import ( + "math/big" + "testing" +) + +func TestInvMod(t *testing.T) { + a := big.NewInt(17) + b := big.NewInt(3120) + e := big.NewInt(2753) // Expected inverse. + i, err := InvMod(a, b) + if err != nil { + t.Errorf("InvMod(%v,%v) failed: %v", a, b, err) + return + } + if i.Cmp(e) != 0 { + t.Errorf("gcd(%v,%v) != %v", a, b, e) + } + + a = big.NewInt(240) + b = big.NewInt(47) + e = big.NewInt(19) // Expected inverse. + i, err = InvMod(a, b) + if err != nil { + t.Errorf("InvMod(%v,%v) failed: %v", a, b, err) + return + } + if i.Cmp(e) != 0 { + t.Errorf("gcd(%v,%v) != %v", a, b, e) + } + + a = big.NewInt(11) + b = big.NewInt(26) + e = big.NewInt(19) // Expected inverse. + i, err = InvMod(a, b) + if err != nil { + t.Errorf("InvMod(%v,%v) failed: %v", a, b, err) + return + } + if i.Cmp(e) != 0 { + t.Errorf("gcd(%v,%v) != %v", a, b, e) + } + + a = big.NewInt(3) + b = big.NewInt(7) + e = big.NewInt(5) // Expected inverse. + i, err = InvMod(a, b) + if err != nil { + t.Errorf("InvMod(%v,%v) failed: %v", a, b, err) + return + } + if i.Cmp(e) != 0 { + t.Errorf("gcd(%v,%v) != %v", a, b, e) + } +} + +func TestRSAGenKey(t *testing.T) { + pair, err := RSAGenKey() + if err != nil { + t.Errorf("genkey: %v", err) + return + } + if pair.Public == nil { + t.Error("genkey: pub key is nil") + return + } + if pair.Public.e.Cmp(big.NewInt(0)) < 1 { + t.Error("genkey: e is invalid") + return + } + if pair.Public.n.Cmp(big.NewInt(0)) < 1 { + t.Error("genkey: n is invalid") + return + } + if pair.Private == nil { + t.Error("genkey: private key is nil") + return + } + if pair.Private.d.Cmp(big.NewInt(0)) < 1 { + t.Error("genkey: d is invalid") + return + } + if pair.Private.n.Cmp(big.NewInt(0)) < 1 { + t.Error("genkey: n is invalid") + return + } + if pair.Public.n.Cmp(pair.Private.n) != 0 { + t.Error("genkey: public.n != private.n") + return + } +} + +func TestRSAEncryptDecrypt(t *testing.T) { + pair, err := RSAGenKey() + if err != nil { + t.Errorf("genkey: %v", err) + return + } + pub := pair.Public + prv := pair.Private + + // [1] Encrypt. + msg := []byte("42") + enc := pub.Encrypt(msg) + if len(enc) < 1 { + t.Errorf("encrypt failed: %v", enc) + return + } + // [1] Decrypt. + dec := prv.Decrypt(enc) + if !BytesEqual(msg, dec) { + t.Errorf("decrypt failed: %v", dec) + return + } + + // [2] Encrypt. + msg = []byte("0xd1a4a6e870b40a261827f17741c19facf80d01a537d55e59abe5d615d961a23f") + enc = pub.Encrypt(msg) + if len(enc) < 1 { + t.Errorf("encrypt failed: %v", enc) + return + } + // [2] Decrypt. + dec = prv.Decrypt(enc) + if !BytesEqual(msg, dec) { + t.Errorf("decrypt failed: %v", dec) + return + } +} diff --git a/lib/sha1.go b/lib/sha1.go index 9a9d6df..5cfff07 100644 --- a/lib/sha1.go +++ b/lib/sha1.go @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/sha1_test.go b/lib/sha1_test.go index d2c8a32..50a7f9f 100644 --- a/lib/sha1_test.go +++ b/lib/sha1_test.go @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/sha256.go b/lib/sha256.go index 10b96b5..42535f3 100644 --- a/lib/sha256.go +++ b/lib/sha256.go @@ -1,4 +1,4 @@ -// Copyright © 2022 siddharth <s@ricketyspace.net> +// Copyright © 2022 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/sha256_test.go b/lib/sha256_test.go index 5b1a797..8b8709b 100644 --- a/lib/sha256_test.go +++ b/lib/sha256_test.go @@ -1,4 +1,4 @@ -// Copyright © 2022 siddharth <s@ricketyspace.net> +// Copyright © 2022 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib @@ -1,4 +1,4 @@ -// Copyright © 2022 siddharth <s@ricketyspace.net> +// Copyright © 2022 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib @@ -8,26 +8,6 @@ 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 @@ -144,17 +124,26 @@ func NewSRPUser(n, g, k, ident, pass string) (*SRPUser, error) { return nil, err } + // Compute verifier. + user.ComputeVerifier(pass) + + return user, nil +} + +func (user *SRPUser) Ident() string { + return user.ident +} + +func (u *SRPUser) ComputeVerifier(pass string) { // Generate private key `x` from salt+pass m := make([]byte, 0) - copy(m, user.salt) + copy(m, u.salt) m = append(m, StrToBytes(pass)...) - user.h.Message(m) - user.x.SetBytes(user.h.Hash()) + u.h.Message(m) + u.x.SetBytes(u.h.Hash()) // Generate password verifier `v` - user.v.Exp(user.g, user.x, user.n) - - return user, nil + u.v.Exp(u.g, u.x, u.n) } func (u *SRPUser) EphemeralKeyGen() { @@ -193,6 +182,21 @@ func (u *SRPUser) EphemeralKeyPub() (*big.Int, error) { return pub, nil } +func (u *SRPUser) EphemeralKeyPubSimple() (*big.Int, error) { + if u.g == nil || u.g.Cmp(big.NewInt(0)) != 1 { + return nil, CPError{"g is not initialized"} + } + if u.b == nil || u.b.Cmp(big.NewInt(0)) != 1 { + return nil, CPError{"b is not initialized"} + } + + // pub is 'B' + pub := new(big.Int) + pub.Exp(u.g, u.b, u.n) + + return pub, nil +} + func (u *SRPUser) SetScramblingParam(a *big.Int) error { b, err := u.EphemeralKeyPub() if err != nil { @@ -222,11 +226,27 @@ func (u *SRPUser) SetScramblingParam(a *big.Int) error { return nil } -func (u *SRPUser) ComputeSessionKey(a *big.Int) error { - if a.Cmp(big.NewInt(0)) != 1 { - return CPError{"a is invalid"} +func (u *SRPUser) SetScramblingParamSimple() error { + // random 128-bits + r, err := RandomBytes(16) + if err != nil { + return err } + // Set scrambling paramter u + u.u = new(big.Int) + u.u.SetBytes(r) + if u.u.Cmp(big.NewInt(0)) != 1 { + return CPError{"u is invalid"} + } + return nil +} + +func (u *SRPUser) GetScramblingParam() []byte { + return u.u.Bytes() +} + +func (u *SRPUser) ComputeSessionKey(a *big.Int) error { // v^u vu := new(big.Int) vu.Exp(u.v, u.u, u.n) @@ -247,7 +267,10 @@ func (u *SRPUser) ComputeSessionKey(a *big.Int) error { } func (u *SRPUser) SessionKeyMacVerify(mac []byte) bool { - return u.h.MacVerify(u.salt, u.sk, mac) + if BytesEqual(HmacSha256(u.sk, u.salt), mac) { + return true + } + return false } func (u *SRPUser) LoggedIn() bool { @@ -370,14 +393,25 @@ func (s *SRPClientSession) SetScramblingParam(b *big.Int) error { return nil } +func (s *SRPClientSession) SetScramblingParamSimple(u []byte) error { + if len(u) < 16 { + return CPError{"server u is invalid"} + } + + // Set scrambling paramter u + s.u = new(big.Int) + s.u.SetBytes(u) + if s.u.Cmp(big.NewInt(0)) != 1 { + return CPError{"u is invalid"} + } + return nil +} + func (s *SRPClientSession) ComputeSessionKey(salt []byte, pass string, b *big.Int) error { if len(salt) < 1 { return CPError{"salt invalid"} } - if len(pass) < 1 { - return CPError{"pass invalid"} - } // salt+pass sp := make([]byte, 0) @@ -423,12 +457,51 @@ func (s *SRPClientSession) ComputeSessionKey(salt []byte, return nil } -func (s *SRPClientSession) SessionKeyMac(salt []byte) ([]byte, error) { - if len(s.sk) < 1 { - return nil, CPError{"sk is invalid"} +func (s *SRPClientSession) ComputeSessionKeySimple(salt []byte, + pass string, b *big.Int) error { + if len(salt) < 1 { + return CPError{"salt invalid"} } + + // salt+pass + sp := make([]byte, 0) + copy(sp, salt) + sp = append(sp, StrToBytes(pass)...) + + // x = H(salt+pass) + x := new(big.Int) + s.h.Message(sp) + x.SetBytes(s.h.Hash()) + + // u * x + ux := new(big.Int) + ux.Mul(s.u, x) + + // a + u*x + aux := new(big.Int) + aux.Add(s.a, ux) + + // S = (B) ^ (a + u*x) + sec := new(big.Int) + sec.Exp(b, aux, s.n) + sb := sec.Bytes() + + // K = H(S) + m := make([]byte, 0) + m = append(m, sb...) + s.h.Message(m) + s.sk = s.h.Hash() + + return nil +} + +func (s *SRPClientSession) SetSessionKey(key []byte) { + s.sk = key +} + +func (s *SRPClientSession) SessionKeyMac(salt []byte) ([]byte, error) { if len(salt) < 1 { return nil, CPError{"salt is invalid"} } - return s.h.Mac(salt, s.sk), nil + return HmacSha256(s.sk, salt), nil } diff --git a/lib/srp_test.go b/lib/srp_test.go index 06d1a27..9d34eeb 100644 --- a/lib/srp_test.go +++ b/lib/srp_test.go @@ -1,4 +1,4 @@ -// Copyright © 2022 siddharth <s@ricketyspace.net> +// Copyright © 2022 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib @@ -397,3 +397,96 @@ func TestSRPSessionKey(t *testing.T) { return } } + +func TestSimplifiedSRP(t *testing.T) { + n := StripSpaceChars( + `ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024 + e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd + 3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec + 6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f + 24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361 + c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552 + bb9ed529077096966d670c354e4abc9804f1746c08ca237327fff + fffffffffffff`) + g := "2" + k := "3" + ident := "s@ricketyspace.net" + pass := "d59d6c93af0f37f272d924979" + + // Init srp server user. + user, err := NewSRPUser(n, g, k, ident, pass) + if err != nil { + t.Errorf("unable to create user on server: %v\n", err) + return + } + + // Get server's pub for user. + user.EphemeralKeyGen() + pubB, err := user.EphemeralKeyPubSimple() + if err != nil { + t.Errorf("server ephemeral pub error: %v\n", err) + return + } + + // Init srp client session. + session, err := NewSRPClientSession(n, g, k, ident) + if err != nil { + t.Errorf("unable to create client session: %v\n", err) + return + } + + // Get client's pub for user. + pubA, err := session.EphemeralKeyPub() + if err != nil { + t.Errorf("client ephemeral pub error: %v\n", err) + return + } + + // Compute server's scrambling parameter for user. + err = user.SetScramblingParamSimple() + if err != nil { + t.Errorf("unable generate server scrambling parameter: %v\n", err) + return + } + + // Compute client's scrambling paramter for user. + err = session.SetScramblingParamSimple(user.u.Bytes()) + if err != nil { + t.Errorf("unable generate client scrambling parameter: %v\n", err) + return + } + + // Compute server's session key for user. + err = user.ComputeSessionKey(pubA) + if err != nil { + t.Errorf("unable to compute server's session key: %v", err) + return + } + + // Compute client's session key for for user. + err = session.ComputeSessionKeySimple(user.salt, pass, pubB) + if err != nil { + t.Errorf("unable to compute client's session key: %v", err) + return + } + + // Verify that the session key is the same. + if !BytesEqual(user.sk, session.sk) { + t.Errorf("server's and client's session key not equal:"+ + " server_sk(%v): client_sk(%v)", user.sk, session.sk) + return + } + + // Generate MAC of client session's session key + sMac, err := session.SessionKeyMac(user.salt) + if err != nil { + t.Errorf("unable to generate client session's mac: %v", err) + return + } + + // Verify MAC with server. + if !user.SessionKeyMacVerify(sMac) { + t.Errorf("client session mac verify failed: %v", err) + return + } +} @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/str_test.go b/lib/str_test.go index 1b1bb60..bd20c39 100644 --- a/lib/str_test.go +++ b/lib/str_test.go @@ -1,4 +1,4 @@ -// Copyright © 2022 siddharth <s@ricketyspace.net> +// Copyright © 2022 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib diff --git a/lib/time.go b/lib/time.go index 03aece4..0efc92e 100644 --- a/lib/time.go +++ b/lib/time.go @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib @@ -1,4 +1,4 @@ -// Copyright © 2021 siddharth <s@ricketyspace.net> +// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net> // SPDX-License-Identifier: ISC package lib |