KRzA/module.rb

655 lines
17 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 ####
#################################################################################
# Funkcje mysqrt(n)
#
# Oblicza wartość pierwiastka z dużych
# liczb
#
# Źródło: https://stackoverflow.com/questions/8226087/how-do-i-get-math-sqrt-to-return-a-bignum-and-not-a-float
#################################################################################
def mysqrt(x)
return 0 if x==0
m=x
p=x
loop do
r=(m+p/m)/2
return m if m<=r
m=r
end
end
#################################################################################
# Funkcja liczenieOrd(p)
#
# Oblicza wartość ord dla podanych p.
#################################################################################
def liczenieOrd(p)
ord = (p + 1 - (2 * mysqrt(p))) % p
return ord
end
#################################################################################
# Zadanie 1
# 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(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
#################################################################################
# Zadanie 2
# 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
#################################################################################
# Zadanie 3
# Funkcja algorytmKodowania(a,b,p,m,n,u)
#
#################################################################################
def algorytmKodowania(a,b,p,m,u)
n = m + SecureRandom.random_number(0..1000000)
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
puts "Punkt na krzywej to #{[x,y].inspect}"
return [x,y]
end
#################################################################################
# Zadanie 4
# Funkcja szyfrowanieElGamala(a,b,p,m,u,px,py,qx,qy)
#
# Zwraca szyfrogramy.
#################################################################################
def szyfrowanieElGamala(a,b,p,u,px,py,qx,qy,pmx,pmy)
y = SecureRandom.random_number(0..liczenieOrd(p))
puts "y = #{y}"
c1 = wielokrotnoscPunktu(a,b,p,y,px,py)
yq = wielokrotnoscPunktu(a,b,p,y,qx,qy)
c2 = sumaPunktow(a,b,p,pmx,pmy,yq[0],yq[1])
puts "Ciphers: C1=#{c1}, C2=#{c2}"
return c1,c2
end
#################################################################################
# Zadanie 5
# Funkcja deKodowanieElGamala(a,b,p,c1x,c1y,c2x,c2y,x)
#
# Zwraca odszyfrowany punkt początkowy na którym była wiadomość.
#################################################################################
def deKododwanieElGamala(a,b,p,c1x,c1y,c2x,c2y,x)
xc1 = wielokrotnoscPunktu(a,b,p,x,c1x,c1y)
pmd = sumaPunktow(a,b,p,c2x,c2y,xc1[0],-xc1[1])
#puts "-------------------DEBUG MODE-------------------\na = #{a}\nb = #{b}\np = #{p}\nc1x = #{c1x} \nc1y = #{c1y} \nc2x = #{c2x} \nc2y = #{c2y} \nx = #{x}\nXC1 = #{xc1.inspect}\npm = #{pmd.inspect}\n-------------------"
return pmd
end
#################################################################################
# Zadanie 6
# Funkcja algorytmDeSzyfrowania(x,y,u)
#
# Zwraca odszyfrowaną wiadomość.
#################################################################################
def algorytmDeSzyfrowania(x,y,u)
m = (x - 1) / u
return m
end
########################### Module 4 ############################################
# Podstawowe operacje na Galois Field GF(2^8)
# Źródła:
# * https://people.scs.carleton.ca/~maheshwa/courses/4109/Seminar11/The_Advanced_Encryption_Standard_AES_.pdf
# * https://cs465.internet.byu.edu/static/lectures/w19/AES.pdf
# * https://en.wikipedia.org/wiki/Finite_field_arithmetic
# * https://swarm.cs.pub.ro/~mbarbulescu/cripto/Understanding%20Cryptography%20by%20Christof%20Paar%20.pdf
# * http://www.cs.man.ac.uk/~banach/COMP61411.Info/CourseSlides/Wk2.2.FinField.pdf
#################################################################################
#################################################################################
# Zadanie 1
# Funkcja suma(a,b) wykorzystujac liczby hex
#################################################################################
def suma(a,b)
binA = a.to_i(16).to_s(2)
binB = b.to_i(16).to_s(2)
return (binA.to_i(2) ^ binB.to_i(2)).to_s(16)
end
#################################################################################
# Zadanie 2
# Funkcja xtime(a) wykorzystujac liczby hex
#################################################################################
def xtime(a)
binA = a.to_i(16).to_s(2)
const = "1B"
dl = binA.length
while dl != 8
binA = "0" + binA
dl = dl + 1
end
if binA[0].to_i == 1
binA[0] = ''
return suma((binA.to_i(2) << 1 ).to_s(16), const)
elsif binA[0].to_i == 0
return (binA.to_i(2) << 1 ).to_s(16)
end
end
#################################################################################
# Zadanie 3
# Funkcja iloczyn(a,b) wykorzystujac liczby hex
# {53} • {CA} = {01}
# {57} • {13} = {fe}
#################################################################################
def iloczyn(a,b)
solve = "0"
binA = a.to_i(16).to_s(2)
len = binA.length - 1
binA.split('').each { |a|
if a == "1"
tmp = b
counter = len
while counter != 0
tmp = xtime(tmp)
counter = counter - 1
end
solve = suma(tmp.to_i(16).to_s(16), solve)
end
len = len - 1
}
return solve
end
#################################################################################
# Zadanie 4
# Funkcja odwrotnosc(a) wykorzystujac liczby hex
#################################################################################
def odwrotnosc(a)
b = a
i = 13
const = 1
while i > 0
if i.to_s(2).to_i & const.to_s(2).to_i == 1
tmp = b
else
tmp = a
end
b = iloczyn(b,tmp)
i = i - 1
end
return b
end