Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 483431b

Browse files
[IMPLEMENTATION] RSA algorithm (#727)
* [IMPLEMENTATION] RSA algorithm * [UPDATE] Intended keyGen algorithm with randomness * [FIX] comment fixed * [UPDATE] Implement suggestions * [FIX] Implement suggestions
1 parent cddedb6 commit 483431b

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed

‎cipher/rsa/rsa2.go‎

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
rsa2.go
3+
description: RSA encryption and decryption including key generation
4+
details: [RSA wiki](https://en.wikipedia.org/wiki/RSA_(cryptosystem))
5+
author(s): [ddaniel27](https://github.com/ddaniel27)
6+
*/
7+
package rsa
8+
9+
import (
10+
"encoding/binary"
11+
"fmt"
12+
"math/big"
13+
"math/rand"
14+
15+
"github.com/TheAlgorithms/Go/math/gcd"
16+
"github.com/TheAlgorithms/Go/math/lcm"
17+
"github.com/TheAlgorithms/Go/math/modular"
18+
"github.com/TheAlgorithms/Go/math/prime"
19+
)
20+
21+
// rsa struct contains the public key, private key and modulus
22+
type rsa struct {
23+
publicKey uint64
24+
privateKey uint64
25+
modulus uint64
26+
}
27+
28+
// New initializes the RSA algorithm
29+
// returns the RSA object
30+
func New() *rsa {
31+
// The following code generates keys for RSA encryption/decryption
32+
// 1. Choose two large prime numbers, p and q and compute n = p * q
33+
p, q := randomPrime() // p and q stands for prime numbers
34+
modulus := p * q // n stands for common number
35+
36+
// 2. Compute the totient of n, lcm(p-1, q-1)
37+
totient := uint64(lcm.Lcm(int64(p-1), int64(q-1)))
38+
39+
// 3. Choose an integer e such that 1 < e < totient(n) and gcd(e, totient(n)) = 1
40+
publicKey := uint64(2) // e stands for encryption key (public key)
41+
for publicKey < totient {
42+
if gcd.Recursive(int64(publicKey), int64(totient)) == 1 {
43+
break
44+
}
45+
publicKey++
46+
}
47+
48+
// 4. Compute d such that d * e ≡ 1 (mod totient(n))
49+
inv, _ := modular.Inverse(int64(publicKey), int64(totient))
50+
privateKey := uint64(inv)
51+
52+
return &rsa{
53+
publicKey: publicKey,
54+
privateKey: privateKey,
55+
modulus: modulus,
56+
}
57+
}
58+
59+
// EncryptString encrypts the data using RSA algorithm
60+
// returns the encrypted string
61+
func (rsa *rsa) EncryptString(data string) string {
62+
var nums []byte
63+
64+
for _, char := range data {
65+
slice := make([]byte, 8)
66+
binary.BigEndian.PutUint64( // convert uint64 to byte slice
67+
slice,
68+
encryptDecryptInt(rsa.publicKey, rsa.modulus, uint64(char)), // encrypt each character
69+
)
70+
nums = append(nums, slice...)
71+
}
72+
73+
return string(nums)
74+
}
75+
76+
// DecryptString decrypts the data using RSA algorithm
77+
// returns the decrypted string
78+
func (rsa *rsa) DecryptString(data string) string {
79+
result := ""
80+
middle := []byte(data)
81+
82+
for i := 0; i < len(middle); i += 8 {
83+
if i+8 > len(middle) {
84+
break
85+
}
86+
87+
slice := middle[i : i+8]
88+
num := binary.BigEndian.Uint64(slice) // convert byte slice to uint64
89+
result += fmt.Sprintf("%c", encryptDecryptInt(rsa.privateKey, rsa.modulus, num))
90+
}
91+
92+
return result
93+
}
94+
95+
// GetPublicKey returns the public key and modulus
96+
func (rsa *rsa) GetPublicKey() (uint64, uint64) {
97+
return rsa.publicKey, rsa.modulus
98+
}
99+
100+
// GetPrivateKey returns the private key
101+
func (rsa *rsa) GetPrivateKey() uint64 {
102+
return rsa.privateKey
103+
}
104+
105+
// encryptDecryptInt encrypts or decrypts the data using RSA algorithm
106+
func encryptDecryptInt(e, n, data uint64) uint64 {
107+
pow := new(big.Int).Exp(big.NewInt(int64(data)), big.NewInt(int64(e)), big.NewInt(int64(n)))
108+
return pow.Uint64()
109+
}
110+
111+
// randomPrime returns two random prime numbers
112+
func randomPrime() (uint64, uint64) {
113+
sieve := prime.SieveEratosthenes(1000)
114+
sieve = sieve[10:] // remove first 10 prime numbers (small numbers)
115+
index1 := rand.Intn(len(sieve))
116+
index2 := rand.Intn(len(sieve))
117+
118+
for index1 == index2 {
119+
index2 = rand.Intn(len(sieve))
120+
}
121+
122+
return uint64(sieve[index1]), uint64(sieve[index2])
123+
}

‎cipher/rsa/rsa2_test.go‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package rsa_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/TheAlgorithms/Go/cipher/rsa"
7+
)
8+
9+
func TestRSA(t *testing.T) {
10+
tests := []struct {
11+
name string
12+
message string
13+
}{
14+
{
15+
name: "Encrypt letter 'a' and decrypt it back",
16+
message: "a",
17+
},
18+
{
19+
name: "Encrypt 'Hello, World!' and decrypt it back",
20+
message: "Hello, World!",
21+
},
22+
}
23+
24+
for _, tt := range tests {
25+
t.Run(tt.name, func(t *testing.T) {
26+
rsa := rsa.New()
27+
encrypted := rsa.EncryptString(tt.message)
28+
decrypted := rsa.DecryptString(encrypted)
29+
if decrypted != tt.message {
30+
t.Errorf("expected %s, got %s", tt.message, decrypted)
31+
}
32+
})
33+
}
34+
}
35+
36+
func BenchmarkRSAEncryption(b *testing.B) {
37+
rsa := rsa.New()
38+
for i := 0; i < b.N; i++ {
39+
rsa.EncryptString("Hello, World!")
40+
}
41+
}
42+
43+
func BenchmarkRSADecryption(b *testing.B) {
44+
rsa := rsa.New()
45+
encrypted := rsa.EncryptString("Hello, World!")
46+
for i := 0; i < b.N; i++ {
47+
rsa.DecryptString(encrypted)
48+
}
49+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /