From 3395cf2eb0858916a51cf0edee242301d6aba584 Mon Sep 17 00:00:00 2001 From: Yaman Malkoc Date: Wed, 9 Feb 2022 11:54:42 -0800 Subject: [PATCH 1/6] pyaes deployment --- spot/benchmarks/aes/LICENSE | 211 +++++++ spot/benchmarks/aes/lambda_function.py | 33 + spot/benchmarks/aes/my-deployment-package.zip | Bin 0 -> 58056 bytes .../package/pyaes-1.6.1.dist-info/INSTALLER | 1 + .../package/pyaes-1.6.1.dist-info/LICENSE.txt | 22 + .../package/pyaes-1.6.1.dist-info/METADATA | 17 + .../aes/package/pyaes-1.6.1.dist-info/RECORD | 15 + .../package/pyaes-1.6.1.dist-info/REQUESTED | 0 .../aes/package/pyaes-1.6.1.dist-info/WHEEL | 5 + .../pyaes-1.6.1.dist-info/top_level.txt | 1 + spot/benchmarks/aes/package/pyaes/__init__.py | 53 ++ spot/benchmarks/aes/package/pyaes/aes.py | 589 ++++++++++++++++++ .../aes/package/pyaes/blockfeeder.py | 227 +++++++ spot/benchmarks/aes/package/pyaes/util.py | 60 ++ spot/benchmarks/aes/pyaes.md | 25 + 15 files changed, 1259 insertions(+) create mode 100644 spot/benchmarks/aes/LICENSE create mode 100644 spot/benchmarks/aes/lambda_function.py create mode 100644 spot/benchmarks/aes/my-deployment-package.zip create mode 100644 spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/INSTALLER create mode 100644 spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/LICENSE.txt create mode 100644 spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/METADATA create mode 100644 spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/RECORD create mode 100644 spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/REQUESTED create mode 100644 spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/WHEEL create mode 100644 spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/top_level.txt create mode 100644 spot/benchmarks/aes/package/pyaes/__init__.py create mode 100644 spot/benchmarks/aes/package/pyaes/aes.py create mode 100644 spot/benchmarks/aes/package/pyaes/blockfeeder.py create mode 100644 spot/benchmarks/aes/package/pyaes/util.py create mode 100644 spot/benchmarks/aes/pyaes.md diff --git a/spot/benchmarks/aes/LICENSE b/spot/benchmarks/aes/LICENSE new file mode 100644 index 0000000..217105e --- /dev/null +++ b/spot/benchmarks/aes/LICENSE @@ -0,0 +1,211 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +------------------------------------------------------------------------------------ +This product bundles various third-party components under other open source licenses. +This section summarizes those components and their licenses. See licenses/ +for text of these licenses. + + +Apache Software Foundation License 2.0 +-------------------------------------- diff --git a/spot/benchmarks/aes/lambda_function.py b/spot/benchmarks/aes/lambda_function.py new file mode 100644 index 0000000..58452aa --- /dev/null +++ b/spot/benchmarks/aes/lambda_function.py @@ -0,0 +1,33 @@ +from time import time +import random +import string +import pyaes + + +def generate(length): + letters = string.ascii_lowercase + string.digits + return ''.join(random.choice(letters) for i in range(length)) + + +def lambda_handler(event, context): + length_of_message = event['length_of_message'] + num_of_iterations = event['num_of_iterations'] + + message = generate(length_of_message) + + # 128-bit key (16 bytes) + KEY = b'\xa1\xf6%\x8c\x87}_\xcd\x89dHE8\xbf\xc9,' + + start = time() + for loops in range(num_of_iterations): + aes = pyaes.AESModeOfOperationCTR(KEY) + ciphertext = aes.encrypt(message) + print(ciphertext) + + aes = pyaes.AESModeOfOperationCTR(KEY) + plaintext = aes.decrypt(ciphertext) + print(plaintext) + aes = None + + latency = time() - start + return latency diff --git a/spot/benchmarks/aes/my-deployment-package.zip b/spot/benchmarks/aes/my-deployment-package.zip new file mode 100644 index 0000000000000000000000000000000000000000..889d4f5f98c419022ded9b942a98e90b8f321ad0 GIT binary patch literal 58056 zcmeFXWmuJMw=N7K6A&h#BIu+AF({En8W98mC8SGIx{*dHkrbs{5R`7Dk?xi*=|;M7 zkLk0%ckQ*m^{(&l_hWk;_rqjz-B*lpj&qE0Ue7aWtc#a0(Eso?o+$qP@E`vn#h}2j za?&-hWoBdHVqs&^e`RaO{K~@6l2u6&4+E=-^x{kOWB(c-1M}h@CI-eu5_t0&%!mGo z`**%G{}E083-Iej44CcT%_lD|CMW;sf0{L@S3M*~_&Q?xgyHP=^i8_-04*AVOV}g` zpLt)5V9%run=AW6LtOUj44fnFt*%a!o5E?=OLtwHx)%z?dL8Vnc?Vg`gZM`{lBJ8C zI&4lu4yre|K35KW6xqxfGY|EbI1To$>bvOM-=hADa_r2$CoWLU_0Qw;%$V{E<`<17 zh9@TWYKw1Eal5FbTddI7B1 zh7+BgtxAd=Q`r^h7S#N_xYQiJqlQiG%p06lTNJYVL=3a4|IyY~5&548AFs%KqXB?KKji-w zk;;7??4?FtD+GWof}j!^U#|l7xYUfsL-6r41j=OLVMgJEF(X+_}%f z&c*WJ?j?CkOFQN#w#?7$Z4As_z2u{@v#~e0q^N7eM`Pv0&TL_6VZf|w;dJQ|I)wgn z!)kVVMhMs}`l0)`8@98w(l#@2Ffe1Wdu{ixjW_?lHDhq=NK1xM=yT%Gj#PSjK6TRo-ZIgKEnrv1Dp?k2%RW%Qwo3(J;B+7{=y)HZ9! zKaR&_VzW3x1m{w{YC;adS9}r!Z@8N5pXbIGj^{i)e)qzXbO~cI zBy%!Rbcz6LZQV`x>+0jj*`+*JTm9boId)8er`hS=I z<;S#z|5!f7^WvtW{J^6ZxbZppbJEe$h0?=PF=0H)QdoZPP3ih&x;PcdHNUAPx%w7; zVNymZJ))J`@y-~=+IovUV4AQ<-*||aFx|%amf@f#n2XF(O29K?!RDK7*BDQ|uNY&i zN*}uQRw&@cmr!wbR7IKBy4tgVU7mA!I;AIU@=B;6gSU5!o%|pku1u>97KMht5U(?i zfA@?XZ$`>mFIlNRJzyI5XRKP~RZ)i5!5XgBM$Nc#}A|2x8U;n88Evn_kpDT$g zD2o4&>F2*jWHWVS9YhK`r(yj2iJ!O{H2TG>QCy#A)mO=LFLs5v<&c2|yoInzua zr-Sg(!BYqPmqauygTp)3yK|Hb=JtIfWOGZ#ccwL~cX8a4u%X|$j&6OrwmbhCFXZ<5`quZXFm3gMH#~b25yxBBn>Z?_89&tX)X#V0^ zch@wr_!*b*^V;O>WP&%#4@ZxxGv#UqGnVbkiBB#FZYJ*g<+>>C@jZ65zB73HQdh?( z(#{qZnH`NSk}I03eiqJN=W^0YqK7Fj4u;e=OYHj%Gl@1ge~$T{Fg}Uu`cq;0J#+Bq zg^YEz;C^e&Sd*$}e(T3n?zrTL3jvro0bbU10<(`klYRW!k4evRw5?ZlXsziOpHvu=$tp21 z_p)79C86hg#dZJUdkQrT1&X&~YQ5*jRgQ*|AFiCWaCKf_B(dUQKNvrVmeBUBFtjqL zxbN>8fr}70z0b$W$EwrNuSq(QW4m;OI6XY>oYJ8>GG)b|e!mmgD$X8Zev|fQf-t>K z=Yx{bALa|Uc=3;k4FfTW-lSTnQri$}6?lCzxPX0l@8C1Nl*JD$>Tp_$oX#O!`qxpG zRe`^@G5Be}Q#-xG#XJZ=O53pB4$>uI$E>2z-#9LV@r8Ygl>#;ilfTEB`vSzieh`J zVlA7U{Ax{9Vm~gPH-GR^1jVk?l}B@tJRg@+)?66fyHlm_jp23ozBIs@zd4bvBIjRB z)|~f}&*m$i6mcLzI`=_=$eaq!2QslX_HVmAV{abJ^u6`5{pHTFNIHxk)frE;Ka8sP zFRR`BDCk-=A-y&>^IbTURxyFFB~<eKf4@b#-+nq`iynh&NA z6>JRWo=)((@AnRsspEMRk-ebqD62}!)98q2wE1`;;6bprNb9#RR(F;<$EU9xS8J(U zqYq@ZeQO-`by?&dPQ2{xjyyvgsuz!nl5b-4tHm{s*Hp}4+KS?swkycIyNd51T{XcM zZqzYG(P6xMGi2t=Pf`*x5j?)yBSX_OWi!LJ+_JD30PhBo3j3T4Dw!qTzougEFk?WK9dd(m8Yz>a#*^G&y3~>>b?m4ZQ z!z6fDYC@|Q_$A(o+?*k=3koASatZkD>=RjpLD3-6ylOf_Q;DRz9rNMhexuRh?S>Z9 z9znN(-FCI7c!_?x-|*L$KedHEW2$n%o$$V$HO71YQ8zZz?t7k1`StU9`=+iNfuBhN zXpFRN6us4x2sjM`+@4sI*PVICOgFL?S(~j|$IKDfSJD$&Dx<2wa*cJLPH^hzk$*R{i|sY%k_h z4DCKbkuo5@Y|9~Uf8*Ox4{o$3L1;l*PL1kR+uQU4^&85}ylN>CJt4KkDM6O{H*Qdt zeQI2P{b^3%dXB&9=ecQ|8{sChO$`CR^$lA`MPrujQ|72_$?q^e+vU=3kNIekX>5ly z_tbI8!+9fhwTxoZWR=_@c~9s}#Y^7la}VJP|Mt;ZXE!&Z(kxn})PiGMtdGYnuBkxa zk2gnz1BE5A{8&;KL6hLUKkb23zPY-egEw~iPix)zzdGJW9DUEGjxc*LlUIBzF^t7A zPuKL8-JF9!IZygS91HK2@g#pqvQR45IR6!EChP&i9p&*SHf8qpnaa%gfqfSmBpyp$ z821<8r@o!;JaV@canH6WvRBJT@y!8_lxL+*;MHJ>&cV943>7He^ zp6@x0*qOG`*FYIlUn>4R>dVihg@hQ~9*Jf%?{SC*y;D=j`Px#}lTPQzA}1lLrA#RM z*yOj9w>O>4H_N(DYyXY|N3s7_(TAzu?K?VWuu&~`vq z(7ZPqc5r)s_2=jnvwJV7S&c8uO}hM0sV$(2v=rxSn6QYP^nUcFC*6dZQfvU_ggvNu z&+_%kx~%fU$^C)(41TOz$47WXtvBS@oqzP3F&-$@eObOK!Z<^z+Z$ePox+ko$F38T zp(Nm}c`x^Q)4BVz8U@0h%i&V0&eEw{u4My1VbfYob60O+FD>__Bxd=3DYCx9Mrepj zY_!zkYt^=LJZVmXfiMXj33QT&wNrx=$ zc~Yr$$`@Ooi^Uox{-b*>h6ms$UAUIrK+W48e?54ntTj>~R_g=EIR#z6KBlg-2!N}xQQL8{yu!Vnk zG9k5|^VwF=`tfEY{z)RKCgx;qZcSZmVw=Ksr9?r>T@vx$KbZY=ZqwpgXX=_&^M(T6 z0>(G$Oy7J^AZ{3Y;49nQFa=Ypx6cbho@8tCL~3O{A9WYSArJ(UaoVCZj2 zoDz2L&SRGiC-=a6M@EfHLjScKv{q~RL=Wx81zZdak1i6kt-T@*jOHRA(Eoi0BQd0g+KA)J&FpD)k3(n6?NJd!01eD3oy7jqTZ zt33fNCdE!XBUuy`O=WEQ$iQHur%CdOvlvBjIH9V{XTE35GF}+*YRUJM%%40%JgEIK zM2cau+a!ob_bcI}F)IEp=A$I$Y?9CYFrge>)-XTRE@}OFQlu#J z>siiq{t5N#zq_f z3O85Gd0rl|XBn+pVpaP%@{9Y-MRv{k_d6yzql>dcWZ&FBnM+NWDvyd`HB9-Mbb}RO4UAj$DocD_xFMsF@+YYtRz6|HUQ$G0M!7gV^#gax9 zI7Bs2HiVx`CuZ`|XO)#Qrd;}<$uvcD+RArr_*H5}S@YusyRBGy_v=; zx;6E7^K{s@CFnG&{Xsz8t@KtO@u$OeG!K6BQLr4ZmcGGH9LhgHhNUG`V4$e(z25mm zhIM`8Jy!W|+6hapzIR2RJhuCIbUN-GM=Lj_aNs;8(ALYzXX}|eJ8KRw;;3pc%wNik zH%s@F$Q*Tur%z-qr9|yD#873Kxi7W~_3>=xILY?3(wAt|&9SL~?&nNTjUOP}-j}zsu zqenGm(03Dc-@6pi-nnWM#J95b)ARR@S8VH5aa||6jO$p8wPEh_sWOE9Iy#-ng+h9a zmh-}bMg=9xUW5D8uBYFS3I2@q8EdcC?F{(0oO3s_!?7MS-J{f_y&-kv?_5I0w%O17 zqow?lxMur34;8nBh8lr^n~OgMW=faobUw@39WloDfBmH7C_YvHK#-X@cDb2**~sSx zt@~4<`yJou=Jvn+i6^?|EF(7M_L=DRijQdK_e`F7& zv9JGbKbjvpM{%re;ozPVIj|NnpMLm7zr(7$`1_FW5a+*AP3&PUQcMa1BVrW;gWz9O z1GfPGJJb9(O2$N$+eZ?Ku-uaxL2;^}_)J5xn6`tbT^%u)qKszrv{)RrP5Mj`tRJ4q zEBs8)Poa@A^t zy2Z#=|FhY_+a8B=M6LCEM-`phKUXzv9*j#Bh^x`dMb@ucurp}q4#g%tp7QOCop-3v z$PJt4a-!r)_K2(;wae7JZh5<(!CPP8){a7M-MW6MZ28ZMIexQ}{o3*=`}UtUd-s;Z ze(}x-UNj%--!L!58+3hIzV0Bv^zdU;;Oeg#8I|?&iSgMYe*CdHeIv2MT~*ha ze)SbYf{Ex>^_;My{xiSUvH6X?T92GlWOIY}Np4lUe&To8ZrrJv^f2zq>GNy%#tN$8xZcHiCo z6}jJiLPX`UcX%{q5&M;uO6ZSa#7X1F^wzVvu@kvOA@{=x<%2|qDfffjvD@8L(U%fq zr!A>Gb{Z8{7kh_7s-4_T&PJ=|dbQW6TMJn?J@$T%M?b0f6Cd=Ay)i_o*&!u5PS z$7(kt@(zv0*quVF;bv>4@ltCCqufFAF(1pK^M!}?$DOfzm6c`{`PzdeH}{g9Uz65V z&Fxt@R#!P5Sg6ETYo34SCz>sIsA;J+5&y^j;QUab6jgV)-D@&j`7n{%?WkjL!MNIt zbZg$(;C#BHWIOAz<_99m-?8D6qmm=}>5=@ncO^69Kh@g0(`;FqZ;NUL#H z%jt^9v}(NE}}nj+>{O2{mHBC*(MK$rcN#*`kGFZk4vz;IvAHahPuGwo?w7J2=IM zhv$S)yL+HMY%l%tnv>mL>Ns66tWqO%I1ftJ&h;2bC!*#rlA~_pan%1d_sdk4Rq)Tu zkNL$`GTJ~l?%#7)-L~gmI$Geg_ueK-6pBw&)s9N$N^B_3dg6Y(biSx9#OKByvpPwC zP~&E{+S}DunC;M*nfIWxyQ64-IrdEUup!HWZjL@^$bnFkz|b?2wUfKXHTv}K(YeBy z!ou^#n(7iv!RUmwPMwwU-#@(kxLtoYddXROgi*NXywWqQI{$TB`;e$)=Owvqbtmu%X@ zPFJx%UD^#)3t}#NEAtj-1s0p%?MGy;)FXKi*TU>#7;CIj+Nq#=c-zRm z1aIQ7i!_C|R_4HBQbsy9N0~HBvW0cT_FQ$8eQe$&__A*jk!Ak}(^+4B?!&pZs?FTk z0J0Nnel1PHMmwStzkz0vb|Ts6)c`gP*}iKE$ceU>Dc-91j3+{|DNfsK#8F<8Rd}5q zF$~AelmV1i1AeE?8&*7AvaN5>j(068`@;D7xJf`vk`gg34^?3@TTm|Fh1}|}> zgeAJ|N5|()9PQ6^Fy&S854apj%SI@e9hB}hPKLxsvwL*r8!>432#-6(xRxSaE-SlA z+{B*Y*#Gf%Oke9s$sIWvzq2)0+pRQiOS1r5y-EGJp)FUtj@y1}S-VHBZH?W3KAldz zvS)olR@&(|JTN^`qjQ5(^|Vsbvb%=;jAgeX+N1j= znUK-3=8|K|)GMJsU71IYoE4dK5xNkRid_GBIlNq9>D!aA ziY=WtvU2t-RpGwz8$*%`CkaORB~4*Ueon1>YpGmb^mCGfDsSE8P}1>KhWCf;)u>+7 z)k;Qlp2_|!P+|?(zCVOt{Isy153iiC;7OXC%fz=2toR(pEXe+iyz+ah#RKuOeNqCk ztNrV{^-26_iBXt#dOlDR@Gw1hYd0lZId-G=Nn{x z;UnKV8;-k)Drko6Q?^KlH6DzZa#o1h*tA-HNYj#99;6MLXm;)?WZwR16Q;kf%-SBf zCTRF^tAHvGFH`agsfyMCmR>4Zr!uW{TGq`$qKDWglA=Dv_VEQ>x3WczmY?acwRR7< zFd)@OjY)hshz>8EhR}y(T|Cpee{xKjN1pliTFX;i-6!omGG~M)yi%ov+TORm=(bnu zMCO0K&Uqp_6y7wPCl{^o>gP9sggnKXk8>B76}}mCN*R)bjjYOMuRb+@;1*LbrTS}4 zgefH=#W^>cOto02@pEhrIlUhBntw=moTv?HL45 zygKQ5RL8yY?Ss+Jg7A`TJ8Ap$52s07SUUmO*Xb&*Ka@1AkIOjFN<=ih%{4r`A7T=n zU-Gk{*~O|LNzCB(yWqD5+v!JlYKx~sXGG>S1PQM-xB7}Qvbmuq8zkD*IsNx*1{qj4v#)qkK zGeL?g8==Hr*bgYUF1AyrxBqI*uYK8UJ!8g$u$DH%jiV;S!0CAIMZP0Kj6*1Wy*Y69 zhqyJa;;^{o50hu+ULQmqZq#( z94e#1Q!10^wbS&)nuqv~_4NXOJbf!QvuD8<-eSkGn$$GRtPv#z_A)yJhodA?2Z zq6?Ufsef}Hhb-WPU}O5`ecBHCs9Q`yzla28m?jav^i(}>`~j2|=h$-X&n}6y{5tJtb#&oH zP(u0#D&LH@%s4S!la*vDD{R_PzEINMGwWbeRN!PwHs|{! z=Fgr>T6XqBhPgo8#N)pE*Od&zN2a;n-Huj_d5jHY!p1a4&|q*<(3`MbR+F=*fAO#T`WbBk@S|D{?(3jKPM zh5qIJBb7jGi`2OCtahtP@mDu*Ye+?OQ`+W5I4RpTPCgk_jsGP)>aIe79~@rJ(LYFG zP8;9!s)2V-FSgW)jOcq-+daZvlf31OVLSVlbl18@nR!JyPK&};oD+Z9+}41~X{)>a zIcriSD^b1=K2h{2Jp7{2_Un29U$z35vN&F{LE?LxAoEB^-A1;(es8B-p;NqU zH7lScx7sdaep^Im){Mt$j4>) z!S$s6`s3h4m5h?UFLw38 z&yuB`l6ShX%tygJIp*(^ug_G3ijRCkHft-Wm0k@V9dCZAVdYBn#rzD9Tm5PL*>rim z@xy}K`X=|(yPRCT`bHcm@Sb%BjSvO1$z*4SVHD)!<;}}wO^ixe@*0!&607}Luv_s@ z;${&m{$@@$k42kVcFEZu?x{XlWqmAX z`i{b=LK^<1bT;zB>kVo3#tM%l2czn+aAaPLICSF~`tlR#(o}BB81wqHsF+U-UTl(4 z7$*8%Qt}O`nAH9V+h4td@tiIapq=QJ_TNm4f~5x z8@tio53#T93X3(EdA|1#YDi0YPWZmOm&R7@l1EE;k-+B$V>|9id!5E>vMJ2n1q3PE z(t7NXUys3k`+FA@6-L}~>(|Cj*CZPjWYkizC2A-+OGa=%JFE8?(BMAJ6t7vrn=7|o zYo_{s{X~Z)Sf@Usgjc4nusrX}z#HaQx>#$tQDa%g0TH2QmvM5fIaNPg!w|J3&!WI> zA8Q>~K|I?{iRKMSHneD7AfA$lDa?65!)V#r@rqzl{vnn0Z~YFj%kTLS9bD_?4T*he z`H21)cVi~k=}KHKar+y(4H^@YQ6?K6f{HWhjIonf9+}`=rEbDiT{s^j)=foaym?kh z-jw<%Qe-FPT#b>IWd-a^# z{_50B6o2fcuB{)zkr?CiCAxjI)gj+HIbUq8r||Aq(|k8KRVcgpl=4_di^zDruh;$N zBW_X)l8cFDl&8y&c!pjuq}}!|NogXzR9kR8*6GJqLcOd1*$-|T{+V2}lu?fSba~rf zw~_=@LXCcjxhfb)NMOw{zqCrrA0n+*x}1ej4||h0E*erK<;45U-eKUA_sl}fIx)6+ zMoFnqt)?2cl0u{7^X%w**aWuZu6$R9$F}iE9U2c9X_2p}u$D(;-rB29ag{WD?~*@h zoqZ^Te?#rtNHrotE}i2dCEc-+(#v+i$$cx6p4jajsn#w(%3kKeZ&xvGkS`1`fWHM$DqcGN? zgR!vlV2|fqWRIsl7o2KAg@zoq;xCfdBq)N_m;4675pfySa~%te#b}H{O^94_hdsD^ zBJ4DUvBE}#u}r35T)H2uhlBj;hKH2wzJv-*xW(bg>Vqh1k}?+FzY7y4CSkU!3S$+> zad@AKT|%}bT$cJ`go$h+q~xHP03)p18Ve6$qMp@U4!c$3g(zB(fP>%|3%halc-k>0 zVFp>hMbNXuj8rfqS4T2tcJyJL`0P4NOVA_CPxc6F#Sy$z?TMgI_eOBAUgb#2Pw(+; z3WLp=dm?tt@R7z^Ca@VW@(8^bB2^5Dlw80-e$7RpLJ7foN8tYA5X}4yZm>dxC|1GG zi%8?OYk$oe8b^f+wczDQvbKla7$;-4c7yp~J^Df)M5+e@*-}Esk;Daqja-a{OES<) z2xB>O34_!85FF{&zfnW5)YJu3XvbyLvsn1t`5&{dB2Yc{m|!&6hMTjo@BzEAFyCU2 z=dn2)aR-I!DFn;AT{0G)Z3EPlpihE{G(H0WHff1r#YA2~g?7PNt1ocSL^E^HxPT9j z(I>Hl(Oe=}F}Vb&XWG~>g}kxwYN{`SW1j@|?1Tap8V4v-L!<5qpp;z{tDFkncmZf- zf#dnJw(I{PK!pmzo3XGK8X9KTz1TIuq-!5V;An8H96VIdusXPj3<3&fL9ZE<4@;yo zb0qEc!{NF85CaVVJa#pH2>ovKbVXpo92lJo>xF`M*u4;T9)JX2c#91};n*YzQ_~TC z#>3`dN_0G;l#$4m7nIRFujIKVg+~!aCi#&A&Rt}jXkTdkdld40B+Vl@+V=PT;KzKm<1CRdd|t= znd^)A{iO$^8k_aog;D~@m;MLu`$(Tn?S5UR-XjAwgev<>` zkfM4<8Iv(PUtuDriIOp0X*g<~VMq1gbQKY-Ue>z={bz)z+C^CI4x9zzoaqKf(kd0I z_78-ZE&LvM3l0N#hz8IaK^UDmz|w$CQyyU~HED>shpb@PZUAbYA7W;b1UY?>gt<2+ ziiMI!8}%Xp5)69^IO!lk^?awm@0h~t;P9NH!);O)#_FT>0q6q+nqU{*KmpX?`Ai7T z5I!(77DsIv22!#MCRqfB3&4rF*1*{#Vpw57d*#5+%b{XG1$fA>GQbzI_+TEWo`|l( zV7gCI5S7L<00cWzaEu&~G6dTmIj!pPQ!tx8oCBkq;E;ELT>aI6roAr%PhGeU@|MBsOb77j9qc5*}bA`~JL zB5@hbnI8CnbtLQw@fV#mM|2!CW5NGm2TkIA**=g3z-k)6KzkbSMY0!Aq4!@(mW0Hm zUkWV459^Mi$xRiehBX(Q(fkFhnhpc}fU_--97$U+?eRSz)i{7gvLAxp)*IfY0(0Vk zqg+)PVgXFu5nxhz5v;H&*qj(amp(9l&lv{Tn*=a(1#CWm4rACo@JRu%y>TGWqy06Q z@;30L7#8>)!WTVS5Y1U7Fd7LtkQoC10DKIVTsH+8L^B0!v`Ix2OAQM)=MJ8;f%skp z_}SI?0H1)9vKjsf_=Q{GkR~|i830yA4ZH=8pOb?JkiHBYQa%Nk6T?QXsV05bhxEK^ zf`$&@5z=F)G6KK~$J~Ql3b`w3?L*pTcjum0UD{vYi zpf1?QfV(%K2r_jhDWC{;ZcYjVDB=7Huq?Q?JRu3Q6EeV(J21T;@Tvu*Xf-%ltOVe=EiO1wDtsxA2Y`R#L(`NA>%_q^ z62$<{kgl6xDhhdao=Cvj!OGWG#@!x;`b2iZzL4cuhkZ~=a6 zpi$Wo{I3+z!@m#EgA>gHCe~A+*4hJpFa!$zzZ~&@IpY7196@37DL3<8Uf#jijHJK@ zoyB-nGUd^A%wPisMNrSswBBeW0`sWJ;ST13J*zd-B#y*syWi&ye2rT7HC;* z{#^D$Enh%Hh9s2?JAr+NVBroMBSLoerJ&7f)WkEj(;mIvthV;g(-$|ScdU3n-S-vb zEcLzCUM=nNIqEY(JT}hOT=d%?_f_4?#I@!Hy^^k{i3gG*5o@RQUi&-vf_K_ltOV(t zTr@|WgorO6C~yvHYD|17i{vtVKQbK~cg@5~P5-V|$$e^-MuHCv*IzVno7=yVkWp{! zi))gNy`EfT@X_yHHTEX6Foj;Kp+xf|4sPa{w15#4uk0h1YTB>Ov?@u|g<%r0I-fnC zjV{Q|u4GD&`GjhOhdT*~@RP=j{0hP;$R2d0HO%sE!r*cD8f8Jzx$MIK5L4}+MgEbE zx_@nyO;K#ziOcib@@%PaalE=}>eo6hVb|5fF~iulC|a!uO`;FG(b)6I1e(J8t}Vmy zGMt|bNzD=#_dfgIkbitA)1lF|JsCmu$XG;CtI;yBoqap*W%Tob8w zG>L4;O-1vTmp5MWIw)M8DtQsWTg0#}v-7#_W;Urqn0J)8mcFlHPZ(QT*|zY#h^HFVacG^h9$asg33wf*NUJIAj&OX{FXCd(88hqqpqY&*;K7S8 z!-~6fyMt+8C~rJ_9k0g0&9XmrL1~bl)G|DPquO3}tR(uF$(?+JoWSY|SJSNcsc%L` zb4kz?$3DLLeN`sRETd9665dSh{kWpy?DHd`ZLi2|Kk?=#T14U{QKI|;F*lL*F1v;I zh0O2?Yd#sUcW`WRNUrY+Cnm3%nTzzLL|eT*CtK*+VIch(6yK?VViXU=oWxrsSUo1m)bliNjbU?Mprdon2d^-#vLpU6H- z=l+GYn=+%cB;{O>=Zh)1n0E&|6Y_(jwYhrrT*n5Y9lw(HG%3c`XN^XgYZ@s$d89$| z^Yj*uCF#0K7M(7)+Xr&2orR>**>cn@H?3~mOl)8^UXz4U2Vo(*9nB15$1=A;$NRQ1 zzV?|?HXonouR1QU1h6o!NQ$~yZUh^%JT<49;)#jLj{ewhQj z`L-M~;@k37g+s#|gUn?c)MWIcgC5y>>AsBFN;ALjH&zlF-D|E#bD7Tcp_N`^ecX$Y z=C4Ngzh}p)+@WscGN0i_h?&y)^2b!>O^3I%XxP7cqvE=HUnY4bD8~H54?>qwl_*P0 zhU%h1x>D*{?!=#;lq(yHkPn#ECO_$urvJpUe7sY{xMuuzpu)A_n|@HV$k@$@&B*xY zcS+RA#FzY3g4m+w`6f3S%%x5$Gn*MEJU$9}%(j(7&z+8}wnjDCT%L;iY0jrq`8+f8 zCB>|I+)W~dn(6G7O4s-Kfzbx$2Bl8Yx_;W)+Yv1#&xbfF?b##QQx&Ld*b1?DvS-zi zDU&Sc+|GT5d00$_x*Q96H1w-Qtn!n@!w)#+9?_4*^xx1UH8);wct5o<%4Q&fu&f;A zz4MfIyK&CS5qk!LpmYGv@R%tND6r!u8 z&ugi1Tw>yTGvtQ6gA|GCDI&K$0NXOMe`I;lzJs3A^Df;M_tCQksrXlFf#$91E0yap z;vH*TeUu$P@+CU*eO1EcuNiQr<`*=)+)4X-^8>k!(#ap(H}UWDrTPXn71WH&|LiA? z7S>)s)j}b)3*E~Il-a)*|7q;1SE2WX@79Qr(?8t2Q7aq`KKxgtKg3cUWkU}3^D| z>Q5-5p;g6jfvT1g3O+Xjm}{U1Ev5Ci{)Af67WAMCNaGDDD5h^i$6<*;PVYdk#tE%| zrXS+BCX8o-UIKc!?4Zjiom@E930n7{{3{O8gZ^V2Vg#K?6`cPBN<>GfBDJ6o7J@Fp z2%4S|P@W1gQMIM$${mVTIIpq5Q|QZaK`eplSnnIyRu|oCfiXZ9Yav8}^z~225^BK- zWqgk)bSa`(ef{~u(Ep(ow^`6UCZPFl>Vrwuv603gog}frG2O5I?Hxk9pvum-g8{Md zp6y%2fFM-%Ael*);(=+Q&vsWg7A{wUqSpc3q5uoP%qBvjAcR4K3qSin6w)7qUQIyy z9}R0Aif%3nP>c*j75m z;$f4}qN8CrU!jWH4l0Bg|1p%uETPT2-GyRGYFA+`w+Wa9JP~g5W}(1WP;R( z76tV|KI}Oo{i}QfvE*5R_)X4{#M=px=Lh{TTBbYZ00N>w>9~P9&1mciEm#X7C@v3y z9dh6pAWL9WW20&vLDrT5&D^cmGY1w2F&XWqBUI7%u2TXkTIhOMnw>KS7UQ ze-YFPK!rAlAr(LqyU;MA^)y~k=6G*`D#r(O@&JGa=%2d^h~tB>KNSNR1qkS?8-xV3 z(gO^jO_77%vI?RmT6VGrp&3L9G##qBz*ghIs7-xnNdeqZ4)Vq#`1=eO`Dls-)l*3V zY!itd06t3xEh+~ns~p=HLkJ5wJ(Yxcdhf6LhgPYVoS~H!gNdgKg@G3Tz+S01JfV?K z{R2?z3&N>l6~SzPchm3C!J~z23(%1B9Rch) zXzc}_p$j0i!szVBK%GFBO?@B+fMWzeWkc&u`hI9#9gbv&W`Po*gnEdjGqCqQh$3$H zz$IuP!5V0VXaUYk4O!bMaHFN*zl7$r43aO9bTQE41`KeP1!SS%(g4lPF9CR9Z{tdc zA<(*#cryTUpe(OA!YrV`8driE6%Dk=1p#FL0EBa0v`B!a2%x|?#6MKgK?t8AHmDdO zutC_Ju>2>wVqmACoq$e00$8&XWJER)oj{R7ulW@;B}qS!3&zEbhwMQvkVT8WK#^`N zKnvn9Kn9*%KqoIyL(mrx-qL``907!5=p#r$cE|tpy^J7A{3hARnNl(c&iDIUqj)t%bo<%4kyo-$jGJc!A!FArp^)Mu?W6Tu6;?;)l{I zHvM_Z%8^v|^>201A_#hQBKYqkh^&#KSiMv4K_9#ZsS}uck^rS63#oQY1S?An91qtV z9Sl2`0F#@;$4SP-it2BTW z0XI%dKyqLv5aiLjO$DXbxDq~7qa`}H&0s|n(Ye636MKc6km=S%$IrO7KO=|#fK{8WwxywOA3AytO%)fzFF4N&B#NePl zHq<^up!dO<(U(JO==&Nt`v@20BzBkyE+$)i!H7qo;IZw)GH^$QK4TcVr!b^iuz7%@Atnu;YV5u@yx2R2vKqsYLH;ePk;l_TsN9cZ1>AVOE7uRYKd7YQMWzU_i+UY-M}8AmIpzM$F@ z!9^-QK#LKCSm1cH=5ITMzQ{u-V6dL@CAhc)_d;Dxb9Cb$+S><9jtxQv9{@{AzzYIk zcJzLY(3nLZ8*IS^6oI}h+6jls43pk$ruq&TTTPyKwi&Nf2jXQG;qes@(NiqV3ua z%1!V~Hy#YGcCTHWIni)Rj9l0uag(j-ezFIHxw{shoScek3r(A{yLS3_XYbly7L@28 zGCQo)($2N{RI|FG6uk0S!=k8LV)y8+L@_DL;?G5glX9{|X*WevYcT=;?uQ4w2NF*8 zEJIU6qK9#^iC(L#!mbuya#w#lO`=zgIv%A>WL!2?a}}I9Q^_S^2i?$DYWwC-dql?duokLPk1j@}bwo`7D@49<;ITZyLCx^@^erA5Jv`Q>p zU*&UU`JSt}#k(bVFtM0)qJ~OzS+PxXquPHSoSP}L&8d8%A)n0_xwx_u;zm`NySZ(z zD!4f~K8wT#1CQXMr*K>iJ0y$`}UmG!Ci~`ClsdIk@KcsT?GYs zt^y&s{l7V{3zm)zl^?oVB+6~BHn?U7=aO&nZdCiWfsJCQwQ=Tci`}Zf=RVxF=c#^N zHzaVZhOON_yL#a27N1MIYfoA2P&Y(=Na2`hyJ;Ha+L@foy~BB>ny`6j@ep-eTVipQ z+x09w*J-CXMX-5d$o9CLRr~7FYLDx>UoPi1CwcW`-_Y1$`2|?r)WvoEYwpz@PNHf= z>(J$+V`}Zi<<%tD^*6cmzd2u5zvv&5JdC-cO*gmt%{4nK*K*7La&=noP~%a#g!b&* zs*qb}cJ9&Eo_95&k+vLpjr1W)MKHF8dq%hI9&eVQW831waiw~q%c5&k)h!D1o-^j4h*^rZ*ZJ z^;PS$)!5G4<2PNzHx5+a_Um^rPDFZ@j1^7Ot8KxvqQXM*c3o z#690~JT8-nwQhUIt;#R=$8UQkz~IoELkbyfv3c7Kw@%+&#}q~qvJb7WAlf{qx9Og#of1lqO6>91pf>#vYi~W0Hz?|-QIOK9u#v| zKW+!0jXP@ZOq;%OMf&GH-`dlZ;3Urhv`QZGQ6wI$nU=c7hvzE&26s8MEZ#s5E?t1* zY6j(|?C_2VHjfS&9HH)Mhb*psa@9=C71*&ClqlO~85$qDa_CH@oo=n@^~dimi&<#;5dT(U5d1T zNN_x03kpqp?5g^-hJ*q`@QGAd%ydRvBw$X?)%3Y<4MNK%3O1P=J%Pa%1_@j=%e!>`kZzQ#t=IHW+-0qFUBJODNGeg@%I{&D=RzDffwhvIe%da{R`8*vp0%L zQR+(hCYXO*LyM1YuHjKen{a+c1)3K7X804 zP51eqm~xK$H#Q08_+v1Sp~7wO);%dRMZQ^d8|S!ugBh3g<7F2EXh;ftTBh{5=il@S zt#C0TWbL@>LJzf!g0t@jcKy|1D$XokSsSll)}cCeL)FK=rhf_J${C2qdJ^q21kFku zN!Bxt#dYKaa+6Iy9u{V z@t2w^_Imm^>M2eRpjFPH7CB|;1KSYA#pjh3eFOWqtt2vsjz5#v%*jD}D~AlOK2P}C z2RM@LR)mkB_0Ka!a~Lrgz->d_R%f8IqV5R#@FLUTubo$*+24mm4v+BLfE|;Wr*qG& z8JD~zZ{=$Ub9BV7e%4%RwOZo#b5-pEs+uDbVBoUkWtHgFY&jo0RH#^5+mM(26PRACanlhOGP#1-1J*MKs*bvvIeL@+aEqoQ40d?^KBEIXzvSXkTu_$i|=2Z-Sb4sppD_jtvG=mxK1=3mw> z@bnpaiSM?`E(}Syq&4Jd*Uv@&5t*NU67YSxT$(RO!RqRFmXP{5KO`lLDrX+_W}#ff zXl26b<<6;(?_LpAMha$w=cIkn|6&>Ylk=l`S>HZDDud8nL@6aVC5%#H3ECd;;ZpNO ziIc5t+0{Xjc`GSj^<!6;di_xf7wyjr=c+d{hVf!&9rSG~T6(J{; zA%Ezg4OUllz~+}HpkJAN<8BH!pa+c?&zI%%N8I!WTxy1JJPY;crXvXio zzPei678wgUSvl!roUCPUPXsn6WnzClpE+pP$0wB8Yg_PWL7W;5~Bu8^Z$4lAn7-&b;DUl@O@e* zCnU^v;AVUA3t6q2U4`u98C5eOK_(8}1*DF% z*bgj2WEZ8HSK%|eQnKYOro&Qpv5~g;M#}@S_pav}9vmxiT7BTOFqVGP@Qq#Zdx`s< zrOEZs>Z@hJEg{G3GyjU*#FLbRAu4q@$7|%|CAh6ia&xQ4Wq#1GRrqRC_TDn4*&S*vQD&_%}#Na{|k z1@z^fCOfCkUU@(X=qLNX`1K(PL=+);XDct;&D%8L=JxFkk52H~`zp=RoHqfX^Ewx& z-LWpm=M|4-nBG*`N(O{Z3{ak-vuaR|V#JzFUzE(Llz1_3{d(p^8>fVg;gWqPoC>i* zMA|nSj=P=7fU_DG-7@QUe2Z=qyli>Lmu2%97w%ru!%(@o^!j!Cq@;?9jEabUV7rvM z=CR0ydT8o}Tbo=5#Z9oMC9&UEU)$h|mkG#^H+m>2ojf$mR_-XC(55-XeKKQDbYho` z?BesuVaA(&j`q1$vRKI0pwtHgPqyj>C8c`WH&->YDWvXUW1)fYf|C_-)oSRQcXS(J@=Qh85>oemTR;N-O=$rbMSz#oH+pJcjkLcPl`C3 zUj~azTlt|ImPe^s%9PF&FShmyKdj|#8!Du2%Vt$9&Lk+x&GLpg7AM8~-&+6u#Q0&C zKFzp@aTJtF#`}tFxQ1Mwa$L*2oQ|kT!4s{!BPW`iX!QYi2 z;H_I|Bu+^6dt%`ri96 zBG2GaS?I9uaEu7i7;N?=U)kateYPXIfyQs173?s2l>K_iwq~wXv(0o?W{3TcVwkHK zY!Lq<*ors<>{&!H{fFIb-gtnv6^ppHub+_pIO4A36CS1W=Mq72JL2Y4{0U*18?{xa1Z}f$nrs^piN0fxZ z&NbS7t`Zu$WZ9b<6hqt8kSFpf&b}UA(lRMyE|K#$9lC|yvk#3OcK*x_Uy@78%eE_6 zr<|bIpw^_-9`&ykFM-C_10@RT?OjA#g@mwB6* zV4uLsn17OzXfX+;dhGpzwe`l1@>7aFTW!Kek?WqNfY7n$Ua4`k`kN_KA7<5wV&Qdj zU2@llx;@Ja!Bo)wJ@nA=k=IP?T$C|zw4na}O|Whb>!%BB4=rcYkA++QVxS)rk!KeR12p?zZO3tbAS);pbphxt;yicne~ zoJ;FVouw)AdU(x`Wa*@oij#`9vqr7ECJST67L#veug#XxM_mdx*H44z(_4^ZQjY4Z(!zZW?vZ!~LnS{p*_Q;om<5;jJBbruhs_O!!f==5olw9A>CZJT4d zh}Tw*C%W5lPYs&|%$Dr@Q!r?|y2;?O$&mO<-6;#>iJn;NxpU4Li|!xSH`O)5j$!RJ z3;ycuEsesjp`vslcOH*WwJYavkMJ=z%YMA%Q_r8Do<83u-7=_j$@onC`YWH@4n*li|cnDPBE%c;TB?xW)O z(VVnrZa*?kg||g38E>$R5}fb02GN##5ls72Uq(=qlxqwn-oLLObGL6qHFh=CyHN*? zy=e5pu>__r-d^Dbz1A6;MDxX(bJla5^l+(vOw3W(^i;$o%q&p*J*l=@Q{w+~-qA9( zGsR)#HqtDO{6b+YmxOy<<4t!CMH&7&DCP{j-tsoSj?I!AvYhBzkg~`YSw3+KHmxrT z%Mt9@ut%m{+*y6@=-8+DfUQHmKI^p-&|p=6>v&~@()vX|=85&4DFkIxVpf}SmN3Lf zc#N)c8(q6G!NXX#+G#_5zkUi*5o0eM98s^ydgK*$ex~ncUzXdR%Izw#RQ@N~J*05w zRmkO&-AjcVm0xL3ejH5RiDAwh>gF`Y)C-I)E$o%&$Y0JZ&vyH*B+rAc*Q-N--JXDv zy`%Jp-bZhf91}UOXGHWlxW|RuQ(@34cpoGSIZ6(cTZdSV^u|n0yV{b=ikY=j>MZeD&-1 z1?;pT@AmARw48$|L!+`faOGk$+OHbB7>wI38r+E7PF1G@WXg71PjzLd(HIvhKl5GA zuqx|k)$?|$6`!jAKw7W&mgT2?ub8t1esRxmoZja+H?L=gpjN!5vPueU>hE&zTn&fg z2d>9pSmgtlShcQ>DB1#)VWJj`sF98-a0o1luO`Yo=Q8Z?ji`Fi`!ssDo_Bn=o_93= zYD8si?d<04V{QE(xKYI$&bqAtsY6bT$v>tL=xu2Ssj%i!eb<7&?)}Ks^AwgZ>XQcn zethtLlw|?FOKvZh;i^X`ddEB3d#(R<_vHH>!tz!+sOg&t;s#{L_MadxiptFdvz=pw zIl6i*cH>(8jeYfy4~a|R_o|e8d92QH20|M6!Ff+^YjAMJ>Jz1b8L=L{-ftb5VS!&W z+&+(3$@KzrdW`Die&r%w636&oDBv+09>r*pwOBoJh~s}5{YJ0U)=72NQNh0ar4aet zp~(+JuXhbiwa(8zjKASC=h~en0Zi|X55pLWCckmf0YvDJ^zJ0qG=GklU(NNHC4_kp z%QKb3ra;3bFN_YYrI|xRM}dH)JGXZn44Hd)$_t16Vv5kvH5&tga)OR;}N8S2IkL7`{ZZ#MhusO= z)ywar`VP}N*;)wlWuW^EP+Vg{-k(J9 zg9+K<`zM&K!U}bs@tP4DEvrU!x3VFoIlju-Nk1DQpG`fN-n~Pb2-!KaI$!4cJ*tWS z!!lY-^o>bo&`y`5m}-U$DQyBB12J0wQoKtZIso%|7dS$6Nka9$Jat!JT-A=X{4Vcj zRP>1ER)|$$73meB`bs9Z9Ps2Um0Z(1WUYeTq)O_d-__ua%Kws?Mjwr8vSs`W~+D~f@L8((o*Z)|ah2tFK`geAK# zD04tV0icIU_ip?YW^$tr6^C+|%{@_vf*;Up8^_lBLuW{%eI1T;oT0Dd=as(El{(W^ zFe=vXwLX~BV0DtXf9p!uwkvlalkwIs=so-!ZDD`Wvt0+D^y+=h35NW+{kq}qgh%xx zI}UHnj&G>fYWc0|UvKFx)v3NLE8TwG{d1oQWabSehc6SWh0-5(;h?UUQkpG}S5B-s zg%>$P&!JDs+>TB4H*)`T??~RLJ;>90~WZ2mj-?~18gqUAe(3rxW ziDkd`Q~thdSzLP~^8JmFhCuxT#|Jd%u}G2WE?vHVZ)Jfy|3;cT0_|+gkNL?J|X$aCF-Dcn^m<&^kf@ zI`tmsNaK3>;7paTIt0^XsomKTk<0-~KYn~6q9wKPbp-mHi)G|(wWwHs|072tVCq|K z2b*`o&6%c@k4k+0_HaOU>s7#0C ztuh2%BuJ_w4HWfHO=wu`pKAx++b?Asa`W5l+tUg0ZPWy;WPx6cU+6ZS^=SrM%%?

(4^KSe4WR6&emRByRJJV}pWPhq+ng6*=07dgIu+#z^) z^5sglA)C9d`zY6@>%BkpV5}BU-?mY^t zyutf>7MdS8TgKhG{`1n~;0XRh7XIxD0RKD=ttJEBv_15@*&;pP1fzr?c5!JGf~Kwr z2kEM4vv1AdmZ(U217@$($3<$JpQVnS)DGjw{r<4odTAL7H?D?@n6F;Ze(b$#__g&9 zr^WzJOy()0%xY^kbBIlG-Mflkh3M;@lhECoBgm^#Wz@k{xzP=V@X__-E=3k-d!&0n z+MOT71su-$v32yC&SjsUd1~!_uXEdQ?GT@l6#&?kCOf7}A$=TL?ioesNH1HhAly|00p?+E;7>?Ay_IyZb8hPL>qCV@uV z2_2~z_bv&W`*VX+CD)2?O1r?n)H+}Y%5yGzNc_Mi8Y=!<<(UvrKKcOMw3B*+RL^ZFdLhZY01O^ax7EuBj70KHZ z6u~ZKt-e=DDbkxc+vULN0gU!ULm-7>#&z#la>8sQi>z&uy0QCwP_@4MI7T4b+S@Ju}=KGQT*^t6i-cevDwcHPrmr0F_gr4g*A^Cy+#M7rSfG6i1M6{VDQO7?0DVu_d3+Q@P!1EIj z66dWkXq!7+81mLzgCWA?$r}Zc8XSA(DHOzFf4c1tH?OgJHR)IJ{oZ>I9$y~b#6>hn z@;0AR_oQxVY6x={jCuCFkeF3e`<9p>A(s9$`ra{uIcmBcCBvFt{Wwi6T6MVPwl~1!?aUG!AIYO9QhS};JYsK4KQ~O_Fc{oahx+l_Ijh#U^ITO?2p7G{ zY2~w9Ua@O5JCCp^3<{L$8mIsBE-vJK8QkM8e9DfV6uyz$OEm{>B=#^01VeF zW-VA%aw4C-HnvvFK6p{d)l*{Y(dYIVY^LZZS*{ZIJvF-Y=ioZFoWMEA_oi#015USA zgA}ajVSxtn)`3S8Pa?7-SA!b&i|wzUPg%sop7(isHeoty7lgCNqe=0HNWQUf%aQH; zwEJktiBvPS^~p6JcrijhMxvb~9l!*#^>55el(lXD(jYics}9j))tk|ec=X+I6xX!^ zu;YLc&ljj=8cTQMw!>1@gh1{GeORDJkLL3ZI!1gcEe_P$8TrGYFkKxG_wAr=``qp2 zY#7UF*4-OYAGr9J)K!R$>rdK|vvZ!G{`X0a-&gLNsD9aa*L&@oRtIJ%=+FB`<@X^x zd^J4!;iIn4hRVIXPi?B<%H)yEre;pd=1#0|Z&-EU13s=7U$tTkrh~7A@XkRw9>e-c zUUtb_eD$SIRU-Wr;Y$^U9i~xS`>F(T!t0hSRAwfd(JzL+?is^VBh@XJG-D6^)rBaO zvbe}CO9Tgsh-bjYZcab^EM{n+-4soE(;o7=R^cF1Ve(xo*u#U@Wc0ceo1-s_duFqo zjLldq-p#hSO?~9enAyORgd`=`rHcx{b^G}KoOqAL=r`ddP=~lhQ>k?I*WoWC*(q20 zYFlNiSa(DN6IkoOiVtNw#na!HOTQ$|q|V8gr4L;Vuxt}n<@(7dbLRb#2QTf8k;ijS z8G=}sr#_o}-BZ-^QTcP}Y*tdQ>XwP#D>*JD{vnfuuQ@Z98|fG28RpmM?eqI&>j(s| z+6bual<5Wk8Qu>m9&nWto>~W6Qq4Y@4PEeU@!@rx6?B^Ny8|??$%tuSuJWP(#aY9Z zR-A6s-&36g`?GvQ`jLsn_kjVeT@)hVLI>YvLR89tSf70;f~(tF?J5MFBj|+;%7c&q;qi_V8SdQua&Trx z0QU&t;v#NU()-PGXVZJdR>X|oWCbako`c#f%1W!FGYS*Cnk@9C1i58F+3TD%j6}1` zkM<{!>0A@`rZ(DNq}$CC80{%8o%+{u7bWG1fO`j1{`T6A zqXO3o_b_&W-5(1<@^tGj@z_;R&~jhy$)t9fUx3?(twd7N*QfWwDBe>!c#@Gs-}j^< zX|rC%*J<!!YqaP`0aI@FVi5zf+@6sG5m>1x$q&+L1*X(F_KGPjC z!JCc@W&ZCkMoK;pVLH7$UwjTxvl7suJ8(7^VtMkouJ-n>zlALPVdvKuJMDiz;_J1> z(fn<^gLD5Mj`;p^-u~xDdfTml06P2GV9{CVqA(5gsJ}P0luh}S~YksKLOnx zVA}c4vrK@qiwrEUS8X>}8QR9x)%VaLE@OP}QRR=yN0pbAc$GNDDutI8E>1L^Ot!?O z?|TlWBs%7b9&4!CNGdGT8^b@e-m!2iHvZXNi~Wo4y+fc>M?W|BVd*g?Adec9B6!XVDdE?#ZZuCWn3|$<6rS%PwZXa z_E&mlLjh2!%2dho>VnP5r_R(19zF#ho~@j7C%@^c-LrmaQ4v~uNA;05e2jf#e*!Xk zKhP(@ARwTEiN;F6CQh1Pkuoe(SXYQTQ=FGYG{@!LI>spT6AM>Ea$V?f*fR5H=0v+>29IiXn(O9n}Xa>d$5sofX`&kr^Wr&U-nD>j3J z)Kg-|xMF*c3BCX?yQuD1SCf`Xy4_d|Wq>Dpg?DDOcw-h(Y$yw9-t#yYiWc+{ZFK_Q zk5P#Z>~1Eh^yC|Mpt@=!Ov}wLgWT?vEO<*eqUeeYtupV;5htb zcHYiPkyfO<&@w^d`CG>yhd=J79ZD?eQ9T?mF;F7*t!>CwD{i)!F#0CF8k4}txO5o3 z*Xz??omP4?wfpSrmGA&cN(b0@HC9!f86tYZ@hgcg-?~C0J3#5`r-&qv*`x3C{QX5v z!p)nrnHRqTbZv^@#XkpODW=#0f4G448|^jemTic}E+}T&W7) zrSB|^Gq{)hfGtZ;?cs<_G!u`}Tm9u^0-ood0vv3y#!p|Utpp?`)7i&;d?z7p^i+Q| z*|RsmK2n?pZU0f+G%a7tuxJUQW$f@k!n4icVNJ4ZuSI5GU@z1jcX0TT{fBQRrul+~ zpC7^>^d-~xK3g@kPyS{WsBKzMZaDD}E`Uj<=vA{%+9w*^a820VpU&Gd z@O#*tT>nX-*QzjbzwVpvG`yvNO>e=Fl0W9t$)}Fqiw2E3{hYrQTR}Svse`BS7_O@zY|m(x;eS?$zr3 z;(gV?(#t}5^YCkeIK+1Z)7wm9bSU-UZtyz(nFoFGvP7s%@Zt)2znZ(oBi*-%G&sza zu4}sawM*99gEngP76n8s+C^3OoY3(PZD!1lOf0KM@874FFL56C;Lo&rFv0dxQ$I^phw0 z7VQx-vyVL!eIB{*#JSKWG;c`H=?e|B3a%F@jJRKo#3rKNWh0ZbVGADs{y!P!o=A<5 zt>xc@g$vv;2f2y|nQ_j^S`MQx^5GL5^B;}33*q_diBFWwBCKc%?K};)g@S7w3EYD{f42!5bv!L-*$9DG&En8g{c9yu*|irwP~_Vw-=I ze=@v?WX}=9C#%9^MM(m%xNTfiSp2{UrC$I%y$y^*}07C6zAb>Tm*;u_ePEZ_y}cD zVsfH9FfkKpbi@)Dc^r-oHRZiF>gc^NNz0CB}sO8F-imr!5wu18%QA{?$V0>tre^A2M_+KR{TU5 zk<0dgia-2a?wu0y((qC)Vgvkf6$(9C0+?AYumpcIGALKk35O+8EmzD5FFn#BSJnyF zEYc`f$_ala(l1wG9S0PtlPj@~*A(fNE4Pjt6ls+!y^en#Nj+E3TT(>=0!LD&=Hm0N zhyRn|@1rNUxM~qj)cCe4Y;OQ0Tr>?4fB=;{OcWngNSW|oAWhyAjUr`4Ika$Sk@rQJ zwQ%*3lA`SWI1)%fQPzH3Z=}2^ryvd)@?I5_Ag(4-97}3KX%wD}GOQvkCxS;vfrU%} zRsal=sEP)H=N>))CYvIyi`YhKSK)6FG$Y)w3{&{Wk@ZN$D$W*s%5ZA=ObbGPpXC`Y1ari427zVNS#lk`YCIdIw5480n3YZ@>|bgsTuW5D3Er zQ2eJvP_j1sMHnYS3d?;;VgXQsX<^A4aNQ!!QNRZLok(k>f(NHOPJ6^6k`r||fPe$0 zgrvpNT@q#siAqRE5uJj65o;mH1rekW1SMN|-)W>gg6a?9H5Vr_&Y23X9yJ}_YZV$j zIy(GL6%xHWpYRG*(g^!i`-gEQd=TX9qK^Uphr>8F;XAIx>wt3@E|`mnfC#21N5ihF9Tkt-^=)pVz z^yPSENEa}L3E4!%Br>Q97ebJMUL# zKFZRAnhkF^q5~D;K>)=`h_pjJ#?r`8>Vzku=uVlScsej$q$A23ODKciMqnLLgJP4R z5)O|=xxB{}j_5;?HjuXA-Yz_aI6(nCC@zUZ@g|W&T(p;XZs8dyh6akA@Me^;2h|*a z3gM3O#{vR~IU>4Ix>y2v!mtR(QleAgDrE}6VO%mF1Ri^pGT`sS*dO)>I7;ssPhn6l zoIe0UWfeVQI-)1a&-KXZ06fZ1^+-Pv*(;k;6Zb~!=i-$R^GEdNl9rH0Dog3H|HhG0 z5iKEn1q0;@mjE_lM7ejJ2v}gexeuL)(qRm_JWhmWFkr5b6JQ2LnajOS0D=kU3ak?~ z!8mgH)(L}PiVfC6zli_7K>xUy|LEJzpn|_?_Z!@5F3O)Ug7?I82>cccfE&$Pt;*ud)z>h&*pomX#*a*83F(_^iwoDv8Nl*#PQQ3;rb)t zD2@gyj_^gqE{Y0EEsvLo%t4U^kY2x#3O_llAv9VKrw4&wQ<~)A|9>((3#aD?za}-w z!!s)RkHXHk7xSd-RgVDW!?*%Ih}*Dq?EmNGZ@iSg!r5JIN7N7k*TX45U>N08F8+V- z(4Jt&mvtYP)dxYuUZnzn4F44t4aVZ(#o>)`5&evmp{BZ{e9r@)3LAM}l;u8*PL$|N zWHlGX7nmnlJ{5;I@+nw66|X4L84OCrb%-nK$0p^|}Sis3ZGE~t+@Mn=3V89fKU&K60s0y$}=ne}3 zD+K`9aCReMDCz(zHlo{06%@V)9UDGpWFo@T122=H7}1TQ^S6H zLNp@K1J{DU8b97FlvI5hs@ku&>&=6|aJ z%PdYp0w%(I74kQPo?IOF!&Om494Nx4U`Y+4hhTCILOT@}4ZsQ_KonPtAPMnOlu(Os z4B;b+-%n73fQSP62@ep^DjY$AScGjAfgoWYLI5mlf@>6MjO4FkX(5^juLZLQu$Kc^ z5o%Q=Ex16K5LjS}s17ELq^zRd!fQsFgQ=#-7Kknop;$^8oCQJv@-CJ`hI|2_jsTz@ z$Pg(Ka7L`42xLffA`+2&D9KYgD3Kz-I$Q#!iKUkz8;m$W;WZGq5iz6gG>}(@m!Vj( zLZ_5as!*IsL?VjMgZ+|R94Ue#Y9Miom_<=GkcASSAVRP>mqej}u<#fZO#u0|!EGwq z`Jbas4`l$`FfPCcfy@5iHH;BwJ88gYj=%?@!YO5P@hR8C|26bYd%%TwKuuw*Ecgb0 zj|=xco-`ImL<6rtMO*{dPMM#HY*ZP<1n7d1fbXRe@WLK~`BRCCV9a3NR6+-sELb=d zum&Rp-!&m%fboDInh;sx_902D?zE5^MU11Qs)))7F$fG;VG0Krsg0tjVus+FBY{=y zEhK*7SzyK~iUqu2gcTMz1vrNJBXF_8GQ^Y-CkPv?q70rQjyh5dd-s%>4Zw$Z>Ol%6 zSHvww7NaDvvZr{NxYm(ygsBH*CV&y~1S|CmCk0{eL1;m^819brM+IZ?8;C*)lp-)F z$M+6A5CWaD%ie@u;s#Ee>G7RT703b4y%=Pu?NwV7i_$` zwTQ4B49XBD#ypy6FON4(9QExfo{0G7_mZM-<})Q#7TZL+&jXY0G5WlWj`LJs*(>~} z2ZsXd4#P`%H_FnmP`oUfi6$T4^|@ib+!STw*R=u|FVK^6*hbW_sclGqP^u2)JPSz2 z$7)@5gg)Q<2Pn%I7;@{>x1liX4xZP_fk{cY_<@uTpROBLaTJ?B=8U)|$zq=9DgU}r zJItDwqg))Th^s&g((_4OHyVk}g)8fZAIV_+&jo$p>%=3vxzdjkqe98Ec!H=8J=Qr! z4DA$jy5n@H<{yF{AM&i%42R`%tLa8r;oMHI;Pn{~P#RUrU3}#Jnu9b;B1qzpaQ*SH zYrdwMQp7d+67Hgw8i5lJ~->3)bC9dnMOk+Az-0r>M*GX>=YpSjenPh{J+uQ^ncM1 zzC%wDD}%Ft)v((Uq@kyc-^{3F&XjyvDVpJE!-NSjXPhbB2mi#2~SYWfRE9ZJqYE7R!FjB>T!{ z-J3xAJX#m5R&-F%;)`*kVCMsg_~fsXj>y_%4T3Th5pM`bgL4-VO=*e%7l(;0pV0NB z;WDs-PJOf@-W4rKqCCk|f6OIM`jJwE4r2&j5U)?}y68wnKBJ0tL^ck_b7J?gjdsfoO;@ESHsvNVl53mdbqHJ>K{zdmIj?-poNs>;-@BRP zE058b$noJ>=O2EatC>5QRE_~UAF;5LG*S2fO;YL&F|r%~oHmsGmuo|K)&Ch9Owz{w zvox$PjQk4?xuv*-zt2DZMZ<`hC9=u;(`~AND_L^6jPaYX?-d$l@VxSU(PSi1=;RA1 zTl6!l_-0!6!N}!kR={k4v25Jd-T8>bk*dH;NE~WB32p;vjnbAEk=*tKok)RrqYI|39P( z<#8OVRV8H7!)Uz)g_hZyAEIz<4WZ&Y+>R&MNhaHpSNmd2bC-kqn?ET%X$A>&U&M`J z_6dRtEFxS%Q3TQ5Kh;$MYHy+*q{vN8N>krZB;pG7+BMV|wJ&ouZSR>B3f@FU)?T@y0?Spi#Q2~pme>>KE z7)XSK+9&-|Q*gPg1h0_*FPkjas>>zX;^LFzvnbkmQqB}ISRtiVfw9_mSUG`7(^yu& zv`ZsL2eu47pv&~3{aD;UAW#Kz>U-G#5OP}4)h{vEa6Z0l4#}>X9*AD-@4Ji|umNgM z`Ph$T4R8T-YR)1DjDTU^mKbp*Fx6?jMfe%&kgl4Ifg;%qDG0D;DTP5|vLd?eoSF6D$*`N4r?)x1+YW{Mf;b`uT{)l zMKY|RWk7F&jJJ@W>c;*e`HWW(hN?7V^dfMeWnhgRc=^t5%@Ek4FD_Dj_F3B!s6Fjt z)8TIKVDwVr)4+3}b@lWhZ|1-Y;N(=Cjd#|-Q(*km&u?jcYit?Wkh&^n#2Rjf^;E;u zmv7U^HA~>_NlOj(gMpXlPHVit;OWc$HBwfQjBk*p>cGT-+Y_3)U*+7h<_hGV_Hj7r z>CRi6mYK#j=cfUtwCoOWGe#j+b_eVkF_6zSJws|$XXyj-K+UO^-e~Jr1DS)-i>E`E zaoSr37~ z&?L6pkYh@z^E5a$m!eXmO~HUQQ||bL$yF47(Y-f=3LZhbIKi4%;J`_u3*S^r$sW_OG0x!HLek=Eh9ZgurpwRyLLQ}KEiY!k*-^V6tM@Y8+osjn z6SwMl?v#a`pJQy6Q?lgb-kca$lyY59Rozw1YV8lHsHtnaTfqnX@lpL`SNBD?X5q~= zrOQlpfG3$)sn_bxz3(<1Od~~xWuBW5{rxPb?WEQwc-2bMW6WgY9V(#PR)J3W?)jHU z;Npi#&5=i87S`i%youNU6uts~z2SDnHrVj3VI~FEoz|`~7TIb#oG-H8KP{8l$ z(itn?t>b4;AxD^w815(ayxMb{Kg%pr48|E0Wx2)j{8r3g1e_w9?9Fptj|1vr_<4b2Oe9vXb#Q=H5@h#W7DAZPKGf$_~eS zy~!>DuK)xDrL>xHVH4W3P3`D&6Iao?-LAcv9lzbZQsx}~KWJku$pz-PeFLbnl@8MLfj*!`x(v{id zB;1+ON~++=*e7L-B38!i)|+Qvn}IIdZ@7t|ug-qH?Hu2eXti>w+(w<|0YFRo+WN57k36}GP>Yv6?mirw1c&+_2x=<5SLd*KFxYP-t z5ZtfugteUY?0<0f6<~2}Te=Csf&{nV?hxE9Sa5gg;O?#+LU5NL!GgQHc5t^~!GpWI zbn}{X=H9vI&6%0|9?<=DRadWnt$(e(zg1Pu{=MAnstk65B&(A;qu%xwZ##o3Y{)*@VJyId4x3BZaKY}wNi6%fD=886_4R@zRerGziOXpO#R}z|`}#U|j)eys z?-zczO(UrMdcPe_oFTy$LMfW=bF=K}HWr!KO8JhqLp8smi8$sfex)sJ`xZxE{;7wU5Md&KN$=DK?r^5uAN5Db0F!}+VL zFSLd1DB;xni9^30>U6ZV6eWuQz1-Ht&den3{JVY&k>5U!cwHQ>M^Ve|hxt`@=&B{M zsueVAbNYE3xuuGpX^7dKu?T7HOeyx%Li8Ti66iHbuQmJCx>rtu&+c5dQ+m7I4&WnR zb6DJm=6GEsp%a{dPE?bNInJka7rsR|W~@)lUMf!G1uRUP*wN@z#Tzhc!iH^r;}VyI z_}&eLD!CuMEgkd!>EPlpA`CqJSZ1l4_W{+-SfVH0e&O5CpU3x>frEp|2UdY5{VRDT zE3G$7mDq#3M<(?;XJ;W3;2vpG=0jTaBOhc5pW4W(xKdAJ^rNX>0MLMyg+<>}KtH3l z{J!))O4$3d7hZdJBWA}V*4fB<279AWaWt_cD--gfP)^X_S2}aBGw^G`g0z4eLr?<4 z@d{XN<<4O?Ju+P^U8t2-l^EFm_)zSs##^=1L zK`?U7)6$uFak=MFL(9y7OWChlUe+ZP!Bzd^E=_R8l&oMqdjlLAEce%e)zj z5y>oO^#@`8ZK>Pgzl5WsI-3-RlmWaRb)D1L?1U;|5ZKH4M)+OSZpS_ zzF1?U=eJc}RU`3>E|Rk30a3z@Ac_|MEmu#^3FxUHsL5$#YRFnJ*{S8Y7IPt+nmQwh z?6rhjD!e>5PhcWak9(!4EgEj<5m&xpZ~MkiMFmUC>30U7OA97RTpOYvTGFxgy{Jj;xUS;CyUkC%#|?LNw#`a66c}5 zdCQrDmURDkQEbqQ2Ox^X^*HubS74B?=Q3d185ePoX?K_#V~x4aCK1}-Xuu3zW4BhQ z*PP%8enX5TM%kMyo%#}nO`l=(_DpGH;c=y1Pk@b-t*xEEqrjG@lH0~*MvLE?aCfS( z9lG8EBhfV0r`d8;DLY614ngm}s-hpa%65)!d+sPIp%)pw4j?cCN2vIyQr)z0edQW4 z7I$V`HHQq@m^5O~-NO2OEva1S!%fzG1S`l_MAP?vujd%%tSwel(1FZ;MNm@??5M4+ zD_|#7i5+EMX;Jndef~SNk(W%~eglUSQ7vPhnNE%wZ;PG12oEcG(2c zIox(tCjG`i)sIJuw4d{ixjK{yHbRd^duK`=26`NCPZQsygccd<>bG2OTb>;?CVzV^ zasCn}uB}j%ij^|INlp^pOTrn@`JqCQh@UeXnTABD#XRM9zx2j*WZBT<-mzWvb=IW# zVp`ChP0!dzumDWhU$`m!RKH=5>7Pv3FWoG>R(B|&jG zuZMkOPV~*;d{cbGS7xyYJ)1x_w$?A#0WV*{QyZ<42sSz3fgaDjsNHgg>#5|^vcBEB zSlKyBpFVbIV^6lG@I&mU97?Ph-(__!85&G6|qN|g@U>MT8nmU?E#WXk1M8eMU<2Kkf z1V7w}hcTfqs`c=!+9nR35Q+E@*ij!09ZlLCrV7KQE>VsRM{a^Ov)*+->=h!jOWH2Z z#%bwsGFaQ?G<@c^WAaw)$nivEAPBI`VnRPMdtFm{O)7b5-3B;eTln2+o^1VbIrLFM zvga%cgW_l{ku%QMN3sV0;Xyx@a)}Ut$^&%{3}Ky9{t{40mDE~aCCJ14U+tNfL0&URTK1U7GHW@DQxZg<#hPSAjH!HC@R7!1P(`pUl( zLsgo|m(E=&#?OHMbWplM`0!Y^qbhQZVNjp%Pn;l{dcZnx_%3v5V9$BMyv_MgqatU z!SJ{%=f!BbaW85aSs(|Ak4Ubff^KjI;Jy`Ojq~tpiZ4!NUTR!w#$tR(g&1k`uYVUc zBzrZU__|HwgTbU{RP;|Cbi9$Dj_xfiF+z4mLVJnwJB)^Y# z!DZHFM(NFYcbo&8fvEe0gsXvbed%t;qpb&<<=lAS^n8|Ha?)hdW6nIB0pqdjZYATx ztRd+E(xrv1!lq!(a$U?q7zrcmCHeqz-h25`02dnfPovo#c7Pw%P;)iaIZOin(_GJ4 z&dow=JDhXC_WmK)*EVmirsl;n;ak(Jxf3~3OK=tKbj>VQ^nkoaN4>I+&`V1kT^Xep zL-`ZyVvi1G(N9Uc9I}h6;usQ2_X-~Cy@ z?KLp>i7Ro|cqu_<1Ij<{d%k7^jP8|oVRDg%I62&DO4wU0^;F?Z)a{s`7AZrTi2FL!n0EQr-a<^tz6)!;l2Td%pI=1*~ zGmYAPt{Iwc9h(2lx~!RK>nr$d zA0JGtvV~7KBYw`_$W_|co#>OExQ0z5T$uitpWGWZx<#*fp%d0d2;vH(-dQG~hdBeq zi#|g8fv1|0dCpTGq2~F6)WSmI{)md3DeiNZMn&l4&$vax)qCA0QhAQF31cSNXr^Uq z2+6!4Zs$+Wn5!(xgx|bij#QxaZ6y;UgA6Y`9rX}g`blT5@T4WYiU|9#Y{~Q$w66kB_KyeTNyWuzUQve+ zsXqA487_Z&u=*(Bu|TdC-H4+CXv3mjkmsivJ;V{C+%+PD%wa=mGF{?wPsPG|u=D?^ zL@a{enlXq<0mKLxASFk?n}VeP)`)H3H{D&_laY?QSm6(&Nz5C8>qBt-oA+}ck(?1@+PImUb1l;p1KV?3TmDp|N|!06?1T91r(-2kVhQj6XF62nAdkqEySVRiY~&43XNh zX1}C_1`H?_dll?2;othq1;|t;7m99mW`tm{%9vFc7Bs*r{&Y*i0zCpk6#(4;?y9(a@pg&fdbJkVVR za1=m~XE&avD=PQ6cRF|Lw_MRc3mV`!6;>^v(B&$_xj+^c`8jlj#z&z){JKNl`jcM~ zj^8BVXaNHbn4ymwP&*EPgp*%TemSwqoP#DV^6W%+pPTU?*;w7z(?kQ8TWkIl2R3hy z{^|46%y|UlBRz#}B*}fkV$Xgy(BkI`{B%gD^VT0&B1yM$K=qsHC)(vePZ9S(Lu@d8pfz=W{sF4g<=4rRe4f6wMBr(wsm18Lgt% zY;TBK%zL;zT1R*$e|Taw&l*nXa;{k001XV_;+LU(`CRQTZX#1z?ql|iWFqF|=R8nq z*)IvfvQTCkYwG!-7|;)zNgzVW1xEfc*gC)#+2tn}vK9{}UK0Mve-vE;e%~K~0ezpS zo@)y`U;rRPc8>5zcnCDt6XKx4gbDE{M!)Ud{2f}Hj@?|;3OS!-r8D%qcBs>3&sJ9X zT+2xAFBZc0vqiG%-#sIKe%>!q?Z*k-c=`}9u&VPs!koUBH6@(x@Npo}vo}DKeIxK)DIdT| z=n_rQsxSmPJpLRa2H6`|6Ts}TJrZql3ZNczlA?ajI$DWA%yXd>{PAg99@;+`mpy*8Xy^QV01BRyjLQ5PVggY8fCd_ z9KS95o4?t}o|x}~)|kKt*f58Dur_0Lt!&{dT>FQeRC;`xq*xznfQ8# zq4d<1y#@y;(=oDaGI*tDr64Om!q@;5rcA3?q6T0+l%DnxO1b)di(U-3N|S{$H_J|a z+hu82rT$$@d=6n^g~u&HXZVM2 zxwe$n;w&)lFk54sBQ!0hgW2R@sJiyD)hL%Tx^K6APs1jnk-GyR)+R8-1n9!IE+Hsc zeVK2_Sf-VJb#ib#Yv3V_9csLMGk`1X7rTbJ^F}X!&wyJ{mUYS^>fq%bUa9zJv;EqJ zC#8WO63Zv%gVR*>_qbRUG(5CB7mdv&`m?5Pu_pthkz3I}mLox)GMm~)N$2z)G z+A6NTC$x8%1B+gb6aBSs9^R?+WYz2R)ONK?hlT@LlE=RQFift>He6d@!&RA{+W>~8 zMNaC$pTWSs!&G;-wzJq4y4IfjMcRB^k8{6)LdMj)1zDvFbpixaG5JjHPHEQ;jrNLP znX#bA-Mu$oGf%TN7UBT80ce+NB|c%uH=; zPGJDurVA>HZNp7MA4i4MeWz_reN=!;S?9%byWg!O>w;K34)Y!uRIHLOQ79?S675C& z1vx43ZC>-`>%pxh!($8t_K+}tyO^AAQJ3*Z)=u1M*o}4M4wNb4) znbS;xT{;wCuDo3jL5r7^j}xl-p*^|T+TjcT%S*;z#c(iDvNOa#=HAkVVRBz@I}gt$ z4-MS|cRHcqFf23T@v5XsDaUXetl?kG(uR6rTakP-%-*HJSaicypFNpuU`Z6 z=!Myorp=;z;pJcAR%X5-r0x=kPU!Nk`xvI(&S~G4wsL(c@@)W*+`p8|pwjsb;hTn@ zvbtUXVs-vDpN_^6{e;F%?l&CL5#QfYm&WWC5fPSUAq&-`@osZnwD|%;-w=A?heI&? zq)_2)YPplOb44hedNmHRMT!aT%0wcb#?fR7A%#WzEpu0HgX5_vzO(N-O8Na~3#mCm zFRWTW_lz}iPh+?-)WutAAH83WeHltg32-2LOT53QL2JKnJ)?GE&_2wT&ER{6no8}# zye(dM5fhna_XT*O)E}V>Vr633&OBk$z5L}S-GMk+DGgd*=m%9#@8+OFCO!&LG|=&x zsC&3QX4C{~kHnm8#Oq|4P5bzA3YK*e-K_`qA7thEaW*MnfCppP`S;~ERNFY-bflvrwuWAx8j=<@?vrNW30?Vc3+Lb~XzcEa z96V@KjZxn$4oH)i3*OvEuw~&e(5yJPc2WA@UB;lZnI5R6^5KOm*$sNHt3F`6`R35d zR|e`eh;&P1a_ws+zV_EXh#ue$deFAI^Zi-*Gi2br_mE}O3}&*xanOk~E-Ec8wAAO( zRJTzUgNYW;_nj!l7=6|NyKr`P#7dlpWu&i2{?U&w&W9h-?k}OuSIy;ua$N_Bdx+NA z>_jwMi+7Fxh6mlUERcwk&h1px?xjl)<5w@9**A$XvL@0Y`;9+#kMHhg0UlEh=abWL zb8na1zsT=Ro*gqTQy0jx~*gA|#iBViTI zrb<_)Ntv`Ky3Nm7$1gW)55^WsU}moJ$hh3oAuT_Ccg%PSC<*&&3LmlTEcc>^$&-Ib z7v!pJ7ma==8<~1TCRs;RN1!Xh$uOBVBuMAaKS?e>FpVgMSu>jDo2oFp})VZ0;GG zsVYp=`qEFycWa)8_@!E-%~AFE#W3WZG8u9aP05PqFbn#V*}7nZ_zL_2EpZh0o?*{r z3FW0lBcYz#Pe2rrS;Og8sf?sODo(y|7WG&6la$PRVwZ79Lgp(!R?YgE0%1h31hDdV z)l7^ZQyYXJl?$TbRgkIh1y-7C2L8c^UpXxfZyJZke>IjW7K2k|XNiCBiJduvGtTE#=}@Gv;Y0n_&-~9x}?~NA~YO(xF4j;sY zucQhl)QMv*nQ_NLdSBrUANuK}Pi$;;#Yf%N^hrz83_S8X?y_~@4fu+Y0q7`J3?ADn z`3rS__tzHzb%)EiQt0W{NPHcchR#KybJuC=Q^ zhC`4xL(hoah~FjXJ>>LM&aK4B zTx{_R+#ZtLz5gWIF`>IDB22BUe#o!E4`lvkXNshGGa3D8Y%md~9ndB^n^=E9GGQ0d z(GY)c(m(Gq4fJ?4^>`)%?Z<^U0T z%9ZUTm_F`j;6}p8NnB-d6n%XAZVvgjM+FZ!Og&DUBlHntUg7M5{VL z!zovERG=wRO|Ss5dy*CTIh+nD_K1(12lfhqdNgYZ86YXf0Ja$gr3?Os(s~>&im`|r*@p`oto7S4xw*qCB+fIORaDC zYrCy$_IeUz6H`QJkzbLFHI{92r%UT9eQjods{MsMJ}56S(>qb9(5Kw0UfkL;&_N?o zw17UAei}oLo20T_kw{1Qn}a=tTCBr+Ut90I9ZdkN?~gK~)b~c!OXsB{g6zgL9E6eu zzgc7H2V}Q>W75jNvCykOLJgTo%}MzK^zHustxCu(;ZW|_4I28WT0{r1`yv3rl?{lS zh}~a2?oDDW6L!Wws_;8272Tfy%;_)|6*U(MU=rOf9ScB>eS>8BlKnfL?0hbWb*1gM z7ntjUL98@RDne}xeExNgRE{`bC5-8N^X>MqMj+fekTKwvH6lVPqvBv|uW-=eG!?}; zfSjVEmuG=6@91Q|QfjHPK2hpdhzf!()H0XE!IgA3>^ewK{T>oqM&81C5|yXVH2P2$ z1?_2R&PhNoz#0!WR~`r4Hwdp3&;34_zErHPJZ^>!xIMvnwR-oy!|v?+xUM@+5Acq~ zXcBWuJ5R%^#kT3!>|ugsb<1HTanHulB77KW3v&{AzWZ;@6}jBiMF?*TcS!1j7av@taws$taRB$;%cWOvZ?91{* zW=>KX6Dk$}lH=L6{HwkO+sYA0S|*t|50EJJNe`>wk=Zvlgzu@Z-`tm^zwMq0D}1!r zFLCGGW3qYQbHN6^Ns!O0yd|4+dweQfoX3G_z2`6WFDl{vaCs!j>lBKg91+;J{TFSTI zismmXE;}Q7NPZJ$L2t|yF@k=ZL{mMs9&2@0Vlk+Dy4!iW{n}YTR5z=+Xg#vqF-C*r~=)Dfr0{vm1Itco> zUC!25;-AE~#r^5(c4!YIh2MO z)(-|2Bcnu4yp`NfQm;Jqrf9uGH3AP z2K797K9dZ+JAZOL3xcq^EQXR?+!>8Knz~OGKRivHbt2RLo#^dMgFtPl*7zk>=uT(X zoI|6$2?8!tDQ#Zkfy1;=w3ZzAT>Cm@Fc(Tjaz-TrQqP4w%$YuXQSVw%YFfF_d2U(f z5KmU$&P?dOBwS8QBvb9O_@!rkWr1F0&@i^HXzA@-fLa7{kBb$sEL5%lAm9(4!sxo~ ze@jreB(8QVyFGAC%7qoWvH_dZ=xeT)z4&tZvVG<>GP4t4~<5$sODL zYTe5#z%vs-mZ^n}0P_9y9va2XeIUO<&f;fJL%BA$JAXSi<`acIN59y%B>rf87RJmk z-@QqgnyH>P#$YD(I&g3D_T|Glb37R1gn#GwnnADDmzFiO%8QU+RP+VX9*oBcU;D_i zB4Oxli-0r?b3vu4y2UXpX%FH)yQ)v-rDHAQ3w3>i<_jNXPcU)nJF8SsQza>aJ+NJX zA`B+|y`MN*@P1O=#zOcf*rrgycN<5n%QhDMCgqn~0e z>K{!cbyZWZ;1MNm71z6l_!I+v9n+G$$<+FQ-Nshi{Of$)ZtsSlP!ey#y&&--9#Yq! zW*vUK>aSys#^}-Ge%BlPzW4ad3-WsWfxY&Qa?@63*#LR5Ul$(3P?PFN?eP*pQK0qP z)gf1j3_s{8fENHD8*9|0O=5A5I`JT1(83%o9ZPC(TRBT8odh|=)2Z=@^k;vttGs?= zokK|TDp6EO0c?7x0&acb_5kc}#KO1>fnG7RLb~2tR;xk?X<7)y?B~YD3B5b#~l+mQ$+GKH=0>4EWRjc7gq#Pu4w_CMTH z^0;h1csDWWH@&u256~ymgx<+{@7z!j<%H7wiLOm1!26zc+R?i z+?n+bSTCCX@*7^!i>a?4QM)8G(G3&9=ZeMS#H>G2NTwGLYFYmN5!(0ZEWPEI3EwN* zj~br1)T#4`Yy#e78eHn%w2#E=3$c4eEQ}F1JoCK<+iX)Kq)4!v{A*~-ZW$>J6U;qL@(jvl`BERGsl= z2KYv660D#7H9RGY2K~a!{Ip6A8GL-owv&Hk*mzOC55pz`5*$)S605q&2CZoLiVF)feQW317?V}E6R`eY?q#iGw{$=QOE?}%~tqkcm zR9SPug`K;hK)qvn~D{yC3QVaYzmJmB0uS*^gc#+md@YW=Gd%L)zfibJ34T zQE6D!2c~aSS{5C_$UezJip#D;gtaQHe(^q86TPM0@~9m_?Pk3%?>;aA_uqqu@iK<8 zrWH~~k0K5-FBUL2Zn-!&VfJz!GvKbE706NA)2)7ql=xJ+N8iq4mR8V%#;z#q@h3F+D(Iotfd@FsBGTiTfs-P z)Ypo#NE?j&HgA+-_ewvMmPz;DekYfIi*b}s;9a9*Agm!-mn;U}Y1(+KS;?-Ed-&@Z+QgpCs}>l1 z4r-I?<(%goOfkndi=T=h{5b=3@(%B`QRJYX%}MD4z7rfp?*jt)8}~H%Dt;jo{2X0a zIHE?`OWF&Llj;o^=WR3ZmCoXr9~sZr<6|CWpPycNSLW5iJo?R?(f)_O_D|bK&fv4g z(ClV%n>P)VJ2=B^JWg@z3HD00c>+I)thOz?VG5w)qr~Sk$oXV*2Nxf!-3c&YhVz6O3^ck!wOXi|m!|J`Au4VuWFTC`NTKYP4 z=6=PwMO`&_?5AG!@;>obK~%!e)-cSNnLqYF1)>s`RjH9|Ar=r5iF+GgQyWgwjQ1?{z=0W(Q(nJb#Ad6=y%8}&5 zbcT;Nn|Bx7kM)>nS~lJAs&{%HI*p7d6g|7UKBqyysLyL6$jnA2xDtB%>r2x9I3ZY| zb*sX7y3t_f_FTkn+#ogCMQa)iv=V=OO$u?0DlF;9{^6QCSA|QMX7quhz$j1>RZXE6 z^*|m;w|S4urKC7Nmi7xH3cJ}aK|>GKFFf5z*wB?_Lp43DBG|ekv7WjVnZ4`_r#VU? z->`s(AHb*-cgRYQIA6&?C@ztVEZrWTIA{iEI*+0~EMR-6dxKk-jLs;#m(FCI!fCsc z*4_IgTi8d8mZzl#-vyg$FJYWH5fnh&L=BYDru*-iNVG;icqrI%chiWFep3Py1`DA^ z{D|e5o-Q{i8YDb=)1{j2)s*wa6Jy7%nIm!qC1Ebji0G@4>u`68(R4I(cQ#;aQ1A!r z73>26F%8g#&4mr+E_FBs97P=&U>-4PeA%0*+V_53zTgu`e*04)O~fiz$c)iB*FE8| zHquAKPsJ(xAoOiK@BJ!VwxllFS5?96QX!M12kTES`(D@)`zxt|o!uKiXgqjPd|gp| z0!tsiIbjE5yRb1Y(anCiP(0+|2}}jeDyfRMr}v8X8T@Ae+cxxmH zzfoPSK^wRt?C;3?=+|M|E3h3t#!L4|ZbRf8_M>i_L~8^{L4o^r=S5WK=;ly7aUOQM?S7B1A!Pb98dnE}`MA-x*q^6xN_C0{TvG z{5EPzdkctfy%?u=&{;uY@nUesS!vPvT&t#)@m=uvV?|?<%BmwVLr^iPY2KfI05FQ2 zgl|_0N*V`wCr)A00b#MabI3xiRe^tB;JD{0fszmpkb87Fy;isSb^QLuIaROcGILFI zu0c}bulnU}hb*sKaeMgM5~`*}@Cfy^04TN^`}je%=_I0fVa?_$kl#^J!^G|p(4F{= zw*U1l2=~>80At8g@9!rUTUg3ZE3tdyOA5~P@GzOmP(b5uUb;Tc zw5>V0TbaLUYv^x;oSb;sDF_9Iv(tyU^tE(#vHNy+8E<^e!+-M-6huwKXHv&^UGGhiTbarYJo#J*SRBzuOg)1Qn;Hw=?Z`r}jP+{Ewd~fNr zzVJAjw&}G$Em$R#Hb9rfq(h$@>h<9=e1g+Bvd}&QfNp;vHV*H(tz|}kIQQHzxzdd^lRU0WJBJ4Z~4wecE7 z8Wn#x3ayNoN+3xflGde21(`%BaAbckIY;1qiT@N+obOuCt*P7W&o)H=eMvearjO@5 z+9Uo+(~tK$L%J2TV;nq$n~rGfNC>sB%{V0R3Q(j!r|~3v$OmhYz(zAt`Fp;}@g=oIQ?T^^um&$=xIQ;nwhEe=Insn+v$V{W^8 zT}G&I-~j@5Dl})?KdPffFS(1{@Lx6?oT+(8vav63M%%Jo$&dDDCE`}UX4`jjrEgO6 z<4XCMRNs9;7klNPd>X7$dtP zTj=@SB*dZ>y&QAyjU}jHGvnL~XTeNFbP`?GTdlht342b zj;r736yk0dc)&fl0)JCsksRwEK;BL`S7A_VxWOHu(QIJL-L(;o7%jelNkkyhqWNCc z6J_k>+);6Famw#vYLShyEt!en&sd3ZVxx{^7}m7*`1-Wb=_CpIVfR zylv103VBht(oozWddk15rlFRy7c-I{2|vI$2|C>n#^M zQ`r_ILN~&Al12L0X=4h}^^;VTIKjC_0=~%@mDHJv4NEDN8@QA~iyNc3Wb@=z#g69P_8zLA8+E=XkY4;Wo#a$7z)1Qbv>ti7{R;ui z5wP}IfIMNJ2oiZO*6d_4W@mQtsR1Tgm2!fhu!u2q__)})Ut-Df8o-2^xjDMhiWj}! zyNm*XetoZ;|d_)){7^c<&0TKXZuXT6?MpDCe&G-uVJX=TQx< zv0ZI51}&AR%;m-p`z>P_cUBSrnq`rXMgu`@3o@EYTM-nv`Lua@BlB=#!7`C!<#hN7 z8fj-|*qbABn>Mn{7d7c;Z?|-b1U>v)Ab8dpSKP3r>Ji(#X}1!d<; z!{w^O%Ytg-IFt8MGlk{zG`-4d{8}M$ab}9<#2jP6zL2z7qsYOd=7UIEpDyzc1#-B&#ab${sF!pUkS{%ui{Cp1-gPv+VyADIl+nc|- zcPcPq7@*R9kK=Q64^cP-S~I2WLj?wmmlpbzgcWgj&5WCOX!_(H)+}d9TIQ1=XER8r zfdAf5(^M@>_*>6}+KNc(R!!8=go~O@O`-Ez7eE`gS!4sKoqItTp1{X`aCzg@94Fx^ z9p}`PZiyY$$rKKbi3R`&Ia%F-dqglZ96~}Os`QFv!42#t|UmN&1} z%$1nzqURqPBF^g-UN=*^gS!^O-NQA|$ zylZ5{l-_j)6~#b|#^=^_;^aW68jKO-4AZPTTcgaecI(T^qU~tJ@S6iVog+y;yxl<$ z9=^X{FHu^s=>GV6xaGQ%1Z?bO66Y=CU33Y*&=hZ&6>=vKA#bF4#3; zE(gChS)F;K$Q53bgLR7T2=2RU1g<`6?%{#sjnCass!E2*%$JoobD3J}bNh>PI97qA znrzAzdR~?N6Qkwqn-GKeW5F2lTr(lYQ{_Q+y`D zPv)$3rdRKWK@-RaV7tL5kvY_5tS1^PzMD$d4xsmMq4|{MfN9?zX+7NoQG1%Q<2~B~ zu!8gX8E8(V#uoX=EAj*wR~l)Wa0{?tJ_Imc`o7kQV6DLgiX`Mt0Dp~t1h~Un`%6_) zvARS(ZRx|!c>A(5$`%UfdoC;9;2-5P?J4doQ3%00)F>z7mmQdKWCshYLBz92EXo)| zj$+$;@ys_py~?CMIwyvPs*k#L2Lgq#dshr;ev#>K3fINlNsF^-v|#-U4Y- zQ5uua~a&%vrt|@D3hKtUy9Ou@p(DZ4yqT&G93Vl-~a>3FtIYd z)(v6$WQ-=xg_{&F)1BsugoHv1Sik;8m{VV-4>mzLcz-`(6hODlC${I%1v z(`tiJi2G48&SJ!X&j+kv%4OyELCB|U?k9@P{HsV^&E{S@w9S(xbJ7He@3{j{nt@hJ zKRDx76&p0F!oD4Jd(U?c3CT~+a=&i0G|Rcp?0hnbUu5lPMECw2OI<$l8YV;4=IVqL zRuiYs&yL3Mw9H=CIaCv(ES%X*D&T!f_dlW;Y^ z-(2j2X^CKd(Tc^et`5Fe3F{K7*J4HEb5&EBw}@+-uNqAQa&cQucd$J-<6zu417+G; z5?BTE)jW7uAa@8Z(3S4n7t<8zNNpY_Tb1#3(XW!I0-T2EVkvj`9Wu5!XO9+omOeY6CKNQn z_n?GKn%5Ax)WbW%L1y*F8HSej$&1aBG@T_0m!hT|M{=i6TQ%Km30w)ux4#s>dC*(?k;)Fv3_13R?W}~C$DN>f6i0{i)S83<%n$IsME+v4$}V5#qG$wRMh8xn zYZ+k_9tTdp=bQ`eTU%$LA&b|cA}5^qT8Qu$zN9#c!)G!73OK77^e~^%n%RuXU$O87 zeDEul^6M+tU9b)+GH2K)G1tZp80SN2CY21%ZT97Bp#~UgW!dnmBd?e$KLO3FPl*{H z9k_}ID|-*C_?RFKpU#38Ugp1ggc*5x{mJDYGwQXAej-QW}t*6hMf^(r-Q^I_S~LSQ%@51YhcQ@5vKh$$VV>BGMI>ziJ`N>qnEJ zi0w#@)qlYMusk!nveLOSRNJj_BMB_;p3~xQYwtkmM$SM}JnWYXmr*LpkBU0+YdmOC z{N1W3sJu+~B`BlwRB(DJ)QGX3(FEoL%L`u#B&zh^H1Yhe zC@iV?n40|P#c|2<5}3)RoDpQzE3s2r%3q8ktJlIHWufcL8q$xj(H2(SydB!_;#z2e z7iIq>G0talHh0bjkI&oj>UI@TngGD}GFwVj6`)ux(C0aYmCYNuHJi|8fcpcjbndXk z0bV5yZcx+Dl?YwVe?273*hnuAj+sBs^@}ir(W75kXM~i`YrWg2o2}0+FH_s#)b#Ez zf3CB+lo6f8b?n{d1Q3m9!?{M*&xKo-Mmxe??_?WBagJHkt8nHAAfoOiHng5c=HXg| z=X07r7Wm-c_ET(@-<&k0*)a3|08h9$6C;ir^8st`yiQQswQ?8p2c2q^wqWYAGJlhP zqY&(p9C&FqaH8i7=M0w-h;r$T1g47k=37mE^5SQ6A88V}Y8)m@ODv?YWd~@4!gyyc zRa5eyk$YZ|q_SWnrqmY49^a>$I))VbnTBegV4+YO3pWHW2MKjkQ~U%YsM_@YTqM!k$J zb088bAt~|d#fxV-N?Rj4V^br5xtqO-tCfTOKcsS*pi-19|5c7MLv>QN8>&xzq6I6l zu&$Yc=7M!i#*Qw5upgmKZ{-bDOv++&S_6L;HPKxcw&Z^o8XqR3g+o-vCZ`j_ZbGdTGS++@`khnfY9!RU&r5a4 zK{?Wz4DaE6A9D0U9QJR;*Xs|HA)6GtL=v`)e6{C_Y*fwaU$9upx{WOfuia&J^9d9h zg7rQl{YHjWL`;Cm?(9s@r(#!PnD~bK(U$*r8c_9om00qS!Dn!?0?Pb8~#d*^sM~y7!2gd|=r4}M zo?kk8LB)ZX*;u$)*jP-hTwIy0?9CmZ(xY%MUiJOgJpXC?&#HO04Gx<(5QI*oFQ5}C z(SO*67SW5m0OkMIwyLDKlB&f2jPRe{FSV8i=tFHiKM4PVunxujd+)VANJ`58y8ybb zCKm8eojY|Y%wY*}1AUH@mG|Kv)gZ&}_4>N6jdEAqbpUH`X0 z@-pI*ifWSoJIsF)1`Xq%KcxQw^SmQ3U<4ZC-^ZgWsiGmNrY`w!XQiJsxeFS`bJ}10 z1LV)VQzQI$ATo+->SFTplB)kMVI2csFzumM-JztB{DrX3|1F4uq`H`dn7Y{ijPdtu z!T*!3=fUv-s-gM^TmSZ8*dd8m?1X-*mGs36?7#RM`cGT`s=eyy^*?+0pQYoZJCH~P z(@bZt2<=;1%cKZWWT=vC_q=OePQ2t^P20BIj8Thko*uQV_uUhMW z&NF}3M1=7_EdEo5_V2cVYZ%q5S_L{#6$4UlAQ${todu+y8$^e{HA#6)9)-?~wksx&Gg2 z{I6}wpHP1mS^fNrzinEecAuLTH&5gjFJZ5s$HG33D`h#j=L!D>7WDUd%KAU+y$#|4 E0DOysqyPW_ literal 0 HcmV?d00001 diff --git a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/INSTALLER b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/LICENSE.txt b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/LICENSE.txt new file mode 100644 index 0000000..0417a6c --- /dev/null +++ b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 Richard Moore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/METADATA b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/METADATA new file mode 100644 index 0000000..33b6850 --- /dev/null +++ b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/METADATA @@ -0,0 +1,17 @@ +Metadata-Version: 2.1 +Name: pyaes +Version: 1.6.1 +Summary: Pure-Python Implementation of the AES block-cipher and common modes of operation +Home-page: https://github.com/ricmoo/pyaes +Author: Richard Moore +Author-email: pyaes@ricmoo.com +License: License :: OSI Approved :: MIT License +Platform: UNKNOWN +Classifier: Topic :: Security :: Cryptography +Classifier: License :: OSI Approved :: MIT License + +A pure-Python implementation of the AES (FIPS-197) +block-cipher algorithm and common modes of operation (CBC, CFB, CTR, ECB, +OFB) with no dependencies beyond standard Python libraries. See README.md +for API reference and details. + diff --git a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/RECORD b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/RECORD new file mode 100644 index 0000000..b95d37f --- /dev/null +++ b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/RECORD @@ -0,0 +1,15 @@ +pyaes-1.6.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pyaes-1.6.1.dist-info/LICENSE.txt,sha256=Hv5seLKLQgPTl-qbaL3JxljSHNmvr4roIj3vg_Kn670,1081 +pyaes-1.6.1.dist-info/METADATA,sha256=_t9OvQ23mS9RCk7a8xCjBb7t8XRkkL542DS3arky08c,630 +pyaes-1.6.1.dist-info/RECORD,, +pyaes-1.6.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pyaes-1.6.1.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92 +pyaes-1.6.1.dist-info/top_level.txt,sha256=MuEdP4TkshZ7UFveg3brCBIrlZx0bXoAbp36EYTWZDs,6 +pyaes/__init__.py,sha256=4g4rXe3v6TxyWd-PWfAX3h-tc3tF9IB0o2sJ1gECJuc,2087 +pyaes/__pycache__/__init__.cpython-38.pyc,, +pyaes/__pycache__/aes.cpython-38.pyc,, +pyaes/__pycache__/blockfeeder.cpython-38.pyc,, +pyaes/__pycache__/util.cpython-38.pyc,, +pyaes/aes.py,sha256=XcD_etlIcErpgU_Ccg-bR5WZCSp6RuH9nVW3iVOhpD8,60310 +pyaes/blockfeeder.py,sha256=NMVQ9m0oS0woZvFxMNZGv2w_wr8oBiAyaIZXguEuDkQ,8123 +pyaes/util.py,sha256=tjLWrQmQly6wlp7BVR6NMCuvJBR2hk-GES5ANT8CxS8,2050 diff --git a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/REQUESTED b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/WHEEL b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/WHEEL new file mode 100644 index 0000000..385faab --- /dev/null +++ b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/top_level.txt b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/top_level.txt new file mode 100644 index 0000000..2e726cc --- /dev/null +++ b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/top_level.txt @@ -0,0 +1 @@ +pyaes diff --git a/spot/benchmarks/aes/package/pyaes/__init__.py b/spot/benchmarks/aes/package/pyaes/__init__.py new file mode 100644 index 0000000..5712f79 --- /dev/null +++ b/spot/benchmarks/aes/package/pyaes/__init__.py @@ -0,0 +1,53 @@ +# The MIT License (MIT) +# +# Copyright (c) 2014 Richard Moore +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# This is a pure-Python implementation of the AES algorithm and AES common +# modes of operation. + +# See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard +# See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation + + +# Supported key sizes: +# 128-bit +# 192-bit +# 256-bit + + +# Supported modes of operation: +# ECB - Electronic Codebook +# CBC - Cipher-Block Chaining +# CFB - Cipher Feedback +# OFB - Output Feedback +# CTR - Counter + +# See the README.md for API details and general information. + +# Also useful, PyCrypto, a crypto library implemented in C with Python bindings: +# https://www.dlitz.net/software/pycrypto/ + + +VERSION = [1, 3, 0] + +from .aes import AES, AESModeOfOperationCTR, AESModeOfOperationCBC, AESModeOfOperationCFB, AESModeOfOperationECB, AESModeOfOperationOFB, AESModesOfOperation, Counter +from .blockfeeder import decrypt_stream, Decrypter, encrypt_stream, Encrypter +from .blockfeeder import PADDING_NONE, PADDING_DEFAULT diff --git a/spot/benchmarks/aes/package/pyaes/aes.py b/spot/benchmarks/aes/package/pyaes/aes.py new file mode 100644 index 0000000..c6e8bc0 --- /dev/null +++ b/spot/benchmarks/aes/package/pyaes/aes.py @@ -0,0 +1,589 @@ +# The MIT License (MIT) +# +# Copyright (c) 2014 Richard Moore +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# This is a pure-Python implementation of the AES algorithm and AES common +# modes of operation. + +# See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard + +# Honestly, the best description of the modes of operations are the wonderful +# diagrams on Wikipedia. They explain in moments what my words could never +# achieve. Hence the inline documentation here is sparer than I'd prefer. +# See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation + +# Also useful, PyCrypto, a crypto library implemented in C with Python bindings: +# https://www.dlitz.net/software/pycrypto/ + + +# Supported key sizes: +# 128-bit +# 192-bit +# 256-bit + + +# Supported modes of operation: +# ECB - Electronic Codebook +# CBC - Cipher-Block Chaining +# CFB - Cipher Feedback +# OFB - Output Feedback +# CTR - Counter + + +# See the README.md for API details and general information. + + +import copy +import struct + +__all__ = ["AES", "AESModeOfOperationCTR", "AESModeOfOperationCBC", "AESModeOfOperationCFB", + "AESModeOfOperationECB", "AESModeOfOperationOFB", "AESModesOfOperation", "Counter"] + + +def _compact_word(word): + return (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3] + +def _string_to_bytes(text): + return list(ord(c) for c in text) + +def _bytes_to_string(binary): + return "".join(chr(b) for b in binary) + +def _concat_list(a, b): + return a + b + + +# Python 3 compatibility +try: + xrange +except Exception: + xrange = range + + # Python 3 supports bytes, which is already an array of integers + def _string_to_bytes(text): + if isinstance(text, bytes): + return text + return [ord(c) for c in text] + + # In Python 3, we return bytes + def _bytes_to_string(binary): + return bytes(binary) + + # Python 3 cannot concatenate a list onto a bytes, so we bytes-ify it first + def _concat_list(a, b): + return a + bytes(b) + + +# Based *largely* on the Rijndael implementation +# See: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf +class AES(object): + '''Encapsulates the AES block cipher. + + You generally should not need this. Use the AESModeOfOperation classes + below instead.''' + + # Number of rounds by keysize + number_of_rounds = {16: 10, 24: 12, 32: 14} + + # Round constant words + rcon = [ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ] + + # S-box and Inverse S-box (S is for Substitution) + S = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ] + Si =[ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ] + + # Transformations for encryption + T1 = [ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a ] + T2 = [ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 ] + T3 = [ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 ] + T4 = [ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c ] + + # Transformations for decryption + T5 = [ 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 ] + T6 = [ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 ] + T7 = [ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 ] + T8 = [ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 ] + + # Transformations for decryption key expansion + U1 = [ 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3 ] + U2 = [ 0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697 ] + U3 = [ 0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46 ] + U4 = [ 0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d ] + + def __init__(self, key): + + if len(key) not in (16, 24, 32): + raise ValueError('Invalid key size') + + rounds = self.number_of_rounds[len(key)] + + # Encryption round keys + self._Ke = [[0] * 4 for i in xrange(rounds + 1)] + + # Decryption round keys + self._Kd = [[0] * 4 for i in xrange(rounds + 1)] + + round_key_count = (rounds + 1) * 4 + KC = len(key) // 4 + + # Convert the key into ints + tk = [ struct.unpack('>i', key[i:i + 4])[0] for i in xrange(0, len(key), 4) ] + + # Copy values into round key arrays + for i in xrange(0, KC): + self._Ke[i // 4][i % 4] = tk[i] + self._Kd[rounds - (i // 4)][i % 4] = tk[i] + + # Key expansion (fips-197 section 5.2) + rconpointer = 0 + t = KC + while t < round_key_count: + + tt = tk[KC - 1] + tk[0] ^= ((self.S[(tt >> 16) & 0xFF] << 24) ^ + (self.S[(tt >> 8) & 0xFF] << 16) ^ + (self.S[ tt & 0xFF] << 8) ^ + self.S[(tt >> 24) & 0xFF] ^ + (self.rcon[rconpointer] << 24)) + rconpointer += 1 + + if KC != 8: + for i in xrange(1, KC): + tk[i] ^= tk[i - 1] + + # Key expansion for 256-bit keys is "slightly different" (fips-197) + else: + for i in xrange(1, KC // 2): + tk[i] ^= tk[i - 1] + tt = tk[KC // 2 - 1] + + tk[KC // 2] ^= (self.S[ tt & 0xFF] ^ + (self.S[(tt >> 8) & 0xFF] << 8) ^ + (self.S[(tt >> 16) & 0xFF] << 16) ^ + (self.S[(tt >> 24) & 0xFF] << 24)) + + for i in xrange(KC // 2 + 1, KC): + tk[i] ^= tk[i - 1] + + # Copy values into round key arrays + j = 0 + while j < KC and t < round_key_count: + self._Ke[t // 4][t % 4] = tk[j] + self._Kd[rounds - (t // 4)][t % 4] = tk[j] + j += 1 + t += 1 + + # Inverse-Cipher-ify the decryption round key (fips-197 section 5.3) + for r in xrange(1, rounds): + for j in xrange(0, 4): + tt = self._Kd[r][j] + self._Kd[r][j] = (self.U1[(tt >> 24) & 0xFF] ^ + self.U2[(tt >> 16) & 0xFF] ^ + self.U3[(tt >> 8) & 0xFF] ^ + self.U4[ tt & 0xFF]) + + def encrypt(self, plaintext): + 'Encrypt a block of plain text using the AES block cipher.' + + if len(plaintext) != 16: + raise ValueError('wrong block length') + + rounds = len(self._Ke) - 1 + (s1, s2, s3) = [1, 2, 3] + a = [0, 0, 0, 0] + + # Convert plaintext to (ints ^ key) + t = [(_compact_word(plaintext[4 * i:4 * i + 4]) ^ self._Ke[0][i]) for i in xrange(0, 4)] + + # Apply round transforms + for r in xrange(1, rounds): + for i in xrange(0, 4): + a[i] = (self.T1[(t[ i ] >> 24) & 0xFF] ^ + self.T2[(t[(i + s1) % 4] >> 16) & 0xFF] ^ + self.T3[(t[(i + s2) % 4] >> 8) & 0xFF] ^ + self.T4[ t[(i + s3) % 4] & 0xFF] ^ + self._Ke[r][i]) + t = copy.copy(a) + + # The last round is special + result = [ ] + for i in xrange(0, 4): + tt = self._Ke[rounds][i] + result.append((self.S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) + result.append((self.S[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) + result.append((self.S[(t[(i + s2) % 4] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) + result.append((self.S[ t[(i + s3) % 4] & 0xFF] ^ tt ) & 0xFF) + + return result + + def decrypt(self, ciphertext): + 'Decrypt a block of cipher text using the AES block cipher.' + + if len(ciphertext) != 16: + raise ValueError('wrong block length') + + rounds = len(self._Kd) - 1 + (s1, s2, s3) = [3, 2, 1] + a = [0, 0, 0, 0] + + # Convert ciphertext to (ints ^ key) + t = [(_compact_word(ciphertext[4 * i:4 * i + 4]) ^ self._Kd[0][i]) for i in xrange(0, 4)] + + # Apply round transforms + for r in xrange(1, rounds): + for i in xrange(0, 4): + a[i] = (self.T5[(t[ i ] >> 24) & 0xFF] ^ + self.T6[(t[(i + s1) % 4] >> 16) & 0xFF] ^ + self.T7[(t[(i + s2) % 4] >> 8) & 0xFF] ^ + self.T8[ t[(i + s3) % 4] & 0xFF] ^ + self._Kd[r][i]) + t = copy.copy(a) + + # The last round is special + result = [ ] + for i in xrange(0, 4): + tt = self._Kd[rounds][i] + result.append((self.Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) + result.append((self.Si[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) + result.append((self.Si[(t[(i + s2) % 4] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) + result.append((self.Si[ t[(i + s3) % 4] & 0xFF] ^ tt ) & 0xFF) + + return result + + +class Counter(object): + '''A counter object for the Counter (CTR) mode of operation. + + To create a custom counter, you can usually just override the + increment method.''' + + def __init__(self, initial_value = 1): + + # Convert the value into an array of bytes long + self._counter = [ ((initial_value >> i) % 256) for i in xrange(128 - 8, -1, -8) ] + + value = property(lambda s: s._counter) + + def increment(self): + '''Increment the counter (overflow rolls back to 0).''' + + for i in xrange(len(self._counter) - 1, -1, -1): + self._counter[i] += 1 + + if self._counter[i] < 256: break + + # Carry the one + self._counter[i] = 0 + + # Overflow + else: + self._counter = [ 0 ] * len(self._counter) + + +class AESBlockModeOfOperation(object): + '''Super-class for AES modes of operation that require blocks.''' + def __init__(self, key): + self._aes = AES(key) + + def decrypt(self, ciphertext): + raise Exception('not implemented') + + def encrypt(self, plaintext): + raise Exception('not implemented') + + +class AESStreamModeOfOperation(AESBlockModeOfOperation): + '''Super-class for AES modes of operation that are stream-ciphers.''' + +class AESSegmentModeOfOperation(AESStreamModeOfOperation): + '''Super-class for AES modes of operation that segment data.''' + + segment_bytes = 16 + + + +class AESModeOfOperationECB(AESBlockModeOfOperation): + '''AES Electronic Codebook Mode of Operation. + + o Block-cipher, so data must be padded to 16 byte boundaries + + Security Notes: + o This mode is not recommended + o Any two identical blocks produce identical encrypted values, + exposing data patterns. (See the image of Tux on wikipedia) + + Also see: + o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29 + o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.1''' + + + name = "Electronic Codebook (ECB)" + + def encrypt(self, plaintext): + if len(plaintext) != 16: + raise ValueError('plaintext block must be 16 bytes') + + plaintext = _string_to_bytes(plaintext) + return _bytes_to_string(self._aes.encrypt(plaintext)) + + def decrypt(self, ciphertext): + if len(ciphertext) != 16: + raise ValueError('ciphertext block must be 16 bytes') + + ciphertext = _string_to_bytes(ciphertext) + return _bytes_to_string(self._aes.decrypt(ciphertext)) + + + +class AESModeOfOperationCBC(AESBlockModeOfOperation): + '''AES Cipher-Block Chaining Mode of Operation. + + o The Initialization Vector (IV) + o Block-cipher, so data must be padded to 16 byte boundaries + o An incorrect initialization vector will only cause the first + block to be corrupt; all other blocks will be intact + o A corrupt bit in the cipher text will cause a block to be + corrupted, and the next block to be inverted, but all other + blocks will be intact. + + Security Notes: + o This method (and CTR) ARE recommended. + + Also see: + o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29 + o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.2''' + + + name = "Cipher-Block Chaining (CBC)" + + def __init__(self, key, iv = None): + if iv is None: + self._last_cipherblock = [ 0 ] * 16 + elif len(iv) != 16: + raise ValueError('initialization vector must be 16 bytes') + else: + self._last_cipherblock = _string_to_bytes(iv) + + AESBlockModeOfOperation.__init__(self, key) + + def encrypt(self, plaintext): + if len(plaintext) != 16: + raise ValueError('plaintext block must be 16 bytes') + + plaintext = _string_to_bytes(plaintext) + precipherblock = [ (p ^ l) for (p, l) in zip(plaintext, self._last_cipherblock) ] + self._last_cipherblock = self._aes.encrypt(precipherblock) + + return _bytes_to_string(self._last_cipherblock) + + def decrypt(self, ciphertext): + if len(ciphertext) != 16: + raise ValueError('ciphertext block must be 16 bytes') + + cipherblock = _string_to_bytes(ciphertext) + plaintext = [ (p ^ l) for (p, l) in zip(self._aes.decrypt(cipherblock), self._last_cipherblock) ] + self._last_cipherblock = cipherblock + + return _bytes_to_string(plaintext) + + + +class AESModeOfOperationCFB(AESSegmentModeOfOperation): + '''AES Cipher Feedback Mode of Operation. + + o A stream-cipher, so input does not need to be padded to blocks, + but does need to be padded to segment_size + + Also see: + o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29 + o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.3''' + + + name = "Cipher Feedback (CFB)" + + def __init__(self, key, iv, segment_size = 1): + if segment_size == 0: segment_size = 1 + + if iv is None: + self._shift_register = [ 0 ] * 16 + elif len(iv) != 16: + raise ValueError('initialization vector must be 16 bytes') + else: + self._shift_register = _string_to_bytes(iv) + + self._segment_bytes = segment_size + + AESBlockModeOfOperation.__init__(self, key) + + segment_bytes = property(lambda s: s._segment_bytes) + + def encrypt(self, plaintext): + if len(plaintext) % self._segment_bytes != 0: + raise ValueError('plaintext block must be a multiple of segment_size') + + plaintext = _string_to_bytes(plaintext) + + # Break block into segments + encrypted = [ ] + for i in xrange(0, len(plaintext), self._segment_bytes): + plaintext_segment = plaintext[i: i + self._segment_bytes] + xor_segment = self._aes.encrypt(self._shift_register)[:len(plaintext_segment)] + cipher_segment = [ (p ^ x) for (p, x) in zip(plaintext_segment, xor_segment) ] + + # Shift the top bits out and the ciphertext in + self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment) + + encrypted.extend(cipher_segment) + + return _bytes_to_string(encrypted) + + def decrypt(self, ciphertext): + if len(ciphertext) % self._segment_bytes != 0: + raise ValueError('ciphertext block must be a multiple of segment_size') + + ciphertext = _string_to_bytes(ciphertext) + + # Break block into segments + decrypted = [ ] + for i in xrange(0, len(ciphertext), self._segment_bytes): + cipher_segment = ciphertext[i: i + self._segment_bytes] + xor_segment = self._aes.encrypt(self._shift_register)[:len(cipher_segment)] + plaintext_segment = [ (p ^ x) for (p, x) in zip(cipher_segment, xor_segment) ] + + # Shift the top bits out and the ciphertext in + self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment) + + decrypted.extend(plaintext_segment) + + return _bytes_to_string(decrypted) + + + +class AESModeOfOperationOFB(AESStreamModeOfOperation): + '''AES Output Feedback Mode of Operation. + + o A stream-cipher, so input does not need to be padded to blocks, + allowing arbitrary length data. + o A bit twiddled in the cipher text, twiddles the same bit in the + same bit in the plain text, which can be useful for error + correction techniques. + + Also see: + o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_feedback_.28OFB.29 + o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.4''' + + + name = "Output Feedback (OFB)" + + def __init__(self, key, iv = None): + if iv is None: + self._last_precipherblock = [ 0 ] * 16 + elif len(iv) != 16: + raise ValueError('initialization vector must be 16 bytes') + else: + self._last_precipherblock = _string_to_bytes(iv) + + self._remaining_block = [ ] + + AESBlockModeOfOperation.__init__(self, key) + + def encrypt(self, plaintext): + encrypted = [ ] + for p in _string_to_bytes(plaintext): + if len(self._remaining_block) == 0: + self._remaining_block = self._aes.encrypt(self._last_precipherblock) + self._last_precipherblock = [ ] + precipherbyte = self._remaining_block.pop(0) + self._last_precipherblock.append(precipherbyte) + cipherbyte = p ^ precipherbyte + encrypted.append(cipherbyte) + + return _bytes_to_string(encrypted) + + def decrypt(self, ciphertext): + # AES-OFB is symetric + return self.encrypt(ciphertext) + + + +class AESModeOfOperationCTR(AESStreamModeOfOperation): + '''AES Counter Mode of Operation. + + o A stream-cipher, so input does not need to be padded to blocks, + allowing arbitrary length data. + o The counter must be the same size as the key size (ie. len(key)) + o Each block independant of the other, so a corrupt byte will not + damage future blocks. + o Each block has a uniue counter value associated with it, which + contributes to the encrypted value, so no data patterns are + leaked. + o Also known as: Counter Mode (CM), Integer Counter Mode (ICM) and + Segmented Integer Counter (SIC + + Security Notes: + o This method (and CBC) ARE recommended. + o Each message block is associated with a counter value which must be + unique for ALL messages with the same key. Otherwise security may be + compromised. + + Also see: + + o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29 + o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.5 + and Appendix B for managing the initial counter''' + + + name = "Counter (CTR)" + + def __init__(self, key, counter = None): + AESBlockModeOfOperation.__init__(self, key) + + if counter is None: + counter = Counter() + + self._counter = counter + self._remaining_counter = [ ] + + def encrypt(self, plaintext): + while len(self._remaining_counter) < len(plaintext): + self._remaining_counter += self._aes.encrypt(self._counter.value) + self._counter.increment() + + plaintext = _string_to_bytes(plaintext) + + encrypted = [ (p ^ c) for (p, c) in zip(plaintext, self._remaining_counter) ] + self._remaining_counter = self._remaining_counter[len(encrypted):] + + return _bytes_to_string(encrypted) + + def decrypt(self, crypttext): + # AES-CTR is symetric + return self.encrypt(crypttext) + + +# Simple lookup table for each mode +AESModesOfOperation = dict( + ctr = AESModeOfOperationCTR, + cbc = AESModeOfOperationCBC, + cfb = AESModeOfOperationCFB, + ecb = AESModeOfOperationECB, + ofb = AESModeOfOperationOFB, +) diff --git a/spot/benchmarks/aes/package/pyaes/blockfeeder.py b/spot/benchmarks/aes/package/pyaes/blockfeeder.py new file mode 100644 index 0000000..b9a904d --- /dev/null +++ b/spot/benchmarks/aes/package/pyaes/blockfeeder.py @@ -0,0 +1,227 @@ +# The MIT License (MIT) +# +# Copyright (c) 2014 Richard Moore +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + + +from .aes import AESBlockModeOfOperation, AESSegmentModeOfOperation, AESStreamModeOfOperation +from .util import append_PKCS7_padding, strip_PKCS7_padding, to_bufferable + + +# First we inject three functions to each of the modes of operations +# +# _can_consume(size) +# - Given a size, determine how many bytes could be consumed in +# a single call to either the decrypt or encrypt method +# +# _final_encrypt(data, padding = PADDING_DEFAULT) +# - call and return encrypt on this (last) chunk of data, +# padding as necessary; this will always be at least 16 +# bytes unless the total incoming input was less than 16 +# bytes +# +# _final_decrypt(data, padding = PADDING_DEFAULT) +# - same as _final_encrypt except for decrypt, for +# stripping off padding +# + +PADDING_NONE = 'none' +PADDING_DEFAULT = 'default' + +# @TODO: Ciphertext stealing and explicit PKCS#7 +# PADDING_CIPHERTEXT_STEALING +# PADDING_PKCS7 + +# ECB and CBC are block-only ciphers + +def _block_can_consume(self, size): + if size >= 16: return 16 + return 0 + +# After padding, we may have more than one block +def _block_final_encrypt(self, data, padding = PADDING_DEFAULT): + if padding == PADDING_DEFAULT: + data = append_PKCS7_padding(data) + + elif padding == PADDING_NONE: + if len(data) != 16: + raise Exception('invalid data length for final block') + else: + raise Exception('invalid padding option') + + if len(data) == 32: + return self.encrypt(data[:16]) + self.encrypt(data[16:]) + + return self.encrypt(data) + + +def _block_final_decrypt(self, data, padding = PADDING_DEFAULT): + if padding == PADDING_DEFAULT: + return strip_PKCS7_padding(self.decrypt(data)) + + if padding == PADDING_NONE: + if len(data) != 16: + raise Exception('invalid data length for final block') + return self.decrypt(data) + + raise Exception('invalid padding option') + +AESBlockModeOfOperation._can_consume = _block_can_consume +AESBlockModeOfOperation._final_encrypt = _block_final_encrypt +AESBlockModeOfOperation._final_decrypt = _block_final_decrypt + + + +# CFB is a segment cipher + +def _segment_can_consume(self, size): + return self.segment_bytes * int(size // self.segment_bytes) + +# CFB can handle a non-segment-sized block at the end using the remaining cipherblock +def _segment_final_encrypt(self, data, padding = PADDING_DEFAULT): + if padding != PADDING_DEFAULT: + raise Exception('invalid padding option') + + faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes))) + padded = data + to_bufferable(faux_padding) + return self.encrypt(padded)[:len(data)] + +# CFB can handle a non-segment-sized block at the end using the remaining cipherblock +def _segment_final_decrypt(self, data, padding = PADDING_DEFAULT): + if padding != PADDING_DEFAULT: + raise Exception('invalid padding option') + + faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes))) + padded = data + to_bufferable(faux_padding) + return self.decrypt(padded)[:len(data)] + +AESSegmentModeOfOperation._can_consume = _segment_can_consume +AESSegmentModeOfOperation._final_encrypt = _segment_final_encrypt +AESSegmentModeOfOperation._final_decrypt = _segment_final_decrypt + + + +# OFB and CTR are stream ciphers + +def _stream_can_consume(self, size): + return size + +def _stream_final_encrypt(self, data, padding = PADDING_DEFAULT): + if padding not in [PADDING_NONE, PADDING_DEFAULT]: + raise Exception('invalid padding option') + + return self.encrypt(data) + +def _stream_final_decrypt(self, data, padding = PADDING_DEFAULT): + if padding not in [PADDING_NONE, PADDING_DEFAULT]: + raise Exception('invalid padding option') + + return self.decrypt(data) + +AESStreamModeOfOperation._can_consume = _stream_can_consume +AESStreamModeOfOperation._final_encrypt = _stream_final_encrypt +AESStreamModeOfOperation._final_decrypt = _stream_final_decrypt + + + +class BlockFeeder(object): + '''The super-class for objects to handle chunking a stream of bytes + into the appropriate block size for the underlying mode of operation + and applying (or stripping) padding, as necessary.''' + + def __init__(self, mode, feed, final, padding = PADDING_DEFAULT): + self._mode = mode + self._feed = feed + self._final = final + self._buffer = to_bufferable("") + self._padding = padding + + def feed(self, data = None): + '''Provide bytes to encrypt (or decrypt), returning any bytes + possible from this or any previous calls to feed. + + Call with None or an empty string to flush the mode of + operation and return any final bytes; no further calls to + feed may be made.''' + + if self._buffer is None: + raise ValueError('already finished feeder') + + # Finalize; process the spare bytes we were keeping + if data is None: + result = self._final(self._buffer, self._padding) + self._buffer = None + return result + + self._buffer += to_bufferable(data) + + # We keep 16 bytes around so we can determine padding + result = to_bufferable('') + while len(self._buffer) > 16: + can_consume = self._mode._can_consume(len(self._buffer) - 16) + if can_consume == 0: break + result += self._feed(self._buffer[:can_consume]) + self._buffer = self._buffer[can_consume:] + + return result + + +class Encrypter(BlockFeeder): + 'Accepts bytes of plaintext and returns encrypted ciphertext.' + + def __init__(self, mode, padding = PADDING_DEFAULT): + BlockFeeder.__init__(self, mode, mode.encrypt, mode._final_encrypt, padding) + + +class Decrypter(BlockFeeder): + 'Accepts bytes of ciphertext and returns decrypted plaintext.' + + def __init__(self, mode, padding = PADDING_DEFAULT): + BlockFeeder.__init__(self, mode, mode.decrypt, mode._final_decrypt, padding) + + +# 8kb blocks +BLOCK_SIZE = (1 << 13) + +def _feed_stream(feeder, in_stream, out_stream, block_size = BLOCK_SIZE): + 'Uses feeder to read and convert from in_stream and write to out_stream.' + + while True: + chunk = in_stream.read(block_size) + if not chunk: + break + converted = feeder.feed(chunk) + out_stream.write(converted) + converted = feeder.feed() + out_stream.write(converted) + + +def encrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT): + 'Encrypts a stream of bytes from in_stream to out_stream using mode.' + + encrypter = Encrypter(mode, padding = padding) + _feed_stream(encrypter, in_stream, out_stream, block_size) + + +def decrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT): + 'Decrypts a stream of bytes from in_stream to out_stream using mode.' + + decrypter = Decrypter(mode, padding = padding) + _feed_stream(decrypter, in_stream, out_stream, block_size) diff --git a/spot/benchmarks/aes/package/pyaes/util.py b/spot/benchmarks/aes/package/pyaes/util.py new file mode 100644 index 0000000..081a375 --- /dev/null +++ b/spot/benchmarks/aes/package/pyaes/util.py @@ -0,0 +1,60 @@ +# The MIT License (MIT) +# +# Copyright (c) 2014 Richard Moore +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# Why to_bufferable? +# Python 3 is very different from Python 2.x when it comes to strings of text +# and strings of bytes; in Python 3, strings of bytes do not exist, instead to +# represent arbitrary binary data, we must use the "bytes" object. This method +# ensures the object behaves as we need it to. + +def to_bufferable(binary): + return binary + +def _get_byte(c): + return ord(c) + +try: + xrange +except: + + def to_bufferable(binary): + if isinstance(binary, bytes): + return binary + return bytes(ord(b) for b in binary) + + def _get_byte(c): + return c + +def append_PKCS7_padding(data): + pad = 16 - (len(data) % 16) + return data + to_bufferable(chr(pad) * pad) + +def strip_PKCS7_padding(data): + if len(data) % 16 != 0: + raise ValueError("invalid length") + + pad = _get_byte(data[-1]) + + if pad > 16: + raise ValueError("invalid padding byte") + + return data[:-pad] diff --git a/spot/benchmarks/aes/pyaes.md b/spot/benchmarks/aes/pyaes.md new file mode 100644 index 0000000..2f94df2 --- /dev/null +++ b/spot/benchmarks/aes/pyaes.md @@ -0,0 +1,25 @@ +THIS WIKI PAGE IS TAKEN FROM https://github.com/kmu-bigdata/serverless-faas-workbench/wiki/pyaes +## Pyaes + +Pyaes benchmark that performs private key-based encryption and decryption. It is a pure-Python implementation of the AES block-cipher algorithm in CTR mode. + +**Library** : pyaes, time, json + +[aws-build-deployment-package](https://github.com/kmu-bigdata/serverless-faas-workbench/wiki/aws-build-deployment-package) -> pyaes + +```text +(message example) +58pjx102ajfdil3cphd1wlt9b1i5wo5c5ys0f82td2j68y7k5g2c5f5n06ez6brwltrfdq8shuy7rcnzk7qym3eqsmfzuz5k7mjo +(encrypt message ciphertext) +���������単}�����6����� va��m��Puf/wf1�� 2�A��O;R�טi�et�,=xƴ�oe���xa%0b +``` + + +**Input**(test-event) example: +```json +{ + "length_of_message": [LENGTH OF MESSAGE], + "num_of_iterations": [NUMBER OF ENCRYPT, DECRYPT ITERARTIONS] +} +``` +**Output** : latency and cipertext From 919ac4d0e5fdcec16f93886193d942ee5d0ca16f Mon Sep 17 00:00:00 2001 From: Yaman Malkoc Date: Wed, 9 Feb 2022 14:37:29 -0800 Subject: [PATCH 2/6] benchmark aes use ready --- spot/benchmarks/aes/config.json | 1 + spot/benchmarks/aes/main.py | 9 + spot/benchmarks/aes/my-deployment-package.zip | Bin 58056 -> 0 bytes .../package/pyaes-1.6.1.dist-info/INSTALLER | 1 - .../package/pyaes-1.6.1.dist-info/LICENSE.txt | 22 - .../package/pyaes-1.6.1.dist-info/METADATA | 17 - .../aes/package/pyaes-1.6.1.dist-info/RECORD | 15 - .../package/pyaes-1.6.1.dist-info/REQUESTED | 0 .../aes/package/pyaes-1.6.1.dist-info/WHEEL | 5 - .../pyaes-1.6.1.dist-info/top_level.txt | 1 - spot/benchmarks/aes/package/pyaes/__init__.py | 53 -- spot/benchmarks/aes/package/pyaes/aes.py | 589 ------------------ .../aes/package/pyaes/blockfeeder.py | 227 ------- spot/benchmarks/aes/package/pyaes/util.py | 60 -- spot/benchmarks/aes/payload.json | 50 ++ spot/benchmarks/formplug/config.json | 33 +- spot/benchmarks/formplug/main.py | 2 +- 17 files changed, 93 insertions(+), 992 deletions(-) create mode 100644 spot/benchmarks/aes/config.json create mode 100644 spot/benchmarks/aes/main.py delete mode 100644 spot/benchmarks/aes/my-deployment-package.zip delete mode 100644 spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/INSTALLER delete mode 100644 spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/LICENSE.txt delete mode 100644 spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/METADATA delete mode 100644 spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/RECORD delete mode 100644 spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/REQUESTED delete mode 100644 spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/WHEEL delete mode 100644 spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/top_level.txt delete mode 100644 spot/benchmarks/aes/package/pyaes/__init__.py delete mode 100644 spot/benchmarks/aes/package/pyaes/aes.py delete mode 100644 spot/benchmarks/aes/package/pyaes/blockfeeder.py delete mode 100644 spot/benchmarks/aes/package/pyaes/util.py create mode 100644 spot/benchmarks/aes/payload.json diff --git a/spot/benchmarks/aes/config.json b/spot/benchmarks/aes/config.json new file mode 100644 index 0000000..1ac3a4d --- /dev/null +++ b/spot/benchmarks/aes/config.json @@ -0,0 +1 @@ +{"function_name": "pyaes", "folder_name": "aes", "last_log_timestamp": 1644444006734, "vendor": "AWS", "DB_URL": "localhost", "DB_PORT": 27017, "workload_path": "spot/benchmarks/aes/workload.json", "region": "us-east-2", "mem_size": 128, "workload": {"test_name": "IntegrationTest1", "test_duration_in_seconds": 15, "random_seed": 100, "blocking_cli": false, "instances": {"instance1": {"application": "pyaes", "distribution": "Poisson", "rate": 5, "activity_window": [5, 10], "payload": "spot/benchmarks/aes/payload.json", "host": "x8siu0es68.execute-api.us-east-2.amazonaws.com", "stage": "default", "resource": "/pyaes?format=json"}}}} \ No newline at end of file diff --git a/spot/benchmarks/aes/main.py b/spot/benchmarks/aes/main.py new file mode 100644 index 0000000..f7d3e62 --- /dev/null +++ b/spot/benchmarks/aes/main.py @@ -0,0 +1,9 @@ +from spot.Spot import Spot +import os + + +def executeAes(): + # os.getcwd() + file_path = os.path.join(os.path.dirname(__file__), "config.json") + benchmark = Spot(file_path) + benchmark.execute() diff --git a/spot/benchmarks/aes/my-deployment-package.zip b/spot/benchmarks/aes/my-deployment-package.zip deleted file mode 100644 index 889d4f5f98c419022ded9b942a98e90b8f321ad0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58056 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 E0DOysqyPW_ diff --git a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/INSTALLER b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/LICENSE.txt b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/LICENSE.txt deleted file mode 100644 index 0417a6c..0000000 --- a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/LICENSE.txt +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Richard Moore - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/METADATA b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/METADATA deleted file mode 100644 index 33b6850..0000000 --- a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/METADATA +++ /dev/null @@ -1,17 +0,0 @@ -Metadata-Version: 2.1 -Name: pyaes -Version: 1.6.1 -Summary: Pure-Python Implementation of the AES block-cipher and common modes of operation -Home-page: https://github.com/ricmoo/pyaes -Author: Richard Moore -Author-email: pyaes@ricmoo.com -License: License :: OSI Approved :: MIT License -Platform: UNKNOWN -Classifier: Topic :: Security :: Cryptography -Classifier: License :: OSI Approved :: MIT License - -A pure-Python implementation of the AES (FIPS-197) -block-cipher algorithm and common modes of operation (CBC, CFB, CTR, ECB, -OFB) with no dependencies beyond standard Python libraries. See README.md -for API reference and details. - diff --git a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/RECORD b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/RECORD deleted file mode 100644 index b95d37f..0000000 --- a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/RECORD +++ /dev/null @@ -1,15 +0,0 @@ -pyaes-1.6.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -pyaes-1.6.1.dist-info/LICENSE.txt,sha256=Hv5seLKLQgPTl-qbaL3JxljSHNmvr4roIj3vg_Kn670,1081 -pyaes-1.6.1.dist-info/METADATA,sha256=_t9OvQ23mS9RCk7a8xCjBb7t8XRkkL542DS3arky08c,630 -pyaes-1.6.1.dist-info/RECORD,, -pyaes-1.6.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -pyaes-1.6.1.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92 -pyaes-1.6.1.dist-info/top_level.txt,sha256=MuEdP4TkshZ7UFveg3brCBIrlZx0bXoAbp36EYTWZDs,6 -pyaes/__init__.py,sha256=4g4rXe3v6TxyWd-PWfAX3h-tc3tF9IB0o2sJ1gECJuc,2087 -pyaes/__pycache__/__init__.cpython-38.pyc,, -pyaes/__pycache__/aes.cpython-38.pyc,, -pyaes/__pycache__/blockfeeder.cpython-38.pyc,, -pyaes/__pycache__/util.cpython-38.pyc,, -pyaes/aes.py,sha256=XcD_etlIcErpgU_Ccg-bR5WZCSp6RuH9nVW3iVOhpD8,60310 -pyaes/blockfeeder.py,sha256=NMVQ9m0oS0woZvFxMNZGv2w_wr8oBiAyaIZXguEuDkQ,8123 -pyaes/util.py,sha256=tjLWrQmQly6wlp7BVR6NMCuvJBR2hk-GES5ANT8CxS8,2050 diff --git a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/REQUESTED b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/WHEEL b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/WHEEL deleted file mode 100644 index 385faab..0000000 --- a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.36.2) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/top_level.txt b/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/top_level.txt deleted file mode 100644 index 2e726cc..0000000 --- a/spot/benchmarks/aes/package/pyaes-1.6.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -pyaes diff --git a/spot/benchmarks/aes/package/pyaes/__init__.py b/spot/benchmarks/aes/package/pyaes/__init__.py deleted file mode 100644 index 5712f79..0000000 --- a/spot/benchmarks/aes/package/pyaes/__init__.py +++ /dev/null @@ -1,53 +0,0 @@ -# The MIT License (MIT) -# -# Copyright (c) 2014 Richard Moore -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -# This is a pure-Python implementation of the AES algorithm and AES common -# modes of operation. - -# See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard -# See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation - - -# Supported key sizes: -# 128-bit -# 192-bit -# 256-bit - - -# Supported modes of operation: -# ECB - Electronic Codebook -# CBC - Cipher-Block Chaining -# CFB - Cipher Feedback -# OFB - Output Feedback -# CTR - Counter - -# See the README.md for API details and general information. - -# Also useful, PyCrypto, a crypto library implemented in C with Python bindings: -# https://www.dlitz.net/software/pycrypto/ - - -VERSION = [1, 3, 0] - -from .aes import AES, AESModeOfOperationCTR, AESModeOfOperationCBC, AESModeOfOperationCFB, AESModeOfOperationECB, AESModeOfOperationOFB, AESModesOfOperation, Counter -from .blockfeeder import decrypt_stream, Decrypter, encrypt_stream, Encrypter -from .blockfeeder import PADDING_NONE, PADDING_DEFAULT diff --git a/spot/benchmarks/aes/package/pyaes/aes.py b/spot/benchmarks/aes/package/pyaes/aes.py deleted file mode 100644 index c6e8bc0..0000000 --- a/spot/benchmarks/aes/package/pyaes/aes.py +++ /dev/null @@ -1,589 +0,0 @@ -# The MIT License (MIT) -# -# Copyright (c) 2014 Richard Moore -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -# This is a pure-Python implementation of the AES algorithm and AES common -# modes of operation. - -# See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard - -# Honestly, the best description of the modes of operations are the wonderful -# diagrams on Wikipedia. They explain in moments what my words could never -# achieve. Hence the inline documentation here is sparer than I'd prefer. -# See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation - -# Also useful, PyCrypto, a crypto library implemented in C with Python bindings: -# https://www.dlitz.net/software/pycrypto/ - - -# Supported key sizes: -# 128-bit -# 192-bit -# 256-bit - - -# Supported modes of operation: -# ECB - Electronic Codebook -# CBC - Cipher-Block Chaining -# CFB - Cipher Feedback -# OFB - Output Feedback -# CTR - Counter - - -# See the README.md for API details and general information. - - -import copy -import struct - -__all__ = ["AES", "AESModeOfOperationCTR", "AESModeOfOperationCBC", "AESModeOfOperationCFB", - "AESModeOfOperationECB", "AESModeOfOperationOFB", "AESModesOfOperation", "Counter"] - - -def _compact_word(word): - return (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3] - -def _string_to_bytes(text): - return list(ord(c) for c in text) - -def _bytes_to_string(binary): - return "".join(chr(b) for b in binary) - -def _concat_list(a, b): - return a + b - - -# Python 3 compatibility -try: - xrange -except Exception: - xrange = range - - # Python 3 supports bytes, which is already an array of integers - def _string_to_bytes(text): - if isinstance(text, bytes): - return text - return [ord(c) for c in text] - - # In Python 3, we return bytes - def _bytes_to_string(binary): - return bytes(binary) - - # Python 3 cannot concatenate a list onto a bytes, so we bytes-ify it first - def _concat_list(a, b): - return a + bytes(b) - - -# Based *largely* on the Rijndael implementation -# See: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf -class AES(object): - '''Encapsulates the AES block cipher. - - You generally should not need this. Use the AESModeOfOperation classes - below instead.''' - - # Number of rounds by keysize - number_of_rounds = {16: 10, 24: 12, 32: 14} - - # Round constant words - rcon = [ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ] - - # S-box and Inverse S-box (S is for Substitution) - S = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ] - Si =[ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ] - - # Transformations for encryption - T1 = [ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a ] - T2 = [ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 ] - T3 = [ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 ] - T4 = [ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c ] - - # Transformations for decryption - T5 = [ 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 ] - T6 = [ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 ] - T7 = [ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 ] - T8 = [ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 ] - - # Transformations for decryption key expansion - U1 = [ 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3 ] - U2 = [ 0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697 ] - U3 = [ 0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46 ] - U4 = [ 0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d ] - - def __init__(self, key): - - if len(key) not in (16, 24, 32): - raise ValueError('Invalid key size') - - rounds = self.number_of_rounds[len(key)] - - # Encryption round keys - self._Ke = [[0] * 4 for i in xrange(rounds + 1)] - - # Decryption round keys - self._Kd = [[0] * 4 for i in xrange(rounds + 1)] - - round_key_count = (rounds + 1) * 4 - KC = len(key) // 4 - - # Convert the key into ints - tk = [ struct.unpack('>i', key[i:i + 4])[0] for i in xrange(0, len(key), 4) ] - - # Copy values into round key arrays - for i in xrange(0, KC): - self._Ke[i // 4][i % 4] = tk[i] - self._Kd[rounds - (i // 4)][i % 4] = tk[i] - - # Key expansion (fips-197 section 5.2) - rconpointer = 0 - t = KC - while t < round_key_count: - - tt = tk[KC - 1] - tk[0] ^= ((self.S[(tt >> 16) & 0xFF] << 24) ^ - (self.S[(tt >> 8) & 0xFF] << 16) ^ - (self.S[ tt & 0xFF] << 8) ^ - self.S[(tt >> 24) & 0xFF] ^ - (self.rcon[rconpointer] << 24)) - rconpointer += 1 - - if KC != 8: - for i in xrange(1, KC): - tk[i] ^= tk[i - 1] - - # Key expansion for 256-bit keys is "slightly different" (fips-197) - else: - for i in xrange(1, KC // 2): - tk[i] ^= tk[i - 1] - tt = tk[KC // 2 - 1] - - tk[KC // 2] ^= (self.S[ tt & 0xFF] ^ - (self.S[(tt >> 8) & 0xFF] << 8) ^ - (self.S[(tt >> 16) & 0xFF] << 16) ^ - (self.S[(tt >> 24) & 0xFF] << 24)) - - for i in xrange(KC // 2 + 1, KC): - tk[i] ^= tk[i - 1] - - # Copy values into round key arrays - j = 0 - while j < KC and t < round_key_count: - self._Ke[t // 4][t % 4] = tk[j] - self._Kd[rounds - (t // 4)][t % 4] = tk[j] - j += 1 - t += 1 - - # Inverse-Cipher-ify the decryption round key (fips-197 section 5.3) - for r in xrange(1, rounds): - for j in xrange(0, 4): - tt = self._Kd[r][j] - self._Kd[r][j] = (self.U1[(tt >> 24) & 0xFF] ^ - self.U2[(tt >> 16) & 0xFF] ^ - self.U3[(tt >> 8) & 0xFF] ^ - self.U4[ tt & 0xFF]) - - def encrypt(self, plaintext): - 'Encrypt a block of plain text using the AES block cipher.' - - if len(plaintext) != 16: - raise ValueError('wrong block length') - - rounds = len(self._Ke) - 1 - (s1, s2, s3) = [1, 2, 3] - a = [0, 0, 0, 0] - - # Convert plaintext to (ints ^ key) - t = [(_compact_word(plaintext[4 * i:4 * i + 4]) ^ self._Ke[0][i]) for i in xrange(0, 4)] - - # Apply round transforms - for r in xrange(1, rounds): - for i in xrange(0, 4): - a[i] = (self.T1[(t[ i ] >> 24) & 0xFF] ^ - self.T2[(t[(i + s1) % 4] >> 16) & 0xFF] ^ - self.T3[(t[(i + s2) % 4] >> 8) & 0xFF] ^ - self.T4[ t[(i + s3) % 4] & 0xFF] ^ - self._Ke[r][i]) - t = copy.copy(a) - - # The last round is special - result = [ ] - for i in xrange(0, 4): - tt = self._Ke[rounds][i] - result.append((self.S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) - result.append((self.S[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) - result.append((self.S[(t[(i + s2) % 4] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) - result.append((self.S[ t[(i + s3) % 4] & 0xFF] ^ tt ) & 0xFF) - - return result - - def decrypt(self, ciphertext): - 'Decrypt a block of cipher text using the AES block cipher.' - - if len(ciphertext) != 16: - raise ValueError('wrong block length') - - rounds = len(self._Kd) - 1 - (s1, s2, s3) = [3, 2, 1] - a = [0, 0, 0, 0] - - # Convert ciphertext to (ints ^ key) - t = [(_compact_word(ciphertext[4 * i:4 * i + 4]) ^ self._Kd[0][i]) for i in xrange(0, 4)] - - # Apply round transforms - for r in xrange(1, rounds): - for i in xrange(0, 4): - a[i] = (self.T5[(t[ i ] >> 24) & 0xFF] ^ - self.T6[(t[(i + s1) % 4] >> 16) & 0xFF] ^ - self.T7[(t[(i + s2) % 4] >> 8) & 0xFF] ^ - self.T8[ t[(i + s3) % 4] & 0xFF] ^ - self._Kd[r][i]) - t = copy.copy(a) - - # The last round is special - result = [ ] - for i in xrange(0, 4): - tt = self._Kd[rounds][i] - result.append((self.Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) - result.append((self.Si[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) - result.append((self.Si[(t[(i + s2) % 4] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) - result.append((self.Si[ t[(i + s3) % 4] & 0xFF] ^ tt ) & 0xFF) - - return result - - -class Counter(object): - '''A counter object for the Counter (CTR) mode of operation. - - To create a custom counter, you can usually just override the - increment method.''' - - def __init__(self, initial_value = 1): - - # Convert the value into an array of bytes long - self._counter = [ ((initial_value >> i) % 256) for i in xrange(128 - 8, -1, -8) ] - - value = property(lambda s: s._counter) - - def increment(self): - '''Increment the counter (overflow rolls back to 0).''' - - for i in xrange(len(self._counter) - 1, -1, -1): - self._counter[i] += 1 - - if self._counter[i] < 256: break - - # Carry the one - self._counter[i] = 0 - - # Overflow - else: - self._counter = [ 0 ] * len(self._counter) - - -class AESBlockModeOfOperation(object): - '''Super-class for AES modes of operation that require blocks.''' - def __init__(self, key): - self._aes = AES(key) - - def decrypt(self, ciphertext): - raise Exception('not implemented') - - def encrypt(self, plaintext): - raise Exception('not implemented') - - -class AESStreamModeOfOperation(AESBlockModeOfOperation): - '''Super-class for AES modes of operation that are stream-ciphers.''' - -class AESSegmentModeOfOperation(AESStreamModeOfOperation): - '''Super-class for AES modes of operation that segment data.''' - - segment_bytes = 16 - - - -class AESModeOfOperationECB(AESBlockModeOfOperation): - '''AES Electronic Codebook Mode of Operation. - - o Block-cipher, so data must be padded to 16 byte boundaries - - Security Notes: - o This mode is not recommended - o Any two identical blocks produce identical encrypted values, - exposing data patterns. (See the image of Tux on wikipedia) - - Also see: - o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29 - o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.1''' - - - name = "Electronic Codebook (ECB)" - - def encrypt(self, plaintext): - if len(plaintext) != 16: - raise ValueError('plaintext block must be 16 bytes') - - plaintext = _string_to_bytes(plaintext) - return _bytes_to_string(self._aes.encrypt(plaintext)) - - def decrypt(self, ciphertext): - if len(ciphertext) != 16: - raise ValueError('ciphertext block must be 16 bytes') - - ciphertext = _string_to_bytes(ciphertext) - return _bytes_to_string(self._aes.decrypt(ciphertext)) - - - -class AESModeOfOperationCBC(AESBlockModeOfOperation): - '''AES Cipher-Block Chaining Mode of Operation. - - o The Initialization Vector (IV) - o Block-cipher, so data must be padded to 16 byte boundaries - o An incorrect initialization vector will only cause the first - block to be corrupt; all other blocks will be intact - o A corrupt bit in the cipher text will cause a block to be - corrupted, and the next block to be inverted, but all other - blocks will be intact. - - Security Notes: - o This method (and CTR) ARE recommended. - - Also see: - o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29 - o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.2''' - - - name = "Cipher-Block Chaining (CBC)" - - def __init__(self, key, iv = None): - if iv is None: - self._last_cipherblock = [ 0 ] * 16 - elif len(iv) != 16: - raise ValueError('initialization vector must be 16 bytes') - else: - self._last_cipherblock = _string_to_bytes(iv) - - AESBlockModeOfOperation.__init__(self, key) - - def encrypt(self, plaintext): - if len(plaintext) != 16: - raise ValueError('plaintext block must be 16 bytes') - - plaintext = _string_to_bytes(plaintext) - precipherblock = [ (p ^ l) for (p, l) in zip(plaintext, self._last_cipherblock) ] - self._last_cipherblock = self._aes.encrypt(precipherblock) - - return _bytes_to_string(self._last_cipherblock) - - def decrypt(self, ciphertext): - if len(ciphertext) != 16: - raise ValueError('ciphertext block must be 16 bytes') - - cipherblock = _string_to_bytes(ciphertext) - plaintext = [ (p ^ l) for (p, l) in zip(self._aes.decrypt(cipherblock), self._last_cipherblock) ] - self._last_cipherblock = cipherblock - - return _bytes_to_string(plaintext) - - - -class AESModeOfOperationCFB(AESSegmentModeOfOperation): - '''AES Cipher Feedback Mode of Operation. - - o A stream-cipher, so input does not need to be padded to blocks, - but does need to be padded to segment_size - - Also see: - o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29 - o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.3''' - - - name = "Cipher Feedback (CFB)" - - def __init__(self, key, iv, segment_size = 1): - if segment_size == 0: segment_size = 1 - - if iv is None: - self._shift_register = [ 0 ] * 16 - elif len(iv) != 16: - raise ValueError('initialization vector must be 16 bytes') - else: - self._shift_register = _string_to_bytes(iv) - - self._segment_bytes = segment_size - - AESBlockModeOfOperation.__init__(self, key) - - segment_bytes = property(lambda s: s._segment_bytes) - - def encrypt(self, plaintext): - if len(plaintext) % self._segment_bytes != 0: - raise ValueError('plaintext block must be a multiple of segment_size') - - plaintext = _string_to_bytes(plaintext) - - # Break block into segments - encrypted = [ ] - for i in xrange(0, len(plaintext), self._segment_bytes): - plaintext_segment = plaintext[i: i + self._segment_bytes] - xor_segment = self._aes.encrypt(self._shift_register)[:len(plaintext_segment)] - cipher_segment = [ (p ^ x) for (p, x) in zip(plaintext_segment, xor_segment) ] - - # Shift the top bits out and the ciphertext in - self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment) - - encrypted.extend(cipher_segment) - - return _bytes_to_string(encrypted) - - def decrypt(self, ciphertext): - if len(ciphertext) % self._segment_bytes != 0: - raise ValueError('ciphertext block must be a multiple of segment_size') - - ciphertext = _string_to_bytes(ciphertext) - - # Break block into segments - decrypted = [ ] - for i in xrange(0, len(ciphertext), self._segment_bytes): - cipher_segment = ciphertext[i: i + self._segment_bytes] - xor_segment = self._aes.encrypt(self._shift_register)[:len(cipher_segment)] - plaintext_segment = [ (p ^ x) for (p, x) in zip(cipher_segment, xor_segment) ] - - # Shift the top bits out and the ciphertext in - self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment) - - decrypted.extend(plaintext_segment) - - return _bytes_to_string(decrypted) - - - -class AESModeOfOperationOFB(AESStreamModeOfOperation): - '''AES Output Feedback Mode of Operation. - - o A stream-cipher, so input does not need to be padded to blocks, - allowing arbitrary length data. - o A bit twiddled in the cipher text, twiddles the same bit in the - same bit in the plain text, which can be useful for error - correction techniques. - - Also see: - o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_feedback_.28OFB.29 - o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.4''' - - - name = "Output Feedback (OFB)" - - def __init__(self, key, iv = None): - if iv is None: - self._last_precipherblock = [ 0 ] * 16 - elif len(iv) != 16: - raise ValueError('initialization vector must be 16 bytes') - else: - self._last_precipherblock = _string_to_bytes(iv) - - self._remaining_block = [ ] - - AESBlockModeOfOperation.__init__(self, key) - - def encrypt(self, plaintext): - encrypted = [ ] - for p in _string_to_bytes(plaintext): - if len(self._remaining_block) == 0: - self._remaining_block = self._aes.encrypt(self._last_precipherblock) - self._last_precipherblock = [ ] - precipherbyte = self._remaining_block.pop(0) - self._last_precipherblock.append(precipherbyte) - cipherbyte = p ^ precipherbyte - encrypted.append(cipherbyte) - - return _bytes_to_string(encrypted) - - def decrypt(self, ciphertext): - # AES-OFB is symetric - return self.encrypt(ciphertext) - - - -class AESModeOfOperationCTR(AESStreamModeOfOperation): - '''AES Counter Mode of Operation. - - o A stream-cipher, so input does not need to be padded to blocks, - allowing arbitrary length data. - o The counter must be the same size as the key size (ie. len(key)) - o Each block independant of the other, so a corrupt byte will not - damage future blocks. - o Each block has a uniue counter value associated with it, which - contributes to the encrypted value, so no data patterns are - leaked. - o Also known as: Counter Mode (CM), Integer Counter Mode (ICM) and - Segmented Integer Counter (SIC - - Security Notes: - o This method (and CBC) ARE recommended. - o Each message block is associated with a counter value which must be - unique for ALL messages with the same key. Otherwise security may be - compromised. - - Also see: - - o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29 - o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.5 - and Appendix B for managing the initial counter''' - - - name = "Counter (CTR)" - - def __init__(self, key, counter = None): - AESBlockModeOfOperation.__init__(self, key) - - if counter is None: - counter = Counter() - - self._counter = counter - self._remaining_counter = [ ] - - def encrypt(self, plaintext): - while len(self._remaining_counter) < len(plaintext): - self._remaining_counter += self._aes.encrypt(self._counter.value) - self._counter.increment() - - plaintext = _string_to_bytes(plaintext) - - encrypted = [ (p ^ c) for (p, c) in zip(plaintext, self._remaining_counter) ] - self._remaining_counter = self._remaining_counter[len(encrypted):] - - return _bytes_to_string(encrypted) - - def decrypt(self, crypttext): - # AES-CTR is symetric - return self.encrypt(crypttext) - - -# Simple lookup table for each mode -AESModesOfOperation = dict( - ctr = AESModeOfOperationCTR, - cbc = AESModeOfOperationCBC, - cfb = AESModeOfOperationCFB, - ecb = AESModeOfOperationECB, - ofb = AESModeOfOperationOFB, -) diff --git a/spot/benchmarks/aes/package/pyaes/blockfeeder.py b/spot/benchmarks/aes/package/pyaes/blockfeeder.py deleted file mode 100644 index b9a904d..0000000 --- a/spot/benchmarks/aes/package/pyaes/blockfeeder.py +++ /dev/null @@ -1,227 +0,0 @@ -# The MIT License (MIT) -# -# Copyright (c) 2014 Richard Moore -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - - -from .aes import AESBlockModeOfOperation, AESSegmentModeOfOperation, AESStreamModeOfOperation -from .util import append_PKCS7_padding, strip_PKCS7_padding, to_bufferable - - -# First we inject three functions to each of the modes of operations -# -# _can_consume(size) -# - Given a size, determine how many bytes could be consumed in -# a single call to either the decrypt or encrypt method -# -# _final_encrypt(data, padding = PADDING_DEFAULT) -# - call and return encrypt on this (last) chunk of data, -# padding as necessary; this will always be at least 16 -# bytes unless the total incoming input was less than 16 -# bytes -# -# _final_decrypt(data, padding = PADDING_DEFAULT) -# - same as _final_encrypt except for decrypt, for -# stripping off padding -# - -PADDING_NONE = 'none' -PADDING_DEFAULT = 'default' - -# @TODO: Ciphertext stealing and explicit PKCS#7 -# PADDING_CIPHERTEXT_STEALING -# PADDING_PKCS7 - -# ECB and CBC are block-only ciphers - -def _block_can_consume(self, size): - if size >= 16: return 16 - return 0 - -# After padding, we may have more than one block -def _block_final_encrypt(self, data, padding = PADDING_DEFAULT): - if padding == PADDING_DEFAULT: - data = append_PKCS7_padding(data) - - elif padding == PADDING_NONE: - if len(data) != 16: - raise Exception('invalid data length for final block') - else: - raise Exception('invalid padding option') - - if len(data) == 32: - return self.encrypt(data[:16]) + self.encrypt(data[16:]) - - return self.encrypt(data) - - -def _block_final_decrypt(self, data, padding = PADDING_DEFAULT): - if padding == PADDING_DEFAULT: - return strip_PKCS7_padding(self.decrypt(data)) - - if padding == PADDING_NONE: - if len(data) != 16: - raise Exception('invalid data length for final block') - return self.decrypt(data) - - raise Exception('invalid padding option') - -AESBlockModeOfOperation._can_consume = _block_can_consume -AESBlockModeOfOperation._final_encrypt = _block_final_encrypt -AESBlockModeOfOperation._final_decrypt = _block_final_decrypt - - - -# CFB is a segment cipher - -def _segment_can_consume(self, size): - return self.segment_bytes * int(size // self.segment_bytes) - -# CFB can handle a non-segment-sized block at the end using the remaining cipherblock -def _segment_final_encrypt(self, data, padding = PADDING_DEFAULT): - if padding != PADDING_DEFAULT: - raise Exception('invalid padding option') - - faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes))) - padded = data + to_bufferable(faux_padding) - return self.encrypt(padded)[:len(data)] - -# CFB can handle a non-segment-sized block at the end using the remaining cipherblock -def _segment_final_decrypt(self, data, padding = PADDING_DEFAULT): - if padding != PADDING_DEFAULT: - raise Exception('invalid padding option') - - faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes))) - padded = data + to_bufferable(faux_padding) - return self.decrypt(padded)[:len(data)] - -AESSegmentModeOfOperation._can_consume = _segment_can_consume -AESSegmentModeOfOperation._final_encrypt = _segment_final_encrypt -AESSegmentModeOfOperation._final_decrypt = _segment_final_decrypt - - - -# OFB and CTR are stream ciphers - -def _stream_can_consume(self, size): - return size - -def _stream_final_encrypt(self, data, padding = PADDING_DEFAULT): - if padding not in [PADDING_NONE, PADDING_DEFAULT]: - raise Exception('invalid padding option') - - return self.encrypt(data) - -def _stream_final_decrypt(self, data, padding = PADDING_DEFAULT): - if padding not in [PADDING_NONE, PADDING_DEFAULT]: - raise Exception('invalid padding option') - - return self.decrypt(data) - -AESStreamModeOfOperation._can_consume = _stream_can_consume -AESStreamModeOfOperation._final_encrypt = _stream_final_encrypt -AESStreamModeOfOperation._final_decrypt = _stream_final_decrypt - - - -class BlockFeeder(object): - '''The super-class for objects to handle chunking a stream of bytes - into the appropriate block size for the underlying mode of operation - and applying (or stripping) padding, as necessary.''' - - def __init__(self, mode, feed, final, padding = PADDING_DEFAULT): - self._mode = mode - self._feed = feed - self._final = final - self._buffer = to_bufferable("") - self._padding = padding - - def feed(self, data = None): - '''Provide bytes to encrypt (or decrypt), returning any bytes - possible from this or any previous calls to feed. - - Call with None or an empty string to flush the mode of - operation and return any final bytes; no further calls to - feed may be made.''' - - if self._buffer is None: - raise ValueError('already finished feeder') - - # Finalize; process the spare bytes we were keeping - if data is None: - result = self._final(self._buffer, self._padding) - self._buffer = None - return result - - self._buffer += to_bufferable(data) - - # We keep 16 bytes around so we can determine padding - result = to_bufferable('') - while len(self._buffer) > 16: - can_consume = self._mode._can_consume(len(self._buffer) - 16) - if can_consume == 0: break - result += self._feed(self._buffer[:can_consume]) - self._buffer = self._buffer[can_consume:] - - return result - - -class Encrypter(BlockFeeder): - 'Accepts bytes of plaintext and returns encrypted ciphertext.' - - def __init__(self, mode, padding = PADDING_DEFAULT): - BlockFeeder.__init__(self, mode, mode.encrypt, mode._final_encrypt, padding) - - -class Decrypter(BlockFeeder): - 'Accepts bytes of ciphertext and returns decrypted plaintext.' - - def __init__(self, mode, padding = PADDING_DEFAULT): - BlockFeeder.__init__(self, mode, mode.decrypt, mode._final_decrypt, padding) - - -# 8kb blocks -BLOCK_SIZE = (1 << 13) - -def _feed_stream(feeder, in_stream, out_stream, block_size = BLOCK_SIZE): - 'Uses feeder to read and convert from in_stream and write to out_stream.' - - while True: - chunk = in_stream.read(block_size) - if not chunk: - break - converted = feeder.feed(chunk) - out_stream.write(converted) - converted = feeder.feed() - out_stream.write(converted) - - -def encrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT): - 'Encrypts a stream of bytes from in_stream to out_stream using mode.' - - encrypter = Encrypter(mode, padding = padding) - _feed_stream(encrypter, in_stream, out_stream, block_size) - - -def decrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT): - 'Decrypts a stream of bytes from in_stream to out_stream using mode.' - - decrypter = Decrypter(mode, padding = padding) - _feed_stream(decrypter, in_stream, out_stream, block_size) diff --git a/spot/benchmarks/aes/package/pyaes/util.py b/spot/benchmarks/aes/package/pyaes/util.py deleted file mode 100644 index 081a375..0000000 --- a/spot/benchmarks/aes/package/pyaes/util.py +++ /dev/null @@ -1,60 +0,0 @@ -# The MIT License (MIT) -# -# Copyright (c) 2014 Richard Moore -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -# Why to_bufferable? -# Python 3 is very different from Python 2.x when it comes to strings of text -# and strings of bytes; in Python 3, strings of bytes do not exist, instead to -# represent arbitrary binary data, we must use the "bytes" object. This method -# ensures the object behaves as we need it to. - -def to_bufferable(binary): - return binary - -def _get_byte(c): - return ord(c) - -try: - xrange -except: - - def to_bufferable(binary): - if isinstance(binary, bytes): - return binary - return bytes(ord(b) for b in binary) - - def _get_byte(c): - return c - -def append_PKCS7_padding(data): - pad = 16 - (len(data) % 16) - return data + to_bufferable(chr(pad) * pad) - -def strip_PKCS7_padding(data): - if len(data) % 16 != 0: - raise ValueError("invalid length") - - pad = _get_byte(data[-1]) - - if pad > 16: - raise ValueError("invalid padding byte") - - return data[:-pad] diff --git a/spot/benchmarks/aes/payload.json b/spot/benchmarks/aes/payload.json new file mode 100644 index 0000000..e8c8b69 --- /dev/null +++ b/spot/benchmarks/aes/payload.json @@ -0,0 +1,50 @@ +[ + { + "length_of_message": 16, + "num_of_iterations": 1 + }, + { + "length_of_message": 32, + "num_of_iterations": 1 + }, + { + "length_of_message": 64, + "num_of_iterations": 1 + }, + { + "length_of_message": 128, + "num_of_iterations": 1 + }, + { + "length_of_message": 16, + "num_of_iterations": 3 + }, + { + "length_of_message": 32, + "num_of_iterations": 3 + }, + { + "length_of_message": 64, + "num_of_iterations": 3 + }, + { + "length_of_message": 128, + "num_of_iterations": 3 + }, + { + "length_of_message": 16, + "num_of_iterations": 5 + }, + { + "length_of_message": 32, + "num_of_iterations": 5 + }, + { + "length_of_message": 64, + "num_of_iterations": 5 + }, + { + "length_of_message": 128, + "num_of_iterations": 5 + } +] \ No newline at end of file diff --git a/spot/benchmarks/formplug/config.json b/spot/benchmarks/formplug/config.json index acc59cc..9fc38a6 100644 --- a/spot/benchmarks/formplug/config.json +++ b/spot/benchmarks/formplug/config.json @@ -1 +1,32 @@ -{"function_name": "formplug-dev-receive", "folder_name": "formplug", "last_log_timestamp": 1644018632028, "vendor": "AWS", "DB_URL": "localhost", "DB_PORT": 27017, "workload_path": "spot/benchmarks/HelloWorld/workload.json", "region": "us-east-2", "mem_size": 128, "workload": {"test_name": "IntegrationTest1", "test_duration_in_seconds": 15, "random_seed": 100, "blocking_cli": false, "instances": {"instance1": {"application": "formplug-dev-receive", "distribution": "Poisson", "rate": 5, "activity_window": [5, 10], "payload": "spot/benchmarks/formplug/payload.json", "host": "psihxi4hxi.execute-api.us-east-2.amazonaws.com", "stage": "dev", "resource": "?format=json"}}}} \ No newline at end of file +{ + "function_name": "formplug-dev-receive", + "folder_name": "formplug", + "last_log_timestamp": 1644018632028, + "vendor": "AWS", + "DB_URL": "localhost", + "DB_PORT": 27017, + "workload_path": "spot/benchmarks/HelloWorld/workload.json", + "region": "us-east-2", + "mem_size": 128, + "workload": { + "test_name": "IntegrationTest1", + "test_duration_in_seconds": 15, + "random_seed": 100, + "blocking_cli": false, + "instances": { + "instance1": { + "application": "formplug-dev-receive", + "distribution": "Poisson", + "rate": 5, + "activity_window": [ + 5, + 10 + ], + "payload": "spot/benchmarks/formplug/payload.json", + "host": "psihxi4hxi.execute-api.us-east-2.amazonaws.com", + "stage": "dev", + "resource": "?format=json" + } + } + } +} \ No newline at end of file diff --git a/spot/benchmarks/formplug/main.py b/spot/benchmarks/formplug/main.py index 688a872..dd08653 100644 --- a/spot/benchmarks/formplug/main.py +++ b/spot/benchmarks/formplug/main.py @@ -6,4 +6,4 @@ def executeFormplug(): # os.getcwd() file_path = os.path.join(os.path.dirname(__file__), "config.json") benchmark = Spot(file_path) - benchmark.execute() + benchmark.execute() \ No newline at end of file From 6bd087698498b5256576063261dec41963bac83d Mon Sep 17 00:00:00 2001 From: Yaman Malkoc Date: Wed, 9 Feb 2022 15:19:43 -0800 Subject: [PATCH 3/6] formatting and main.py execution changes --- spot/benchmarks/aes/config.json | 33 ++++++++++++++++++++++++++++++++- spot/main.py | 5 ++--- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/spot/benchmarks/aes/config.json b/spot/benchmarks/aes/config.json index 1ac3a4d..6752e22 100644 --- a/spot/benchmarks/aes/config.json +++ b/spot/benchmarks/aes/config.json @@ -1 +1,32 @@ -{"function_name": "pyaes", "folder_name": "aes", "last_log_timestamp": 1644444006734, "vendor": "AWS", "DB_URL": "localhost", "DB_PORT": 27017, "workload_path": "spot/benchmarks/aes/workload.json", "region": "us-east-2", "mem_size": 128, "workload": {"test_name": "IntegrationTest1", "test_duration_in_seconds": 15, "random_seed": 100, "blocking_cli": false, "instances": {"instance1": {"application": "pyaes", "distribution": "Poisson", "rate": 5, "activity_window": [5, 10], "payload": "spot/benchmarks/aes/payload.json", "host": "x8siu0es68.execute-api.us-east-2.amazonaws.com", "stage": "default", "resource": "/pyaes?format=json"}}}} \ No newline at end of file +{ + "function_name": "pyaes", + "folder_name": "aes", + "last_log_timestamp": 1644444006734, + "vendor": "AWS", + "DB_URL": "localhost", + "DB_PORT": 27017, + "workload_path": "spot/benchmarks/aes/workload.json", + "region": "us-east-2", + "mem_size": 128, + "workload": { + "test_name": "IntegrationTest1", + "test_duration_in_seconds": 15, + "random_seed": 100, + "blocking_cli": false, + "instances": { + "instance1": { + "application": "pyaes", + "distribution": "Poisson", + "rate": 5, + "activity_window": [ + 5, + 10 + ], + "payload": "spot/benchmarks/aes/payload.json", + "host": "x8siu0es68.execute-api.us-east-2.amazonaws.com", + "stage": "default", + "resource": "/pyaes?format=json" + } + } + } +} \ No newline at end of file diff --git a/spot/main.py b/spot/main.py index 9f64dd3..d21567e 100644 --- a/spot/main.py +++ b/spot/main.py @@ -1,10 +1,9 @@ -from spot.benchmarks.AWSHelloWorld.main import executeAWSHelloWorld -from spot.benchmarks.formplug.main import executeFormplug +from spot.benchmarks.aes.main import executeAes def main(): # executeAWSHelloWorld() - executeFormplug() + executeAes() if __name__ == "__main__": From e04241b5776b0ce39afb298968cbcbd4e3e418d8 Mon Sep 17 00:00:00 2001 From: Yaman Malkoc Date: Thu, 10 Feb 2022 11:14:21 -0800 Subject: [PATCH 4/6] format fixes --- spot/benchmarks/aes/config.json | 2 +- spot/benchmarks/aes/main.py | 1 + spot/benchmarks/aes/payload.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/spot/benchmarks/aes/config.json b/spot/benchmarks/aes/config.json index 6752e22..af48141 100644 --- a/spot/benchmarks/aes/config.json +++ b/spot/benchmarks/aes/config.json @@ -29,4 +29,4 @@ } } } -} \ No newline at end of file +} diff --git a/spot/benchmarks/aes/main.py b/spot/benchmarks/aes/main.py index f7d3e62..dedff78 100644 --- a/spot/benchmarks/aes/main.py +++ b/spot/benchmarks/aes/main.py @@ -7,3 +7,4 @@ def executeAes(): file_path = os.path.join(os.path.dirname(__file__), "config.json") benchmark = Spot(file_path) benchmark.execute() + \ No newline at end of file diff --git a/spot/benchmarks/aes/payload.json b/spot/benchmarks/aes/payload.json index e8c8b69..a7198f9 100644 --- a/spot/benchmarks/aes/payload.json +++ b/spot/benchmarks/aes/payload.json @@ -47,4 +47,4 @@ "length_of_message": 128, "num_of_iterations": 5 } -] \ No newline at end of file +] From ebb93186bf42510d90fdbca5e66c6cc6f9711d4e Mon Sep 17 00:00:00 2001 From: Yaman Malkoc Date: Thu, 10 Feb 2022 11:16:38 -0800 Subject: [PATCH 5/6] format fix --- spot/benchmarks/aes/main.py | 1 - spot/benchmarks/formplug/config.json | 33 +--------------------------- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/spot/benchmarks/aes/main.py b/spot/benchmarks/aes/main.py index dedff78..f7d3e62 100644 --- a/spot/benchmarks/aes/main.py +++ b/spot/benchmarks/aes/main.py @@ -7,4 +7,3 @@ def executeAes(): file_path = os.path.join(os.path.dirname(__file__), "config.json") benchmark = Spot(file_path) benchmark.execute() - \ No newline at end of file diff --git a/spot/benchmarks/formplug/config.json b/spot/benchmarks/formplug/config.json index 9fc38a6..06f77c3 100644 --- a/spot/benchmarks/formplug/config.json +++ b/spot/benchmarks/formplug/config.json @@ -1,32 +1 @@ -{ - "function_name": "formplug-dev-receive", - "folder_name": "formplug", - "last_log_timestamp": 1644018632028, - "vendor": "AWS", - "DB_URL": "localhost", - "DB_PORT": 27017, - "workload_path": "spot/benchmarks/HelloWorld/workload.json", - "region": "us-east-2", - "mem_size": 128, - "workload": { - "test_name": "IntegrationTest1", - "test_duration_in_seconds": 15, - "random_seed": 100, - "blocking_cli": false, - "instances": { - "instance1": { - "application": "formplug-dev-receive", - "distribution": "Poisson", - "rate": 5, - "activity_window": [ - 5, - 10 - ], - "payload": "spot/benchmarks/formplug/payload.json", - "host": "psihxi4hxi.execute-api.us-east-2.amazonaws.com", - "stage": "dev", - "resource": "?format=json" - } - } - } -} \ No newline at end of file +{"function_name": "formplug-dev-receive", "folder_name": "formplug", "last_log_timestamp": 1644018632028, "vendor": "AWS", "DB_URL": "localhost", "DB_PORT": 27017, "workload_path": "spot/benchmarks/HelloWorld/workload.json", "region": "us-east-2", "mem_size": 128, "workload": {"test_name": "IntegrationTest1", "test_duration_in_seconds": 15, "random_seed": 100, "blocking_cli": false, "instances": {"instance1": {"application": "formplug-dev-receive", "distribution": "Poisson", "rate": 5, "activity_window": [5, 10], "payload": "spot/benchmarks/formplug/payload.json", "host": "psihxi4hxi.execute-api.us-east-2.amazonaws.com", "stage": "dev", "resource": "?format=json"}}}} From ec7bd638ad997b824c0310d1cb501b2fda0c9ec0 Mon Sep 17 00:00:00 2001 From: Yaman Malkoc Date: Thu, 10 Feb 2022 11:19:01 -0800 Subject: [PATCH 6/6] black fixes --- spot/benchmarks/aes/lambda_function.py | 8 ++++---- spot/benchmarks/formplug/main.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spot/benchmarks/aes/lambda_function.py b/spot/benchmarks/aes/lambda_function.py index 58452aa..ff59d28 100644 --- a/spot/benchmarks/aes/lambda_function.py +++ b/spot/benchmarks/aes/lambda_function.py @@ -6,17 +6,17 @@ def generate(length): letters = string.ascii_lowercase + string.digits - return ''.join(random.choice(letters) for i in range(length)) + return "".join(random.choice(letters) for i in range(length)) def lambda_handler(event, context): - length_of_message = event['length_of_message'] - num_of_iterations = event['num_of_iterations'] + length_of_message = event["length_of_message"] + num_of_iterations = event["num_of_iterations"] message = generate(length_of_message) # 128-bit key (16 bytes) - KEY = b'\xa1\xf6%\x8c\x87}_\xcd\x89dHE8\xbf\xc9,' + KEY = b"\xa1\xf6%\x8c\x87}_\xcd\x89dHE8\xbf\xc9," start = time() for loops in range(num_of_iterations): diff --git a/spot/benchmarks/formplug/main.py b/spot/benchmarks/formplug/main.py index dd08653..688a872 100644 --- a/spot/benchmarks/formplug/main.py +++ b/spot/benchmarks/formplug/main.py @@ -6,4 +6,4 @@ def executeFormplug(): # os.getcwd() file_path = os.path.join(os.path.dirname(__file__), "config.json") benchmark = Spot(file_path) - benchmark.execute() \ No newline at end of file + benchmark.execute()