summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/aes.go2
-rw-r--r--lib/b64.go2
-rw-r--r--lib/blocks.go2
-rw-r--r--lib/brute.go2
-rw-r--r--lib/byte.go2
-rw-r--r--lib/cbrt.go121
-rw-r--r--lib/cbrt_test.go37
-rw-r--r--lib/dh.go2
-rw-r--r--lib/dh_test.go2
-rw-r--r--lib/error.go2
-rw-r--r--lib/gf.go2
-rw-r--r--lib/hamming.go2
-rw-r--r--lib/hash.go2
-rw-r--r--lib/hash_test.go2
-rw-r--r--lib/hex.go2
-rw-r--r--lib/md4.go2
-rw-r--r--lib/md4_test.go2
-rw-r--r--lib/rand.go2
-rw-r--r--lib/rng.go2
-rw-r--r--lib/rsa.go157
-rw-r--r--lib/rsa_test.go133
-rw-r--r--lib/sha1.go2
-rw-r--r--lib/sha1_test.go2
-rw-r--r--lib/sha256.go2
-rw-r--r--lib/sha256_test.go2
-rw-r--r--lib/srp.go149
-rw-r--r--lib/srp_test.go95
-rw-r--r--lib/str.go2
-rw-r--r--lib/str_test.go2
-rw-r--r--lib/time.go2
-rw-r--r--lib/xor.go2
31 files changed, 678 insertions, 64 deletions
diff --git a/lib/aes.go b/lib/aes.go
index 3a5b6de..28dc520 100644
--- a/lib/aes.go
+++ b/lib/aes.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/b64.go b/lib/b64.go
index df0a579..f0e1ba5 100644
--- a/lib/b64.go
+++ b/lib/b64.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/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
+ }
+}
diff --git a/lib/dh.go b/lib/dh.go
index 0782033..7631ae5 100644
--- a/lib/dh.go
+++ b/lib/dh.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/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
diff --git a/lib/gf.go b/lib/gf.go
index c29c1e2..46a1296 100644
--- a/lib/gf.go
+++ b/lib/gf.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/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
diff --git a/lib/hex.go b/lib/hex.go
index a234775..9e0a078 100644
--- a/lib/hex.go
+++ b/lib/hex.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/md4.go b/lib/md4.go
index f02ea93..8d9bc09 100644
--- a/lib/md4.go
+++ b/lib/md4.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/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
diff --git a/lib/rng.go b/lib/rng.go
index 9b4066f..78bd2c9 100644
--- a/lib/rng.go
+++ b/lib/rng.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/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
diff --git a/lib/srp.go b/lib/srp.go
index 18cf5dd..e9417c4 100644
--- a/lib/srp.go
+++ b/lib/srp.go
@@ -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
+ }
+}
diff --git a/lib/str.go b/lib/str.go
index 2f6ece4..e4ff237 100644
--- a/lib/str.go
+++ b/lib/str.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/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
diff --git a/lib/xor.go b/lib/xor.go
index 4a60a6b..994f6e8 100644
--- a/lib/xor.go
+++ b/lib/xor.go
@@ -1,4 +1,4 @@
-// Copyright © 2021 siddharth <s@ricketyspace.net>
+// Copyright © 2021 siddharth ravikumar <s@ricketyspace.net>
// SPDX-License-Identifier: ISC
package lib