|
| 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 | +} |
0 commit comments