summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsiddharth ravikumar <s@ricketyspace.net>2022-08-14 13:05:53 -0400
committersiddharth ravikumar <s@ricketyspace.net>2022-08-14 13:05:53 -0400
commit3aadff0d4782858afb687593ba54a6066467c95d (patch)
treef166a13e56e1d81f036a7eb99f7d409826f17abb
parenteb436e38563783b901c271d5779d35ecad7c45f9 (diff)
lib: add `RSAGenKey`
-rw-r--r--lib/rsa.go77
-rw-r--r--lib/rsa_test.go36
2 files changed, 113 insertions, 0 deletions
diff --git a/lib/rsa.go b/lib/rsa.go
index 2c0769b..17cf6b0 100644
--- a/lib/rsa.go
+++ b/lib/rsa.go
@@ -4,6 +4,7 @@
package lib
import (
+ "crypto/rand"
"math/big"
)
@@ -13,6 +14,22 @@ type GCDResult struct {
Y *big.Int // Bézout coefficient 'y'
}
+// 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())
@@ -98,3 +115,63 @@ func invmod(a, n *big.Int) (*big.Int, error) {
}
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
+}
diff --git a/lib/rsa_test.go b/lib/rsa_test.go
index 6e04ee7..f735f75 100644
--- a/lib/rsa_test.go
+++ b/lib/rsa_test.go
@@ -100,3 +100,39 @@ func TestInvMod(t *testing.T) {
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
+ }
+}