From 3aadff0d4782858afb687593ba54a6066467c95d Mon Sep 17 00:00:00 2001 From: siddharth ravikumar Date: Sun, 14 Aug 2022 13:05:53 -0400 Subject: lib: add `RSAGenKey` --- lib/rsa.go | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/rsa_test.go | 36 +++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) 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 + } +} -- cgit v1.2.3