TheAlgorithms-Ruby/ciphers/merkle_hellman_cryptosystem.rb

72 lines
1.3 KiB
Ruby
Raw Normal View History

2021-02-07 08:05:54 +01:00
require 'openssl'
class MerkleHellman
2021-01-13 23:26:24 +01:00
SMALLEST_KNAPSACK_ITEM = 2**32
STEP = 2**32
2021-02-07 08:05:54 +01:00
def initialize(size)
@size = size
sum = SMALLEST_KNAPSACK_ITEM
@easy_knapsack = size.times.map do |_k|
x = sum + rand(STEP)
sum += x
x
2021-01-13 23:26:24 +01:00
end
2021-02-07 08:05:54 +01:00
@n = sum + rand(STEP)
2021-01-13 23:26:24 +01:00
loop do
2021-02-07 08:05:54 +01:00
@a = rand(0..@n)
break if @a.gcd(@n) == 1
2021-01-13 23:26:24 +01:00
end
@hard_knapsack = @easy_knapsack.map do |x|
2021-02-07 08:05:54 +01:00
(@a * x) % @n
2021-01-13 23:26:24 +01:00
end
end
2021-02-07 08:05:54 +01:00
def encrypt(msg)
raise ArgumentError, "max length is #{@size / 8} characters" if msg.length * 8 > @size
c = 0
msg.each_codepoint.reverse_each.with_index do |ch, i|
7.downto(0) do |j|
wj = ch.>>(j).& 1
c += wj * @hard_knapsack[i * 8 + 7 - j]
2021-01-13 23:26:24 +01:00
end
end
2021-02-07 08:05:54 +01:00
c
2021-01-13 23:26:24 +01:00
end
2021-02-07 08:05:54 +01:00
def decrypt(c)
p = @a.to_bn.mod_inverse(@n).mod_mul(c, @n).to_i
byte = 0
msg = []
@easy_knapsack.reverse_each.with_index do |x, i|
bit = 0
2021-01-13 23:26:24 +01:00
if p >= x
2021-02-07 08:05:54 +01:00
p -= x
bit = 1
2021-01-13 23:26:24 +01:00
end
2021-02-07 08:05:54 +01:00
byte |= (bit << (i % 8))
2021-01-13 23:26:24 +01:00
if i % 8 == 7
2021-02-07 08:05:54 +01:00
msg << byte.chr
byte = 0
2021-01-13 23:26:24 +01:00
end
end
2021-02-07 08:05:54 +01:00
msg.join
2021-01-13 23:26:24 +01:00
end
2021-02-07 08:05:54 +01:00
attr_accessor :hard_knapsack
end
2021-02-07 08:05:54 +01:00
str = 'Hello there, this is my plaintext'
mh = MerkleHellman.new(str.length * 8)
puts "[*] Encrypting \"#{str}\""
c = mh.encrypt(str)
puts "[*] Ciphertext : #{c}"
decrypted = mh.decrypt(c)
puts "[*] after decryption : \"#{decrypted}\""