From 5996bcbe25af46fafceed7d2a4659d9c8b6bf3ac Mon Sep 17 00:00:00 2001 From: arnaucode Date: Sat, 21 Jul 2018 12:39:43 +0200 Subject: [PATCH] rsa encrypt & decrypt, blind signatures, homomorphic multiplication --- README.md | 18 +++++++++ prime/prime.go | 49 +++++++++++++++++++++++++ rsa/rsa.go | 98 +++++++++++++++++++++++++++++++++++++++++++++++++ rsa/rsa_test.go | 54 +++++++++++++++++++++++++++ 4 files changed, 219 insertions(+) create mode 100644 README.md create mode 100644 prime/prime.go create mode 100644 rsa/rsa.go create mode 100644 rsa/rsa_test.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..71c2f46 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# cryptofun + +Crypto algorithms from scratch. Academic purposes only. + + +## RSA +- [x] GenerateKeyPair +- [x] Encrypt +- [x] Decrypt +- [x] Blind +- [x] Blind Signature +- [x] Unblind Signature +- [x] Verify Signature +- [x] Homomorphic Multiplication + +## Paillier +## ECC +## Shamir Secret Sharing diff --git a/prime/prime.go b/prime/prime.go new file mode 100644 index 0000000..a412287 --- /dev/null +++ b/prime/prime.go @@ -0,0 +1,49 @@ +package prime + +import "math/rand" + +func RandInt(min int, max int) int { + r := rand.Intn(max-min) + min + return r +} +func RandPrime(min int, max int) int { + primes := SieveOfEratosthenes(max) + randN := rand.Intn(len(primes)-0) + 0 + return primes[randN] +} + +// return list of primes less than N +func SieveOfEratosthenes(N int) (primes []int) { + b := make([]bool, N) + for i := 2; i < N; i++ { + if b[i] == true { + continue + } + primes = append(primes, i) + for k := i * i; k < N; k += i { + b[k] = true + } + } + return +} + +func Gcd(a, b int) int { + var bgcd func(a, b, res int) int + bgcd = func(a, b, res int) int { + switch { + case a == b: + return res * a + case a%2 == 0 && b%2 == 0: + return bgcd(a/2, b/2, 2*res) + case a%2 == 0: + return bgcd(a/2, b, res) + case b%2 == 0: + return bgcd(a, b/2, res) + case a > b: + return bgcd(a-b, b, res) + default: + return bgcd(a, b-a, res) + } + } + return bgcd(a, b, 1) +} diff --git a/rsa/rsa.go b/rsa/rsa.go new file mode 100644 index 0000000..7d02224 --- /dev/null +++ b/rsa/rsa.go @@ -0,0 +1,98 @@ +package rsa + +import ( + "bytes" + "math/big" + "math/rand" + "time" + + prime "../prime" +) + +const ( + MaxPrime = 2000 + MinPrime = 500 +) + +type PublicKey struct { + E *big.Int `json:"e"` + N *big.Int `json:"n"` +} +type PublicKeyString struct { + E string `json:"e"` + N string `json:"n"` +} +type PrivateKey struct { + D *big.Int `json:"d"` + N *big.Int `json:"n"` +} + +type Key struct { + PubK PublicKey + PrivK PrivateKey +} + +func GenerateKeyPair() (key Key) { + rand.Seed(time.Now().Unix()) + p := prime.RandPrime(MinPrime, MaxPrime) + q := prime.RandPrime(MinPrime, MaxPrime) + + n := p * q + phi := (p - 1) * (q - 1) + e := 65537 + var pubK PublicKey + pubK.E = big.NewInt(int64(e)) + pubK.N = big.NewInt(int64(n)) + + d := new(big.Int).ModInverse(big.NewInt(int64(e)), big.NewInt(int64(phi))) + + var privK PrivateKey + privK.D = d + privK.N = big.NewInt(int64(n)) + + key.PubK = pubK + key.PrivK = privK + return key +} + +func Encrypt(m *big.Int, pubK PublicKey) *big.Int { + Me := new(big.Int).Exp(m, pubK.E, nil) + c := new(big.Int).Mod(Me, pubK.N) + return c +} +func Decrypt(c *big.Int, privK PrivateKey) *big.Int { + Cd := new(big.Int).Exp(c, privK.D, nil) + m := new(big.Int).Mod(Cd, privK.N) + return m +} + +func Blind(m *big.Int, r *big.Int, pubK PublicKey) *big.Int { + rE := new(big.Int).Exp(r, pubK.E, nil) + mrE := new(big.Int).Mul(m, rE) + mBlinded := new(big.Int).Mod(mrE, pubK.N) + return mBlinded +} + +func BlindSign(m *big.Int, privK PrivateKey) *big.Int { + sigma := new(big.Int).Exp(m, privK.D, privK.N) + return sigma +} +func Unblind(sigma *big.Int, r *big.Int, pubK PublicKey) *big.Int { + r1 := new(big.Int).ModInverse(r, pubK.N) + bsr := new(big.Int).Mul(sigma, r1) + sig := new(big.Int).Mod(bsr, pubK.N) + return sig +} +func Verify(msg *big.Int, mSigned *big.Int, pubK PublicKey) bool { + //decrypt the mSigned with pubK + Cd := new(big.Int).Exp(mSigned, pubK.E, nil) + m := new(big.Int).Mod(Cd, pubK.N) + return bytes.Equal(msg.Bytes(), m.Bytes()) +} + +func HomomorphicMul(c1 *big.Int, c2 *big.Int, pubK PublicKey) *big.Int { + c1c2 := new(big.Int).Mul(c1, c2) + n2 := new(big.Int).Mul(pubK.N, pubK.N) + d := new(big.Int).Mod(c1c2, n2) + return d +} diff --git a/rsa/rsa_test.go b/rsa/rsa_test.go new file mode 100644 index 0000000..30a234f --- /dev/null +++ b/rsa/rsa_test.go @@ -0,0 +1,54 @@ +package rsa + +import ( + "bytes" + "math/big" + "testing" +) + +func TestEncryptDecrypt(t *testing.T) { + key := GenerateKeyPair() + + mBytes := []byte("Hi") + m := new(big.Int).SetBytes(mBytes) + c := Encrypt(m, key.PubK) + + d := Decrypt(c, key.PrivK) + if m == d { + t.Errorf("m not equal to decrypted") + } +} +func TestBlindSignature(t *testing.T) { + key := GenerateKeyPair() + + mBytes := []byte("Hi") + m := new(big.Int).SetBytes(mBytes) + c := Encrypt(m, key.PubK) + + d := Decrypt(c, key.PrivK) + if m == d { + t.Errorf("decrypted d not equal to original m") + } + rVal := big.NewInt(int64(101)) + mBlinded := Blind(m, rVal, key.PubK) + sigma := BlindSign(mBlinded, key.PrivK) + mSigned := Unblind(sigma, rVal, key.PubK) + verified := Verify(m, mSigned, key.PubK) + if !verified { + t.Errorf("false, signature not verified") + } +} + +func TestHomomorphiMultiplication(t *testing.T) { + key := GenerateKeyPair() + + n1 := big.NewInt(int64(11)) + n2 := big.NewInt(int64(15)) + c1 := Encrypt(n1, key.PubK) + c2 := Encrypt(n2, key.PubK) + c3c4 := HomomorphicMul(c1, c2, key.PubK) + d := Decrypt(c3c4, key.PrivK) + if !bytes.Equal(new(big.Int).Mul(n1, n2).Bytes(), d.Bytes()) { + t.Errorf("decrypted result not equal to original result") + } +}