558 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Ruby
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			558 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Ruby
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/ruby
 | |
| # coding: utf-8
 | |
| 
 | |
| #####################################
 | |
| #
 | |
| # Marcin Woźniak
 | |
| # s434812
 | |
| #
 | |
| #####################################
 | |
| 
 | |
| require 'openssl'
 | |
| require 'securerandom'
 | |
| require 'prime'
 | |
| require 'thread'
 | |
| require 'thwait'
 | |
| 
 | |
| ####################################
 | |
| # Funkcja nwd(a,b)
 | |
| #
 | |
| # Oblicza nwd podanych liczb np
 | |
| # nwd(10,14) => 2
 | |
| #
 | |
| ####################################
 | |
| def nwd(a, b)
 | |
|   if a == 0
 | |
|     return false
 | |
|   end
 | |
|   b == 0 ? a : nwd(b, a.modulo(b))
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja extended_euklides(a,b)
 | |
| #
 | |
| # Oblicza rozszerzony algorytm euklidesa
 | |
| # zwracajac u,v
 | |
| # extended_euklides(10,14) => [3, -2]
 | |
| #
 | |
| #####################################
 | |
| def extended_euklides(a, b)
 | |
|   return 1, 0 if b == 0
 | |
| 
 | |
|   q, r = a.divmod b
 | |
|   s, t = extended_euklides(b, r)
 | |
| 
 | |
|   return t, s - q * t
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja random_gen_Zn(k,n)
 | |
| #
 | |
| # Oblicza losowy element z zbioru Z_n
 | |
| # random_gen_Zn(1,10) => 1
 | |
| #
 | |
| ####################################
 | |
| def random_gen_Zn(k,n)
 | |
| 
 | |
|   if n == 0
 | |
|     n = 2 ** k
 | |
|   end
 | |
| 
 | |
|   if k == 1
 | |
|     max = 1
 | |
|   else
 | |
|     kb = k.to_s(2)
 | |
|     minimum = []
 | |
|     minimum << 1
 | |
|     k = kb.length - 1
 | |
| 
 | |
|     while (k != 0) do
 | |
|       j = SecureRandom.random_number(2)
 | |
|       minimum << j
 | |
|       k = k - 1
 | |
|     end
 | |
|     min = minimum.join.to_i(2)
 | |
|     max = n - 1
 | |
|     if min < max
 | |
|       return SecureRandom.random_number(min..max)
 | |
|     end
 | |
|   end
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja reciprocal_Phi_p(n,p)
 | |
| #
 | |
| # Oblicza odwrotnosc w grupie Phi(n)
 | |
| # reciprocal_Phi_p(10,7) => 5
 | |
| #
 | |
| # Funkcja oblicza 10^(-1) mod 7 = 5
 | |
| # Dowód: 5 * 10 mod 7 = 1
 | |
| #        a^(-1) * a mod p = e = 1
 | |
| ####################################
 | |
| def reciprocal_Phi_p(n,p)
 | |
|   u = extended_euklides(n,p)[0]
 | |
|   v = extended_euklides(n,p)[1]
 | |
| 
 | |
|   if (u * n % p) == 1
 | |
|     if u < 0
 | |
|       return u + p
 | |
|     end
 | |
|     return u
 | |
|   else
 | |
|     if v < 0
 | |
|       return v + p
 | |
|     end
 | |
|     return v
 | |
|   end
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja betterExponentiation(x,k,n)
 | |
| #
 | |
| # Oblicza potęgi x^k mod n
 | |
| # betterExponentiation(8,2,30) => 4
 | |
| #
 | |
| ####################################
 | |
| def betterExponentiation(x,k,n)
 | |
|   if n == 0
 | |
|     return false
 | |
|   end
 | |
| 
 | |
|   if x == 0
 | |
|     return 0
 | |
|   end
 | |
| 
 | |
|   if x < n && x > 0
 | |
|     b = k.to_s(2).reverse
 | |
|     l = b.count "[0-1]"
 | |
|     y = 1
 | |
|     i = l - 1
 | |
| 
 | |
|     while i >= 0
 | |
|       y = y**2 % n
 | |
|       if b[i]=="1"
 | |
|         y = y * x % n
 | |
|       end
 | |
|       i = i - 1
 | |
|     end
 | |
|     return y
 | |
|   end
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja remSqEuler(a,b)
 | |
| #
 | |
| # Sprawdzenie czy element a jest
 | |
| # reszta kwadratowa w Z_p
 | |
| # remSqEuler(3,13) => true
 | |
| #
 | |
| ####################################
 | |
| def remSqEuler(a,p)
 | |
|   ans = betterExponentiation(a,(p-1)/2,p)
 | |
|   if ans == 1 && primalityTest(p)
 | |
|     return true
 | |
|   else
 | |
|     return false
 | |
|   end
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja squareRootFp(a,b)
 | |
| #
 | |
| ####################################
 | |
| def squareRootFp(p,b)
 | |
|   if p % 4 == 3 && remSqEuler(p,b) == true
 | |
|       a = betterExponentiation(b, (p+1)/4, p)
 | |
|       return a
 | |
|   end
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja primalityTest(n)
 | |
| #
 | |
| # Test pierwszości
 | |
| # primalityTest(13) => true
 | |
| #
 | |
| ####################################
 | |
| def primalityTest(n)
 | |
|   if n == 1
 | |
|     return false
 | |
|   end
 | |
| 
 | |
|   if n == 2 || n == 3
 | |
|     return true
 | |
|   end
 | |
| 
 | |
|   counter = 10
 | |
|   while (counter != 0) do
 | |
|     b = SecureRandom.random_number(2..n-2) # Tez dziala n-1
 | |
|       if betterExponentiation(b,n-1,n) != 1
 | |
|         return false
 | |
|       end
 | |
|       counter = counter - 1
 | |
|   end
 | |
|   return true
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja specyficPrimaryNumber
 | |
| #
 | |
| # Generuje potrzebne do pierwszego
 | |
| # ElGamala
 | |
| #####################################
 | |
| def specyficPrimaryNumber
 | |
|   p = 0
 | |
|   q = 0
 | |
| 
 | |
|   qThread = Thread.new {
 | |
|   while true
 | |
|     q = SecureRandom.random_number(2 ** 256)
 | |
|     if primalityTest(q)
 | |
|       break
 | |
|     end
 | |
|   end
 | |
|   }
 | |
| 
 | |
|   qThread.join
 | |
| 
 | |
|   while true do
 | |
|     q = SecureRandom.random_number(2 ** 256)
 | |
|     p = 2 * q + 1
 | |
|     if primalityTest(p)
 | |
|       return p,q
 | |
|     end
 | |
|   end
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja generator(a,b)
 | |
| #
 | |
| # Generuje generator dla podanych liczb
 | |
| # do RSA i ElGamala
 | |
| #
 | |
| ####################################
 | |
| def generator(p,q)
 | |
|   while true
 | |
|     g = SecureRandom.random_number(2..p-2)
 | |
|     if betterExponentiation(g,q,p) == 1
 | |
|       next
 | |
|     else
 | |
|       return g
 | |
|     end
 | |
|   end
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja generate(n)
 | |
| #
 | |
| # Generator liczby losowej o podanej
 | |
| # n-bitowej liczbie
 | |
| #
 | |
| ####################################
 | |
| def generate(n)
 | |
|   return `openssl prime -generate -bits '#{n}'`.gsub(/\n$/, '').to_i
 | |
| end
 | |
| 
 | |
| #### MODULE 2 ####
 | |
| 
 | |
| ####################################
 | |
| # Funkcja returnRownanie(a,b,p)
 | |
| #
 | |
| # Zwraca ładniejszą formę równania
 | |
| #
 | |
| ####################################
 | |
| def returnRownanie(a,b,p)
 | |
|   puts
 | |
|   puts "Równanie krzywej jest równe: " + "Y^2 = X^3+" + a.inspect + "X+" + b.inspect + " mod "+ p.inspect
 | |
|   puts
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja delta(a,b,p)
 | |
| #
 | |
| # Oblicza deltę dla krzywej
 | |
| # eliptycznej o podanych parametrach
 | |
| # a,b nad ciałem F_p
 | |
| #
 | |
| ####################################
 | |
| def delta(a,b,p)
 | |
|   d = ((4 * betterExponentiation(a,3,p) % p) + (27 * betterExponentiation(b,2,p) % p)) % p
 | |
|   return d
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja rownanieKrzywej(a,b,p,x)
 | |
| #
 | |
| # Oblicza wartość fx dla podanej
 | |
| # krzywej eliptycznej o podanych
 | |
| # parametrach a,b,p,x
 | |
| #
 | |
| ####################################
 | |
| def rownanieKrzywej(a,b,p,x)
 | |
|   fx = ((betterExponentiation(x,3,p) + (a * x) % p + b % p) % p) % p
 | |
|   return fx
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja generatorKrzywej(p)
 | |
| #
 | |
| # Generuje krzywą o podanej liczbie
 | |
| # pierwszej p.
 | |
| #
 | |
| ####################################
 | |
| def generatorKrzywej(p)
 | |
|   a = 0
 | |
|   b = 0
 | |
| 
 | |
|   while true
 | |
|     if primalityTest(p) &&  (p % 4 == 3)
 | |
|       threads = []
 | |
| 
 | |
|       threads << Thread.new {
 | |
|         a = SecureRandom.random_number(1..p-1)
 | |
|       }
 | |
| 
 | |
|       threads << Thread.new {
 | |
|         b = SecureRandom.random_number(1..p-1)
 | |
|       }
 | |
| 
 | |
|       ThreadsWait.all_waits(*threads)
 | |
|       if delta(a,b,p) != 0
 | |
|         #returnRownanie(a,b,p)
 | |
|         return a,b
 | |
|       end
 | |
|     else
 | |
|       puts "Liczba nie spełnia wymagań"
 | |
|       break
 | |
|     end
 | |
|   end
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja punktNaKrzywej(a,b,p)
 | |
| #
 | |
| # Zwraca losowy punkt na krzywej
 | |
| # eliptycznej o podanych wartościach
 | |
| # a,p,p.
 | |
| #
 | |
| ####################################
 | |
| def punktNaKrzywej(a,b,p)
 | |
|   if (delta(a,b,p) != 0) &&  (p % 4 == 3)
 | |
|     while true
 | |
|       x = SecureRandom.random_number(0..p-1)
 | |
|       fx = rownanieKrzywej(a,b,p,x)
 | |
|       if remSqEuler(fx,p)
 | |
|         y = betterExponentiation(fx,((p+1)/4),p)
 | |
|         return x,y
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja czyPunktNalezyDoKrzywej(a,b,p,x,y)
 | |
| #
 | |
| # Sprawdza czy podany punkt nalezy
 | |
| # do krzywej eliptycznej.
 | |
| #
 | |
| ####################################
 | |
| def czyPunktNalezyDoKrzywej(a,b,p,x,y)
 | |
|   fx = rownanieKrzywej(a,b,p,x)
 | |
| 
 | |
|   if fx == betterExponentiation(y,2,p)
 | |
|     return true
 | |
|   else
 | |
|     return false
 | |
|   end
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja punktPrzeciwny(x,y)
 | |
| #
 | |
| # Zwraca przeciwny punkt dla (x,y)
 | |
| #
 | |
| ####################################
 | |
| def punktPrzeciwny(x,y)
 | |
|   return x,-y
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja sumaPunktow(a,b,p,x1,y1,x2,y2)
 | |
| #
 | |
| # Oblicza sumę punktów na krzywej
 | |
| # eliptycznej dla podanych a,b,p,x1,y1,x2,y2
 | |
| #
 | |
| ####################################
 | |
| def sumaPunktow(a,b,p,x1,y1,x2,y2)
 | |
|   # 0 - element neutrany --> P + 0 = P
 | |
|   if (x1 == "e" && y1 == "e" )
 | |
|     return x2,y2
 | |
|   elsif (x2 == "e" && y2 == "e")
 | |
|     return x1,y1
 | |
|   end
 | |
|   # P + Q = R
 | |
|   if (x1 != x2)
 | |
|     lambda = (((y2 - y1) % p) * reciprocal_Phi_p((x2 - x1),p)) % p
 | |
|     x3 = (betterExponentiation(lambda,2,p) - (x1 % p) - (x2 % p)) % p
 | |
|     y3 = (lambda * (x1 - x3) - y1) % p
 | |
|     return x3,y3
 | |
|   end
 | |
|   # P + -Q = 0 DZIALA
 | |
|   if (x1 == x2) && (y1 == -y2)
 | |
|     #puts "0 - el.neutralny"
 | |
|     return "e","e"
 | |
|   end
 | |
|   # P + P = 2P DZIALA
 | |
|   if (x1 == x2) && (y1 == y2)
 | |
|     lambda = (((3 * betterExponentiation(x1,2,p) % p + a) % p) * reciprocal_Phi_p(2 * y1,p)) % p
 | |
|     x3 = (betterExponentiation(lambda,2,p) - (x1 % p) - (x2 % p)) % p
 | |
|     y3 = (lambda * (x1 - x3) - y1) % p
 | |
|     return x3,y3
 | |
|   end
 | |
|   # P + -Q = 0 DZIALA
 | |
|   if (x1 == x2) && (y1 == y2%p)
 | |
|     #puts "0 - el.neutralny"
 | |
|     return "e","e"
 | |
|   end
 | |
| end
 | |
| 
 | |
| #### MODULE 3 ####
 | |
| 
 | |
| ####################################
 | |
| # Funkcja wielokrotnoscPunktu(a,b,p,n,x,y)
 | |
| #
 | |
| # Oblicza wielokrotność punktów np.
 | |
| # 2n = n + n
 | |
| ####################################
 | |
| def wielokrotnoscPunktu(a,b,p,n,x,y)
 | |
|   punktQ = [x,y]
 | |
|   punktR = ["e","e"]
 | |
| 
 | |
|   while n > 0
 | |
|     if n % 2 == 1
 | |
|       punktR = sumaPunktow(a,b,p,punktR[0],punktR[1],punktQ[0],punktQ[1])
 | |
|       n = n - 1
 | |
|     end
 | |
|     punktQ = sumaPunktow(a,b,p,punktQ[0],punktQ[1],punktQ[0],punktQ[1])
 | |
|     n = n / 2
 | |
|   end
 | |
|   return punktR
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja liczenieOrd(a,b,p)
 | |
| #
 | |
| # Oblicza wartość ord dla podanych
 | |
| # a,b,p.
 | |
| ####################################
 | |
| def liczenieOrd(a,b,p)
 | |
|   threads = []
 | |
|   punktyNaKrzywej = Array.new
 | |
|   unikalnePunktyNaKrzywej = Array.new
 | |
| 
 | |
|   threads << Thread.new {
 | |
|     counter = 10
 | |
|     while counter > 0
 | |
|       punktyNaKrzywej <<  punktNaKrzywej(a,b,p)[0]
 | |
|       counter = counter -1
 | |
|     end
 | |
|   }
 | |
| 
 | |
|   threads << Thread.new {
 | |
|     counter = 10
 | |
|     while counter > 0
 | |
|       punktyNaKrzywej <<  punktNaKrzywej(a,b,p)[0]
 | |
|       counter = counter -1
 | |
|     end
 | |
|   }
 | |
| 
 | |
|   threads << Thread.new {
 | |
|     counter = 10
 | |
|     while counter > 0
 | |
|       punktyNaKrzywej <<  punktNaKrzywej(a,b,p)[0]
 | |
|       counter = counter -1
 | |
|     end
 | |
|   }
 | |
| 
 | |
|   ThreadsWait.all_waits(*threads)
 | |
| 
 | |
|   punktyNaKrzywej.sort.each { |e|
 | |
|     unikalnePunktyNaKrzywej.push(e) if e != unikalnePunktyNaKrzywej[-1]
 | |
|   }
 | |
| 
 | |
|   return unikalnePunktyNaKrzywej.count
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja generowanieKluczyElGamalKrzywaEliptyczna(k)
 | |
| #
 | |
| # Generatoruje klucz publiczny
 | |
| # oraz prywatny.
 | |
| ####################################
 | |
| def generowanieKluczyElGamalKrzywaEliptyczna(k)
 | |
|   while true
 | |
|   p = generate(k)
 | |
|     if (primalityTest(p)) && (p % 4 == 3)
 | |
|       krzywa = generatorKrzywej(p)
 | |
|       a = krzywa[0].to_i
 | |
|       b = krzywa[1].to_i
 | |
| 
 | |
|       punktyNaKrzywej = Array.new
 | |
| 
 | |
|       punktP = punktNaKrzywej(a,b,p)
 | |
|       ord = liczenieOrd(a,b,p)
 | |
| 
 | |
|       while true
 | |
|         x = SecureRandom.random_number(1..ord)
 | |
|         if x < ord
 | |
|           punktQ = wielokrotnoscPunktu(a,b,p,x,punktP[0],punktP[1])
 | |
|           pubKey = [a,b,p,punktP[0],punktP[1],punktQ[0],punktQ[1]]
 | |
|           privKey = [a,b,p,punktP[0],punktP[1],punktQ[0],punktQ[1],x]
 | |
|           return a,b,p,punktP[0],punktP[1],punktQ[0],punktQ[1],x
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja algorytmKodowania(a,b,p,m,n,u)
 | |
| #
 | |
| ####################################
 | |
| def algorytmKodowania(a,b,p,m,n,u)
 | |
|   if (m < n) && (p > n*u)
 | |
|     for i in 1..u
 | |
|       x = (m * u % p) + (i % p)
 | |
|       fx = rownanieKrzywej(a,b,p,x)
 | |
|       if remSqEuler(fx,p)
 | |
|         y = betterExponentiation(fx,((p+1)/4),p)
 | |
|       end
 | |
|     end
 | |
|   else
 | |
|     puts "Nieprawidołowe dane"
 | |
|   end
 | |
|   return [x,y]
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja algorytmDeKodowania(a,b,p,x,y,n,u)
 | |
| #
 | |
| # Zwraca odszyfrowaną wiadomość.
 | |
| ####################################
 | |
| def algorytmDeKodowania(a,b,p,x,y,n,u)
 | |
|   m = (x - 1) / u
 | |
|   return m
 | |
| end
 | |
| 
 | |
| ####################################
 | |
| # Funkcja szyfrowanieElGamala(m,n,u,a,b,p,px,py,qx,qy)
 | |
| #
 | |
| # Koduje wiadomość na punkt na krzywej
 | |
| # eliptycznej.
 | |
| ####################################
 | |
| def szyfrowanieElGamala(m,n,u,a,b,p,px,py,qx,qy)
 | |
|   c = algorytmKodowania(a,b,p,m,n,u)
 | |
|   puts "Wiadomość na prostej jako punkt #{c.inspect}"
 | |
|   return c
 | |
| end
 |