From 43a72c3fb71c70bbe157ae520f29f25b7a08803e Mon Sep 17 00:00:00 2001 From: Lukian Date: Thu, 23 Jan 2025 17:57:15 +0100 Subject: [PATCH] First commit --- .gitignore | 2 + lib/__pycache__/arithmetics.cpython-313.pyc | Bin 0 -> 1150 bytes .../diffie_hellman.cpython-313.pyc | Bin 0 -> 1331 bytes lib/__pycache__/miller_rabin.cpython-313.pyc | Bin 0 -> 2117 bytes lib/__pycache__/rsa.cpython-313.pyc | Bin 0 -> 1779 bytes lib/arithmetics.py | 39 ++++++++++++ lib/diffie_hellman.py | 21 +++++++ lib/miller_rabin.py | 40 ++++++++++++ lib/rsa.py | 35 +++++++++++ main.py | 59 ++++++++++++++++++ requirements.txt | 1 + tests.py | 16 +++++ 12 files changed, 213 insertions(+) create mode 100644 .gitignore create mode 100644 lib/__pycache__/arithmetics.cpython-313.pyc create mode 100644 lib/__pycache__/diffie_hellman.cpython-313.pyc create mode 100644 lib/__pycache__/miller_rabin.cpython-313.pyc create mode 100644 lib/__pycache__/rsa.cpython-313.pyc create mode 100644 lib/arithmetics.py create mode 100644 lib/diffie_hellman.py create mode 100644 lib/miller_rabin.py create mode 100644 lib/rsa.py create mode 100644 main.py create mode 100644 requirements.txt create mode 100644 tests.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b65602 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +cr/ +.venv/ diff --git a/lib/__pycache__/arithmetics.cpython-313.pyc b/lib/__pycache__/arithmetics.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..006ef0ff871045814d7a6b4f71c820971b34af08 GIT binary patch literal 1150 zcmY*XOG_J36h3!mGI{#~TPs3c=pu_4i*;jdA)-=S6l4g5R$AgXXv9qP&cxPD33M|d z2oWl{blZQ^?$V))LRapFYN5-1=f?DL;hxt$uY108oz12Q=gW`g?k|n#J1hN@xD~FS zK{zLiw#X8=8m_)Y4-=L#PWy%we_q&XS}|qSEE9h5TVK;kD677k%%wt63B`6OYN06| zzad>)@7DxJ8^rqcD-e_wu3i$Bw(x0hT4t$T5Nt|%8uvf1+g@cA&b=<;o z-EPzz*Y^s`&T+jey@D-I4*hz;KYUO)sBRZ3vg+^E9KULNGlwUkS*!0H*5Aks(s2=Q z4Wvok>_Bt1n@R_j_H;Ls?TFS&XS4mNduQTo|FZabbUIjN^Kff55b$l4I+fP*KtxGO zXM)P5>3%d{<}Kmp_1V7&EH02G}?yb z1;~j|-?evg+TYQ5>@+zk(_nJ2Pxw#X1PJ~UPXxvH$KAo9An`Rl5FB+XXVdM+pNuh? zg+nNcp;-T~Q67fE{2c^t)YTYwOLGl{8#j$+cSWg>`+eXp^612k!P|t)=!=r+0$J!Q zC7sdFW4*BxCi3(n5wniyl3|I35#$B7<)u98!pBfMp*}9LStPMYl#9zDmWM$?tu`Bq zlTf@3#Zf4HkG-%MeAGa~G%$W$b&nnCIdTlI9Ol(QFqmYjxztT0o5el}HrpoV)CG`7 z?fGw+tim{x1-d2y>J=c)nj(1a6whL`q->@+n h(Z#)BE+Vi_k6p~&uok68MV3uq7d>`4_meeM`!|xm@fiRB literal 0 HcmV?d00001 diff --git a/lib/__pycache__/diffie_hellman.cpython-313.pyc b/lib/__pycache__/diffie_hellman.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b3fc1559826cf5ba146ba0ac985218504139506 GIT binary patch literal 1331 zcmbtT&r92I6#sscG>uJLt&VND4QrIK9%|NEcNo(l^B~HEEffk0rPf$8+O&R?ZVEf} zC|>LiLcG=6{BLAEYzy0I?BK0XcO2}!q^%tY9`=R2-|zc<@AFsic|uwUEVA!Si(1&T%0-%pTwp0{E;U_|>2{5o1t_+E0wD45bxa_~ zWWDcr!}Z0!ppXoi>t>sDUFbR9h&}0wE6{QV8cPC5Nq{3m=ejqVTy`|gO_MWz?E*~~ zcw<6v#j;T<>C7D|>UNIh&8)~rn+TpZyS1UM=zDid2^<^@5=aa zH3x6xifjaK#VJ}TAa(LxihhwMK1&l#+LDy|BIrla!)RmINja}iWpWv7bjD=CA9x@g}8fU{m-2isA$HqX8 zz-LVXfqvxJ(Zb<^GwI};^rUd|sJYnOJze^gI$dtb$#WseVwg<#7$&hOkOBhTJN>Y?Jjdgedp zS0gsu0FxaHl4dcqiG9 zmy)tCQCS@+!U%ncZ`*&RPlZ6&4i*Z1@@6+(=+2;q_e)Mo`a8H3%wPl3fnIJq)B zBitfMDRYMI82ULw@)Jpl3_bd^;8VxJZ6cBIKTSOy~}D^32yZ%xbQXGwednVNtM&IdJBI)X9n3 z*GO;6^)zgN^lJ@c`?fp1dj}Q9cBDaZv$U-=Xdn|U8meF12^12GH$JK_w!sXcca04yDvZbt~Q$)L<0*0T5+2H7d z%?)8S5}t!hh@r0QYlJ+w4fo|Yc?0|6Wq+4_6d=+?u#x~z8d51KXBa;83x9A$k-utj|O)TcQItw5e(F%6|Lp1Rxf}@#b+>l!f4@*qpQ`cw*iOtfymU()hx|pZT9m7jwUj+;|-!@v%T9(Ln~a3$bnf zcTV>}8Fs_mFjRhsJ?5x>NHQ3@sE?2~^^u3M;o(Ztr%Y>X% zGG|yMVJ3J|FdYybfyRcqFPHoXa?7rAG(m~y*(j20NI1S&f)`ncUhX6I4(Q&7pYs_I z=o>(K`gzUGa)9?%LU1!X8E@J%niEH6D|!oL+6`~$l{Vhe#*b^SWfC8SzUkn5Wz?W& zjHo>ZmKz!gh+mo z#(9FT1R%p99>A}#fdGJpYq{5FD0U)83H_00dM=WI>v(i`^A9arf55Yp)Oeu&08I9~;b<|dR^IWoOCM|yBJo8mZ=CPG zv|cV3d8P9@;SXd9&@jjr;daAGqkaNYs#Y}bGZ<|I>&U_X*hdFlJs`lmkToBk<5w^$gJwP;z`T$(7tZl3h*SEmD+UCZC!He; R6p6+>5CLn7e<9=X{R8NEi3tDz literal 0 HcmV?d00001 diff --git a/lib/__pycache__/rsa.cpython-313.pyc b/lib/__pycache__/rsa.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3ecd8ed39b09d11efb5e1a5e1930e8dbf1689577 GIT binary patch literal 1779 zcmb_c&1)M+6rb5$Nvr*^E#k5ML zL+J6&w<1Dsm@yjiQ0ccpd4>#R;O`I#Bqo^K!flaAiNF`S9VQXbg)P|-x8yB3D`X`@ znnvGCBx-~LFL=V-qZkqJK-4HcD;rV1q8bW#)%R93zM}2mw0_E9ty65%Ffr>5Vi)lc zC=>7#eD;3^>4Px@~ ztT2a;@OoOH;fhr*n}km7nDqkLwoBDY!68<~OpAo2qS&Fh<}x*rNYHF%w^}hXEN05q{S0xpuRBeuvgA$yvKMMZgH%zN?$_{X zq2J|+SMuyjdA5sta;mj*a>jnGs6Spi(LV7udfIFo`yx`cpRT>u^!AO`S|3sX#PWMR zm%zvH_EXSH==t08$N^;*pa-KKH$Zpd`S?NzAzRF0Ls$U%<%B?TuVjdJX!Gq^-C?=U zj1T^dFh!tz5nhcDn9{!`Ttt_bzlSk-q(!)IWEIgZp0=kMjjtT>0#()uaecFGW2 z7-8`6L!#krV%2vmRNN_+s9LF(3YNWR64y*e$OHrvc8rAG*nlb_XSZ3fDK;rCxe;&! zW7r@n=u~DTcwjbNav4mZA#xAl(?Tce#ZJvzIoRu|GmlqWE5~wlKLkRb=*0GOu(Wv4 zc%fZs-8zh>dEA^x7fvpH+qw)eW{I)HGTgUh*-R{ad5#~ z^lFDoFQ$_1&>(`;*x24*l&b?7MJHd$(=TPn(Ua$(s-}06?a!Y}=ZVfx;|jS5vd9QE z8bFtTV4s5W@0U7{bHdVa{~RLhV2%XB8UVMiT5_rn;jVoICa=U>Il6B_=OU)f?-jWM zK{GJ>=itK{7khg1$xScj)p~03xs)72E|N>I{y#$|A45(6Itzm5|2v>1GXR=|AT|j@ z%Tc9ucpv%mLPfXf(n)w8t_S=w>sHaF>X;EUXNrXc&l9{%_br=h;}&5IqoQTkIa@ia zc!vn9d=!)&QtwOXbE9m2Mdo3N@!Wj`A78{6_rnNJ{EC!6P~ta~^rZ-ncRuqG2=ANj vId6HuR6nlZ3mwr%AUtuvgnt?1RNM6th)y89Ky=*!bNb int: + result = 1 + while b > 0: + if (b & 1) > 0: + result = (result * a) % m + b = b >> 1 + a = (a * a) % m + return result + +def gcd(a: int, b: int) -> int: + if b == 0: + return a + return gcd(b, a % b) + +def mod_inverse(A: int, M: int) -> int: + m0 = M + y = 0 + x = 1 + if (M == 1): + return 0 + while (A > 1): + # q is quotient + q = A // M + t = M + # m is remainder now, process + # same as Euclid's algo + M = A % M + A = t + t = y + # Update x and y + y = x - q * y + x = t + # Make x positive + if (x < 0): + x = x + m0 + return x + diff --git a/lib/diffie_hellman.py b/lib/diffie_hellman.py new file mode 100644 index 0000000..2117e87 --- /dev/null +++ b/lib/diffie_hellman.py @@ -0,0 +1,21 @@ +# Python Diffie-Hillman implémentation + +import random + +import lib.miller_rabin as miller +import lib.arithmetics as arithm + +def get_p_and_g(n: int) -> (int, int): + p = miller.get_random_prime(n) + g = random.randint(2**(n-1), p) + return (p, g) + +def get_x(n: int) -> int: + return random.randint(2**(n-1), 2**n - 1) + +def get_X(x: int, p: int, g: int) -> int: + return arithm.modpow(g, x, p) + +def get_K(X: int, y: int, p: int): + return arithm.modpow(X, y, p) + diff --git a/lib/miller_rabin.py b/lib/miller_rabin.py new file mode 100644 index 0000000..5d4c10a --- /dev/null +++ b/lib/miller_rabin.py @@ -0,0 +1,40 @@ +# Python Miller-Rabin implementation + +import random +import lib.arithmetics as arithm + +def get_d_and_s(n: int) -> (int, int): + d = n - 1 + s = 0 + while d % 2 == 0: + d //= 2 + s += 1 + return (d, s) + +def rabin_witness(n: int, a: int) -> bool: + d, s = get_d_and_s(n) + x = arithm.modpow(a, d, n) + if x == 1 or x == n - 1: + return False + for _ in range(s - 1): + x = arithm.modpow(x, 2, n) + if x == n - 1: + return False + return True + +def miller_rabin(n: int, k: int) -> bool: + if n < 3: return False + for _ in range(k): + a = random.randint(2, n - 1) + if rabin_witness(n, a): return False + return True + +def is_prime(n: int) -> bool: + return miller_rabin(n, 25) + +def get_random_prime(n: int) -> int: + a = random.randint(2**(n-1), 2**(n) - 1) + while not is_prime(a): + a = random.randint(2**(n-1), 2**(n) - 1) + return a + diff --git a/lib/rsa.py b/lib/rsa.py new file mode 100644 index 0000000..0ae2a7c --- /dev/null +++ b/lib/rsa.py @@ -0,0 +1,35 @@ +# Python RSA implementation + +import random +import sys + +import lib.arithmetics as arithm +import lib.miller_rabin as miller + +def get_p_and_q(n: int) -> (int, int): + # Get two random prime numbers + p = miller.get_random_prime(n) + q = miller.get_random_prime(n) + # Ensure the two numbers are differents + while p == q: + q = get_random_prime(n) + return (p, q) + +def get_keys(l: int) -> int: + p, q = get_p_and_q(l // 2) + n = p * q + phy_n = (p - 1) * (q - 1) + e = 65537 + while arithm.gcd(e, phy_n) != 1: + p, q = get_p_and_q(l // 2) + n = p * q + phy_n = (p - 1) * (q - 1) + d = arithm.mod_inverse(e, phy_n) + return (e, d, n) + +def encrypt(m: int, e: int, n: int) -> int: + return arithm.modpow(m, e, n) + +def decrypt(c: int, d: int, n: int) -> int: + return arithm.modpow(c, d, n) + diff --git a/main.py b/main.py new file mode 100644 index 0000000..4b8be63 --- /dev/null +++ b/main.py @@ -0,0 +1,59 @@ +import lib.rsa as rsa +import lib.diffie_hellman as diffie +from hashlib import sha256 + +BITS = 32 +ALPH = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5, 'g': 6, 'h': 7, 'i': 8, 'j': 9, 'k': 10, 'l': 11, 'm': 12, 'n': 13, 'o': 14, 'p': 15, 'q': 16, 'r': 17, 's': 18, 't': 19, 'u': 20, 'v': 21, 'w': 22, 'x': 23, 'y': 24, 'z': 25, ' ': 26} +LEN = BITS // 5 + +def encode(text): + sum = 0 + for i in range(len(text)): + sum += ALPH[text[i]] * 27 ** i + return sum + +def decode(num): + text = "" + while num > 0: + text += list(ALPH.keys())[num % 27] + num //= 27 + return text + +def encrypt(text, e, n): + crypt = [] + while len(text) > 0: + if len(text) >= LEN: + crypt.append(rsa.encrypt(encode(text[:LEN]), e, n)) + text = text[LEN:] + else: + crypt.append(rsa.encrypt(encode(text), e, n)) + text = "" + return crypt + +def decrypt(crypt, d, n): + text = "" + for i in range(len(crypt)): + text += decode(rsa.decrypt(crypt[i], d, n)) + return text + +if __name__ == "__main__": + p, g = diffie.get_p_and_g(BITS) + + a = diffie.get_x(BITS) + b = diffie.get_x(BITS) + + A = diffie.get_X(a, p, g) + B = diffie.get_X(b, p, g) + + K_a = diffie.get_K(B, a, p) + K_b = diffie.get_K(A, b, p) + + e, d, n = rsa.get_keys(BITS) + + c_d = d ^ K_a + h_d = sha256(str(c_d).encode()) + + m = "hello world" + crypt = encrypt(m, e, n) + print(crypt) + print(decrypt(crypt, d, n)) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ + diff --git a/tests.py b/tests.py new file mode 100644 index 0000000..1f6516f --- /dev/null +++ b/tests.py @@ -0,0 +1,16 @@ +import lib.rsa as rsa +import lib.arithmetics as arithm +import lib.miller_rabin as miller + +for i in range(100): + for j in range(100): + assert arithm.modpow(i, j, 20) == pow(i, j, 20) + +for i in range(3, 100): + if miller.is_prime(i): print(i) + +e, d, n = rsa.get_keys(2048) +c = rsa.encrypt(22, e, n) +m = rsa.decrypt(c, d, n) +print(m) +