Изначально задаются два простых числа (случайных) и по ним вычисляется открытый и закрытый ключ. А затем получается, что если использовать правильную формулу при шифровке с помощью открытого ключа, то расшифровать сообщение можно закрытым ключом, опять же если задействовать правильную формулу. Это уже доказали всякие умные дядьки, так что нам можно просто пользоваться плодами их работы.
Выходит что-то такое
# frozen_string_literal: true
require 'prime'
class SimpleRSA
def initialize(limit = 20)
p = random_prime(limit)
q = random_prime(limit)
@max = p * q
totient = (p - 1) * (q - 1)
@pub_key = pub_key_from totient
@priv_key = priv_key_from totient
end
def encrypt(string)
message = message_for string
message.map do |char_code|
(char_code**@pub_key) % @max
end
end
def decrypt(secret)
secret.map do |s_char|
(
(s_char**@priv_key) % @max
).chr
end.join
end
private
def priv_key_from(totient)
d = gcd_extended(totient, @pub_key)[2]
d.positive? ? d : (totient - d.abs)
end
def pub_key_from(totient, generator = Prime::EratosthenesGenerator.new)
next_prime = generator.next
return if next_prime >= totient
return next_prime if gcd_extended(next_prime, totient)[0] == 1
pub_key_from totient, generator
end
def gcd_extended(a, b)
return b, 0, 1 if a.zero?
gcd, x1, y1 = gcd_extended(b % a, a)
x = y1 - (b / a) * x1
y = x1
[gcd, x, y]
end
def random_prime(limit)
Prime.take(rand(0..limit)).last
end
def message_for(str)
str
.upcase
.chars
.map(&:ord)
end
end
d = SimpleRSA.new
enc_message = d.encrypt('hi from kruk')
puts enc_message.inspect
puts d.decrypt(enc_message).inspect
Это пока наброски грядущих уроков, но в целом любопытная штука