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