From 5121ce5bdbc92e134a42220a1aa23f95037c7625 Mon Sep 17 00:00:00 2001 From: Paul Bakker
_W$-br%wz-$*_NcuP8LGhNV>Ji3Qk-9(yXn)V7bKp;P`R@}X+W z(9lrq6>S-|?w+2gdNhuMtF?6}Ml?o)RD=wR$0!7JcS`q|^*6zq{lC8}95k|GKtD`S zr^BJnH7FV}uJJs8FoudZa3xhe1Ar!WP`i>yu~a!*kdDkw@;!VsyvNPk+n6WTNoasX z+6RN-jqj-TJop#P?(J)s2?_)wIWUcBI+KHSTmg7RdVE=aXqwsc4&L>9F9zk*x8cl7 z_e!ps1K87OwO^~w`TF>r+_CCW!8D-+oM|D7YinzYzjYu#e-gQQQ{8<{XDjJ-*|^`> z>TZpH<3I(1>v5XSf@7u2`wQgNXd#mC`1!;XUQsAuJ`MAS&_ck%53oXFIgE|mPe$hn zF}{Y2)X17t+FlIAD^(v>Rq=6pk6$Fs$V8~_PKN_zcve;xw1o+pDkcSLeMntVSXS+ z@l`NT0-!)3Ac|qRAjjX17l`h=n 8xVC h2OK%GIpyT&{5% z5mSyk!g`sh*{T#zaI(+6`j4&T@pPm-AKfeYlSOTv!^~{QcJnVlL; $%Isy_-Jc!@Gs`<$IN22)LMN-8>~2K-vxjX+Vo#lwiEV)XLvV- @M-bP}>ZrATMz2w&<6>XdZ7-`qID?9cile>t zjJE~AAeC{RkfCETdVl%-yrH}tN={n(CCfwD@%ZM!6(J5^Jojq0bSe^68bMrTab@{R zk6-vc>W>No4mlZ%eneUcfU=r5sOVT|z@NS;{so2S=i55%r+=pn_4?%Sek_e)DqE?< zqF=fuxkgHE 2{ !?c&M}(}I+DSP_27hfOLHOXOkFBJ`lNd03lM!C& zTN^a#m8K*4siJ7qTIfN@E{p##N-Cx>+xS~b(8NpvV)s QpwsXM{sv-VXLNIT z)?U`@knXdTo(8fzRfl(Bm09uQtp&&!y~J@ Ys#Nx2mXDQ)fl@xl_93l?5*1 z?A>){*x#wA4D)TA0-ALD2R>CvF9sM^Xc3|9FE-G;Cw}{duHEv`b;{tah29LXK3J7X zvi#iG*k}%80A)n0!DqV=81&Qq=}2h!QRiS0s%8Bbe6Pa!213!))AwB#p#JUb?4X50 zK1O>51ry@orr!uTp|)V+iV}@Qa~1B|D_raFx;FJdC^oL~&Nu<&^H=g2GHL$#mS* z-T+=DlR)Kj-eLjNnwFNJ?s)(=IWqOqz~<#_#J8IVRw}$!Md@k}q(%xm8K7jTgL_(g zaI4wXh1nt{#KgoTB!Vf;*F6LXdfTdZ-c!ozQQINyhuGAPgZPxr?j9D^GLJ;N;1?3V zC^7w;wzUaR{xVH_?QusfDlz?vZIlTJWsk~iuF}0iA$u^QAg@UYLl8u0?;dYy@|-UV zBm?Aa9Ja=V1>RC!v%*6MFf;UBOVfF$kp&p~?c29VY+p9c7iCVSOP8QF+mu~ui|d}> zvx>fT4y6aJ2-ZRMl-v{b>65i98>=oa55a*YP&Lgp5+LsMJATco^+RYOSR*SjC1v8z zpP+sQGHe|IbiWHk#1VuGVjHwmf&Sy12$D(7yG~@gm1hyHRSXmqXyOTkm)@T4&Gnzi z$K|%5j{4FZC(nHu&ZIOqruHHx3Q+ifJ{vXYdAj?rl^E^vrkyOT8L#i=?!|ICXd9KE z7gq d+250SN<-5epGr`IzI# ki||@a1P5r4$x!fco5ZPVMnvlyj%B0CCT5pD%^j|TZA;TdkFL# zh_J*i9`WnH+0Chn{i3Us9X#Bv#J9Zd0~vHiz>y z0WY #teP7yo#CTLN1Lte90Fepv2AFfuZAyNnyd=T zw7e^di|y9`R1Xdgg8B>HV998mQ!3BtVq*l3J~zSE!ExS$!gG>9k1uUutous<3nH>r zN$jb3687ovjVmatfoM%$`mhCMQ05MEDUfF~TL<(E44~R3b-nGFMWC8fXv6OF(tR1V zrt9kuU_Fp3HS}8SyA1Y{;boKWu2XwQxD&a0uXyj^k>DUu1phqzP&hxy*!aCwWMxL? z^y=}LKQPANgJ%gWNLi1eFOF8Te(?g>Uwwi2^`uj%^U(dwZMs5xtTv}u`XSVw#pyD; z)>aU6SSH?tLJ95bNUvl4SBjtjw3~mbW(5^KK~v7{A3;NKi2v$N^6u)Ts^O8}zmLz^ zd?5H!>;1bdF0r$-Gche9K4mCS0Aw3d fpMWrYvs{pU4eLLi7RSqz^ r-(ymWux{yUH< z6{hIw*UuXSRs&=Q0JLFYVW2`KXf{j(oD9sM3SbRSSC`hnA$EP?S`>BSJ5NF;%o)m^ zs6|Cv$BLwk@3>AM2G%vhd}k8>RWSx=s`MP{?eNYXaMSoXQe5?;G_4O%WHW8Aqe5mj z;Gf)_PC*|ZqE+wcBkdw|m-O?1Eb%_xRAmVe^`8tRxE dr!U!@yS_q0su>tw6ShBYE$z6M9j%B>h;C0{~!`t*I z-1E?Lz}@9gA~U9>yjWpGSudBv#1({kJ*322LE~v%Hio{+u6FtLrneLU_##ux2{Q>o z$*nn~%YjBz<30rXec{@*oI RWfi#qCWwhN9sW)hHot{9j*4cpuo7&F*I3Z-1I4M*`3RPjY715vOo(lhO3ye zr0rh7zj&lfPug$==fb;NB$0TDcWbd@L86<+;&Mq{L87#kjFu%2_t&31dEz1bEW%b` z!HL4_j<4kVha{e+ZczUQZleq~Y&8n@8GB0tB** ~v9wK#KMtD~xuR+`_1 z%O%4$jFr9Yf1;Y=OmTNsS({XCSnJN6JDQpX{BNscXhg+xRWg{^*ua-Exu?%}v3BC@ z_+TqH_iCx(xb_pNeEsJoqiB`-7s_I%#(Kt0X=z787*X(;joYjXjIZA0jBW#ci!+)e zkr5@!QgO?Q?jk*;eh|$U9o;=Vq!A=5kJuGITYq^G#e!si2g>?Y0w%^|;AM1hE<8ij zsRF*s?gxk7r<|UWK-PTVi`-8(Hf)Ox2=M;qJF&Z3i(ew6E}|gBQ{am;G&Ga~p00-G z)w&!*+tt6d2piC2)sm1=z;pKK)tQT=>AcQtK73$*`6JUe^84>9Qxx=c(cRunu6s$e z_I{s*Kh36z%s5w-m6iEGctE;3Idn=y8OWt*XX%2-n7tsLyXk#;d~kBK2Y4sG1KU7Q z7xBuGxB=tX0YI=vCFt(A(o#^b^A;Buy(>Qh1Gc#MOqY(3A&xI_IQoMxVW7PieOT6@ z6@bmdsSm&+&(6+vb=`?d>D^EO!V~B6cX>u6UmRaj7wEe3?%QqF;{DRT<9^tP$ohe$ z(^&X815HG8g9N8a(A*HO(oc&L%tlWCA`T~_*Y9xAcnWP$$P;^&IsDMGrnIyapbyl0 z? YlQY&7}1REJvEdsn27GibS-RjDmRIeA~_8WuUQ;;F;4?6oFm8AvhqH>TwJ^5EAn9(qD2(ye<;YGK=FM z^3xm191C{7(3{REumGuv5W9d&AkDlHY*-B{BIS3k$0?J?4W@xDzoFv+p3-UU_e~X_ z%x^9U9l(|TQ$zF^KYVB>^q|Zwo_WR$Wf;4-WEbxiBBbvo;kK|G%~^<2Wnc*#Asf zv<(~F6Sd#I?Sgol{N{1U9;j--LN)2@jP|n@xWn!L_s_o6@Yba_y}fsnx`wXnxumKQ zcM@mmf>Q$822p0Pqb)lA0?)(e&)_}U%eX)gslrRA&lhJcew*10Y^1vH?tG!0qygeg zKaa2jD~DEfn(~rk=bnch^PgX5($aC|S`+YlS^bL|S%2*-)+TCSiZX-sL0Z5AspJZd zxJ}$1NsvU_%@g0h?*x~ktt;RKu;_rA8^VCX;x6HUi9z 1S~ F3=l%~W&7TdK;}zn#(hIx@09+l+MD{OQx? z^*sq@3Lz~-5r|Wn<9zK59CyPEN!p6RFa#T3gPSHq{swR9+B(hhXkJe8p-0py_+3Dr zQ2xZgz%V>Cgy6UpuT}n1KkwqpSSg0D+bm2>xWRz(TBbMIeU7R3$iI8AJ1joK0qLEE z8xm~1z+*#WV`C#D;JNSc(>qj+>$pOEAc_ j+_xoq`h%cJ$NmQ2F|q&$P0A1 zTv0>-t#ghskF~=4Ij(-It_C0sq 25rU{bbv3MRYHgI1HaexoR%O SV2Kp!HkPLQ6Y`#ZOw%l 8Cx;eN@S!?dHZW*KP wjby+Mqyi z9I8x29gP=99$o^uMOOAj$*6^;B}hXX8&hBaUEDirH^r}EyYnb!4bMB~id*ZJ1&%Yj zJK~|2!9Q0ltLeTT-_AlW7o($Awu6VqrK)pP*wgbkOt5Al#Ld($>ea12{R6cj(a(30 zYMjx$bY#GIySW_z31)kOdE*U=$rqNKOI)YYqSo!fxuvw=iew=b&3lXK1g97T<3hY| zxSzmJy^;bh`dt0IYcGk7nq6g1!Isi$Rtz2g` }nZcjVR_wAz833OfTTk7@s7ph|$bDp~>m>W))`Rv=o+k(NW@Psz7q+ad7$mm2Vc zXC8EgBNvd1-P}ekN_xwN(cho`X`B6LE)tqf=s2P{bzKghkEoM2B zXf1xWTUHAU7__})*Rym(lfSe6{H(?eIXNna%j+|3XcM?XSV#!OB_z5(NJ~gaSc)>M zhi(!lg|(X>9&dGX{07HgdM~f8aY%7$Px?__uYbT{VJ2oJH7{P_t~QhJcraUt562?( z4T)VJjRYhZ$ywjBmKS1#@srkIEglpYEi#n=lqL$mZ4&Nlcr|dFHO>ycBsdt{?j%yD zfbjuMf4J!o^zi}rXgCBdb2txxWKXWXdYmfAHT#Y0W2@hkIdO}fCkB+cX-0qj0_z$8 z(P#Q`8rT(8ZHL!Oor=%H7^!90sIKcwZ|)x+9zu(Le0<#06xeRQUEbSo%txms-s5 l(H{z22Z(5BI>&Ghz5Oq8<%j zU@N(@>8g_oP8OiwHm6%__y2~qx3{mQ<8dG54O;QU-h^AXvcmtYT)kQZyq}K>l{xR` z>vOaz{kXDsoqBnGuGlQKDfDL=+`MM9gf5GHebF#Bs|QeNy=&R;U_l8?oW%JFeCU5( zXxrZacH7$8z?~GyD*cV23Y(e6F6X%qs@-K8QoYwm3J7=-Y@CG^avMDAy5~j&Acw)0 zidBR(B^>A~6G8tlN^o5Zu_v0c_oHR^rmYTme!<9 strVAOB~W<;}mWeqhsi>q<8Y32is1*`1x8 z;7!}To}IQU=Ci$USB6b>{V~h|3|fKzyES{Z{gi@}RjSziPXrj3bM-ncwt(h=3YlBU zaCRm-Vm%_cVO;e>N_XBBln%5I@Egb8K9VeN)ws=y8LRMQKT+LH7 SOR04r);C1E?s%$ z)1w>=HXWZ+nZMt7wSlP@&6k<%PJhnKc?r~kJGK7~j(2yzfwOjJ>Ef@qAh3i~c)zQF zLh19b{Yp|&(zR>Xdg4$od6<=Ae!1YuZ@)~$ou%eFT)2qqt%O!3s7Un>zd=9XR%& DZM91zXAWHYN!02FrG>T4tUAOC=bnDaLr*5m=n z59BMk8KZZab6_ZfV`zw;&p(O`;Je5Dwy0~g65o7^0&H=9!)VvzOk8>W7gZBRodsZ- zZ!|3&4zq$`1x}jKa~ssr?u)(!_d>t@@fs6hVd2fe2PWVz0wVhg4JmIJ2OZX_+m+aY zXZpnfF26K*>#OG-rQ+YdZE0y)xb@mi=FiMbrg0%i5pf!XHy_gYD{wF$Wa;r;&cF3+ zjktlpxR3$;idE~rdYZ(OTuKptWw0T)!17!mz>8KRa7sn&TwYbi@oWnOR06gM{X7mF z;$d<<)!6nxo1O*y+sQI_-( 2Ag-*J2_W94n92;3)_jCy|rNHJgv%>*XNIdqBs z3a3|MaCZIX!P}+vUUKvJz@c^`a`(%oD@#0xi8H4j-v&^JS!eoIm{&N-_(mRzeqa+n zVg ?2*ii!deVibV%Xyh>PQ&V0@uRsEIU_myg)g=uX84#YOyK>rv9}W zuE^oFpet0K-rj$#O4A?Re5D!Hw2mHGJD*9g5=pQXNsAWvw8tUns^^gA^DA?_dtl&A zFGe~4g0aMQ#_r*@PsG10tHk_I%kiRT8tM0WPevyYBMSWH;5j~@@c9X(skJ!d5O8)@ z6cwRTWRYghM^?_UTcEPB>EqPEq#Uhw6P!$rlEK~%v?X|tY%Tl A zV(l$?-8wyqgO?lqh}(-f%?Q h?cJ&srV72 z_p}y=(LxKhk~oml3ylP{wY0#I91naOk7@2&cI2&|{M8bM>=Yw~j9$;(QA?6w>hJiG zksz1o4HiiI;`!UboX4Ug=$G*wgaP$negS)fx1;0N`MAwXxq4D!V$ioBaut|BKY1aZ zq|8fEP0QhN+eiMu(;J3xSSYzhgFD;(bZKR~I6rl3F{ce#iRmq7__CV{;wXa!`Xl~( zBi>D1F<_cMO#nv#_5Am5Pw;{Ly9w&c2}vv>47~oflJBAN2at^4Wb`PTJ`i#k{qyH^ zCRQ7eYW>MtD@Kt`9f?SlxbXGD*eVP=rVUSW5t@6|=*Z;3^w^@3Qw96Md)$%gdxwLo z&PrXN)WCdFShM}f;SMN?U^z& !hn-6NpNg9){Z!Z z+Wivfs0REEvge#)JN4zDmXVQnkOU-IgoF{F#zseRcY)u8lPvvHZ6)6(3z;Oo12|Ix zJX{%m-nPBi#8g#>rHOPl+7@anJr`$Z6648gsMXw$dYW0#eoTG}6lKu3q%Vkpc$YT_ z^c1JpfOZWdo4X7fF{5dZP(iy Sf-5d9Fl9 zkTNNaC=;-T=sbooE^ZnyyTqG#!;l(%7~#_Hku&w*O;@xSfO{}ltUcH9fFV2CRg4Jr z-x1w;Cp`z!;Kpzje5@CPfKlqYSA-9Y+AV0oEfl8yDhq7X0Lv}y36@fU6U!&mqXZqy z?Ukni6(Bp0{Kr0aF7NnXyA;_ j<}Ksm;_~yaN45qu%R&x3 z-rodj%++nX@C7t8kv_*yq(0R6oO$!p2bhKgu!eTHg#Lypt+pjA(L?}s9kU=3fVaW8 zF#F*)m;lU*L2Fm$RB%*<(W&$~s1r`lz+Rz;ja*v>1JBNmlll9*UZKv!M~P13^?qLS zW2@Ru+qZ8GUn*kRxCoVayBfPhJ%p3eO+^#{6po!8^}k-$9ei2S_+~SXr=&t4gXu(P zv=rsw3_m6t+VY7s7l1)bCnqN>D=TN`w;zj{2Gdlg&@jkSHU`V}ZONEd#lW68PROqp z?09Np>d|VBGhJ+Fx%Cm&CE$|}R|%*`8WzHY^8e0l-0!>lx@Pk^Oi}<%2AVM-93b8E z^`DfCYGu>bi~;`;O_ADK1^k${{D~-ngkMk)3N4*p>fi;Ez1NLP9~8VU;U)B9=uZDZ z;cRHYb8V2FzZ~BIFcf6(o&io4%8ZK=nKm$-8r%re%Hm1+mNB>t;GF@sebMo)#^vo< zyt%d85$hzBIFdPYRNf!Ip;oWrqHfXqGw8LUh-eGUz^<&4fte4n8G?PzLRnZ?c+S^% zA4@8eQ)eqJkbM@m;x5Z}Kux^dQk(Nf81vJQNpxy#(5V<@^rrUR!Tj{Le{zzdYuk7! z943GoUW10%s&U=o?3EgEb5(fb|Mvn|Z7k~00?!X4O6Mk!(_^ G)1twj0;^14_qY&SWr-^yh3w#c zwsNnpeKcFj&*Z zxJ_Oio06};40x-5QF)fdbIDVVs+K5xfA^R83=&ddpgE$F8gFr-`6#E}&!U9%zFazy zX8J2om2otFtVqQuie~BQwIK^QXDq>MW=QEb2jo+c47g 5 zUS0p<3_ =_HF@!0P! zDPRf$yQ3v4+#r>l%;W3P?Odz7AwxSE?uy2az=FqjG;#mVEBH1qD1C_9d4|i9*0#Kk zzXG%{FCAc8%HYOTXCPmp=U5pjhT`|LtE+b_xPAS^`wY}2$f#>;1@&muI(T>udFcYr z{rB6hGEjf*?CfCTQ1;tmA-L7S^{z8f1E!Bq< p5TNqew znzq9vfM$6)R$XuIpX+y^;JW95uK+50lDSV1-1;!n9R)_WoWaCEn% j%}EIEQyrL0uUzG*hKI=t}kf^&vO z%1I+vZ!PX4B2*b?0)(@gi HZCp<7f*9A z;t&lbO!Rpw8E&l=Q6X3A%2HUNq1b4#d#c=z`EJ-pNljkw^~8Bbs?9rU0zbZL>w%s! zSAMza?S^p3c15|H#SsXh<4a9p(#UnCFONpp85g78!1SQnJH?NRVD<&4Ij9GspDQDl z0~ON%R|hF_PzGm!qmupt!8CI16&DO8;_8F{Oio(*!fK~i3Ouf(+Uv-fFYa(En7yZ$ ztlqV6aS7G_urGr68ChR~P<#hmj%&5CYpVy73lPKB*5n^9+WiEKgVNT1`9?AgXngQ$ zFza9>{Aj*X(ye)a15aygd+PmbbbsgO=W9<7pXUg{Y@pC2o4ofiOls1lE8@d2ScWVT zMsfn$)M7MTKLtsSj*!FxOofECb>Lr*mSF>{ooj_kMsbQIWge|6-o8?s1xh %NOWNBLXbKgL* z0OrRJ#Ti{EKDFtZ>A=O0RK~yiAWVvWfoOVGOH&gjx4kvQ9_52Y0va57j(-+Qe>}WhT|saQQjak3k)*udEX?nYB0Z)|eAXs(r<8!~B-{ zE%lcwblvG11P5!-Ng42w3 _a2AnzI^XL z;J*EmdYtO`oX>e**Y&zyujj!AiU?%T=>$VelL76*oqo!`7EX<4k!arlB?daq(E?o7 zm&%}MW1${FuKynNsxm;6$Qf8Ai9zokcg?16g|{gP77It%f$fSD0GR0ydCWV8V}) zB@~wmoPt6M&$Bg}{tjEEL*rC;-g6<{sxeK2xNi_3l)j5U5Z`A5-fnR0uMLC4?g(bf zeV^=~7!N?8BH9=0Fb4O_3ZH}oB;51IHZL;qI6}<{+L6q1Nz^vzX}4m`aJH9k)PyFl z$SZ>~ByANBPfmhgQ$*@677G3s=`jV@++?+oKn2BhCLfMuMVW%62}gJzmKj8*9?{1) z6Oh$$B5=!Y!rd8~0%9917oc}X!nv 6sP^*&p#3UpY)TjsDyR}3VlP A3q`&I`P0P zY4s l63cn*-6- zb`+!dl?qE3G2*7JY08Zo`}Y>4P#O31syiGSD5Ab)W@op!Eq;gD%+3#o@2aK;!lCpf zg!%|s1j@Qz-GrF9_%ttL{a4^5!G7=x7F<_b6a1yaF&Ymg^1z8~%uS}Xd-)UNHX;M> zbK1ZvEqFeGD}jfHcO=0j=!J=jmLW$zy|0TxrGY~uu=nI%Yg~e0OpYaACeN&^knvj` zh;$NCDc#PnL!aI=X%qZiJpTnef$hS-{N~IpO^P8QFBr9kVj1f%NPHd`W&)iHIvT9b z2Y2Du|1zBcpxBxP9^Y1FeZ3<{jUNTFAzBDZ)HmtJD0GQ0BnailYz1KT;or9H1!uF5 zr6n45^2NRsD=Vv}{0Xe2VBHQXo)B+#I>2qNj2yJ%MaTCD7LQ_-@C0Wv$ch!%S1@`(c6%9ya1e$razoF+iVF8SNHK(C;mXweKMHX4 zD@I^!h22T!FJNB4rN5u40w;;SfdNF8vDEW*I8e_+a^b?)3Mk$)=Qa!2?<6w|kj5=M zHSv$W38q#c3EfA4Xa6ZFIjU@i9!m4h;Ed@i1EhouE8!nP$%DQkpN43jBIR!<#q(Co z)wKN&t{L4}DEk0gB31_PaC<+Td{3oBa^$t}=Ec}b7x-y!kE5=`f^N >?obHs(-u>yvK+t}#3dU_DcqZ`XrVTmEdKA~@Dk3&KKK$!BJ@Rq5* zz7R~*kf^q7FchVWVF}whL=L)PdIrIIGyy+`iOw$19rSW2XmDQv0|^$G>5Bi{rL_?` zY7Za^2cAcmx6_zrPjVi$nqnQ|_};DW0`+>D-420)rn>h-suF83^ S)1%Z~ z58-8SOcP=kFf)Ef_h8HxS`z0X?L9j?gG0oPWjhvM#~*^m+gn@t(YL%>fml?mwf9Bw zIgT@;4|0a2mI=V3fMr-jOU2Z7B)6TUyC%m=x+0QOj1LCi!M^9U-bQ(y?R;)6^4a422RXx^RR)B{t@yXd-!$`F=i-F(Nnz7 z7)^;{f|HaUoC^?H04pLRA*yPtsU#mCgnJ1LvyP_Fn(+%`zRkDMukZU1KF-X@Xo5o! zj%uYX-&xgY+uz{1v9SJ1i~h@V>5gbwi!B|BU&oIhKR}REP*CtEoj(=Z^Aw@} oK15f*+vtY#r>&I5pU|7y&95S6_qDLL#52wg$xXi+M z0KO8CUoenYP(pMLKAX@651T7g1|1^<%tz?4zBD(BN=RJ6NjCGz)4@#Fq)SQ|9hWlc zJBtU%aniQ) )eWVkaYnVGOlQhMQ zsxgQ54zmrn%wATc+F$ZCvlL7w(6Fz2ysm#Pr2wPBLk@YjiaGf$4DsI|HOPp65$y`4 zO9ZCtb3yB91tL3|u+JNrg6fA>3Dp7g+c-B!Oj-Ln?XGZylNbfOKN0A8EP{Ll18SfQ zcB#v~ c;Wx>%{Xt{~+pL?pTu?7bg>_B4U0= zwvbNiv1X8s !TR*LZKf?9`yQKtMAO^3%%28i6XxmwumRnIK{b zo*YG6kLDx+V)E$|N6D%Zb-i~N8NdXD77Fp?k8iP-u*Ptl_Z p49P*jRU`cagG*=6$2CuYA(62OfD1@$~YBD&7f_j$+6;h|8JMq_ndUD%wVH%-{p z6v1yHH?v}Pzb!CHneP=m!Fsnf>wtkl*D~SAlB$IL4da?|Bn$)=s1BQ>m0;5hotO&N zpe;QGhaA*LpqjMdZRRuLOkFmD%d)kKkW{r;E1Lca!uK$$D4uLPBqS41iF(}}{R*SX z*AEK)WUDWSY|$mn%@z}Sm+c!S|AUFaL9oyOdLa--!1 p;9l}SBNsR zq(Yy4iI@tS`*?PF1)imOutY@2fP=E#O`6xU>rv4wb->gl&A~1nPMaR U>4oAUTa77mS_Z+843Pl$5UD}uMj| |RNgsV$XFy80W@I&t zYa~Nk1ed0Cx7}w-0?q3|N-4Yu&W)+cOcaYddWe^s?0U!ko>uc(1rlP{%6T84StuVk zYw!~XV)pJsJ_uU<+eO*=gHukU$1P}EM6eYqLjfU#2?esVO-+i6_kXoq(=;Tn_7fXj zW )j9(KTgYs$WVu{{Md{ z8OKQ;ydTnujRd$4Am8g!Fy@A=45OY=s6+mn6dfxq>EDfgDi!``i6z@uQ6`ja)X;^$ zVK{SgecbNf@aMIx{(Amx9;*@EZMjHgIRqPB2-A`bHxqgY`C;Hb^5bd-IyO2{P~8}( z$C6L3yTQ}l%dJ-37=ug?k=B};p|LS iXP|1)>m~E$470|MPpvfGCFV)+auD=Stehh;q30H|^Ba z6ex+ffsd=uBe%CM$Haj*VSO-b-=J0gM)Au%%B_DD4%s4|%Y_2hpwHxPa5nA(`{;+n z3ioo>!=jtQI*&CWoDOt^pwnq@K#$bu|D1P~x&_1y8!r?AjyK8!7@1jF{%3ph2L}f` z4#FPi6 `DR?*_M-+=H$<&xFE1uD zk>7sCM%~u%$OZYxRuk_yrj>z!m{ )GTbUI+N1%@YTXn0|=Ws>i|@VSJXVc5ph zJJJ!BZJ;BpLMF#Rno?C)2eu!OoQD)uB)5Y^af*sxF+%reW1{``H~bWzKYRcRO#@g0 zkB*OftZf+^$}vxO?f*Tw8*eFa1#u|wcP#cxt32T2YY#lSxO^-=({UXAoHq;(^XnDG zHJJhiAYh!@)bZ}=jMUe}o}8nOYF%8H%6V7Nb-D;>#4>VoA=B;EoTF9`?H2^x!AQKN z6OmL5ySGd%&&~e82l^(yRTx;n%mIF-Vgbr}x$s--u2TJyV0&>bO2;8+5U(YFN=lg4 z5oR|+o{w#AZ*HbO@Kqlp9+E#r26SAXuxu7km3a?3@7!-PLIc5;+q6aK{{0V4O>Fd1 ziy=}YQV~ HH{Ah%QiZ1xU+sZTsT!#h;X()tQs={7k&;f zC_#$yhqVE)cQ6Hqe>;&!g4r@gGwu(5V_6~{07kO%@}6R2CBA?4iWGRNR04c_&p?o= zi+zvO_)npa?U@Hd%ByQk%04pSCq*s&oQFuKX0 *ioOpOoW1BhDXWM@N%Zkb@k>#I7Fa?ge+j OQKy;p8Txi;qj>Ps9d}^2V4;9vZT@9HzupCTG zJUwqP<_2ofHy%tZEO1`J*WRm2r`lx8R~F=8%=`ACzJBmHQ;`Xrpc8)buc(nFJ3G#r ziuHz-eCU4F4UW#vzqBD>@UqV)Pa;r6R1`|#&=x3AP$KIWVOZ++g&>Z_r<`0@ByOQB z;4ANPF5D>-zm?od^4KGpdZrj%=XOW;>gZN8OW)75dF)pXi6B!YmE{v4*7Gk7sj2SO z*6DKvI62;*0#$J6?7iUS)XWSwX{_<(k7lWH0P!N7V;wxH^8T&qeVZH*<)C47f?DTe0 z)~aW9Iw+-}p=GMPC_K;gVBhwPi(qK_&goZu&iho(SLglnJ{zmyJJar=*iE@qNsnZs z(H-g-dWQR6pYbX5RHmDvzbgUzDa ME#y&=h =74p lT0aRWo7o4zu@r{A1UXq zQv8y?8=gUjOAV1`IfvNKM?grBUj%83A6~%I@!X(oR=V1U-E28(WVjfUT{bp08o5O4 z8(_%jvBs{P52_0%b$JvV{AFqz mDQl{I5wIx5iDRHd zb#}^qC;0j6qSgsL2l8Mu^8h$b=M>}v%;m6c-mwaN&_LbwX9NrnH~o!4rgiM7|2Hcs zx%v1sy&sKUHW^xhUMW8QmMlBl`0>$^K;dPp=s&G($a}ICKx!WhCg76nU7izNdM=Ap zOQQxvMHnWP ?(^hRR60vLzjvM#)~y z=hyW4vnh8vW3nRLAf1-3oITCiEoGCg%FjNYNt3cIioB%IS+>yE+B QYERn=V3Wa+AUhJ$&eVRkS=qDPmio8ps3xr(U2skS@6V?o89!FO;^I|n?$}@c? ztlS1kIrZ}g6 IBiP=jhw_M96~EAbq*= z4f*D6J4?-Ede!e c(+Fem_J zQq)rH;Q`$bCn=E_V)BFADi?K^tO>HO!tk3jXwRV_p}CX~ok<;b9Qu+C6PnMsSTM#& z ?btfpdpwrR=`W9c&iE)U1p0>tb;@nRPk RZ$!3GIb$pvO?sQterBNQQZmaS5zFw!;oG#B`dkEk>zLm z?EE(wGgY1) TW&7P|Ow0((!Z6S)mCf#!;=~S!ev13U z@638H=8tgGIM2 f*4NqDx&0v0; ecu?4Y#>nx$LybPzA^^HzJGFC!cwbc| z>3 X)g}EsaE7Vk8IAC^7t}Ht8+(k`{HJJW_#41dtiq9IFo^}fQ zvHXU$;byGe`?8IQ2UT)GQf0z4iP~dW2h$|!FdIOLglzd+ooCI{*RBQMLzW!fW>;M? znmmXqpB7hC#IC;w8_4Ix*1sID%Pybkbh5WoEJ>`Sz7>7R%o_I@siw`g(paB4GGfvn zV;YO}eecINOB>xBp;hc07F4UV^kj8=@J70ov{%D}{1a6B><0wND_+9iZsaYgHO2?+ zL*aK7Qc+D(G4K<`**{~f S!67W7$P{W#Y3h{a4G-!W6VTs=j3#` z_9hW#l(o}~i}Ukq9A2LdZ+0n0*SzaZe0 }T!bci`w+EURSVe*jSbzey_}7CjKwsU#rh9c2WVlK$On4&%T5t}R(&@uN zD7HXV2j&5& @C%#Kj@qQzW8 zEIf_&8V o;}bT3qa9zOx`-*oWOQ;7!}x+Yb(E`yjXM03Me;3guZ_ zBx7V8$Gu2mXqE1g!2EECjNal=yrfGR{qI%~Y5G<>u!RHu1^17CHa0j!auiXbaZpa; zEL}t9L{+-hD!LX6HuRWD^HoYU*d_wI=lU&ct-tf@i{ K zI$d%C_(UTPZOtbl5thMKrE1zV+&|v}5mdI38^Dxrh5#kcMcP@Ae6k4d8W>>tjQ=#P z8-KO00@-L(>ybCp^-X7$_VXaj@gr!HmNn6$dE?qd6JI@uF}*xIy2<57EClnludg5b zEKb?*{5@7oZ{vWL3HsVky8fh b zL0yG63;d=B9`JvEJHZZ*P00Zc9ozrwTV~M+cx + +#define XYSSL_ERR_MPI_FILE_IO_ERROR -0x0002 +#define XYSSL_ERR_MPI_BAD_INPUT_DATA -0x0004 +#define XYSSL_ERR_MPI_INVALID_CHARACTER -0x0006 +#define XYSSL_ERR_MPI_BUFFER_TOO_SMALL -0x0008 +#define XYSSL_ERR_MPI_NEGATIVE_VALUE -0x000A +#define XYSSL_ERR_MPI_DIVISION_BY_ZERO -0x000C +#define XYSSL_ERR_MPI_NOT_ACCEPTABLE -0x000E + +#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup + +/* + * Define the base integer type, architecture-wise + */ +#if defined(XYSSL_HAVE_INT8) +typedef unsigned char t_int; +typedef unsigned short t_dbl; +#else +#if defined(XYSSL_HAVE_INT16) +typedef unsigned short t_int; +typedef unsigned long t_dbl; +#else + typedef unsigned long t_int; + #if defined(_MSC_VER) && defined(_M_IX86) + typedef unsigned __int64 t_dbl; + #else + #if defined(__amd64__) || defined(__x86_64__) || \ + defined(__ppc64__) || defined(__powerpc64__) || \ + defined(__ia64__) || defined(__alpha__) + typedef unsigned int t_dbl __attribute__((mode(TI))); + #else + typedef unsigned long long t_dbl; + #endif + #endif +#endif +#endif + +/** + * \brief MPI structure + */ +typedef struct +{ + int s; /*!< integer sign */ + int n; /*!< total # of limbs */ + t_int *p; /*!< pointer to limbs */ +} +mpi; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initialize one or more mpi + */ +void mpi_init( mpi *X, ... ); + +/** + * \brief Unallocate one or more mpi + */ +void mpi_free( mpi *X, ... ); + +/** + * \brief Enlarge to the specified number of limbs + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_grow( mpi *X, int nblimbs ); + +/** + * \brief Copy the contents of Y into X + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_copy( mpi *X, mpi *Y ); + +/** + * \brief Swap the contents of X and Y + */ +void mpi_swap( mpi *X, mpi *Y ); + +/** + * \brief Set value from integer + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_lset( mpi *X, int z ); + +/** + * \brief Return the number of least significant bits + */ +int mpi_lsb( mpi *X ); + +/** + * \brief Return the number of most significant bits + */ +int mpi_msb( mpi *X ); + +/** + * \brief Return the total size in bytes + */ +int mpi_size( mpi *X ); + +/** + * \brief Import from an ASCII string + * + * \param X destination mpi + * \param radix input numeric base + * \param s null-terminated string buffer + * + * \return 0 if successful, or an XYSSL_ERR_MPI_XXX error code + */ +int mpi_read_string( mpi *X, int radix, char *s ); + +/** + * \brief Export into an ASCII string + * + * \param X source mpi + * \param radix output numeric base + * \param s string buffer + * \param slen string buffer size + * + * \return 0 if successful, or an XYSSL_ERR_MPI_XXX error code + * + * \note Call this function with *slen = 0 to obtain the + * minimum required buffer size in *slen. + */ +int mpi_write_string( mpi *X, int radix, char *s, int *slen ); + +/** + * \brief Read X from an opened file + * + * \param X destination mpi + * \param radix input numeric base + * \param fin input file handle + * + * \return 0 if successful, or an XYSSL_ERR_MPI_XXX error code + */ +int mpi_read_file( mpi *X, int radix, FILE *fin ); + +/** + * \brief Write X into an opened file, or stdout + * + * \param p prefix, can be NULL + * \param X source mpi + * \param radix output numeric base + * \param fout output file handle + * + * \return 0 if successful, or an XYSSL_ERR_MPI_XXX error code + * + * \note Set fout == NULL to print X on the console. + */ +int mpi_write_file( char *p, mpi *X, int radix, FILE *fout ); + +/** + * \brief Import X from unsigned binary data, big endian + * + * \param X destination mpi + * \param buf input buffer + * \param buflen input buffer size + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_read_binary( mpi *X, unsigned char *buf, int buflen ); + +/** + * \brief Export X into unsigned binary data, big endian + * + * \param X source mpi + * \param buf output buffer + * \param buflen output buffer size + * + * \return 0 if successful, + * XYSSL_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough + * + * \note Call this function with *buflen = 0 to obtain the + * minimum required buffer size in *buflen. + */ +int mpi_write_binary( mpi *X, unsigned char *buf, int buflen ); + +/** + * \brief Left-shift: X <<= count + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_shift_l( mpi *X, int count ); + +/** + * \brief Right-shift: X >>= count + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_shift_r( mpi *X, int count ); + +/** + * \brief Compare unsigned values + * + * \return 1 if |X| is greater than |Y|, + * -1 if |X| is lesser than |Y| or + * 0 if |X| is equal to |Y| + */ +int mpi_cmp_abs( mpi *X, mpi *Y ); + +/** + * \brief Compare signed values + * + * \return 1 if X is greater than Y, + * -1 if X is lesser than Y or + * 0 if X is equal to Y + */ +int mpi_cmp_mpi( mpi *X, mpi *Y ); + +/** + * \brief Compare signed values + * + * \return 1 if X is greater than z, + * -1 if X is lesser than z or + * 0 if X is equal to z + */ +int mpi_cmp_int( mpi *X, int z ); + +/** + * \brief Unsigned addition: X = |A| + |B| + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_add_abs( mpi *X, mpi *A, mpi *B ); + +/** + * \brief Unsigned substraction: X = |A| - |B| + * + * \return 0 if successful, + * XYSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A + */ +int mpi_sub_abs( mpi *X, mpi *A, mpi *B ); + +/** + * \brief Signed addition: X = A + B + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_add_mpi( mpi *X, mpi *A, mpi *B ); + +/** + * \brief Signed substraction: X = A - B + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_sub_mpi( mpi *X, mpi *A, mpi *B ); + +/** + * \brief Signed addition: X = A + b + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_add_int( mpi *X, mpi *A, int b ); + +/** + * \brief Signed substraction: X = A - b + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_sub_int( mpi *X, mpi *A, int b ); + +/** + * \brief Baseline multiplication: X = A * B + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_mul_mpi( mpi *X, mpi *A, mpi *B ); + +/** + * \brief Baseline multiplication: X = A * b + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_mul_int( mpi *X, mpi *A, t_int b ); + +/** + * \brief Division by mpi: A = Q * B + R + * + * \return 0 if successful, + * 1 if memory allocation failed, + * XYSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0 + * + * \note Either Q or R can be NULL. + */ +int mpi_div_mpi( mpi *Q, mpi *R, mpi *A, mpi *B ); + +/** + * \brief Division by int: A = Q * b + R + * + * \return 0 if successful, + * 1 if memory allocation failed, + * XYSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0 + * + * \note Either Q or R can be NULL. + */ +int mpi_div_int( mpi *Q, mpi *R, mpi *A, int b ); + +/** + * \brief Modulo: R = A mod B + * + * \return 0 if successful, + * 1 if memory allocation failed, + * XYSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0 + */ +int mpi_mod_mpi( mpi *R, mpi *A, mpi *B ); + +/** + * \brief Modulo: r = A mod b + * + * \return 0 if successful, + * 1 if memory allocation failed, + * XYSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0 + */ +int mpi_mod_int( t_int *r, mpi *A, int b ); + +/** + * \brief Sliding-window exponentiation: X = A^E mod N + * + * \return 0 if successful, + * 1 if memory allocation failed, + * XYSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or even + * + * \note _RR is used to avoid re-computing R*R mod N across + * multiple calls, which speeds up things a bit. It can + * be set to NULL if the extra performance is unneeded. + */ +int mpi_exp_mod( mpi *X, mpi *A, mpi *E, mpi *N, mpi *_RR ); + +/** + * \brief Greatest common divisor: G = gcd(A, B) + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_gcd( mpi *G, mpi *A, mpi *B ); + +/** + * \brief Modular inverse: X = A^-1 mod N + * + * \return 0 if successful, + * 1 if memory allocation failed, + * XYSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or nil + * XYSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N + */ +int mpi_inv_mod( mpi *X, mpi *A, mpi *N ); + +/** + * \brief Miller-Rabin primality test + * + * \return 0 if successful (probably prime), + * 1 if memory allocation failed, + * XYSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime + */ +int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng ); + +/** + * \brief Prime number generation + * + * \param X destination mpi + * \param nbits required size of X in bits + * \param dh_flag if 1, then (X-1)/2 will be prime too + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * 1 if memory allocation failed, + * XYSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3 + */ +int mpi_gen_prime( mpi *X, int nbits, int dh_flag, + int (*f_rng)(void *), void *p_rng ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mpi_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* bignum.h */ diff --git a/include/polarssl/bn_mul.h b/include/polarssl/bn_mul.h new file mode 100644 index 000000000..4213e74f1 --- /dev/null +++ b/include/polarssl/bn_mul.h @@ -0,0 +1,700 @@ +/** + * \file bn_mul.h + */ +/* + * Multiply source vector [s] with b, add result + * to destination vector [d] and set carry c. + * + * Currently supports: + * + * . IA-32 (386+) . AMD64 / EM64T + * . IA-32 (SSE2) . Motorola 68000 + * . PowerPC, 32-bit . MicroBlaze + * . PowerPC, 64-bit . TriCore + * . SPARC v8 . ARM v3+ + * . Alpha . MIPS32 + * . C, longlong . C, generic + */ +#ifndef XYSSL_BN_MUL_H +#define XYSSL_BN_MUL_H + +#include "xyssl/config.h" + +#if defined(XYSSL_HAVE_ASM) + +#if defined(__GNUC__) +#if defined(__i386__) + +#define MULADDC_INIT \ + asm( "movl %%ebx, %0 " : "=m" (t)); \ + asm( "movl %0, %%esi " :: "m" (s)); \ + asm( "movl %0, %%edi " :: "m" (d)); \ + asm( "movl %0, %%ecx " :: "m" (c)); \ + asm( "movl %0, %%ebx " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "lodsl " ); \ + asm( "mull %ebx " ); \ + asm( "addl %ecx, %eax " ); \ + asm( "adcl $0, %edx " ); \ + asm( "addl (%edi), %eax " ); \ + asm( "adcl $0, %edx " ); \ + asm( "movl %edx, %ecx " ); \ + asm( "stosl " ); + +#if defined(XYSSL_HAVE_SSE2) + +#define MULADDC_HUIT \ + asm( "movd %ecx, %mm1 " ); \ + asm( "movd %ebx, %mm0 " ); \ + asm( "movd (%edi), %mm3 " ); \ + asm( "paddq %mm3, %mm1 " ); \ + asm( "movd (%esi), %mm2 " ); \ + asm( "pmuludq %mm0, %mm2 " ); \ + asm( "movd 4(%esi), %mm4 " ); \ + asm( "pmuludq %mm0, %mm4 " ); \ + asm( "movd 8(%esi), %mm6 " ); \ + asm( "pmuludq %mm0, %mm6 " ); \ + asm( "movd 12(%esi), %mm7 " ); \ + asm( "pmuludq %mm0, %mm7 " ); \ + asm( "paddq %mm2, %mm1 " ); \ + asm( "movd 4(%edi), %mm3 " ); \ + asm( "paddq %mm4, %mm3 " ); \ + asm( "movd 8(%edi), %mm5 " ); \ + asm( "paddq %mm6, %mm5 " ); \ + asm( "movd 12(%edi), %mm4 " ); \ + asm( "paddq %mm4, %mm7 " ); \ + asm( "movd %mm1, (%edi) " ); \ + asm( "movd 16(%esi), %mm2 " ); \ + asm( "pmuludq %mm0, %mm2 " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "movd 20(%esi), %mm4 " ); \ + asm( "pmuludq %mm0, %mm4 " ); \ + asm( "paddq %mm3, %mm1 " ); \ + asm( "movd 24(%esi), %mm6 " ); \ + asm( "pmuludq %mm0, %mm6 " ); \ + asm( "movd %mm1, 4(%edi) " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "movd 28(%esi), %mm3 " ); \ + asm( "pmuludq %mm0, %mm3 " ); \ + asm( "paddq %mm5, %mm1 " ); \ + asm( "movd 16(%edi), %mm5 " ); \ + asm( "paddq %mm5, %mm2 " ); \ + asm( "movd %mm1, 8(%edi) " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "paddq %mm7, %mm1 " ); \ + asm( "movd 20(%edi), %mm5 " ); \ + asm( "paddq %mm5, %mm4 " ); \ + asm( "movd %mm1, 12(%edi) " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "paddq %mm2, %mm1 " ); \ + asm( "movd 24(%edi), %mm5 " ); \ + asm( "paddq %mm5, %mm6 " ); \ + asm( "movd %mm1, 16(%edi) " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "paddq %mm4, %mm1 " ); \ + asm( "movd 28(%edi), %mm5 " ); \ + asm( "paddq %mm5, %mm3 " ); \ + asm( "movd %mm1, 20(%edi) " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "paddq %mm6, %mm1 " ); \ + asm( "movd %mm1, 24(%edi) " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "paddq %mm3, %mm1 " ); \ + asm( "movd %mm1, 28(%edi) " ); \ + asm( "addl $32, %edi " ); \ + asm( "addl $32, %esi " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "movd %mm1, %ecx " ); + +#define MULADDC_STOP \ + asm( "emms " ); \ + asm( "movl %0, %%ebx " :: "m" (t)); \ + asm( "movl %%ecx, %0 " : "=m" (c)); \ + asm( "movl %%edi, %0 " : "=m" (d)); \ + asm( "movl %%esi, %0 " : "=m" (s) :: \ + "eax", "ecx", "edx", "esi", "edi" ); + +#else + +#define MULADDC_STOP \ + asm( "movl %0, %%ebx " :: "m" (t)); \ + asm( "movl %%ecx, %0 " : "=m" (c)); \ + asm( "movl %%edi, %0 " : "=m" (d)); \ + asm( "movl %%esi, %0 " : "=m" (s) :: \ + "eax", "ecx", "edx", "esi", "edi" ); + +#endif /* SSE2 */ +#endif /* i386 */ + +#if defined(__amd64__) || defined (__x86_64__) + +#define MULADDC_INIT \ + asm( "movq %0, %%rsi " :: "m" (s)); \ + asm( "movq %0, %%rdi " :: "m" (d)); \ + asm( "movq %0, %%rcx " :: "m" (c)); \ + asm( "movq %0, %%rbx " :: "m" (b)); \ + asm( "xorq %r8, %r8 " ); + +#define MULADDC_CORE \ + asm( "movq (%rsi),%rax " ); \ + asm( "mulq %rbx " ); \ + asm( "addq $8, %rsi " ); \ + asm( "addq %rcx, %rax " ); \ + asm( "movq %r8, %rcx " ); \ + asm( "adcq $0, %rdx " ); \ + asm( "nop " ); \ + asm( "addq %rax, (%rdi) " ); \ + asm( "adcq %rdx, %rcx " ); \ + asm( "addq $8, %rdi " ); + +#define MULADDC_STOP \ + asm( "movq %%rcx, %0 " : "=m" (c)); \ + asm( "movq %%rdi, %0 " : "=m" (d)); \ + asm( "movq %%rsi, %0 " : "=m" (s) :: \ + "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" ); + +#endif /* AMD64 */ + +#if defined(__mc68020__) || defined(__mcpu32__) + +#define MULADDC_INIT \ + asm( "movl %0, %%a2 " :: "m" (s)); \ + asm( "movl %0, %%a3 " :: "m" (d)); \ + asm( "movl %0, %%d3 " :: "m" (c)); \ + asm( "movl %0, %%d2 " :: "m" (b)); \ + asm( "moveq #0, %d0 " ); + +#define MULADDC_CORE \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "moveq #0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "addxl %d4, %d3 " ); + +#define MULADDC_STOP \ + asm( "movl %%d3, %0 " : "=m" (c)); \ + asm( "movl %%a3, %0 " : "=m" (d)); \ + asm( "movl %%a2, %0 " : "=m" (s) :: \ + "d0", "d1", "d2", "d3", "d4", "a2", "a3" ); + +#define MULADDC_HUIT \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "addxl %d0, %d3 " ); + +#endif /* MC68000 */ + +#if defined(__powerpc__) || defined(__ppc__) +#if defined(__powerpc64__) || defined(__ppc64__) + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( "ld r3, %0 " :: "m" (s)); \ + asm( "ld r4, %0 " :: "m" (d)); \ + asm( "ld r5, %0 " :: "m" (c)); \ + asm( "ld r6, %0 " :: "m" (b)); \ + asm( "addi r3, r3, -8 " ); \ + asm( "addi r4, r4, -8 " ); \ + asm( "addic r5, r5, 0 " ); + +#define MULADDC_CORE \ + asm( "ldu r7, 8(r3) " ); \ + asm( "mulld r8, r7, r6 " ); \ + asm( "mulhdu r9, r7, r6 " ); \ + asm( "adde r8, r8, r5 " ); \ + asm( "ld r7, 8(r4) " ); \ + asm( "addze r5, r9 " ); \ + asm( "addc r8, r8, r7 " ); \ + asm( "stdu r8, 8(r4) " ); + +#define MULADDC_STOP \ + asm( "addze r5, r5 " ); \ + asm( "addi r4, r4, 8 " ); \ + asm( "addi r3, r3, 8 " ); \ + asm( "std r5, %0 " : "=m" (c)); \ + asm( "std r4, %0 " : "=m" (d)); \ + asm( "std r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#else + +#define MULADDC_INIT \ + asm( "ld %%r3, %0 " :: "m" (s)); \ + asm( "ld %%r4, %0 " :: "m" (d)); \ + asm( "ld %%r5, %0 " :: "m" (c)); \ + asm( "ld %%r6, %0 " :: "m" (b)); \ + asm( "addi %r3, %r3, -8 " ); \ + asm( "addi %r4, %r4, -8 " ); \ + asm( "addic %r5, %r5, 0 " ); + +#define MULADDC_CORE \ + asm( "ldu %r7, 8(%r3) " ); \ + asm( "mulld %r8, %r7, %r6 " ); \ + asm( "mulhdu %r9, %r7, %r6 " ); \ + asm( "adde %r8, %r8, %r5 " ); \ + asm( "ld %r7, 8(%r4) " ); \ + asm( "addze %r5, %r9 " ); \ + asm( "addc %r8, %r8, %r7 " ); \ + asm( "stdu %r8, 8(%r4) " ); + +#define MULADDC_STOP \ + asm( "addze %r5, %r5 " ); \ + asm( "addi %r4, %r4, 8 " ); \ + asm( "addi %r3, %r3, 8 " ); \ + asm( "std %%r5, %0 " : "=m" (c)); \ + asm( "std %%r4, %0 " : "=m" (d)); \ + asm( "std %%r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#endif + +#else /* PPC32 */ + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( "lwz r3, %0 " :: "m" (s)); \ + asm( "lwz r4, %0 " :: "m" (d)); \ + asm( "lwz r5, %0 " :: "m" (c)); \ + asm( "lwz r6, %0 " :: "m" (b)); \ + asm( "addi r3, r3, -4 " ); \ + asm( "addi r4, r4, -4 " ); \ + asm( "addic r5, r5, 0 " ); + +#define MULADDC_CORE \ + asm( "lwzu r7, 4(r3) " ); \ + asm( "mullw r8, r7, r6 " ); \ + asm( "mulhwu r9, r7, r6 " ); \ + asm( "adde r8, r8, r5 " ); \ + asm( "lwz r7, 4(r4) " ); \ + asm( "addze r5, r9 " ); \ + asm( "addc r8, r8, r7 " ); \ + asm( "stwu r8, 4(r4) " ); + +#define MULADDC_STOP \ + asm( "addze r5, r5 " ); \ + asm( "addi r4, r4, 4 " ); \ + asm( "addi r3, r3, 4 " ); \ + asm( "stw r5, %0 " : "=m" (c)); \ + asm( "stw r4, %0 " : "=m" (d)); \ + asm( "stw r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#else + +#define MULADDC_INIT \ + asm( "lwz %%r3, %0 " :: "m" (s)); \ + asm( "lwz %%r4, %0 " :: "m" (d)); \ + asm( "lwz %%r5, %0 " :: "m" (c)); \ + asm( "lwz %%r6, %0 " :: "m" (b)); \ + asm( "addi %r3, %r3, -4 " ); \ + asm( "addi %r4, %r4, -4 " ); \ + asm( "addic %r5, %r5, 0 " ); + +#define MULADDC_CORE \ + asm( "lwzu %r7, 4(%r3) " ); \ + asm( "mullw %r8, %r7, %r6 " ); \ + asm( "mulhwu %r9, %r7, %r6 " ); \ + asm( "adde %r8, %r8, %r5 " ); \ + asm( "lwz %r7, 4(%r4) " ); \ + asm( "addze %r5, %r9 " ); \ + asm( "addc %r8, %r8, %r7 " ); \ + asm( "stwu %r8, 4(%r4) " ); + +#define MULADDC_STOP \ + asm( "addze %r5, %r5 " ); \ + asm( "addi %r4, %r4, 4 " ); \ + asm( "addi %r3, %r3, 4 " ); \ + asm( "stw %%r5, %0 " : "=m" (c)); \ + asm( "stw %%r4, %0 " : "=m" (d)); \ + asm( "stw %%r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#endif + +#endif /* PPC32 */ +#endif /* PPC64 */ + +#if defined(__sparc__) + +#define MULADDC_INIT \ + asm( "ld %0, %%o0 " :: "m" (s)); \ + asm( "ld %0, %%o1 " :: "m" (d)); \ + asm( "ld %0, %%o2 " :: "m" (c)); \ + asm( "ld %0, %%o3 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "ld [%o0], %o4 " ); \ + asm( "inc 4, %o0 " ); \ + asm( "ld [%o1], %o5 " ); \ + asm( "umul %o3, %o4, %o4 " ); \ + asm( "addcc %o4, %o2, %o4 " ); \ + asm( "rd %y, %g1 " ); \ + asm( "addx %g1, 0, %g1 " ); \ + asm( "addcc %o4, %o5, %o4 " ); \ + asm( "st %o4, [%o1] " ); \ + asm( "addx %g1, 0, %o2 " ); \ + asm( "inc 4, %o1 " ); + +#define MULADDC_STOP \ + asm( "st %%o2, %0 " : "=m" (c)); \ + asm( "st %%o1, %0 " : "=m" (d)); \ + asm( "st %%o0, %0 " : "=m" (s) :: \ + "g1", "o0", "o1", "o2", "o3", "o4", "o5" ); + +#endif /* SPARCv8 */ + +#if defined(__microblaze__) || defined(microblaze) + +#define MULADDC_INIT \ + asm( "lwi r3, %0 " :: "m" (s)); \ + asm( "lwi r4, %0 " :: "m" (d)); \ + asm( "lwi r5, %0 " :: "m" (c)); \ + asm( "lwi r6, %0 " :: "m" (b)); \ + asm( "andi r7, r6, 0xffff" ); \ + asm( "bsrli r6, r6, 16 " ); + +#define MULADDC_CORE \ + asm( "lhui r8, r3, 0 " ); \ + asm( "addi r3, r3, 2 " ); \ + asm( "lhui r9, r3, 0 " ); \ + asm( "addi r3, r3, 2 " ); \ + asm( "mul r10, r9, r6 " ); \ + asm( "mul r11, r8, r7 " ); \ + asm( "mul r12, r9, r7 " ); \ + asm( "mul r13, r8, r6 " ); \ + asm( "bsrli r8, r10, 16 " ); \ + asm( "bsrli r9, r11, 16 " ); \ + asm( "add r13, r13, r8 " ); \ + asm( "add r13, r13, r9 " ); \ + asm( "bslli r10, r10, 16 " ); \ + asm( "bslli r11, r11, 16 " ); \ + asm( "add r12, r12, r10 " ); \ + asm( "addc r13, r13, r0 " ); \ + asm( "add r12, r12, r11 " ); \ + asm( "addc r13, r13, r0 " ); \ + asm( "lwi r10, r4, 0 " ); \ + asm( "add r12, r12, r10 " ); \ + asm( "addc r13, r13, r0 " ); \ + asm( "add r12, r12, r5 " ); \ + asm( "addc r5, r13, r0 " ); \ + asm( "swi r12, r4, 0 " ); \ + asm( "addi r4, r4, 4 " ); + +#define MULADDC_STOP \ + asm( "swi r5, %0 " : "=m" (c)); \ + asm( "swi r4, %0 " : "=m" (d)); \ + asm( "swi r3, %0 " : "=m" (s) :: \ + "r3", "r4" , "r5" , "r6" , "r7" , "r8" , \ + "r9", "r10", "r11", "r12", "r13" ); + +#endif /* MicroBlaze */ + +#if defined(__tricore__) + +#define MULADDC_INIT \ + asm( "ld.a %%a2, %0 " :: "m" (s)); \ + asm( "ld.a %%a3, %0 " :: "m" (d)); \ + asm( "ld.w %%d4, %0 " :: "m" (c)); \ + asm( "ld.w %%d1, %0 " :: "m" (b)); \ + asm( "xor %d5, %d5 " ); + +#define MULADDC_CORE \ + asm( "ld.w %d0, [%a2+] " ); \ + asm( "madd.u %e2, %e4, %d0, %d1 " ); \ + asm( "ld.w %d0, [%a3] " ); \ + asm( "addx %d2, %d2, %d0 " ); \ + asm( "addc %d3, %d3, 0 " ); \ + asm( "mov %d4, %d3 " ); \ + asm( "st.w [%a3+], %d2 " ); + +#define MULADDC_STOP \ + asm( "st.w %0, %%d4 " : "=m" (c)); \ + asm( "st.a %0, %%a3 " : "=m" (d)); \ + asm( "st.a %0, %%a2 " : "=m" (s) :: \ + "d0", "d1", "e2", "d4", "a2", "a3" ); + +#endif /* TriCore */ + +#if defined(__arm__) + +#define MULADDC_INIT \ + asm( "ldr r0, %0 " :: "m" (s)); \ + asm( "ldr r1, %0 " :: "m" (d)); \ + asm( "ldr r2, %0 " :: "m" (c)); \ + asm( "ldr r3, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "ldr r4, [r0], #4 " ); \ + asm( "mov r5, #0 " ); \ + asm( "ldr r6, [r1] " ); \ + asm( "umlal r2, r5, r3, r4 " ); \ + asm( "adds r7, r6, r2 " ); \ + asm( "adc r2, r5, #0 " ); \ + asm( "str r7, [r1], #4 " ); + +#define MULADDC_STOP \ + asm( "str r2, %0 " : "=m" (c)); \ + asm( "str r1, %0 " : "=m" (d)); \ + asm( "str r0, %0 " : "=m" (s) :: \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" ); + +#endif /* ARMv3 */ + +#if defined(__alpha__) + +#define MULADDC_INIT \ + asm( "ldq $1, %0 " :: "m" (s)); \ + asm( "ldq $2, %0 " :: "m" (d)); \ + asm( "ldq $3, %0 " :: "m" (c)); \ + asm( "ldq $4, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "ldq $6, 0($1) " ); \ + asm( "addq $1, 8, $1 " ); \ + asm( "mulq $6, $4, $7 " ); \ + asm( "umulh $6, $4, $6 " ); \ + asm( "addq $7, $3, $7 " ); \ + asm( "cmpult $7, $3, $3 " ); \ + asm( "ldq $5, 0($2) " ); \ + asm( "addq $7, $5, $7 " ); \ + asm( "cmpult $7, $5, $5 " ); \ + asm( "stq $7, 0($2) " ); \ + asm( "addq $2, 8, $2 " ); \ + asm( "addq $6, $3, $3 " ); \ + asm( "addq $5, $3, $3 " ); + +#define MULADDC_STOP \ + asm( "stq $3, %0 " : "=m" (c)); \ + asm( "stq $2, %0 " : "=m" (d)); \ + asm( "stq $1, %0 " : "=m" (s) :: \ + "$1", "$2", "$3", "$4", "$5", "$6", "$7" ); + +#endif /* Alpha */ + +#if defined(__mips__) + +#define MULADDC_INIT \ + asm( "lw $10, %0 " :: "m" (s)); \ + asm( "lw $11, %0 " :: "m" (d)); \ + asm( "lw $12, %0 " :: "m" (c)); \ + asm( "lw $13, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "lw $14, 0($10) " ); \ + asm( "multu $13, $14 " ); \ + asm( "addi $10, $10, 4 " ); \ + asm( "mflo $14 " ); \ + asm( "mfhi $9 " ); \ + asm( "addu $14, $12, $14 " ); \ + asm( "lw $15, 0($11) " ); \ + asm( "sltu $12, $14, $12 " ); \ + asm( "addu $15, $14, $15 " ); \ + asm( "sltu $14, $15, $14 " ); \ + asm( "addu $12, $12, $9 " ); \ + asm( "sw $15, 0($11) " ); \ + asm( "addu $12, $12, $14 " ); \ + asm( "addi $11, $11, 4 " ); + +#define MULADDC_STOP \ + asm( "sw $12, %0 " : "=m" (c)); \ + asm( "sw $11, %0 " : "=m" (d)); \ + asm( "sw $10, %0 " : "=m" (s) :: \ + "$9", "$10", "$11", "$12", "$13", "$14", "$15" ); + +#endif /* MIPS */ +#endif /* GNUC */ + +#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) + +#define MULADDC_INIT \ + __asm mov esi, s \ + __asm mov edi, d \ + __asm mov ecx, c \ + __asm mov ebx, b + +#define MULADDC_CORE \ + __asm lodsd \ + __asm mul ebx \ + __asm add eax, ecx \ + __asm adc edx, 0 \ + __asm add eax, [edi] \ + __asm adc edx, 0 \ + __asm mov ecx, edx \ + __asm stosd + +#if defined(XYSSL_HAVE_SSE2) + +#define EMIT __asm _emit + +#define MULADDC_HUIT \ + EMIT 0x0F EMIT 0x6E EMIT 0xC9 \ + EMIT 0x0F EMIT 0x6E EMIT 0xC3 \ + EMIT 0x0F EMIT 0x6E EMIT 0x1F \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x16 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xEE \ + EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xFC \ + EMIT 0x0F EMIT 0x7E EMIT 0x0F \ + EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCD \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCF \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDD \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCE \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \ + EMIT 0x83 EMIT 0xC7 EMIT 0x20 \ + EMIT 0x83 EMIT 0xC6 EMIT 0x20 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x7E EMIT 0xC9 + +#define MULADDC_STOP \ + EMIT 0x0F EMIT 0x77 \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#else + +#define MULADDC_STOP \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#endif /* SSE2 */ +#endif /* MSVC */ + +#endif /* XYSSL_HAVE_ASM */ + +#if !defined(MULADDC_CORE) +#if defined(XYSSL_HAVE_LONGLONG) + +#define MULADDC_INIT \ +{ \ + t_dbl r; \ + t_int r0, r1; + +#define MULADDC_CORE \ + r = *(s++) * (t_dbl) b; \ + r0 = r; \ + r1 = r >> biL; \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#else +#define MULADDC_INIT \ +{ \ + t_int s0, s1, b0, b1; \ + t_int r0, r1, rx, ry; \ + b0 = ( b << biH ) >> biH; \ + b1 = ( b >> biH ); + +#define MULADDC_CORE \ + s0 = ( *s << biH ) >> biH; \ + s1 = ( *s >> biH ); s++; \ + rx = s0 * b1; r0 = s0 * b0; \ + ry = s1 * b0; r1 = s1 * b1; \ + r1 += ( rx >> biH ); \ + r1 += ( ry >> biH ); \ + rx <<= biH; ry <<= biH; \ + r0 += rx; r1 += (r0 < rx); \ + r0 += ry; r1 += (r0 < ry); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#endif /* C (generic) */ +#endif /* C (longlong) */ + +#endif /* bn_mul.h */ diff --git a/include/polarssl/certs.h b/include/polarssl/certs.h new file mode 100644 index 000000000..7b91bafbe --- /dev/null +++ b/include/polarssl/certs.h @@ -0,0 +1,24 @@ +/** + * \file certs.h + */ +#ifndef XYSSL_CERTS_H +#define XYSSL_CERTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern char test_ca_crt[]; +extern char test_ca_key[]; +extern char test_ca_pwd[]; +extern char test_srv_crt[]; +extern char test_srv_key[]; +extern char test_cli_crt[]; +extern char test_cli_key[]; +extern char xyssl_ca_crt[]; + +#ifdef __cplusplus +} +#endif + +#endif /* certs.h */ diff --git a/include/polarssl/config.h b/include/polarssl/config.h new file mode 100644 index 000000000..f0c760960 --- /dev/null +++ b/include/polarssl/config.h @@ -0,0 +1,284 @@ +/** + * \file config.h + * + * This set of compile-time options may be used to enable + * or disable features selectively, and reduce the global + * memory footprint. + */ +#ifndef XYSSL_CONFIG_H +#define XYSSL_CONFIG_H + +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +/* + * Uncomment if native integers are 8-bit wide. + * +#define XYSSL_HAVE_INT8 + */ + +/* + * Uncomment if native integers are 16-bit wide. + * +#define XYSSL_HAVE_INT16 + */ + +/* + * Uncomment if the compiler supports long long. + * +#define XYSSL_HAVE_LONGLONG + */ + +/* + * Uncomment to enable the use of assembly code. + */ +#define XYSSL_HAVE_ASM + +/* + * Uncomment if the CPU supports SSE2 (IA-32 specific). + * +#define XYSSL_HAVE_SSE2 + */ + +/* + * Enable all SSL/TLS debugging messages. + */ +#define XYSSL_DEBUG_MSG + +/* + * Enable the checkup functions (*_self_test). + */ +#define XYSSL_SELF_TEST + +/* + * Enable the prime-number generation code. + */ +#define XYSSL_GENPRIME + +/* + * Uncomment this macro to store the AES tables in ROM. + * +#define XYSSL_AES_ROM_TABLES + */ + +/* + * Module: library/aes.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites: + * SSL_RSA_AES_128_SHA + * SSL_RSA_AES_256_SHA + * SSL_EDH_RSA_AES_256_SHA + */ +#define XYSSL_AES_C + +/* + * Module: library/arc4.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites: + * SSL_RSA_RC4_128_MD5 + * SSL_RSA_RC4_128_SHA + */ +#define XYSSL_ARC4_C + +/* + * Module: library/base64.c + * Caller: library/x509parse.c + * + * This module is required for X.509 support. + */ +#define XYSSL_BASE64_C + +/* + * Module: library/bignum.c + * Caller: library/dhm.c + * library/rsa.c + * library/ssl_tls.c + * library/x509parse.c + * + * This module is required for RSA and DHM support. + */ +#define XYSSL_BIGNUM_C + +/* + * Module: library/certs.c + * Caller: + * + * This module is used for testing (ssl_client/server). + */ +#define XYSSL_CERTS_C + +/* + * Module: library/debug.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module provides debugging functions. + */ +#define XYSSL_DEBUG_C + +/* + * Module: library/des.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites: + * SSL_RSA_DES_168_SHA + * SSL_EDH_RSA_DES_168_SHA + */ +#define XYSSL_DES_C + +/* + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module enables the following ciphersuites: + * SSL_EDH_RSA_DES_168_SHA + * SSL_EDH_RSA_AES_256_SHA + */ +#define XYSSL_DHM_C + +/* + * Module: library/havege.c + * Caller: + * + * This module enables the HAVEGE random number generator. + */ +#define XYSSL_HAVEGE_C + +/* + * Module: library/md2.c + * Caller: library/x509parse.c + * + * Uncomment to enable support for (rare) MD2-signed X.509 certs. + * +#define XYSSL_MD2_C + */ + +/* + * Module: library/md4.c + * Caller: library/x509parse.c + * + * Uncomment to enable support for (rare) MD4-signed X.509 certs. + * +#define XYSSL_MD4_C + */ + +/* + * Module: library/md5.c + * Caller: library/ssl_tls.c + * library/x509parse.c + * + * This module is required for SSL/TLS and X.509. + */ +#define XYSSL_MD5_C + +/* + * Module: library/net.c + * Caller: + * + * This module provides TCP/IP networking routines. + */ +#define XYSSL_NET_C + +/* + * Module: library/padlock.c + * Caller: library/aes.c + * + * This modules adds support for the VIA PadLock on x86. + */ +#define XYSSL_PADLOCK_C + +/* + * Module: library/rsa.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * This module is required for SSL/TLS and MD5-signed certificates. + */ +#define XYSSL_RSA_C + +/* + * Module: library/sha1.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509parse.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ +#define XYSSL_SHA1_C + +/* + * Module: library/sha2.c + * Caller: + * + * This module adds support for SHA-224 and SHA-256. + */ +#define XYSSL_SHA2_C + +/* + * Module: library/sha4.c + * Caller: + * + * This module adds support for SHA-384 and SHA-512. + */ +#define XYSSL_SHA4_C + +/* + * Module: library/ssl_cli.c + * Caller: + * + * This module is required for SSL/TLS client support. + */ +#define XYSSL_SSL_CLI_C + +/* + * Module: library/ssl_srv.c + * Caller: + * + * This module is required for SSL/TLS server support. + */ +#define XYSSL_SSL_SRV_C + +/* + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is required for SSL/TLS. + */ +#define XYSSL_SSL_TLS_C + +/* + * Module: library/timing.c + * Caller: library/havege.c + * + * This module is used by the HAVEGE random number generator. + */ +#define XYSSL_TIMING_C + +/* + * Module: library/x509parse.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module is required for X.509 certificate parsing. + */ +#define XYSSL_X509_PARSE_C + +/* + * Module: library/x509_write.c + * Caller: + * + * This module is required for X.509 certificate writing. + */ +#define XYSSL_X509_WRITE_C + +#endif /* config.h */ diff --git a/include/polarssl/debug.h b/include/polarssl/debug.h new file mode 100644 index 000000000..1ffb0ecee --- /dev/null +++ b/include/polarssl/debug.h @@ -0,0 +1,63 @@ +/** + * \file debug.h + */ +#ifndef SSL_DEBUG_H +#define SSL_DEBUG_H + +#include "xyssl/config.h" +#include "xyssl/ssl.h" + +#if defined(XYSSL_DEBUG_MSG) + +#define SSL_DEBUG_MSG( level, args ) \ + debug_print_msg( ssl, level, __FILE__, __LINE__, debug_fmt args ); + +#define SSL_DEBUG_RET( level, text, ret ) \ + debug_print_ret( ssl, level, __FILE__, __LINE__, text, ret ); + +#define SSL_DEBUG_BUF( level, text, buf, len ) \ + debug_print_buf( ssl, level, __FILE__, __LINE__, text, buf, len ); + +#define SSL_DEBUG_MPI( level, text, X ) \ + debug_print_mpi( ssl, level, __FILE__, __LINE__, text, X ); + +#define SSL_DEBUG_CRT( level, text, crt ) \ + debug_print_crt( ssl, level, __FILE__, __LINE__, text, crt ); + +#else + +#define SSL_DEBUG_MSG( level, args ) do { } while( 0 ) +#define SSL_DEBUG_RET( level, text, ret ) do { } while( 0 ) +#define SSL_DEBUG_BUF( level, text, buf, len ) do { } while( 0 ) +#define SSL_DEBUG_MPI( level, text, X ) do { } while( 0 ) +#define SSL_DEBUG_CRT( level, text, crt ) do { } while( 0 ) + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +char *debug_fmt( const char *format, ... ); + +void debug_print_msg( ssl_context *ssl, int level, + char *file, int line, char *text ); + +void debug_print_ret( ssl_context *ssl, int level, + char *file, int line, char *text, int ret ); + +void debug_print_buf( ssl_context *ssl, int level, + char *file, int line, char *text, + unsigned char *buf, int len ); + +void debug_print_mpi( ssl_context *ssl, int level, + char *file, int line, char *text, mpi *X ); + +void debug_print_crt( ssl_context *ssl, int level, + char *file, int line, char *text, x509_cert *crt ); + +#ifdef __cplusplus +} +#endif + +#endif /* debug.h */ diff --git a/include/polarssl/des.h b/include/polarssl/des.h new file mode 100644 index 000000000..f118eac4e --- /dev/null +++ b/include/polarssl/des.h @@ -0,0 +1,149 @@ +/** + * \file des.h + */ +#ifndef XYSSL_DES_H +#define XYSSL_DES_H + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +/** + * \brief DES context structure + */ +typedef struct +{ + int mode; /*!< encrypt/decrypt */ + unsigned long sk[32]; /*!< DES subkeys */ +} +des_context; + +/** + * \brief Triple-DES context structure + */ +typedef struct +{ + int mode; /*!< encrypt/decrypt */ + unsigned long sk[96]; /*!< 3DES subkeys */ +} +des3_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief DES key schedule (56-bit, encryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + */ +void des_setkey_enc( des_context *ctx, unsigned char key[8] ); + +/** + * \brief DES key schedule (56-bit, decryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + */ +void des_setkey_dec( des_context *ctx, unsigned char key[8] ); + +/** + * \brief Triple-DES key schedule (112-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + */ +void des3_set2key_enc( des3_context *ctx, unsigned char key[16] ); + +/** + * \brief Triple-DES key schedule (112-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + */ +void des3_set2key_dec( des3_context *ctx, unsigned char key[16] ); + +/** + * \brief Triple-DES key schedule (168-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + */ +void des3_set3key_enc( des3_context *ctx, unsigned char key[24] ); + +/** + * \brief Triple-DES key schedule (168-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + */ +void des3_set3key_dec( des3_context *ctx, unsigned char key[24] ); + +/** + * \brief DES-ECB block encryption/decryption + * + * \param ctx DES context + * \param input 64-bit input block + * \param output 64-bit output block + */ +void des_crypt_ecb( des_context *ctx, + unsigned char input[8], + unsigned char output[8] ); + +/** + * \brief DES-CBC buffer encryption/decryption + * + * \param ctx DES context + * \param mode DES_ENCRYPT or DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + */ +void des_crypt_cbc( des_context *ctx, + int mode, + int length, + unsigned char iv[8], + unsigned char *input, + unsigned char *output ); + +/** + * \brief 3DES-ECB block encryption/decryption + * + * \param ctx 3DES context + * \param input 64-bit input block + * \param output 64-bit output block + */ +void des3_crypt_ecb( des3_context *ctx, + unsigned char input[8], + unsigned char output[8] ); + +/** + * \brief 3DES-CBC buffer encryption/decryption + * + * \param ctx 3DES context + * \param mode DES_ENCRYPT or DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + */ +void des3_crypt_cbc( des3_context *ctx, + int mode, + int length, + unsigned char iv[8], + unsigned char *input, + unsigned char *output ); + +/* + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int des_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* des.h */ diff --git a/include/polarssl/dhm.h b/include/polarssl/dhm.h new file mode 100644 index 000000000..127d626ca --- /dev/null +++ b/include/polarssl/dhm.h @@ -0,0 +1,122 @@ +/** + * \file dhm.h + */ +#ifndef XYSSL_DHM_H +#define XYSSL_DHM_H + +#include "xyssl/bignum.h" + +#define XYSSL_ERR_DHM_BAD_INPUT_DATA -0x0480 +#define XYSSL_ERR_DHM_READ_PARAMS_FAILED -0x0490 +#define XYSSL_ERR_DHM_MAKE_PARAMS_FAILED -0x04A0 +#define XYSSL_ERR_DHM_READ_PUBLIC_FAILED -0x04B0 +#define XYSSL_ERR_DHM_MAKE_PUBLIC_FAILED -0x04C0 +#define XYSSL_ERR_DHM_CALC_SECRET_FAILED -0x04D0 + +typedef struct +{ + int len; /*!< size(P) in chars */ + mpi P; /*!< prime modulus */ + mpi G; /*!< generator */ + mpi X; /*!< secret value */ + mpi GX; /*!< self = G^X mod P */ + mpi GY; /*!< peer = G^Y mod P */ + mpi K; /*!< key = GY^X mod P */ + mpi RP; /*!< cached R^2 mod P */ +} +dhm_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Parse the ServerKeyExchange parameters + * + * \param ctx DHM context + * \param p &(start of input buffer) + * \param end end of buffer + * + * \return 0 if successful, or an XYSSL_ERR_DHM_XXX error code + */ +int dhm_read_params( dhm_context *ctx, + unsigned char **p, + unsigned char *end ); + +/** + * \brief Setup and write the ServerKeyExchange parameters + * + * \param ctx DHM context + * \param x_size private value size in bits + * \param output destination buffer + * \param olen number of chars written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note This function assumes that ctx->P and ctx->G + * have already been properly set (for example + * using mpi_read_string or mpi_read_binary). + * + * \return 0 if successful, or an XYSSL_ERR_DHM_XXX error code + */ +int dhm_make_params( dhm_context *ctx, int s_size, + unsigned char *output, int *olen, + int (*f_rng)(void *), void *p_rng ); + +/** + * \brief Import the peer's public value G^Y + * + * \param ctx DHM context + * \param input input buffer + * \param ilen size of buffer + * + * \return 0 if successful, or an XYSSL_ERR_DHM_XXX error code + */ +int dhm_read_public( dhm_context *ctx, + unsigned char *input, int ilen ); + +/** + * \brief Create own private value X and export G^X + * + * \param ctx DHM context + * \param x_size private value size in bits + * \param output destination buffer + * \param olen must be equal to ctx->P.len + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, or an XYSSL_ERR_DHM_XXX error code + */ +int dhm_make_public( dhm_context *ctx, int s_size, + unsigned char *output, int olen, + int (*f_rng)(void *), void *p_rng ); + +/** + * \brief Derive and export the shared secret (G^Y)^X mod P + * + * \param ctx DHM context + * \param output destination buffer + * \param olen number of chars written + * + * \return 0 if successful, or an XYSSL_ERR_DHM_XXX error code + */ +int dhm_calc_secret( dhm_context *ctx, + unsigned char *output, int *olen ); + +/* + * \brief Free the components of a DHM key + */ +void dhm_free( dhm_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int dhm_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/polarssl/havege.h b/include/polarssl/havege.h new file mode 100644 index 000000000..3ad84b4a7 --- /dev/null +++ b/include/polarssl/havege.h @@ -0,0 +1,44 @@ +/** + * \file havege.h + */ +#ifndef XYSSL_HAVEGE_H +#define XYSSL_HAVEGE_H + +#define COLLECT_SIZE 1024 + +/** + * \brief HAVEGE state structure + */ +typedef struct +{ + int PT1, PT2, offset[2]; + int pool[COLLECT_SIZE]; + int WALK[8192]; +} +havege_state; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief HAVEGE initialization + * + * \param hs HAVEGE state to be initialized + */ +void havege_init( havege_state *hs ); + +/** + * \brief HAVEGE rand function + * + * \param rng_st points to an HAVEGE state + * + * \return A random int + */ +int havege_rand( void *p_rng ); + +#ifdef __cplusplus +} +#endif + +#endif /* havege.h */ diff --git a/include/polarssl/md2.h b/include/polarssl/md2.h new file mode 100644 index 000000000..c3034835f --- /dev/null +++ b/include/polarssl/md2.h @@ -0,0 +1,120 @@ +/** + * \file md2.h + */ +#ifndef XYSSL_MD2_H +#define XYSSL_MD2_H + +/** + * \brief MD2 context structure + */ +typedef struct +{ + unsigned char cksum[16]; /*!< checksum of the data block */ + unsigned char state[48]; /*!< intermediate digest state */ + unsigned char buffer[16]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ + int left; /*!< amount of data in buffer */ +} +md2_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD2 context setup + * + * \param ctx context to be initialized + */ +void md2_starts( md2_context *ctx ); + +/** + * \brief MD2 process buffer + * + * \param ctx MD2 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md2_update( md2_context *ctx, unsigned char *input, int ilen ); + +/** + * \brief MD2 final digest + * + * \param ctx MD2 context + * \param output MD2 checksum result + */ +void md2_finish( md2_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = MD2( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD2 checksum result + */ +void md2( unsigned char *input, int ilen, unsigned char output[16] ); + +/** + * \brief Output = MD2( file contents ) + * + * \param path input file name + * \param output MD2 checksum result + * + * \return 0 if successful, 1 if fopen failed, + * or 2 if fread failed + */ +int md2_file( char *path, unsigned char output[16] ); + +/** + * \brief MD2 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void md2_hmac_starts( md2_context *ctx, unsigned char *key, int keylen ); + +/** + * \brief MD2 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md2_hmac_update( md2_context *ctx, unsigned char *input, int ilen ); + +/** + * \brief MD2 HMAC final digest + * + * \param ctx HMAC context + * \param output MD2 HMAC checksum result + */ +void md2_hmac_finish( md2_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = HMAC-MD2( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-MD2 result + */ +void md2_hmac( unsigned char *key, int keylen, + unsigned char *input, int ilen, + unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int md2_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* md2.h */ diff --git a/include/polarssl/md4.h b/include/polarssl/md4.h new file mode 100644 index 000000000..f0a7c33ca --- /dev/null +++ b/include/polarssl/md4.h @@ -0,0 +1,119 @@ +/** + * \file md4.h + */ +#ifndef XYSSL_MD4_H +#define XYSSL_MD4_H + +/** + * \brief MD4 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ +} +md4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD4 context setup + * + * \param ctx context to be initialized + */ +void md4_starts( md4_context *ctx ); + +/** + * \brief MD4 process buffer + * + * \param ctx MD4 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md4_update( md4_context *ctx, unsigned char *input, int ilen ); + +/** + * \brief MD4 final digest + * + * \param ctx MD4 context + * \param output MD4 checksum result + */ +void md4_finish( md4_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = MD4( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD4 checksum result + */ +void md4( unsigned char *input, int ilen, unsigned char output[16] ); + +/** + * \brief Output = MD4( file contents ) + * + * \param path input file name + * \param output MD4 checksum result + * + * \return 0 if successful, 1 if fopen failed, + * or 2 if fread failed + */ +int md4_file( char *path, unsigned char output[16] ); + +/** + * \brief MD4 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void md4_hmac_starts( md4_context *ctx, unsigned char *key, int keylen ); + +/** + * \brief MD4 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md4_hmac_update( md4_context *ctx, unsigned char *input, int ilen ); + +/** + * \brief MD4 HMAC final digest + * + * \param ctx HMAC context + * \param output MD4 HMAC checksum result + */ +void md4_hmac_finish( md4_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = HMAC-MD4( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-MD4 result + */ +void md4_hmac( unsigned char *key, int keylen, + unsigned char *input, int ilen, + unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int md4_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* md4.h */ diff --git a/include/polarssl/md5.h b/include/polarssl/md5.h new file mode 100644 index 000000000..a772542b4 --- /dev/null +++ b/include/polarssl/md5.h @@ -0,0 +1,119 @@ +/** + * \file md5.h + */ +#ifndef XYSSL_MD5_H +#define XYSSL_MD5_H + +/** + * \brief MD5 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ +} +md5_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD5 context setup + * + * \param ctx context to be initialized + */ +void md5_starts( md5_context *ctx ); + +/** + * \brief MD5 process buffer + * + * \param ctx MD5 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md5_update( md5_context *ctx, unsigned char *input, int ilen ); + +/** + * \brief MD5 final digest + * + * \param ctx MD5 context + * \param output MD5 checksum result + */ +void md5_finish( md5_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = MD5( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + */ +void md5( unsigned char *input, int ilen, unsigned char output[16] ); + +/** + * \brief Output = MD5( file contents ) + * + * \param path input file name + * \param output MD5 checksum result + * + * \return 0 if successful, 1 if fopen failed, + * or 2 if fread failed + */ +int md5_file( char *path, unsigned char output[16] ); + +/** + * \brief MD5 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void md5_hmac_starts( md5_context *ctx, unsigned char *key, int keylen ); + +/** + * \brief MD5 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md5_hmac_update( md5_context *ctx, unsigned char *input, int ilen ); + +/** + * \brief MD5 HMAC final digest + * + * \param ctx HMAC context + * \param output MD5 HMAC checksum result + */ +void md5_hmac_finish( md5_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = HMAC-MD5( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-MD5 result + */ +void md5_hmac( unsigned char *key, int keylen, + unsigned char *input, int ilen, + unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int md5_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* md5.h */ diff --git a/include/polarssl/net.h b/include/polarssl/net.h new file mode 100644 index 000000000..1860b3d58 --- /dev/null +++ b/include/polarssl/net.h @@ -0,0 +1,103 @@ +/** + * \file net.h + */ +#ifndef XYSSL_NET_H +#define XYSSL_NET_H + +#define XYSSL_ERR_NET_UNKNOWN_HOST -0x0F00 +#define XYSSL_ERR_NET_SOCKET_FAILED -0x0F10 +#define XYSSL_ERR_NET_CONNECT_FAILED -0x0F20 +#define XYSSL_ERR_NET_BIND_FAILED -0x0F30 +#define XYSSL_ERR_NET_LISTEN_FAILED -0x0F40 +#define XYSSL_ERR_NET_ACCEPT_FAILED -0x0F50 +#define XYSSL_ERR_NET_RECV_FAILED -0x0F60 +#define XYSSL_ERR_NET_SEND_FAILED -0x0F70 +#define XYSSL_ERR_NET_CONN_RESET -0x0F80 +#define XYSSL_ERR_NET_TRY_AGAIN -0x0F90 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initiate a TCP connection with host:port + * + * \return 0 if successful, or one of: + * XYSSL_ERR_NET_SOCKET_FAILED, + * XYSSL_ERR_NET_UNKNOWN_HOST, + * XYSSL_ERR_NET_CONNECT_FAILED + */ +int net_connect( int *fd, char *host, int port ); + +/** + * \brief Create a listening socket on bind_ip:port. + * If bind_ip == NULL, all interfaces are binded. + * + * \return 0 if successful, or one of: + * XYSSL_ERR_NET_SOCKET_FAILED, + * XYSSL_ERR_NET_BIND_FAILED, + * XYSSL_ERR_NET_LISTEN_FAILED + */ +int net_bind( int *fd, char *bind_ip, int port ); + +/** + * \brief Accept a connection from a remote client + * + * \return 0 if successful, XYSSL_ERR_NET_ACCEPT_FAILED, or + * XYSSL_ERR_NET_WOULD_BLOCK is bind_fd was set to + * non-blocking and accept() is blocking. + */ +int net_accept( int bind_fd, int *client_fd, void *client_ip ); + +/** + * \brief Set the socket blocking + * + * \return 0 if successful, or a non-zero error code + */ +int net_set_block( int fd ); + +/** + * \brief Set the socket non-blocking + * + * \return 0 if successful, or a non-zero error code + */ +int net_set_nonblock( int fd ); + +/** + * \brief Portable usleep helper + * + * \note Real amount of time slept will not be less than + * select()'s timeout granularity (typically, 10ms). + */ +void net_usleep( unsigned long usec ); + +/** + * \brief Read at most 'len' characters. len is updated to + * reflect the actual number of characters read. + * + * \return This function returns the number of bytes received, + * or a negative error code; XYSSL_ERR_NET_TRY_AGAIN + * indicates read() is blocking. + */ +int net_recv( void *ctx, unsigned char *buf, int len ); + +/** + * \brief Write at most 'len' characters. len is updated to + * reflect the number of characters _not_ written. + * + * \return This function returns the number of bytes sent, + * or a negative error code; XYSSL_ERR_NET_TRY_AGAIN + * indicates write() is blocking. + */ +int net_send( void *ctx, unsigned char *buf, int len ); + +/** + * \brief Gracefully shutdown the connection + */ +void net_close( int fd ); + +#ifdef __cplusplus +} +#endif + +#endif /* net.h */ diff --git a/include/polarssl/openssl.h b/include/polarssl/openssl.h new file mode 100644 index 000000000..0006754e6 --- /dev/null +++ b/include/polarssl/openssl.h @@ -0,0 +1,113 @@ +/** + * \file openssl.h + */ +/* + * OpenSSL wrapper contributed by David Barett + */ +#ifndef XYSSL_OPENSSL_H +#define XYSSL_OPENSSL_H + +#include "xyssl/aes.h" +#include "xyssl/md5.h" +#include "xyssl/rsa.h" +#include "xyssl/sha1.h" + +#define AES_SIZE 16 +#define AES_BLOCK_SIZE 16 +#define AES_KEY aes_context +#define MD5_CTX md5_context +#define SHA_CTX sha1_context + +#define SHA1_Init( CTX ) \ + sha1_starts( (CTX) ) +#define SHA1_Update( CTX, BUF, LEN ) \ + sha1_update( (CTX), (unsigned char *)(BUF), (LEN) ) +#define SHA1_Final( OUT, CTX ) \ + sha1_finish( (CTX), (OUT) ) + +#define MD5_Init( CTX ) \ + md5_starts( (CTX) ) +#define MD5_Update( CTX, BUF, LEN ) \ + md5_update( (CTX), (unsigned char *)(BUF), (LEN) ) +#define MD5_Final( OUT, CTX ) \ + md5_finish( (CTX), (OUT) ) + +#define AES_set_encrypt_key( KEY, KEYSIZE, CTX ) \ + aes_setkey_enc( (CTX), (KEY), (KEYSIZE) ) +#define AES_set_decrypt_key( KEY, KEYSIZE, CTX ) \ + aes_setkey_dec( (CTX), (KEY), (KEYSIZE) ) +#define AES_cbc_encrypt( INPUT, OUTPUT, LEN, CTX, IV, MODE ) \ + aes_crypt_cbc( (CTX), (MODE), (LEN), (IV), (INPUT), (OUTPUT) ) + +/* + * RSA stuff follows. TODO: needs cleanup + */ +inline int __RSA_Passthrough( void *output, void *input, int size ) +{ + memcpy( output, input, size ); + return size; +} + +inline rsa_context* d2i_RSA_PUBKEY( void *ignore, unsigned char **bufptr, + int len ) +{ + unsigned char *buffer = *(unsigned char **) bufptr; + rsa_context *rsa; + + /* + * Not a general-purpose parser: only parses public key from *exactly* + * openssl genrsa -out privkey.pem 512 (or 1024) + * openssl rsa -in privkey.pem -out privatekey.der -outform der + * openssl rsa -in privkey.pem -out pubkey.der -outform der -pubout + * + * TODO: make a general-purpose parse + */ + if( ignore != 0 || ( len != 94 && len != 162 ) ) + return( 0 ); + + rsa = (rsa_context *) malloc( sizeof( rsa_rsa ) ); + if( rsa == NULL ) + return( 0 ); + + memset( rsa, 0, sizeof( rsa_context ) ); + + if( ( len == 94 && + mpi_read_binary( &rsa->N, &buffer[ 25], 64 ) == 0 && + mpi_read_binary( &rsa->E, &buffer[ 91], 3 ) == 0 ) || + ( len == 162 && + mpi_read_binary( &rsa->N, &buffer[ 29], 128 ) == 0 ) && + mpi_read_binary( &rsa->E, &buffer[159], 3 ) == 0 ) + { + /* + * key read successfully + */ + rsa->len = ( mpi_msb( &rsa->N ) + 7 ) >> 3; + return( rsa ); + } + else + { + memset( rsa, 0, sizeof( rsa_context ) ); + free( rsa ); + return( 0 ); + } +} + +#define RSA rsa_context +#define RSA_PKCS1_PADDING 1 /* ignored; always encrypt with this */ +#define RSA_size( CTX ) (CTX)->len +#define RSA_free( CTX ) rsa_free( CTX ) +#define ERR_get_error( ) "ERR_get_error() not supported" +#define RSA_blinding_off( IGNORE ) + +#define d2i_RSAPrivateKey( a, b, c ) new rsa_context /* TODO: C++ bleh */ + +inline int RSA_public_decrypt ( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { int outsize=size; if( !rsa_pkcs1_decrypt( key, RSA_PUBLIC, &outsize, input, output ) ) return outsize; else return -1; } +inline int RSA_private_decrypt( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { int outsize=size; if( !rsa_pkcs1_decrypt( key, RSA_PRIVATE, &outsize, input, output ) ) return outsize; else return -1; } +inline int RSA_public_encrypt ( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { if( !rsa_pkcs1_encrypt( key, RSA_PUBLIC, size, input, output ) ) return RSA_size(key); else return -1; } +inline int RSA_private_encrypt( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { if( !rsa_pkcs1_encrypt( key, RSA_PRIVATE, size, input, output ) ) return RSA_size(key); else return -1; } + +#ifdef __cplusplus +} +#endif + +#endif /* openssl.h */ diff --git a/include/polarssl/padlock.h b/include/polarssl/padlock.h new file mode 100644 index 000000000..e577de71b --- /dev/null +++ b/include/polarssl/padlock.h @@ -0,0 +1,73 @@ +/** + * \file padlock.h + */ +#ifndef XYSSL_PADLOCK_H +#define XYSSL_PADLOCK_H + +#include "xyssl/aes.h" + +#if (defined(__GNUC__) && defined(__i386__)) + +#ifndef XYSSL_HAVE_X86 +#define XYSSL_HAVE_X86 +#endif + +#define PADLOCK_RNG 0x000C +#define PADLOCK_ACE 0x00C0 +#define PADLOCK_PHE 0x0C00 +#define PADLOCK_PMM 0x3000 + +#define PADLOCK_ALIGN16(x) (unsigned long *) (16 + ((long) x & ~15)) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PadLock detection routine + * + * \return 1 if CPU has support for the feature, 0 otherwise + */ +int padlock_supports( int feature ); + +/** + * \brief PadLock AES-ECB block en(de)cryption + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if success, 1 if operation failed + */ +int padlock_xcryptecb( aes_context *ctx, + int mode, + unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief PadLock AES-CBC buffer en(de)cryption + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if success, 1 if operation failed + */ +int padlock_xcryptcbc( aes_context *ctx, + int mode, + int length, + unsigned char iv[16], + unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#endif /* HAVE_X86 */ + +#endif /* padlock.h */ diff --git a/include/polarssl/rsa.h b/include/polarssl/rsa.h new file mode 100644 index 000000000..9a8a5dc23 --- /dev/null +++ b/include/polarssl/rsa.h @@ -0,0 +1,274 @@ +/** + * \file rsa.h + */ +#ifndef XYSSL_RSA_H +#define XYSSL_RSA_H + +#include "xyssl/bignum.h" + +#define XYSSL_ERR_RSA_BAD_INPUT_DATA -0x0400 +#define XYSSL_ERR_RSA_INVALID_PADDING -0x0410 +#define XYSSL_ERR_RSA_KEY_GEN_FAILED -0x0420 +#define XYSSL_ERR_RSA_KEY_CHECK_FAILED -0x0430 +#define XYSSL_ERR_RSA_PUBLIC_FAILED -0x0440 +#define XYSSL_ERR_RSA_PRIVATE_FAILED -0x0450 +#define XYSSL_ERR_RSA_VERIFY_FAILED -0x0460 + +/* + * PKCS#1 constants + */ +#define RSA_RAW 0 +#define RSA_MD2 2 +#define RSA_MD4 3 +#define RSA_MD5 4 +#define RSA_SHA1 5 +#define RSA_SHA256 6 + +#define RSA_PUBLIC 0 +#define RSA_PRIVATE 1 + +#define RSA_PKCS_V15 0 +#define RSA_PKCS_V21 1 + +#define RSA_SIGN 1 +#define RSA_CRYPT 2 + +/* + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * Digest ::= OCTET STRING + */ +#define ASN1_HASH_MDX \ + "\x30\x20\x30\x0C\x06\x08\x2A\x86\x48" \ + "\x86\xF7\x0D\x02\x00\x05\x00\x04\x10" + +#define ASN1_HASH_SHA1 \ + "\x30\x21\x30\x09\x06\x05\x2B\x0E\x03" \ + "\x02\x1A\x05\x00\x04\x14" + +/** + * \brief RSA context structure + */ +typedef struct +{ + int ver; /*!< always 0 */ + int len; /*!< size(N) in chars */ + + mpi N; /*!< public modulus */ + mpi E; /*!< public exponent */ + + mpi D; /*!< private exponent */ + mpi P; /*!< 1st prime factor */ + mpi Q; /*!< 2nd prime factor */ + mpi DP; /*!< D % (P - 1) */ + mpi DQ; /*!< D % (Q - 1) */ + mpi QP; /*!< 1 / (Q % P) */ + + mpi RN; /*!< cached R^2 mod N */ + mpi RP; /*!< cached R^2 mod P */ + mpi RQ; /*!< cached R^2 mod Q */ + + int padding; /*!< 1.5 or OAEP/PSS */ + int hash_id; /*!< hash identifier */ + int (*f_rng)(void *); /*!< RNG function */ + void *p_rng; /*!< RNG parameter */ +} +rsa_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initialize an RSA context + * + * \param ctx RSA context to be initialized + * \param padding RSA_PKCS_V15 or RSA_PKCS_V21 + * \param hash_id RSA_PKCS_V21 hash identifier + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note The hash_id parameter is actually ignored + * when using RSA_PKCS_V15 padding. + * + * \note Currently (xyssl-0.8), RSA_PKCS_V21 padding + * is not supported. + */ +void rsa_init( rsa_context *ctx, + int padding, + int hash_id, + int (*f_rng)(void *), + void *p_rng ); + +/** + * \brief Generate an RSA keypair + * + * \param ctx RSA context that will hold the key + * \param nbits size of the public key in bits + * \param exponent public exponent (e.g., 65537) + * + * \note rsa_init() must be called beforehand to setup + * the RSA context (especially f_rng and p_rng). + * + * \return 0 if successful, or an XYSSL_ERR_RSA_XXX error code + */ +int rsa_gen_key( rsa_context *ctx, int nbits, int exponent ); + +/** + * \brief Check a public RSA key + * + * \param ctx RSA context to be checked + * + * \return 0 if successful, or an XYSSL_ERR_RSA_XXX error code + */ +int rsa_check_pubkey( rsa_context *ctx ); + +/** + * \brief Check a private RSA key + * + * \param ctx RSA context to be checked + * + * \return 0 if successful, or an XYSSL_ERR_RSA_XXX error code + */ +int rsa_check_privkey( rsa_context *ctx ); + +/** + * \brief Do an RSA public key operation + * + * \param ctx RSA context + * \param input input buffer + * \param output output buffer + * + * \return 0 if successful, or an XYSSL_ERR_RSA_XXX error code + * + * \note This function does NOT take care of message + * padding. Also, be sure to set input[0] = 0. + * + * \note The input and output buffers must be large + * enough (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_public( rsa_context *ctx, + unsigned char *input, + unsigned char *output ); + +/** + * \brief Do an RSA private key operation + * + * \param ctx RSA context + * \param input input buffer + * \param output output buffer + * + * \return 0 if successful, or an XYSSL_ERR_RSA_XXX error code + * + * \note The input and output buffers must be large + * enough (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_private( rsa_context *ctx, + unsigned char *input, + unsigned char *output ); + +/** + * \brief Add the message padding, then do an RSA operation + * + * \param ctx RSA context + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param ilen contains the the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \return 0 if successful, or an XYSSL_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_pkcs1_encrypt( rsa_context *ctx, + int mode, int ilen, + unsigned char *input, + unsigned char *output ); + +/** + * \brief Do an RSA operation, then remove the message padding + * + * \param ctx RSA context + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param olen will contain the plaintext length + * + * \return 0 if successful, or an XYSSL_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_pkcs1_decrypt( rsa_context *ctx, + int mode, int *olen, + unsigned char *input, + unsigned char *output ); + +/** + * \brief Do a private RSA to sign a message digest + * + * \param ctx RSA context + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param hash_id RSA_RAW, RSA_MD{2,4,5} or RSA_SHA{1,256} + * \param hashlen message digest length (for RSA_RAW only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an XYSSL_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_pkcs1_sign( rsa_context *ctx, + int mode, + int hash_id, + int hashlen, + unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Do a public RSA and check the message digest + * + * \param ctx points to an RSA public key + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param hash_id RSA_RAW, RSA_MD{2,4,5} or RSA_SHA{1,256} + * \param hashlen message digest length (for RSA_RAW only) + * \param hash buffer holding the message digest + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify operation was successful, + * or an XYSSL_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_pkcs1_verify( rsa_context *ctx, + int mode, + int hash_id, + int hashlen, + unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Free the components of an RSA key + */ +void rsa_free( rsa_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int rsa_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* rsa.h */ diff --git a/include/polarssl/sha1.h b/include/polarssl/sha1.h new file mode 100644 index 000000000..7d44c6721 --- /dev/null +++ b/include/polarssl/sha1.h @@ -0,0 +1,119 @@ +/** + * \file sha1.h + */ +#ifndef XYSSL_SHA1_H +#define XYSSL_SHA1_H + +/** + * \brief SHA-1 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ +} +sha1_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void sha1_starts( sha1_context *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha1_update( sha1_context *ctx, unsigned char *input, int ilen ); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void sha1_finish( sha1_context *ctx, unsigned char output[20] ); + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-1 checksum result + */ +void sha1( unsigned char *input, int ilen, unsigned char output[20] ); + +/** + * \brief Output = SHA-1( file contents ) + * + * \param path input file name + * \param output SHA-1 checksum result + * + * \return 0 if successful, 1 if fopen failed, + * or 2 if fread failed + */ +int sha1_file( char *path, unsigned char output[20] ); + +/** + * \brief SHA-1 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void sha1_hmac_starts( sha1_context *ctx, unsigned char *key, int keylen ); + +/** + * \brief SHA-1 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha1_hmac_update( sha1_context *ctx, unsigned char *input, int ilen ); + +/** + * \brief SHA-1 HMAC final digest + * + * \param ctx HMAC context + * \param output SHA-1 HMAC checksum result + */ +void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] ); + +/** + * \brief Output = HMAC-SHA-1( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-SHA-1 result + */ +void sha1_hmac( unsigned char *key, int keylen, + unsigned char *input, int ilen, + unsigned char output[20] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int sha1_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* sha1.h */ diff --git a/include/polarssl/sha2.h b/include/polarssl/sha2.h new file mode 100644 index 000000000..ad2d37b7c --- /dev/null +++ b/include/polarssl/sha2.h @@ -0,0 +1,127 @@ +/** + * \file sha2.h + */ +#ifndef XYSSL_SHA2_H +#define XYSSL_SHA2_H + +/** + * \brief SHA-256 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[8]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ + int is224; /*!< 0 => SHA-256, else SHA-224 */ +} +sha2_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-256 context setup + * + * \param ctx context to be initialized + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void sha2_starts( sha2_context *ctx, int is224 ); + +/** + * \brief SHA-256 process buffer + * + * \param ctx SHA-256 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha2_update( sha2_context *ctx, unsigned char *input, int ilen ); + +/** + * \brief SHA-256 final digest + * + * \param ctx SHA-256 context + * \param output SHA-224/256 checksum result + */ +void sha2_finish( sha2_context *ctx, unsigned char output[32] ); + +/** + * \brief Output = SHA-256( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-224/256 checksum result + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void sha2( unsigned char *input, int ilen, + unsigned char output[32], int is224 ); + +/** + * \brief Output = SHA-256( file contents ) + * + * \param path input file name + * \param output SHA-224/256 checksum result + * \param is224 0 = use SHA256, 1 = use SHA224 + * + * \return 0 if successful, 1 if fopen failed, + * or 2 if fread failed + */ +int sha2_file( char *path, unsigned char output[32], int is224 ); + +/** + * \brief SHA-256 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void sha2_hmac_starts( sha2_context *ctx, unsigned char *key, int keylen, + int is224 ); + +/** + * \brief SHA-256 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha2_hmac_update( sha2_context *ctx, unsigned char *input, int ilen ); + +/** + * \brief SHA-256 HMAC final digest + * + * \param ctx HMAC context + * \param output SHA-224/256 HMAC checksum result + */ +void sha2_hmac_finish( sha2_context *ctx, unsigned char output[32] ); + +/** + * \brief Output = HMAC-SHA-256( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-SHA-224/256 result + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void sha2_hmac( unsigned char *key, int keylen, + unsigned char *input, int ilen, + unsigned char output[32], int is224 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int sha2_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* sha2.h */ diff --git a/include/polarssl/sha4.h b/include/polarssl/sha4.h new file mode 100644 index 000000000..6c80085ae --- /dev/null +++ b/include/polarssl/sha4.h @@ -0,0 +1,135 @@ +/** + * \file sha4.h + */ +#ifndef XYSSL_SHA4_H +#define XYSSL_SHA4_H + +#if defined(_MSC_VER) || defined(__WATCOMC__) + #define UL64(x) x##ui64 + #define int64 __int64 +#else + #define UL64(x) x##ULL + #define int64 long long +#endif + +/** + * \brief SHA-512 context structure + */ +typedef struct +{ + unsigned int64 total[2]; /*!< number of bytes processed */ + unsigned int64 state[8]; /*!< intermediate digest state */ + unsigned char buffer[128]; /*!< data block being processed */ + + unsigned char ipad[128]; /*!< HMAC: inner padding */ + unsigned char opad[128]; /*!< HMAC: outer padding */ + int is384; /*!< 0 => SHA-512, else SHA-384 */ +} +sha4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-512 context setup + * + * \param ctx context to be initialized + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void sha4_starts( sha4_context *ctx, int is384 ); + +/** + * \brief SHA-512 process buffer + * + * \param ctx SHA-512 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha4_update( sha4_context *ctx, unsigned char *input, int ilen ); + +/** + * \brief SHA-512 final digest + * + * \param ctx SHA-512 context + * \param output SHA-384/512 checksum result + */ +void sha4_finish( sha4_context *ctx, unsigned char output[64] ); + +/** + * \brief Output = SHA-512( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-384/512 checksum result + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void sha4( unsigned char *input, int ilen, + unsigned char output[64], int is384 ); + +/** + * \brief Output = SHA-512( file contents ) + * + * \param path input file name + * \param output SHA-384/512 checksum result + * \param is384 0 = use SHA512, 1 = use SHA384 + * + * \return 0 if successful, 1 if fopen failed, + * or 2 if fread failed + */ +int sha4_file( char *path, unsigned char output[64], int is384 ); + +/** + * \brief SHA-512 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param is384 0 = use SHA512, 1 = use SHA384 + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void sha4_hmac_starts( sha4_context *ctx, unsigned char *key, int keylen, + int is384 ); + +/** + * \brief SHA-512 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha4_hmac_update( sha4_context *ctx, unsigned char *input, int ilen ); + +/** + * \brief SHA-512 HMAC final digest + * + * \param ctx HMAC context + * \param output SHA-384/512 HMAC checksum result + */ +void sha4_hmac_finish( sha4_context *ctx, unsigned char output[64] ); + +/** + * \brief Output = HMAC-SHA-512( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-SHA-384/512 result + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void sha4_hmac( unsigned char *key, int keylen, + unsigned char *input, int ilen, + unsigned char output[64], int is384 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int sha4_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* sha4.h */ diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h new file mode 100644 index 000000000..d6bd0daed --- /dev/null +++ b/include/polarssl/ssl.h @@ -0,0 +1,517 @@ +/** + * \file ssl.h + */ +#ifndef XYSSL_SSL_H +#define XYSSL_SSL_H + +#include + +#include "xyssl/net.h" +#include "xyssl/dhm.h" +#include "xyssl/rsa.h" +#include "xyssl/md5.h" +#include "xyssl/sha1.h" +#include "xyssl/x509.h" + +#define XYSSL_ERR_SSL_FEATURE_UNAVAILABLE -0x1000 +#define XYSSL_ERR_SSL_BAD_INPUT_DATA -0x1800 +#define XYSSL_ERR_SSL_INVALID_MAC -0x2000 +#define XYSSL_ERR_SSL_INVALID_RECORD -0x2800 +#define XYSSL_ERR_SSL_INVALID_MODULUS_SIZE -0x3000 +#define XYSSL_ERR_SSL_UNKNOWN_CIPHER -0x3800 +#define XYSSL_ERR_SSL_NO_CIPHER_CHOSEN -0x4000 +#define XYSSL_ERR_SSL_NO_SESSION_FOUND -0x4800 +#define XYSSL_ERR_SSL_NO_CLIENT_CERTIFICATE -0x5000 +#define XYSSL_ERR_SSL_CERTIFICATE_TOO_LARGE -0x5800 +#define XYSSL_ERR_SSL_CERTIFICATE_REQUIRED -0x6000 +#define XYSSL_ERR_SSL_PRIVATE_KEY_REQUIRED -0x6800 +#define XYSSL_ERR_SSL_CA_CHAIN_REQUIRED -0x7000 +#define XYSSL_ERR_SSL_UNEXPECTED_MESSAGE -0x7800 +#define XYSSL_ERR_SSL_FATAL_ALERT_MESSAGE -0x8000 +#define XYSSL_ERR_SSL_PEER_VERIFY_FAILED -0x8800 +#define XYSSL_ERR_SSL_PEER_CLOSE_NOTIFY -0x9000 +#define XYSSL_ERR_SSL_BAD_HS_CLIENT_HELLO -0x9800 +#define XYSSL_ERR_SSL_BAD_HS_SERVER_HELLO -0xA000 +#define XYSSL_ERR_SSL_BAD_HS_CERTIFICATE -0xA800 +#define XYSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST -0xB000 +#define XYSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE -0xB800 +#define XYSSL_ERR_SSL_BAD_HS_SERVER_HELLO_DONE -0xC000 +#define XYSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE -0xC800 +#define XYSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY -0xD000 +#define XYSSL_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC -0xD800 +#define XYSSL_ERR_SSL_BAD_HS_FINISHED -0xE000 + +/* + * Various constants + */ +#define SSL_MAJOR_VERSION_3 3 +#define SSL_MINOR_VERSION_0 0 /*!< SSL v3.0 */ +#define SSL_MINOR_VERSION_1 1 /*!< TLS v1.0 */ +#define SSL_MINOR_VERSION_2 2 /*!< TLS v1.1 */ + +#define SSL_IS_CLIENT 0 +#define SSL_IS_SERVER 1 +#define SSL_COMPRESS_NULL 0 + +#define SSL_VERIFY_NONE 0 +#define SSL_VERIFY_OPTIONAL 1 +#define SSL_VERIFY_REQUIRED 2 + +#define SSL_MAX_CONTENT_LEN 16384 + +/* + * Allow an extra 512 bytes for the record header + * and encryption overhead (counter + MAC + padding). + */ +#define SSL_BUFFER_LEN (SSL_MAX_CONTENT_LEN + 512) + +/* + * Supported ciphersuites + */ +#define SSL_RSA_RC4_128_MD5 4 +#define SSL_RSA_RC4_128_SHA 5 +#define SSL_RSA_DES_168_SHA 10 +#define SSL_EDH_RSA_DES_168_SHA 22 +#define SSL_RSA_AES_128_SHA 47 +#define SSL_RSA_AES_256_SHA 53 +#define SSL_EDH_RSA_AES_256_SHA 57 + +/* + * Message, alert and handshake types + */ +#define SSL_MSG_CHANGE_CIPHER_SPEC 20 +#define SSL_MSG_ALERT 21 +#define SSL_MSG_HANDSHAKE 22 +#define SSL_MSG_APPLICATION_DATA 23 + +#define SSL_ALERT_CLOSE_NOTIFY 0 +#define SSL_ALERT_WARNING 1 +#define SSL_ALERT_FATAL 2 +#define SSL_ALERT_NO_CERTIFICATE 41 + +#define SSL_HS_HELLO_REQUEST 0 +#define SSL_HS_CLIENT_HELLO 1 +#define SSL_HS_SERVER_HELLO 2 +#define SSL_HS_CERTIFICATE 11 +#define SSL_HS_SERVER_KEY_EXCHANGE 12 +#define SSL_HS_CERTIFICATE_REQUEST 13 +#define SSL_HS_SERVER_HELLO_DONE 14 +#define SSL_HS_CERTIFICATE_VERIFY 15 +#define SSL_HS_CLIENT_KEY_EXCHANGE 16 +#define SSL_HS_FINISHED 20 + +/* + * TLS extensions + */ +#define TLS_EXT_SERVERNAME 0 +#define TLS_EXT_SERVERNAME_HOSTNAME 0 + +/* + * SSL state machine + */ +typedef enum +{ + SSL_HELLO_REQUEST, + SSL_CLIENT_HELLO, + SSL_SERVER_HELLO, + SSL_SERVER_CERTIFICATE, + SSL_SERVER_KEY_EXCHANGE, + SSL_CERTIFICATE_REQUEST, + SSL_SERVER_HELLO_DONE, + SSL_CLIENT_CERTIFICATE, + SSL_CLIENT_KEY_EXCHANGE, + SSL_CERTIFICATE_VERIFY, + SSL_CLIENT_CHANGE_CIPHER_SPEC, + SSL_CLIENT_FINISHED, + SSL_SERVER_CHANGE_CIPHER_SPEC, + SSL_SERVER_FINISHED, + SSL_FLUSH_BUFFERS, + SSL_HANDSHAKE_OVER +} +ssl_states; + +typedef struct _ssl_session ssl_session; +typedef struct _ssl_context ssl_context; + +/* + * This structure is used for session resuming. + */ +struct _ssl_session +{ + time_t start; /*!< starting time */ + int cipher; /*!< chosen cipher */ + int length; /*!< session id length */ + unsigned char id[32]; /*!< session identifier */ + unsigned char master[48]; /*!< the master secret */ + ssl_session *next; /*!< next session entry */ +}; + +struct _ssl_context +{ + /* + * Miscellaneous + */ + int state; /*!< SSL handshake: current state */ + + int major_ver; /*!< equal to SSL_MAJOR_VERSION_3 */ + int minor_ver; /*!< either 0 (SSL3) or 1 (TLS1.0) */ + + int max_major_ver; /*!< max. major version from client */ + int max_minor_ver; /*!< max. minor version from client */ + + /* + * Callbacks (RNG, debug, I/O) + */ + int (*f_rng)(void *); + void (*f_dbg)(void *, int, char *); + int (*f_recv)(void *, unsigned char *, int); + int (*f_send)(void *, unsigned char *, int); + + void *p_rng; /*!< context for the RNG function */ + void *p_dbg; /*!< context for the debug function */ + void *p_recv; /*!< context for reading operations */ + void *p_send; /*!< context for writing operations */ + + /* + * Session layer + */ + int resume; /*!< session resuming flag */ + int timeout; /*!< sess. expiration time */ + ssl_session *session; /*!< current session data */ + int (*s_get)(ssl_context *); /*!< (server) get callback */ + int (*s_set)(ssl_context *); /*!< (server) set callback */ + + /* + * Record layer (incoming data) + */ + unsigned char *in_ctr; /*!< 64-bit incoming message counter */ + unsigned char *in_hdr; /*!< 5-byte record header (in_ctr+8) */ + unsigned char *in_msg; /*!< the message contents (in_hdr+5) */ + unsigned char *in_offt; /*!< read offset in application data */ + + int in_msgtype; /*!< record header: message type */ + int in_msglen; /*!< record header: message length */ + int in_left; /*!< amount of data read so far */ + + int in_hslen; /*!< current handshake message length */ + int nb_zero; /*!< # of 0-length encrypted messages */ + + /* + * Record layer (outgoing data) + */ + unsigned char *out_ctr; /*!< 64-bit outgoing message counter */ + unsigned char *out_hdr; /*!< 5-byte record header (out_ctr+8) */ + unsigned char *out_msg; /*!< the message contents (out_hdr+5) */ + + int out_msgtype; /*!< record header: message type */ + int out_msglen; /*!< record header: message length */ + int out_left; /*!< amount of data not yet written */ + + /* + * PKI layer + */ + rsa_context *rsa_key; /*!< own RSA private key */ + x509_cert *own_cert; /*!< own X.509 certificate */ + x509_cert *ca_chain; /*!< own trusted CA chain */ + x509_cert *peer_cert; /*!< peer X.509 cert chain */ + char *peer_cn; /*!< expected peer CN */ + + int endpoint; /*!< 0: client, 1: server */ + int authmode; /*!< verification mode */ + int client_auth; /*!< flag for client auth. */ + int verify_result; /*!< verification result */ + + /* + * Crypto layer + */ + dhm_context dhm_ctx; /*!< DHM key exchange */ + md5_context fin_md5; /*!< Finished MD5 checksum */ + sha1_context fin_sha1; /*!< Finished SHA-1 checksum */ + + int do_crypt; /*!< en(de)cryption flag */ + int *ciphers; /*!< allowed ciphersuites */ + int pmslen; /*!< premaster length */ + int keylen; /*!< symmetric key length */ + int minlen; /*!< min. ciphertext length */ + int ivlen; /*!< IV length */ + int maclen; /*!< MAC length */ + + unsigned char randbytes[64]; /*!< random bytes */ + unsigned char premaster[256]; /*!< premaster secret */ + + unsigned char iv_enc[16]; /*!< IV (encryption) */ + unsigned char iv_dec[16]; /*!< IV (decryption) */ + + unsigned char mac_enc[32]; /*!< MAC (encryption) */ + unsigned char mac_dec[32]; /*!< MAC (decryption) */ + + unsigned long ctx_enc[128]; /*!< encryption context */ + unsigned long ctx_dec[128]; /*!< decryption context */ + + /* + * TLS extensions + */ + unsigned char *hostname; + unsigned long hostname_len; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int ssl_default_ciphers[]; + +/** + * \brief Initialize an SSL context + * + * \param ssl SSL context + * + * \return 0 if successful, or 1 if memory allocation failed + */ +int ssl_init( ssl_context *ssl ); + +/** + * \brief Set the current endpoint type + * + * \param ssl SSL context + * \param endpoint must be SSL_IS_CLIENT or SSL_IS_SERVER + */ +void ssl_set_endpoint( ssl_context *ssl, int endpoint ); + +/** + * \brief Set the certificate verification mode + * + * \param ssl SSL context + * \param mode can be: + * + * SSL_VERIFY_NONE: peer certificate is not checked (default), + * this is insecure and SHOULD be avoided. + * + * SSL_VERIFY_OPTIONAL: peer certificate is checked, however the + * handshake continues even if verification failed; + * ssl_get_verify_result() can be called after the + * handshake is complete. + * + * SSL_VERIFY_REQUIRED: peer *must* present a valid certificate, + * handshake is aborted if verification failed. + */ +void ssl_set_authmode( ssl_context *ssl, int authmode ); + +/** + * \brief Set the random number generator callback + * + * \param ssl SSL context + * \param f_rng RNG function + * \param p_rng RNG parameter + */ +void ssl_set_rng( ssl_context *ssl, + int (*f_rng)(void *), + void *p_rng ); + +/** + * \brief Set the debug callback + * + * \param ssl SSL context + * \param f_dbg debug function + * \param p_dbg debug parameter + */ +void ssl_set_dbg( ssl_context *ssl, + void (*f_dbg)(void *, int, char *), + void *p_dbg ); + +/** + * \brief Set the underlying BIO read and write callbacks + * + * \param ssl SSL context + * \param f_recv read callback + * \param p_recv read parameter + * \param f_send write callback + * \param p_send write parameter + */ +void ssl_set_bio( ssl_context *ssl, + int (*f_recv)(void *, unsigned char *, int), void *p_recv, + int (*f_send)(void *, unsigned char *, int), void *p_send ); + +/** + * \brief Set the session callbacks (server-side only) + * + * \param ssl SSL context + * \param s_get session get callback + * \param s_set session set callback + */ +void ssl_set_scb( ssl_context *ssl, + int (*s_get)(ssl_context *), + int (*s_set)(ssl_context *) ); + +/** + * \brief Set the session resuming flag, timeout and data + * + * \param ssl SSL context + * \param resume if 0 (default), the session will not be resumed + * \param timeout session timeout in seconds, or 0 (no timeout) + * \param session session context + */ +void ssl_set_session( ssl_context *ssl, int resume, int timeout, + ssl_session *session ); + +/** + * \brief Set the list of allowed ciphersuites + * + * \param ssl SSL context + * \param ciphers 0-terminated list of allowed ciphers + */ +void ssl_set_ciphers( ssl_context *ssl, int *ciphers ); + +/** + * \brief Set the data required to verify peer certificate + * + * \param ssl SSL context + * \param ca_chain trusted CA chain + * \param peer_cn expected peer CommonName (or NULL) + * + * \note TODO: add two more parameters: depth and crl + */ +void ssl_set_ca_chain( ssl_context *ssl, x509_cert *ca_chain, + char *peer_cn ); + +/** + * \brief Set own certificate and private key + * + * \param ssl SSL context + * \param own_cert own public certificate + * \param rsa_key own private RSA key + */ +void ssl_set_own_cert( ssl_context *ssl, x509_cert *own_cert, + rsa_context *rsa_key ); + +/** + * \brief Set the Diffie-Hellman public P and G values, + * read as hexadecimal strings (server-side only) + * + * \param ssl SSL context + * \param dhm_P Diffie-Hellman-Merkle modulus + * \param dhm_G Diffie-Hellman-Merkle generator + * + * \return 0 if successful + */ +int ssl_set_dh_param( ssl_context *ssl, char *dhm_P, char *dhm_G ); + +/** + * \brief Set hostname for ServerName TLS Extension + * + * + * \param ssl SSL context + * \param hostname the server hostname + * + * \return 0 if successful + */ +int ssl_set_hostname( ssl_context *ssl, char *hostname ); + +/** + * \brief Return the number of data bytes available to read + * + * \param ssl SSL context + * + * \return how many bytes are available in the read buffer + */ +int ssl_get_bytes_avail( ssl_context *ssl ); + +/** + * \brief Return the result of the certificate verification + * + * \param ssl SSL context + * + * \return 0 if successful, or a combination of: + * BADCERT_EXPIRED + * BADCERT_REVOKED + * BADCERT_CN_MISMATCH + * BADCERT_NOT_TRUSTED + */ +int ssl_get_verify_result( ssl_context *ssl ); + +/** + * \brief Return the name of the current cipher + * + * \param ssl SSL context + * + * \return a string containing the cipher name + */ +char *ssl_get_cipher( ssl_context *ssl ); + +/** + * \brief Perform the SSL handshake + * + * \param ssl SSL context + * + * \return 0 if successful, XYSSL_ERR_NET_TRY_AGAIN, + * or a specific SSL error code. + */ +int ssl_handshake( ssl_context *ssl ); + +/** + * \brief Read at most 'len' application data bytes + * + * \param ssl SSL context + * \param buf buffer that will hold the data + * \param len how many bytes must be read + * + * \return This function returns the number of bytes read, + * or a negative error code. + */ +int ssl_read( ssl_context *ssl, unsigned char *buf, int len ); + +/** + * \brief Write exactly 'len' application data bytes + * + * \param ssl SSL context + * \param buf buffer holding the data + * \param len how many bytes must be written + * + * \return This function returns the number of bytes written, + * or a negative error code. + * + * \note When this function returns XYSSL_ERR_NET_TRY_AGAIN, + * it must be called later with the *same* arguments, + * until it returns a positive value. + */ +int ssl_write( ssl_context *ssl, unsigned char *buf, int len ); + +/** + * \brief Notify the peer that the connection is being closed + */ +int ssl_close_notify( ssl_context *ssl ); + +/** + * \brief Free an SSL context + */ +void ssl_free( ssl_context *ssl ); + +/* + * Internal functions (do not call directly) + */ +int ssl_handshake_client( ssl_context *ssl ); +int ssl_handshake_server( ssl_context *ssl ); + +int ssl_derive_keys( ssl_context *ssl ); +void ssl_calc_verify( ssl_context *ssl, unsigned char hash[36] ); + +int ssl_read_record( ssl_context *ssl ); +int ssl_fetch_input( ssl_context *ssl, int nb_want ); + +int ssl_write_record( ssl_context *ssl ); +int ssl_flush_output( ssl_context *ssl ); + +int ssl_parse_certificate( ssl_context *ssl ); +int ssl_write_certificate( ssl_context *ssl ); + +int ssl_parse_change_cipher_spec( ssl_context *ssl ); +int ssl_write_change_cipher_spec( ssl_context *ssl ); + +int ssl_parse_finished( ssl_context *ssl ); +int ssl_write_finished( ssl_context *ssl ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl.h */ diff --git a/include/polarssl/timing.h b/include/polarssl/timing.h new file mode 100644 index 000000000..32e53e8c0 --- /dev/null +++ b/include/polarssl/timing.h @@ -0,0 +1,50 @@ +/** + * \file timing.h + */ +#ifndef XYSSL_TIMING_H +#define XYSSL_TIMING_H + +/** + * \brief timer structure + */ +struct hr_time +{ + unsigned char opaque[32]; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int alarmed; + +/** + * \brief Return the CPU cycle counter value + */ +unsigned long hardclock( void ); + +/** + * \brief Return the elapsed time in milliseconds + * + * \param val points to a timer structure + * \param reset if set to 1, the timer is restarted + */ +unsigned long get_timer( struct hr_time *val, int reset ); + +/** + * \brief Setup an alarm clock + * + * \param seconds delay before the "alarmed" flag is set + */ +void set_alarm( int seconds ); + +/** + * \brief Sleep for a certain amount of time + */ +void m_sleep( int milliseconds ); + +#ifdef __cplusplus +} +#endif + +#endif /* timing.h */ diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h new file mode 100644 index 000000000..0ada35501 --- /dev/null +++ b/include/polarssl/x509.h @@ -0,0 +1,295 @@ +/** + * \file x509.h + */ +#ifndef XYSSL_X509_H +#define XYSSL_X509_H + +#include "xyssl/rsa.h" + +#define XYSSL_ERR_ASN1_OUT_OF_DATA -0x0014 +#define XYSSL_ERR_ASN1_UNEXPECTED_TAG -0x0016 +#define XYSSL_ERR_ASN1_INVALID_LENGTH -0x0018 +#define XYSSL_ERR_ASN1_LENGTH_MISMATCH -0x001A +#define XYSSL_ERR_ASN1_INVALID_DATA -0x001C + +#define XYSSL_ERR_X509_FEATURE_UNAVAILABLE -0x0020 +#define XYSSL_ERR_X509_CERT_INVALID_PEM -0x0040 +#define XYSSL_ERR_X509_CERT_INVALID_FORMAT -0x0060 +#define XYSSL_ERR_X509_CERT_INVALID_VERSION -0x0080 +#define XYSSL_ERR_X509_CERT_INVALID_SERIAL -0x00A0 +#define XYSSL_ERR_X509_CERT_INVALID_ALG -0x00C0 +#define XYSSL_ERR_X509_CERT_INVALID_NAME -0x00E0 +#define XYSSL_ERR_X509_CERT_INVALID_DATE -0x0100 +#define XYSSL_ERR_X509_CERT_INVALID_PUBKEY -0x0120 +#define XYSSL_ERR_X509_CERT_INVALID_SIGNATURE -0x0140 +#define XYSSL_ERR_X509_CERT_INVALID_EXTENSIONS -0x0160 +#define XYSSL_ERR_X509_CERT_UNKNOWN_VERSION -0x0180 +#define XYSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG -0x01A0 +#define XYSSL_ERR_X509_CERT_UNKNOWN_PK_ALG -0x01C0 +#define XYSSL_ERR_X509_CERT_SIG_MISMATCH -0x01E0 +#define XYSSL_ERR_X509_CERT_VERIFY_FAILED -0x0200 +#define XYSSL_ERR_X509_KEY_INVALID_PEM -0x0220 +#define XYSSL_ERR_X509_KEY_INVALID_VERSION -0x0240 +#define XYSSL_ERR_X509_KEY_INVALID_FORMAT -0x0260 +#define XYSSL_ERR_X509_KEY_INVALID_ENC_IV -0x0280 +#define XYSSL_ERR_X509_KEY_UNKNOWN_ENC_ALG -0x02A0 +#define XYSSL_ERR_X509_KEY_PASSWORD_REQUIRED -0x02C0 +#define XYSSL_ERR_X509_KEY_PASSWORD_MISMATCH -0x02E0 +#define XYSSL_ERR_X509_POINT_ERROR -0x0300 +#define XYSSL_ERR_X509_VALUE_TO_LENGTH -0x0320 + +#define BADCERT_EXPIRED 1 +#define BADCERT_REVOKED 2 +#define BADCERT_CN_MISMATCH 4 +#define BADCERT_NOT_TRUSTED 8 + +/* + * DER constants + */ +#define ASN1_BOOLEAN 0x01 +#define ASN1_INTEGER 0x02 +#define ASN1_BIT_STRING 0x03 +#define ASN1_OCTET_STRING 0x04 +#define ASN1_NULL 0x05 +#define ASN1_OID 0x06 +#define ASN1_UTF8_STRING 0x0C +#define ASN1_SEQUENCE 0x10 +#define ASN1_SET 0x11 +#define ASN1_PRINTABLE_STRING 0x13 +#define ASN1_T61_STRING 0x14 +#define ASN1_IA5_STRING 0x16 +#define ASN1_UTC_TIME 0x17 +#define ASN1_UNIVERSAL_STRING 0x1C +#define ASN1_BMP_STRING 0x1E +#define ASN1_PRIMITIVE 0x00 +#define ASN1_CONSTRUCTED 0x20 +#define ASN1_CONTEXT_SPECIFIC 0x80 + +/* + * various object identifiers + */ +#define X520_COMMON_NAME 3 +#define X520_COUNTRY 6 +#define X520_LOCALITY 7 +#define X520_STATE 8 +#define X520_ORGANIZATION 10 +#define X520_ORG_UNIT 11 +#define PKCS9_EMAIL 1 + +#define X509_OUTPUT_DER 0x01 +#define X509_OUTPUT_PEM 0x02 +#define PEM_LINE_LENGTH 72 +#define X509_ISSUER 0x01 +#define X509_SUBJECT 0x02 + +#define OID_X520 "\x55\x04" +#define OID_CN "\x55\x04\x03" +#define OID_PKCS1 "\x2A\x86\x48\x86\xF7\x0D\x01\x01" +#define OID_PKCS1_RSA "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01" +#define OID_PKCS1_RSA_SHA "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05" +#define OID_PKCS9 "\x2A\x86\x48\x86\xF7\x0D\x01\x09" +#define OID_PKCS9_EMAIL "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01" + +/* + * Structures for parsing X.509 certificates + */ +typedef struct _x509_buf +{ + int tag; + int len; + unsigned char *p; +} +x509_buf; + +typedef struct _x509_name +{ + x509_buf oid; + x509_buf val; + struct _x509_name *next; +} +x509_name; + +typedef struct _x509_time +{ + int year, mon, day; + int hour, min, sec; +} +x509_time; + +typedef struct _x509_cert +{ + x509_buf raw; + x509_buf tbs; + + int version; + x509_buf serial; + x509_buf sig_oid1; + + x509_buf issuer_raw; + x509_buf subject_raw; + + x509_name issuer; + x509_name subject; + + x509_time valid_from; + x509_time valid_to; + + x509_buf pk_oid; + rsa_context rsa; + + x509_buf issuer_id; + x509_buf subject_id; + x509_buf v3_ext; + + int ca_istrue; + int max_pathlen; + + x509_buf sig_oid2; + x509_buf sig; + + struct _x509_cert *next; +} +x509_cert; + +/* + * Structures for writing X.509 certificates + */ +typedef struct _x509_node +{ + unsigned char *data; + unsigned char *p; + unsigned char *end; + + size_t len; +} +x509_node; + +typedef struct _x509_raw +{ + x509_node raw; + x509_node tbs; + + x509_node version; + x509_node serial; + x509_node tbs_signalg; + x509_node issuer; + x509_node validity; + x509_node subject; + x509_node subpubkey; + + x509_node signalg; + x509_node sign; +} +x509_raw; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Parse one or more certificates and add them + * to the chained list + * + * \param chain points to the start of the chain + * \param buf buffer holding the certificate data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 error code + */ +int x509parse_crt( x509_cert *crt, unsigned char *buf, int buflen ); + +/** + * \brief Load one or more certificates and add them + * to the chained list + * + * \param chain points to the start of the chain + * \param path filename to read the certificates from + * + * \return 0 if successful, or a specific X509 error code + */ +int x509parse_crtfile( x509_cert *crt, char *path ); + +/** + * \brief Parse a private RSA key + * + * \param rsa RSA context to be initialized + * \param buf input buffer + * \param buflen size of the buffer + * \param pwd password for decryption (optional) + * \param pwdlen size of the password + * + * \return 0 if successful, or a specific X509 error code + */ +int x509parse_key( rsa_context *rsa, + unsigned char *buf, int buflen, + unsigned char *pwd, int pwdlen ); + +/** + * \brief Load and parse a private RSA key + * + * \param rsa RSA context to be initialized + * \param path filename to read the private key from + * \param pwd password to decrypt the file (can be NULL) + * + * \return 0 if successful, or a specific X509 error code + */ +int x509parse_keyfile( rsa_context *rsa, char *path, char *password ); + +/** + * \brief Store the certificate DN in printable form into buf; + * no more than (end - buf) characters will be written. + */ +int x509parse_dn_gets( char *buf, char *end, x509_name *dn ); + +/** + * \brief Returns an informational string about the + * certificate. + */ +char *x509parse_cert_info( char *prefix, x509_cert *crt ); + +/** + * \brief Return 0 if the certificate is still valid, + * or BADCERT_EXPIRED + */ +int x509parse_expired( x509_cert *crt ); + +/** + * \brief Verify the certificate signature + * + * \param crt a certificate to be verified + * \param trust_ca the trusted CA chain + * \param cn expected Common Name (can be set to + * NULL if the CN must not be verified) + * \param flags result of the verification + * + * \return 0 if successful or XYSSL_ERR_X509_SIG_VERIFY_FAILED, + * in which case *flags will have one or more of + * the following values set: + * BADCERT_EXPIRED -- + * BADCERT_REVOKED -- + * BADCERT_CN_MISMATCH -- + * BADCERT_NOT_TRUSTED + * + * \note TODO: add two arguments, depth and crl + */ +int x509parse_verify( x509_cert *crt, + x509_cert *trust_ca, + char *cn, int *flags ); + +/** + * \brief Unallocate all certificate data + */ +void x509_free( x509_cert *crt ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int x509_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* x509.h */ diff --git a/library/Makefile b/library/Makefile new file mode 100644 index 000000000..aef615d47 --- /dev/null +++ b/library/Makefile @@ -0,0 +1,57 @@ + +# Also see "include/xyssl/config.h" + +CFLAGS = -I../include -D_FILE_OFFSET_BITS=64 +OFLAGS = -O + +# MicroBlaze specific options: +# CFLAGS += -mno-xl-soft-mul -mxl-barrel-shift + +# To compile on Plan9: +# CFLAGS += -D_BSD_EXTENSION + +# To compile as a shared library: +# CFLAGS += -fPIC + +DLEXT=so +# OSX shared library extension: +# DLEXT=dylib + +OBJS= aes.o arc4.o base64.o \ + bignum.o certs.o debug.o \ + des.o dhm.o havege.o \ + md2.o md4.o md5.o \ + net.o padlock.o rsa.o \ + sha1.o sha2.o sha4.o \ + ssl_cli.o ssl_srv.o ssl_tls.o \ + timing.o x509parse.o + +.SILENT: + +all: static + +static: libxyssl.a + +shared: libxyssl.$(DLEXT) + +libxyssl.a: $(OBJS) + echo " AR $@" + ar r $@ $(OBJS) + echo " RL $@" + ranlib $@ + +libxyssl.so: libxyssl.a + echo " LD $@" + $(CC) -shared -Wl,-soname,$@ -o $@ $(OBJS) + +libxyssl.dylib: libxyssl.a + echo " LD $@" + $(CC) -dynamiclib -o $@ $(OBJS) + +.c.o: + echo " CC $<" + $(CC) $(CFLAGS) $(OFLAGS) -c $< + +clean: + rm -f *.o libxyssl.* + diff --git a/library/aes.c b/library/aes.c new file mode 100644 index 000000000..84fb037c3 --- /dev/null +++ b/library/aes.c @@ -0,0 +1,1134 @@ +/* + * FIPS-197 compliant AES implementation + * + * Copyright (C) 2006-2007 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +#include "xyssl/config.h" + +#if defined(XYSSL_AES_C) + +#include "xyssl/aes.h" +#include "xyssl/padlock.h" + +#include + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_ULONG_LE +#define GET_ULONG_LE(n,b,i) \ +{ \ + (n) = ( (unsigned long) (b)[(i) ] ) \ + | ( (unsigned long) (b)[(i) + 1] << 8 ) \ + | ( (unsigned long) (b)[(i) + 2] << 16 ) \ + | ( (unsigned long) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_ULONG_LE +#define PUT_ULONG_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ +} +#endif + +#if defined(XYSSL_AES_ROM_TABLES) +/* + * Forward S-box + */ +static const unsigned char FSb[256] = +{ + 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 +}; + +/* + * Forward tables + */ +#define FT \ +\ + V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \ + V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \ + V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \ + V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \ + V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \ + V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \ + V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \ + V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \ + V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \ + V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \ + V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \ + V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \ + V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \ + V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \ + V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \ + V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \ + V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \ + V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \ + V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \ + V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \ + V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \ + V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \ + V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \ + V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \ + V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \ + V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \ + V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \ + V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \ + V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \ + V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \ + V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \ + V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \ + V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \ + V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \ + V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \ + V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \ + V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \ + V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \ + V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \ + V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \ + V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \ + V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \ + V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \ + V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \ + V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \ + V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \ + V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \ + V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \ + V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \ + V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \ + V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \ + V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \ + V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \ + V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \ + V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \ + V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \ + V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \ + V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \ + V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \ + V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \ + V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \ + V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \ + V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \ + V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C) + +#define V(a,b,c,d) 0x##a##b##c##d +static const unsigned long FT0[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static const unsigned long FT1[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const unsigned long FT2[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const unsigned long FT3[256] = { FT }; +#undef V + +#undef FT + +/* + * Reverse S-box + */ +static const unsigned char RSb[256] = +{ + 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 +}; + +/* + * Reverse tables + */ +#define RT \ +\ + V(50,A7,F4,51), V(53,65,41,7E), V(C3,A4,17,1A), V(96,5E,27,3A), \ + V(CB,6B,AB,3B), V(F1,45,9D,1F), V(AB,58,FA,AC), V(93,03,E3,4B), \ + V(55,FA,30,20), V(F6,6D,76,AD), V(91,76,CC,88), V(25,4C,02,F5), \ + V(FC,D7,E5,4F), V(D7,CB,2A,C5), V(80,44,35,26), V(8F,A3,62,B5), \ + V(49,5A,B1,DE), V(67,1B,BA,25), V(98,0E,EA,45), V(E1,C0,FE,5D), \ + V(02,75,2F,C3), V(12,F0,4C,81), V(A3,97,46,8D), V(C6,F9,D3,6B), \ + V(E7,5F,8F,03), V(95,9C,92,15), V(EB,7A,6D,BF), V(DA,59,52,95), \ + V(2D,83,BE,D4), V(D3,21,74,58), V(29,69,E0,49), V(44,C8,C9,8E), \ + V(6A,89,C2,75), V(78,79,8E,F4), V(6B,3E,58,99), V(DD,71,B9,27), \ + V(B6,4F,E1,BE), V(17,AD,88,F0), V(66,AC,20,C9), V(B4,3A,CE,7D), \ + V(18,4A,DF,63), V(82,31,1A,E5), V(60,33,51,97), V(45,7F,53,62), \ + V(E0,77,64,B1), V(84,AE,6B,BB), V(1C,A0,81,FE), V(94,2B,08,F9), \ + V(58,68,48,70), V(19,FD,45,8F), V(87,6C,DE,94), V(B7,F8,7B,52), \ + V(23,D3,73,AB), V(E2,02,4B,72), V(57,8F,1F,E3), V(2A,AB,55,66), \ + V(07,28,EB,B2), V(03,C2,B5,2F), V(9A,7B,C5,86), V(A5,08,37,D3), \ + V(F2,87,28,30), V(B2,A5,BF,23), V(BA,6A,03,02), V(5C,82,16,ED), \ + V(2B,1C,CF,8A), V(92,B4,79,A7), V(F0,F2,07,F3), V(A1,E2,69,4E), \ + V(CD,F4,DA,65), V(D5,BE,05,06), V(1F,62,34,D1), V(8A,FE,A6,C4), \ + V(9D,53,2E,34), V(A0,55,F3,A2), V(32,E1,8A,05), V(75,EB,F6,A4), \ + V(39,EC,83,0B), V(AA,EF,60,40), V(06,9F,71,5E), V(51,10,6E,BD), \ + V(F9,8A,21,3E), V(3D,06,DD,96), V(AE,05,3E,DD), V(46,BD,E6,4D), \ + V(B5,8D,54,91), V(05,5D,C4,71), V(6F,D4,06,04), V(FF,15,50,60), \ + V(24,FB,98,19), V(97,E9,BD,D6), V(CC,43,40,89), V(77,9E,D9,67), \ + V(BD,42,E8,B0), V(88,8B,89,07), V(38,5B,19,E7), V(DB,EE,C8,79), \ + V(47,0A,7C,A1), V(E9,0F,42,7C), V(C9,1E,84,F8), V(00,00,00,00), \ + V(83,86,80,09), V(48,ED,2B,32), V(AC,70,11,1E), V(4E,72,5A,6C), \ + V(FB,FF,0E,FD), V(56,38,85,0F), V(1E,D5,AE,3D), V(27,39,2D,36), \ + V(64,D9,0F,0A), V(21,A6,5C,68), V(D1,54,5B,9B), V(3A,2E,36,24), \ + V(B1,67,0A,0C), V(0F,E7,57,93), V(D2,96,EE,B4), V(9E,91,9B,1B), \ + V(4F,C5,C0,80), V(A2,20,DC,61), V(69,4B,77,5A), V(16,1A,12,1C), \ + V(0A,BA,93,E2), V(E5,2A,A0,C0), V(43,E0,22,3C), V(1D,17,1B,12), \ + V(0B,0D,09,0E), V(AD,C7,8B,F2), V(B9,A8,B6,2D), V(C8,A9,1E,14), \ + V(85,19,F1,57), V(4C,07,75,AF), V(BB,DD,99,EE), V(FD,60,7F,A3), \ + V(9F,26,01,F7), V(BC,F5,72,5C), V(C5,3B,66,44), V(34,7E,FB,5B), \ + V(76,29,43,8B), V(DC,C6,23,CB), V(68,FC,ED,B6), V(63,F1,E4,B8), \ + V(CA,DC,31,D7), V(10,85,63,42), V(40,22,97,13), V(20,11,C6,84), \ + V(7D,24,4A,85), V(F8,3D,BB,D2), V(11,32,F9,AE), V(6D,A1,29,C7), \ + V(4B,2F,9E,1D), V(F3,30,B2,DC), V(EC,52,86,0D), V(D0,E3,C1,77), \ + V(6C,16,B3,2B), V(99,B9,70,A9), V(FA,48,94,11), V(22,64,E9,47), \ + V(C4,8C,FC,A8), V(1A,3F,F0,A0), V(D8,2C,7D,56), V(EF,90,33,22), \ + V(C7,4E,49,87), V(C1,D1,38,D9), V(FE,A2,CA,8C), V(36,0B,D4,98), \ + V(CF,81,F5,A6), V(28,DE,7A,A5), V(26,8E,B7,DA), V(A4,BF,AD,3F), \ + V(E4,9D,3A,2C), V(0D,92,78,50), V(9B,CC,5F,6A), V(62,46,7E,54), \ + V(C2,13,8D,F6), V(E8,B8,D8,90), V(5E,F7,39,2E), V(F5,AF,C3,82), \ + V(BE,80,5D,9F), V(7C,93,D0,69), V(A9,2D,D5,6F), V(B3,12,25,CF), \ + V(3B,99,AC,C8), V(A7,7D,18,10), V(6E,63,9C,E8), V(7B,BB,3B,DB), \ + V(09,78,26,CD), V(F4,18,59,6E), V(01,B7,9A,EC), V(A8,9A,4F,83), \ + V(65,6E,95,E6), V(7E,E6,FF,AA), V(08,CF,BC,21), V(E6,E8,15,EF), \ + V(D9,9B,E7,BA), V(CE,36,6F,4A), V(D4,09,9F,EA), V(D6,7C,B0,29), \ + V(AF,B2,A4,31), V(31,23,3F,2A), V(30,94,A5,C6), V(C0,66,A2,35), \ + V(37,BC,4E,74), V(A6,CA,82,FC), V(B0,D0,90,E0), V(15,D8,A7,33), \ + V(4A,98,04,F1), V(F7,DA,EC,41), V(0E,50,CD,7F), V(2F,F6,91,17), \ + V(8D,D6,4D,76), V(4D,B0,EF,43), V(54,4D,AA,CC), V(DF,04,96,E4), \ + V(E3,B5,D1,9E), V(1B,88,6A,4C), V(B8,1F,2C,C1), V(7F,51,65,46), \ + V(04,EA,5E,9D), V(5D,35,8C,01), V(73,74,87,FA), V(2E,41,0B,FB), \ + V(5A,1D,67,B3), V(52,D2,DB,92), V(33,56,10,E9), V(13,47,D6,6D), \ + V(8C,61,D7,9A), V(7A,0C,A1,37), V(8E,14,F8,59), V(89,3C,13,EB), \ + V(EE,27,A9,CE), V(35,C9,61,B7), V(ED,E5,1C,E1), V(3C,B1,47,7A), \ + V(59,DF,D2,9C), V(3F,73,F2,55), V(79,CE,14,18), V(BF,37,C7,73), \ + V(EA,CD,F7,53), V(5B,AA,FD,5F), V(14,6F,3D,DF), V(86,DB,44,78), \ + V(81,F3,AF,CA), V(3E,C4,68,B9), V(2C,34,24,38), V(5F,40,A3,C2), \ + V(72,C3,1D,16), V(0C,25,E2,BC), V(8B,49,3C,28), V(41,95,0D,FF), \ + V(71,01,A8,39), V(DE,B3,0C,08), V(9C,E4,B4,D8), V(90,C1,56,64), \ + V(61,84,CB,7B), V(70,B6,32,D5), V(74,5C,6C,48), V(42,57,B8,D0) + +#define V(a,b,c,d) 0x##a##b##c##d +static const unsigned long RT0[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static const unsigned long RT1[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const unsigned long RT2[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const unsigned long RT3[256] = { RT }; +#undef V + +#undef RT + +/* + * Round constants + */ +static const unsigned long RCON[10] = +{ + 0x00000001, 0x00000002, 0x00000004, 0x00000008, + 0x00000010, 0x00000020, 0x00000040, 0x00000080, + 0x0000001B, 0x00000036 +}; + +#else + +/* + * Forward S-box & tables + */ +static unsigned char FSb[256]; +static unsigned long FT0[256]; +static unsigned long FT1[256]; +static unsigned long FT2[256]; +static unsigned long FT3[256]; + +/* + * Reverse S-box & tables + */ +static unsigned char RSb[256]; +static unsigned long RT0[256]; +static unsigned long RT1[256]; +static unsigned long RT2[256]; +static unsigned long RT3[256]; + +/* + * Round constants + */ +static unsigned long RCON[10]; + +/* + * Tables generation code + */ +#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 ) +#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) +#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 ) + +static int aes_init_done = 0; + +static void aes_gen_tables( void ) +{ + int i, x, y, z; + int pow[256]; + int log[256]; + + /* + * compute pow and log tables over GF(2^8) + */ + for( i = 0, x = 1; i < 256; i++ ) + { + pow[i] = x; + log[x] = i; + x = ( x ^ XTIME( x ) ) & 0xFF; + } + + /* + * calculate the round constants + */ + for( i = 0, x = 1; i < 10; i++ ) + { + RCON[i] = (unsigned long) x; + x = XTIME( x ) & 0xFF; + } + + /* + * generate the forward and reverse S-boxes + */ + FSb[0x00] = 0x63; + RSb[0x63] = 0x00; + + for( i = 1; i < 256; i++ ) + { + x = pow[255 - log[i]]; + + y = x; y = ( (y << 1) | (y >> 7) ) & 0xFF; + x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; + x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; + x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; + x ^= y ^ 0x63; + + FSb[i] = (unsigned char) x; + RSb[x] = (unsigned char) i; + } + + /* + * generate the forward and reverse tables + */ + for( i = 0; i < 256; i++ ) + { + x = FSb[i]; + y = XTIME( x ) & 0xFF; + z = ( y ^ x ) & 0xFF; + + FT0[i] = ( (unsigned long) y ) ^ + ( (unsigned long) x << 8 ) ^ + ( (unsigned long) x << 16 ) ^ + ( (unsigned long) z << 24 ); + + FT1[i] = ROTL8( FT0[i] ); + FT2[i] = ROTL8( FT1[i] ); + FT3[i] = ROTL8( FT2[i] ); + + x = RSb[i]; + + RT0[i] = ( (unsigned long) MUL( 0x0E, x ) ) ^ + ( (unsigned long) MUL( 0x09, x ) << 8 ) ^ + ( (unsigned long) MUL( 0x0D, x ) << 16 ) ^ + ( (unsigned long) MUL( 0x0B, x ) << 24 ); + + RT1[i] = ROTL8( RT0[i] ); + RT2[i] = ROTL8( RT1[i] ); + RT3[i] = ROTL8( RT2[i] ); + } +} + +#endif + +/* + * AES key schedule (encryption) + */ +void aes_setkey_enc( aes_context *ctx, unsigned char *key, int keysize ) +{ + int i; + unsigned long *RK; + +#if !defined(XYSSL_AES_ROM_TABLES) + if( aes_init_done == 0 ) + { + aes_gen_tables(); + aes_init_done = 1; + } +#endif + + switch( keysize ) + { + case 128: ctx->nr = 10; break; + case 192: ctx->nr = 12; break; + case 256: ctx->nr = 14; break; + default : return; + } + +#if defined(PADLOCK_ALIGN16) + ctx->rk = RK = PADLOCK_ALIGN16( ctx->buf ); +#else + ctx->rk = RK = ctx->buf; +#endif + + for( i = 0; i < (keysize >> 5); i++ ) + { + GET_ULONG_LE( RK[i], key, i << 2 ); + } + + switch( ctx->nr ) + { + case 10: + + for( i = 0; i < 10; i++, RK += 4 ) + { + RK[4] = RK[0] ^ RCON[i] ^ + ( (unsigned long) FSb[ ( RK[3] >> 8 ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( RK[3] >> 16 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( RK[3] ) & 0xFF ] << 24 ); + + RK[5] = RK[1] ^ RK[4]; + RK[6] = RK[2] ^ RK[5]; + RK[7] = RK[3] ^ RK[6]; + } + break; + + case 12: + + for( i = 0; i < 8; i++, RK += 6 ) + { + RK[6] = RK[0] ^ RCON[i] ^ + ( (unsigned long) FSb[ ( RK[5] >> 8 ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( RK[5] >> 16 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( RK[5] ) & 0xFF ] << 24 ); + + RK[7] = RK[1] ^ RK[6]; + RK[8] = RK[2] ^ RK[7]; + RK[9] = RK[3] ^ RK[8]; + RK[10] = RK[4] ^ RK[9]; + RK[11] = RK[5] ^ RK[10]; + } + break; + + case 14: + + for( i = 0; i < 7; i++, RK += 8 ) + { + RK[8] = RK[0] ^ RCON[i] ^ + ( (unsigned long) FSb[ ( RK[7] >> 8 ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( RK[7] >> 16 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( RK[7] ) & 0xFF ] << 24 ); + + RK[9] = RK[1] ^ RK[8]; + RK[10] = RK[2] ^ RK[9]; + RK[11] = RK[3] ^ RK[10]; + + RK[12] = RK[4] ^ + ( (unsigned long) FSb[ ( RK[11] ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( RK[11] >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 ); + + RK[13] = RK[5] ^ RK[12]; + RK[14] = RK[6] ^ RK[13]; + RK[15] = RK[7] ^ RK[14]; + } + break; + + default: + + break; + } +} + +/* + * AES key schedule (decryption) + */ +void aes_setkey_dec( aes_context *ctx, unsigned char *key, int keysize ) +{ + int i, j; + aes_context cty; + unsigned long *RK; + unsigned long *SK; + + switch( keysize ) + { + case 128: ctx->nr = 10; break; + case 192: ctx->nr = 12; break; + case 256: ctx->nr = 14; break; + default : return; + } + +#if defined(PADLOCK_ALIGN16) + ctx->rk = RK = PADLOCK_ALIGN16( ctx->buf ); +#else + ctx->rk = RK = ctx->buf; +#endif + + aes_setkey_enc( &cty, key, keysize ); + SK = cty.rk + cty.nr * 4; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + for( i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8 ) + { + for( j = 0; j < 4; j++, SK++ ) + { + *RK++ = RT0[ FSb[ ( *SK ) & 0xFF ] ] ^ + RT1[ FSb[ ( *SK >> 8 ) & 0xFF ] ] ^ + RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^ + RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ]; + } + } + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + memset( &cty, 0, sizeof( aes_context ) ); +} + +#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \ + FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y3 >> 24 ) & 0xFF ]; \ + \ + X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \ + FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y0 >> 24 ) & 0xFF ]; \ + \ + X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \ + FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y1 >> 24 ) & 0xFF ]; \ + \ + X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \ + FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y2 >> 24 ) & 0xFF ]; \ +} + +#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \ + RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y1 >> 24 ) & 0xFF ]; \ + \ + X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \ + RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y2 >> 24 ) & 0xFF ]; \ + \ + X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \ + RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y3 >> 24 ) & 0xFF ]; \ + \ + X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \ + RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y0 >> 24 ) & 0xFF ]; \ +} + +/* + * AES-ECB block encryption/decryption + */ +void aes_crypt_ecb( aes_context *ctx, + int mode, + unsigned char input[16], + unsigned char output[16] ) +{ + int i; + unsigned long *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + +#if defined(XYSSL_PADLOCK_C) && defined(XYSSL_HAVE_X86) + if( padlock_supports( PADLOCK_ACE ) ) + { + if( padlock_xcryptecb( ctx, mode, input, output ) == 0 ) + return; + } +#endif + + RK = ctx->rk; + + GET_ULONG_LE( X0, input, 0 ); X0 ^= *RK++; + GET_ULONG_LE( X1, input, 4 ); X1 ^= *RK++; + GET_ULONG_LE( X2, input, 8 ); X2 ^= *RK++; + GET_ULONG_LE( X3, input, 12 ); X3 ^= *RK++; + + if( mode == AES_DECRYPT ) + { + for( i = (ctx->nr >> 1) - 1; i > 0; i-- ) + { + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (unsigned long) RSb[ ( Y0 ) & 0xFF ] ) ^ + ( (unsigned long) RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); + + X1 = *RK++ ^ \ + ( (unsigned long) RSb[ ( Y1 ) & 0xFF ] ) ^ + ( (unsigned long) RSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); + + X2 = *RK++ ^ \ + ( (unsigned long) RSb[ ( Y2 ) & 0xFF ] ) ^ + ( (unsigned long) RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); + + X3 = *RK++ ^ \ + ( (unsigned long) RSb[ ( Y3 ) & 0xFF ] ) ^ + ( (unsigned long) RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); + } + else /* AES_ENCRYPT */ + { + for( i = (ctx->nr >> 1) - 1; i > 0; i-- ) + { + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (unsigned long) FSb[ ( Y0 ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); + + X1 = *RK++ ^ \ + ( (unsigned long) FSb[ ( Y1 ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); + + X2 = *RK++ ^ \ + ( (unsigned long) FSb[ ( Y2 ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); + + X3 = *RK++ ^ \ + ( (unsigned long) FSb[ ( Y3 ) & 0xFF ] ) ^ + ( (unsigned long) FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ + ( (unsigned long) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ + ( (unsigned long) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); + } + + PUT_ULONG_LE( X0, output, 0 ); + PUT_ULONG_LE( X1, output, 4 ); + PUT_ULONG_LE( X2, output, 8 ); + PUT_ULONG_LE( X3, output, 12 ); +} + +/* + * AES-CBC buffer encryption/decryption + */ +void aes_crypt_cbc( aes_context *ctx, + int mode, + int length, + unsigned char iv[16], + unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[16]; + +#if defined(XYSSL_PADLOCK_C) && defined(XYSSL_HAVE_X86) + if( padlock_supports( PADLOCK_ACE ) ) + { + if( padlock_xcryptcbc( ctx, mode, length, iv, input, output ) == 0 ) + return; + } +#endif + + if( mode == AES_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 16 ); + aes_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + aes_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } +} + +/* + * AES-CFB128 buffer encryption/decryption + */ +void aes_crypt_cfb128( aes_context *ctx, + int mode, + int length, + int *iv_off, + unsigned char iv[16], + unsigned char *input, + unsigned char *output ) +{ + int c, n = *iv_off; + + if( mode == AES_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = (n + 1) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = (n + 1) & 0x0F; + } + } + + *iv_off = n; +} + +#if defined(XYSSL_SELF_TEST) + +#include + +/* + * AES test vectors from: + * + * http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip + */ +static const unsigned char aes_test_ecb_dec[3][16] = +{ + { 0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58, + 0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0 }, + { 0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2, + 0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4 }, + { 0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D, + 0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE } +}; + +static const unsigned char aes_test_ecb_enc[3][16] = +{ + { 0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73, + 0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F }, + { 0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11, + 0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14 }, + { 0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D, + 0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4 } +}; + +static const unsigned char aes_test_cbc_dec[3][16] = +{ + { 0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73, + 0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86 }, + { 0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75, + 0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B }, + { 0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75, + 0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13 } +}; + +static const unsigned char aes_test_cbc_enc[3][16] = +{ + { 0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84, + 0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D }, + { 0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB, + 0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04 }, + { 0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5, + 0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0 } +}; + +/* + * AES-CFB128 test vectors from: + * + * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + */ +static const unsigned char aes_test_cfb128_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }, + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }, + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char aes_test_cfb128_iv[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; + +static const unsigned char aes_test_cfb128_pt[64] = +{ + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 +}; + +static const unsigned char aes_test_cfb128_ct[3][64] = +{ + { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, + 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A, + 0xC8, 0xA6, 0x45, 0x37, 0xA0, 0xB3, 0xA9, 0x3F, + 0xCD, 0xE3, 0xCD, 0xAD, 0x9F, 0x1C, 0xE5, 0x8B, + 0x26, 0x75, 0x1F, 0x67, 0xA3, 0xCB, 0xB1, 0x40, + 0xB1, 0x80, 0x8C, 0xF1, 0x87, 0xA4, 0xF4, 0xDF, + 0xC0, 0x4B, 0x05, 0x35, 0x7C, 0x5D, 0x1C, 0x0E, + 0xEA, 0xC4, 0xC6, 0x6F, 0x9F, 0xF7, 0xF2, 0xE6 }, + { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB, + 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74, + 0x67, 0xCE, 0x7F, 0x7F, 0x81, 0x17, 0x36, 0x21, + 0x96, 0x1A, 0x2B, 0x70, 0x17, 0x1D, 0x3D, 0x7A, + 0x2E, 0x1E, 0x8A, 0x1D, 0xD5, 0x9B, 0x88, 0xB1, + 0xC8, 0xE6, 0x0F, 0xED, 0x1E, 0xFA, 0xC4, 0xC9, + 0xC0, 0x5F, 0x9F, 0x9C, 0xA9, 0x83, 0x4F, 0xA0, + 0x42, 0xAE, 0x8F, 0xBA, 0x58, 0x4B, 0x09, 0xFF }, + { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B, + 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60, + 0x39, 0xFF, 0xED, 0x14, 0x3B, 0x28, 0xB1, 0xC8, + 0x32, 0x11, 0x3C, 0x63, 0x31, 0xE5, 0x40, 0x7B, + 0xDF, 0x10, 0x13, 0x24, 0x15, 0xE5, 0x4B, 0x92, + 0xA1, 0x3E, 0xD0, 0xA8, 0x26, 0x7A, 0xE2, 0xF9, + 0x75, 0xA3, 0x85, 0x74, 0x1A, 0xB9, 0xCE, 0xF8, + 0x20, 0x31, 0x62, 0x3D, 0x55, 0xB1, 0xE4, 0x71 } +}; + +/* + * Checkup routine + */ +int aes_self_test( int verbose ) +{ + int i, j, u, v, offset; + unsigned char key[32]; + unsigned char buf[64]; + unsigned char prv[16]; + unsigned char iv[16]; + aes_context ctx; + + memset( key, 0, 32 ); + + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " AES-ECB-%3d (%s): ", 128 + u * 64, + ( v == AES_DECRYPT ) ? "dec" : "enc" ); + + memset( buf, 0, 16 ); + + if( v == AES_DECRYPT ) + { + aes_setkey_dec( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + aes_crypt_ecb( &ctx, v, buf, buf ); + + if( memcmp( buf, aes_test_ecb_dec[u], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + else + { + aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + aes_crypt_ecb( &ctx, v, buf, buf ); + + if( memcmp( buf, aes_test_ecb_enc[u], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " AES-CBC-%3d (%s): ", 128 + u * 64, + ( v == AES_DECRYPT ) ? "dec" : "enc" ); + + memset( iv , 0, 16 ); + memset( prv, 0, 16 ); + memset( buf, 0, 16 ); + + if( v == AES_DECRYPT ) + { + aes_setkey_dec( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); + + if( memcmp( buf, aes_test_cbc_dec[u], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + else + { + aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + { + unsigned char tmp[16]; + + aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); + + memcpy( tmp, prv, 16 ); + memcpy( prv, buf, 16 ); + memcpy( buf, tmp, 16 ); + } + + if( memcmp( prv, aes_test_cbc_enc[u], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + /* + * CFB128 mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " AES-CFB128-%3d (%s): ", 128 + u * 64, + ( v == AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, aes_test_cfb128_iv, 16 ); + memcpy( key, aes_test_cfb128_key[u], 16 + u * 8 ); + + offset = 0; + aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + if( v == AES_DECRYPT ) + { + memcpy( buf, aes_test_cfb128_ct[u], 64 ); + aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); + + if( memcmp( buf, aes_test_cfb128_pt, 64 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + else + { + memcpy( buf, aes_test_cfb128_pt, 64 ); + aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); + + if( memcmp( buf, aes_test_cfb128_ct[u], 64 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/library/arc4.c b/library/arc4.c new file mode 100644 index 000000000..d226c07c4 --- /dev/null +++ b/library/arc4.c @@ -0,0 +1,158 @@ +/* + * An implementation of the ARCFOUR algorithm + * + * Copyright (C) 2006-2007 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The ARCFOUR algorithm was publicly disclosed on 94/09. + * + * http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0 + */ + +#include "xyssl/config.h" + +#if defined(XYSSL_ARC4_C) + +#include "xyssl/arc4.h" + +/* + * ARC4 key schedule + */ +void arc4_setup( arc4_context *ctx, unsigned char *key, int keylen ) +{ + int i, j, k, a; + unsigned char *m; + + ctx->x = 0; + ctx->y = 0; + m = ctx->m; + + for( i = 0; i < 256; i++ ) + m[i] = (unsigned char) i; + + j = k = 0; + + for( i = 0; i < 256; i++, k++ ) + { + if( k >= keylen ) k = 0; + + a = m[i]; + j = ( j + a + key[k] ) & 0xFF; + m[i] = m[j]; + m[j] = (unsigned char) a; + } +} + +/* + * ARC4 cipher function + */ +void arc4_crypt( arc4_context *ctx, unsigned char *buf, int buflen ) +{ + int i, x, y, a, b; + unsigned char *m; + + x = ctx->x; + y = ctx->y; + m = ctx->m; + + for( i = 0; i < buflen; i++ ) + { + x = ( x + 1 ) & 0xFF; a = m[x]; + y = ( y + a ) & 0xFF; b = m[y]; + + m[x] = (unsigned char) b; + m[y] = (unsigned char) a; + + buf[i] = (unsigned char) + ( buf[i] ^ m[(unsigned char)( a + b )] ); + } + + ctx->x = x; + ctx->y = y; +} + +#if defined(XYSSL_SELF_TEST) + +#include +#include + +/* + * ARC4 tests vectors as posted by Eric Rescorla in sep. 1994: + * + * http://groups.google.com/group/comp.security.misc/msg/10a300c9d21afca0 + */ +static const unsigned char arc4_test_key[3][8] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char arc4_test_pt[3][8] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char arc4_test_ct[3][8] = +{ + { 0x75, 0xB7, 0x87, 0x80, 0x99, 0xE0, 0xC5, 0x96 }, + { 0x74, 0x94, 0xC2, 0xE7, 0x10, 0x4B, 0x08, 0x79 }, + { 0xDE, 0x18, 0x89, 0x41, 0xA3, 0x37, 0x5D, 0x3A } +}; + +/* + * Checkup routine + */ +int arc4_self_test( int verbose ) +{ + int i; + unsigned char buf[8]; + arc4_context ctx; + + for( i = 0; i < 3; i++ ) + { + if( verbose != 0 ) + printf( " ARC4 test #%d: ", i + 1 ); + + memcpy( buf, arc4_test_pt[i], 8 ); + + arc4_setup( &ctx, (unsigned char *) arc4_test_key[i], 8 ); + arc4_crypt( &ctx, buf, 8 ); + + if( memcmp( buf, arc4_test_ct[i], 8 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/library/base64.c b/library/base64.c new file mode 100644 index 000000000..be6c02414 --- /dev/null +++ b/library/base64.c @@ -0,0 +1,249 @@ +/* + * RFC 1521 base64 encoding/decoding + * + * Copyright (C) 2006-2007 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "xyssl/config.h" + +#if defined(XYSSL_BASE64_C) + +#include "xyssl/base64.h" + +static const unsigned char base64_enc_map[64] = +{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/' +}; + +static const unsigned char base64_dec_map[128] = +{ + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, + 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 127, 127, 127, 127, 127 +}; + +/* + * Encode a buffer into base64 format + */ +int base64_encode( unsigned char *dst, int *dlen, + unsigned char *src, int slen ) +{ + int i, n; + int C1, C2, C3; + unsigned char *p; + + if( slen == 0 ) + return( 0 ); + + n = (slen << 3) / 6; + + switch( (slen << 3) - (n * 6) ) + { + case 2: n += 3; break; + case 4: n += 2; break; + default: break; + } + + if( *dlen < n + 1 ) + { + *dlen = n + 1; + return( XYSSL_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + n = (slen / 3) * 3; + + for( i = 0, p = dst; i < n; i += 3 ) + { + C1 = *src++; + C2 = *src++; + C3 = *src++; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F]; + *p++ = base64_enc_map[C3 & 0x3F]; + } + + if( i < slen ) + { + C1 = *src++; + C2 = ((i + 1) < slen) ? *src++ : 0; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + + if( (i + 1) < slen ) + *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F]; + else *p++ = '='; + + *p++ = '='; + } + + *dlen = p - dst; + *p = 0; + + return( 0 ); +} + +/* + * Decode a base64-formatted buffer + */ +int base64_decode( unsigned char *dst, int *dlen, + unsigned char *src, int slen ) +{ + int i, j, n; + unsigned long x; + unsigned char *p; + + for( i = j = n = 0; i < slen; i++ ) + { + if( ( slen - i ) >= 2 && + src[i] == '\r' && src[i + 1] == '\n' ) + continue; + + if( src[i] == '\n' ) + continue; + + if( src[i] == '=' && ++j > 2 ) + return( XYSSL_ERR_BASE64_INVALID_CHARACTER ); + + if( src[i] > 127 || base64_dec_map[src[i]] == 127 ) + return( XYSSL_ERR_BASE64_INVALID_CHARACTER ); + + if( base64_dec_map[src[i]] < 64 && j != 0 ) + return( XYSSL_ERR_BASE64_INVALID_CHARACTER ); + + n++; + } + + if( n == 0 ) + return( 0 ); + + n = ((n * 6) + 7) >> 3; + + if( *dlen < n ) + { + *dlen = n; + return( XYSSL_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) + { + if( *src == '\r' || *src == '\n' ) + continue; + + j -= ( base64_dec_map[*src] == 64 ); + x = (x << 6) | ( base64_dec_map[*src] & 0x3F ); + + if( ++n == 4 ) + { + n = 0; + if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); + if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); + if( j > 2 ) *p++ = (unsigned char)( x ); + } + } + + *dlen = p - dst; + + return( 0 ); +} + +#if defined(XYSSL_SELF_TEST) + +#include +#include + +static const unsigned char base64_test_dec[64] = +{ + 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD, + 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01, + 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09, + 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13, + 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31, + 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38, + 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B, + 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97 +}; + +static const unsigned char base64_test_enc[] = + "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK" + "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw=="; + +/* + * Checkup routine + */ +int base64_self_test( int verbose ) +{ + int len; + unsigned char *src, buffer[128]; + + if( verbose != 0 ) + printf( " Base64 encoding test: " ); + + len = sizeof( buffer ); + src = (unsigned char *) base64_test_dec; + + if( base64_encode( buffer, &len, src, 64 ) != 0 || + memcmp( base64_test_enc, buffer, 88 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n Base64 decoding test: " ); + + len = sizeof( buffer ); + src = (unsigned char *) base64_test_enc; + + if( base64_decode( buffer, &len, src, 88 ) != 0 || + memcmp( base64_test_dec, buffer, 64 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/library/bignum.c b/library/bignum.c new file mode 100644 index 000000000..f25fc4d12 --- /dev/null +++ b/library/bignum.c @@ -0,0 +1,1955 @@ +/* + * Multi-precision integer library + * + * Copyright (C) 2006-2007 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * This MPI implementation is based on: + * + * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf + * http://www.stillhq.com/extracted/gnupg-api/mpi/ + * http://math.libtomcrypt.com/files/tommath.pdf + */ + +#include "xyssl/config.h" + +#if defined(XYSSL_BIGNUM_C) + +#include "xyssl/bignum.h" +#include "xyssl/bn_mul.h" + +#include +#include +#include + +#define ciL ((int) sizeof(t_int)) /* chars in limb */ +#define biL (ciL << 3) /* bits in limb */ +#define biH (ciL << 2) /* half limb size */ + +/* + * Convert between bits/chars and number of limbs + */ +#define BITS_TO_LIMBS(i) (((i) + biL - 1) / biL) +#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL) + +/* + * Initialize one or more mpi + */ +void mpi_init( mpi *X, ... ) +{ + va_list args; + + va_start( args, X ); + + while( X != NULL ) + { + X->s = 1; + X->n = 0; + X->p = NULL; + + X = va_arg( args, mpi* ); + } + + va_end( args ); +} + +/* + * Unallocate one or more mpi + */ +void mpi_free( mpi *X, ... ) +{ + va_list args; + + va_start( args, X ); + + while( X != NULL ) + { + if( X->p != NULL ) + { + memset( X->p, 0, X->n * ciL ); + free( X->p ); + } + + X->s = 1; + X->n = 0; + X->p = NULL; + + X = va_arg( args, mpi* ); + } + + va_end( args ); +} + +/* + * Enlarge to the specified number of limbs + */ +int mpi_grow( mpi *X, int nblimbs ) +{ + t_int *p; + + if( X->n < nblimbs ) + { + if( ( p = (t_int *) malloc( nblimbs * ciL ) ) == NULL ) + return( 1 ); + + memset( p, 0, nblimbs * ciL ); + + if( X->p != NULL ) + { + memcpy( p, X->p, X->n * ciL ); + memset( X->p, 0, X->n * ciL ); + free( X->p ); + } + + X->n = nblimbs; + X->p = p; + } + + return( 0 ); +} + +/* + * Copy the contents of Y into X + */ +int mpi_copy( mpi *X, mpi *Y ) +{ + int ret, i; + + if( X == Y ) + return( 0 ); + + for( i = Y->n - 1; i > 0; i-- ) + if( Y->p[i] != 0 ) + break; + i++; + + X->s = Y->s; + + MPI_CHK( mpi_grow( X, i ) ); + + memset( X->p, 0, X->n * ciL ); + memcpy( X->p, Y->p, i * ciL ); + +cleanup: + + return( ret ); +} + +/* + * Swap the contents of X and Y + */ +void mpi_swap( mpi *X, mpi *Y ) +{ + mpi T; + + memcpy( &T, X, sizeof( mpi ) ); + memcpy( X, Y, sizeof( mpi ) ); + memcpy( Y, &T, sizeof( mpi ) ); +} + +/* + * Set value from integer + */ +int mpi_lset( mpi *X, int z ) +{ + int ret; + + MPI_CHK( mpi_grow( X, 1 ) ); + memset( X->p, 0, X->n * ciL ); + + X->p[0] = ( z < 0 ) ? -z : z; + X->s = ( z < 0 ) ? -1 : 1; + +cleanup: + + return( ret ); +} + +/* + * Return the number of least significant bits + */ +int mpi_lsb( mpi *X ) +{ + int i, j, count = 0; + + for( i = 0; i < X->n; i++ ) + for( j = 0; j < (int) biL; j++, count++ ) + if( ( ( X->p[i] >> j ) & 1 ) != 0 ) + return( count ); + + return( 0 ); +} + +/* + * Return the number of most significant bits + */ +int mpi_msb( mpi *X ) +{ + int i, j; + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + + for( j = biL - 1; j >= 0; j-- ) + if( ( ( X->p[i] >> j ) & 1 ) != 0 ) + break; + + return( ( i * biL ) + j + 1 ); +} + +/* + * Return the total size in bytes + */ +int mpi_size( mpi *X ) +{ + return( ( mpi_msb( X ) + 7 ) >> 3 ); +} + +/* + * Convert an ASCII character to digit value + */ +static int mpi_get_digit( t_int *d, int radix, char c ) +{ + *d = 255; + + if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; + if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; + if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; + + if( *d >= (t_int) radix ) + return( XYSSL_ERR_MPI_INVALID_CHARACTER ); + + return( 0 ); +} + +/* + * Import from an ASCII string + */ +int mpi_read_string( mpi *X, int radix, char *s ) +{ + int ret, i, j, n; + t_int d; + mpi T; + + if( radix < 2 || radix > 16 ) + return( XYSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &T, NULL ); + + if( radix == 16 ) + { + n = BITS_TO_LIMBS( strlen( s ) << 2 ); + + MPI_CHK( mpi_grow( X, n ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = strlen( s ) - 1, j = 0; i >= 0; i--, j++ ) + { + if( i == 0 && s[i] == '-' ) + { + X->s = -1; + break; + } + + MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); + X->p[j / (2 * ciL)] |= d << ( (j % (2 * ciL)) << 2 ); + } + } + else + { + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = 0; i < (int) strlen( s ); i++ ) + { + if( i == 0 && s[i] == '-' ) + { + X->s = -1; + continue; + } + + MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); + MPI_CHK( mpi_mul_int( &T, X, radix ) ); + MPI_CHK( mpi_add_int( X, &T, d ) ); + } + } + +cleanup: + + mpi_free( &T, NULL ); + + return( ret ); +} + +/* + * Helper to write the digits high-order first + */ +static int mpi_write_hlp( mpi *X, int radix, char **p ) +{ + int ret; + t_int r; + + if( radix < 2 || radix > 16 ) + return( XYSSL_ERR_MPI_BAD_INPUT_DATA ); + + MPI_CHK( mpi_mod_int( &r, X, radix ) ); + MPI_CHK( mpi_div_int( X, NULL, X, radix ) ); + + if( mpi_cmp_int( X, 0 ) != 0 ) + MPI_CHK( mpi_write_hlp( X, radix, p ) ); + + if( r < 10 ) + *(*p)++ = (char)( r + 0x30 ); + else + *(*p)++ = (char)( r + 0x37 ); + +cleanup: + + return( ret ); +} + +/* + * Export into an ASCII string + */ +int mpi_write_string( mpi *X, int radix, char *s, int *slen ) +{ + int ret = 0, n; + char *p; + mpi T; + + if( radix < 2 || radix > 16 ) + return( XYSSL_ERR_MPI_BAD_INPUT_DATA ); + + n = mpi_msb( X ); + if( radix >= 4 ) n >>= 1; + if( radix >= 16 ) n >>= 1; + n += 3; + + if( *slen < n ) + { + *slen = n; + return( XYSSL_ERR_MPI_BUFFER_TOO_SMALL ); + } + + p = s; + mpi_init( &T, NULL ); + + if( X->s == -1 ) + *p++ = '-'; + + if( radix == 16 ) + { + int c, i, j, k; + + for( i = X->n - 1, k = 0; i >= 0; i-- ) + { + for( j = ciL - 1; j >= 0; j-- ) + { + c = ( X->p[i] >> (j << 3) ) & 0xFF; + + if( c == 0 && k == 0 && (i + j) != 0 ) + continue; + + p += sprintf( p, "%02X", c ); + k = 1; + } + } + } + else + { + MPI_CHK( mpi_copy( &T, X ) ); + MPI_CHK( mpi_write_hlp( &T, radix, &p ) ); + } + + *p++ = '\0'; + *slen = p - s; + +cleanup: + + mpi_free( &T, NULL ); + + return( ret ); +} + +/* + * Read X from an opened file + */ +int mpi_read_file( mpi *X, int radix, FILE *fin ) +{ + t_int d; + int slen; + char *p; + char s[1024]; + + memset( s, 0, sizeof( s ) ); + if( fgets( s, sizeof( s ) - 1, fin ) == NULL ) + return( XYSSL_ERR_MPI_FILE_IO_ERROR ); + + slen = strlen( s ); + if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; } + if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; } + + p = s + slen; + while( --p >= s ) + if( mpi_get_digit( &d, radix, *p ) != 0 ) + break; + + return( mpi_read_string( X, radix, p + 1 ) ); +} + +/* + * Write X into an opened file (or stdout if fout == NULL) + */ +int mpi_write_file( char *p, mpi *X, int radix, FILE *fout ) +{ + int n, ret; + size_t slen; + size_t plen; + char s[1024]; + + n = sizeof( s ); + memset( s, 0, n ); + n -= 2; + + MPI_CHK( mpi_write_string( X, radix, s, (int *) &n ) ); + + if( p == NULL ) p = ""; + + plen = strlen( p ); + slen = strlen( s ); + s[slen++] = '\r'; + s[slen++] = '\n'; + + if( fout != NULL ) + { + if( fwrite( p, 1, plen, fout ) != plen || + fwrite( s, 1, slen, fout ) != slen ) + return( XYSSL_ERR_MPI_FILE_IO_ERROR ); + } + else + printf( "%s%s", p, s ); + +cleanup: + + return( ret ); +} + +/* + * Import X from unsigned binary data, big endian + */ +int mpi_read_binary( mpi *X, unsigned char *buf, int buflen ) +{ + int ret, i, j, n; + + for( n = 0; n < buflen; n++ ) + if( buf[n] != 0 ) + break; + + MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = buflen - 1, j = 0; i >= n; i--, j++ ) + X->p[j / ciL] |= ((t_int) buf[i]) << ((j % ciL) << 3); + +cleanup: + + return( ret ); +} + +/* + * Export X into unsigned binary data, big endian + */ +int mpi_write_binary( mpi *X, unsigned char *buf, int buflen ) +{ + int i, j, n; + + n = mpi_size( X ); + + if( buflen < n ) + return( XYSSL_ERR_MPI_BUFFER_TOO_SMALL ); + + memset( buf, 0, buflen ); + + for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- ) + buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) ); + + return( 0 ); +} + +/* + * Left-shift: X <<= count + */ +int mpi_shift_l( mpi *X, int count ) +{ + int ret, i, v0, t1; + t_int r0 = 0, r1; + + v0 = count / (biL ); + t1 = count & (biL - 1); + + i = mpi_msb( X ) + count; + + if( X->n * (int) biL < i ) + MPI_CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) ); + + ret = 0; + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = X->n - 1; i >= v0; i-- ) + X->p[i] = X->p[i - v0]; + + for( ; i >= 0; i-- ) + X->p[i] = 0; + } + + /* + * shift by count % limb_size + */ + if( t1 > 0 ) + { + for( i = v0; i < X->n; i++ ) + { + r1 = X->p[i] >> (biL - t1); + X->p[i] <<= t1; + X->p[i] |= r0; + r0 = r1; + } + } + +cleanup: + + return( ret ); +} + +/* + * Right-shift: X >>= count + */ +int mpi_shift_r( mpi *X, int count ) +{ + int i, v0, v1; + t_int r0 = 0, r1; + + v0 = count / biL; + v1 = count & (biL - 1); + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = 0; i < X->n - v0; i++ ) + X->p[i] = X->p[i + v0]; + + for( ; i < X->n; i++ ) + X->p[i] = 0; + } + + /* + * shift by count % limb_size + */ + if( v1 > 0 ) + { + for( i = X->n - 1; i >= 0; i-- ) + { + r1 = X->p[i] << (biL - v1); + X->p[i] >>= v1; + X->p[i] |= r0; + r0 = r1; + } + } + + return( 0 ); +} + +/* + * Compare unsigned values + */ +int mpi_cmp_abs( mpi *X, mpi *Y ) +{ + int i, j; + + for( i = X->n - 1; i >= 0; i-- ) + if( X->p[i] != 0 ) + break; + + for( j = Y->n - 1; j >= 0; j-- ) + if( Y->p[j] != 0 ) + break; + + if( i < 0 && j < 0 ) + return( 0 ); + + if( i > j ) return( 1 ); + if( j > i ) return( -1 ); + + for( ; i >= 0; i-- ) + { + if( X->p[i] > Y->p[i] ) return( 1 ); + if( X->p[i] < Y->p[i] ) return( -1 ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mpi_cmp_mpi( mpi *X, mpi *Y ) +{ + int i, j; + + for( i = X->n - 1; i >= 0; i-- ) + if( X->p[i] != 0 ) + break; + + for( j = Y->n - 1; j >= 0; j-- ) + if( Y->p[j] != 0 ) + break; + + if( i < 0 && j < 0 ) + return( 0 ); + + if( i > j ) return( X->s ); + if( j > i ) return( -X->s ); + + if( X->s > 0 && Y->s < 0 ) return( 1 ); + if( Y->s > 0 && X->s < 0 ) return( -1 ); + + for( ; i >= 0; i-- ) + { + if( X->p[i] > Y->p[i] ) return( X->s ); + if( X->p[i] < Y->p[i] ) return( -X->s ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mpi_cmp_int( mpi *X, int z ) +{ + mpi Y; + t_int p[1]; + + *p = ( z < 0 ) ? -z : z; + Y.s = ( z < 0 ) ? -1 : 1; + Y.n = 1; + Y.p = p; + + return( mpi_cmp_mpi( X, &Y ) ); +} + +/* + * Unsigned addition: X = |A| + |B| (HAC 14.7) + */ +int mpi_add_abs( mpi *X, mpi *A, mpi *B ) +{ + int ret, i, j; + t_int *o, *p, c; + + if( X == B ) + { + mpi *T = A; A = X; B = T; + } + + if( X != A ) + MPI_CHK( mpi_copy( X, A ) ); + + for( j = B->n - 1; j >= 0; j-- ) + if( B->p[j] != 0 ) + break; + + MPI_CHK( mpi_grow( X, j + 1 ) ); + + o = B->p; p = X->p; c = 0; + + for( i = 0; i <= j; i++, o++, p++ ) + { + *p += c; c = ( *p < c ); + *p += *o; c += ( *p < *o ); + } + + while( c != 0 ) + { + if( i >= X->n ) + { + MPI_CHK( mpi_grow( X, i + 1 ) ); + p = X->p + i; + } + + *p += c; c = ( *p < c ); i++; + } + +cleanup: + + return( ret ); +} + +/* + * Helper for mpi substraction + */ +static void mpi_sub_hlp( int n, t_int *s, t_int *d ) +{ + int i; + t_int c, z; + + for( i = c = 0; i < n; i++, s++, d++ ) + { + z = ( *d < c ); *d -= c; + c = ( *d < *s ) + z; *d -= *s; + } + + while( c != 0 ) + { + z = ( *d < c ); *d -= c; + c = z; i++; d++; + } +} + +/* + * Unsigned substraction: X = |A| - |B| (HAC 14.9) + */ +int mpi_sub_abs( mpi *X, mpi *A, mpi *B ) +{ + mpi TB; + int ret, n; + + if( mpi_cmp_abs( A, B ) < 0 ) + return( XYSSL_ERR_MPI_NEGATIVE_VALUE ); + + mpi_init( &TB, NULL ); + + if( X == B ) + { + MPI_CHK( mpi_copy( &TB, B ) ); + B = &TB; + } + + if( X != A ) + MPI_CHK( mpi_copy( X, A ) ); + + ret = 0; + + for( n = B->n - 1; n >= 0; n-- ) + if( B->p[n] != 0 ) + break; + + mpi_sub_hlp( n + 1, B->p, X->p ); + +cleanup: + + mpi_free( &TB, NULL ); + + return( ret ); +} + +/* + * Signed addition: X = A + B + */ +int mpi_add_mpi( mpi *X, mpi *A, mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s < 0 ) + { + if( mpi_cmp_abs( A, B ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MPI_CHK( mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MPI_CHK( mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed substraction: X = A - B + */ +int mpi_sub_mpi( mpi *X, mpi *A, mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s > 0 ) + { + if( mpi_cmp_abs( A, B ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MPI_CHK( mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MPI_CHK( mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed addition: X = A + b + */ +int mpi_add_int( mpi *X, mpi *A, int b ) +{ + mpi _B; + t_int p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_add_mpi( X, A, &_B ) ); +} + +/* + * Signed substraction: X = A - b + */ +int mpi_sub_int( mpi *X, mpi *A, int b ) +{ + mpi _B; + t_int p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_sub_mpi( X, A, &_B ) ); +} + +/* + * Helper for mpi multiplication + */ +static void mpi_mul_hlp( int i, t_int *s, t_int *d, t_int b ) +{ + t_int c = 0, t = 0; + +#if defined(MULADDC_HUIT) + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_HUIT + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#else + for( ; i >= 16; i -= 16 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#endif + + t++; + + do { + *d += c; c = ( *d < c ); d++; + } + while( c != 0 ); +} + +/* + * Baseline multiplication: X = A * B (HAC 14.12) + */ +int mpi_mul_mpi( mpi *X, mpi *A, mpi *B ) +{ + int ret, i, j; + mpi TA, TB; + + mpi_init( &TA, &TB, NULL ); + + if( X == A ) { MPI_CHK( mpi_copy( &TA, A ) ); A = &TA; } + if( X == B ) { MPI_CHK( mpi_copy( &TB, B ) ); B = &TB; } + + for( i = A->n - 1; i >= 0; i-- ) + if( A->p[i] != 0 ) + break; + + for( j = B->n - 1; j >= 0; j-- ) + if( B->p[j] != 0 ) + break; + + MPI_CHK( mpi_grow( X, i + j + 2 ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i++; j >= 0; j-- ) + mpi_mul_hlp( i, A->p, X->p + j, B->p[j] ); + + X->s = A->s * B->s; + +cleanup: + + mpi_free( &TB, &TA, NULL ); + + return( ret ); +} + +/* + * Baseline multiplication: X = A * b + */ +int mpi_mul_int( mpi *X, mpi *A, t_int b ) +{ + mpi _B; + t_int p[1]; + + _B.s = 1; + _B.n = 1; + _B.p = p; + p[0] = b; + + return( mpi_mul_mpi( X, A, &_B ) ); +} + +/* + * Division by mpi: A = Q * B + R (HAC 14.20) + */ +int mpi_div_mpi( mpi *Q, mpi *R, mpi *A, mpi *B ) +{ + int ret, i, n, t, k; + mpi X, Y, Z, T1, T2; + + if( mpi_cmp_int( B, 0 ) == 0 ) + return( XYSSL_ERR_MPI_DIVISION_BY_ZERO ); + + mpi_init( &X, &Y, &Z, &T1, &T2, NULL ); + + if( mpi_cmp_abs( A, B ) < 0 ) + { + if( Q != NULL ) MPI_CHK( mpi_lset( Q, 0 ) ); + if( R != NULL ) MPI_CHK( mpi_copy( R, A ) ); + return( 0 ); + } + + MPI_CHK( mpi_copy( &X, A ) ); + MPI_CHK( mpi_copy( &Y, B ) ); + X.s = Y.s = 1; + + MPI_CHK( mpi_grow( &Z, A->n + 2 ) ); + MPI_CHK( mpi_lset( &Z, 0 ) ); + MPI_CHK( mpi_grow( &T1, 2 ) ); + MPI_CHK( mpi_grow( &T2, 3 ) ); + + k = mpi_msb( &Y ) % biL; + if( k < (int) biL - 1 ) + { + k = biL - 1 - k; + MPI_CHK( mpi_shift_l( &X, k ) ); + MPI_CHK( mpi_shift_l( &Y, k ) ); + } + else k = 0; + + n = X.n - 1; + t = Y.n - 1; + mpi_shift_l( &Y, biL * (n - t) ); + + while( mpi_cmp_mpi( &X, &Y ) >= 0 ) + { + Z.p[n - t]++; + mpi_sub_mpi( &X, &X, &Y ); + } + mpi_shift_r( &Y, biL * (n - t) ); + + for( i = n; i > t ; i-- ) + { + if( X.p[i] >= Y.p[t] ) + Z.p[i - t - 1] = ~0; + else + { +#if defined(XYSSL_HAVE_LONGLONG) + t_dbl r; + + r = (t_dbl) X.p[i] << biL; + r |= (t_dbl) X.p[i - 1]; + r /= Y.p[t]; + if( r > ((t_dbl) 1 << biL) - 1) + r = ((t_dbl) 1 << biL) - 1; + + Z.p[i - t - 1] = (t_int) r; +#else + /* + * __udiv_qrnnd_c, from gmp/longlong.h + */ + t_int q0, q1, r0, r1; + t_int d0, d1, d, m; + + d = Y.p[t]; + d0 = ( d << biH ) >> biH; + d1 = ( d >> biH ); + + q1 = X.p[i] / d1; + r1 = X.p[i] - d1 * q1; + r1 <<= biH; + r1 |= ( X.p[i - 1] >> biH ); + + m = q1 * d0; + if( r1 < m ) + { + q1--, r1 += d; + while( r1 >= d && r1 < m ) + q1--, r1 += d; + } + r1 -= m; + + q0 = r1 / d1; + r0 = r1 - d1 * q0; + r0 <<= biH; + r0 |= ( X.p[i - 1] << biH ) >> biH; + + m = q0 * d0; + if( r0 < m ) + { + q0--, r0 += d; + while( r0 >= d && r0 < m ) + q0--, r0 += d; + } + r0 -= m; + + Z.p[i - t - 1] = ( q1 << biH ) | q0; +#endif + } + + Z.p[i - t - 1]++; + do + { + Z.p[i - t - 1]--; + + MPI_CHK( mpi_lset( &T1, 0 ) ); + T1.p[0] = (t < 1) ? 0 : Y.p[t - 1]; + T1.p[1] = Y.p[t]; + MPI_CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); + + MPI_CHK( mpi_lset( &T2, 0 ) ); + T2.p[0] = (i < 2) ? 0 : X.p[i - 2]; + T2.p[1] = (i < 1) ? 0 : X.p[i - 1]; + T2.p[2] = X.p[i]; + } + while( mpi_cmp_mpi( &T1, &T2 ) > 0 ); + + MPI_CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); + MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); + MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); + + if( mpi_cmp_int( &X, 0 ) < 0 ) + { + MPI_CHK( mpi_copy( &T1, &Y ) ); + MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); + MPI_CHK( mpi_add_mpi( &X, &X, &T1 ) ); + Z.p[i - t - 1]--; + } + } + + if( Q != NULL ) + { + mpi_copy( Q, &Z ); + Q->s = A->s * B->s; + } + + if( R != NULL ) + { + mpi_shift_r( &X, k ); + mpi_copy( R, &X ); + + R->s = A->s; + if( mpi_cmp_int( R, 0 ) == 0 ) + R->s = 1; + } + +cleanup: + + mpi_free( &X, &Y, &Z, &T1, &T2, NULL ); + + return( ret ); +} + +/* + * Division by int: A = Q * b + R + * + * Returns 0 if successful + * 1 if memory allocation failed + * XYSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0 + */ +int mpi_div_int( mpi *Q, mpi *R, mpi *A, int b ) +{ + mpi _B; + t_int p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_div_mpi( Q, R, A, &_B ) ); +} + +/* + * Modulo: R = A mod B + */ +int mpi_mod_mpi( mpi *R, mpi *A, mpi *B ) +{ + int ret; + + MPI_CHK( mpi_div_mpi( NULL, R, A, B ) ); + + while( mpi_cmp_int( R, 0 ) < 0 ) + MPI_CHK( mpi_add_mpi( R, R, B ) ); + + while( mpi_cmp_mpi( R, B ) >= 0 ) + MPI_CHK( mpi_sub_mpi( R, R, B ) ); + +cleanup: + + return( ret ); +} + +/* + * Modulo: r = A mod b + */ +int mpi_mod_int( t_int *r, mpi *A, int b ) +{ + int i; + t_int x, y, z; + + if( b == 0 ) + return( XYSSL_ERR_MPI_DIVISION_BY_ZERO ); + + if( b < 0 ) + b = -b; + + /* + * handle trivial cases + */ + if( b == 1 ) + { + *r = 0; + return( 0 ); + } + + if( b == 2 ) + { + *r = A->p[0] & 1; + return( 0 ); + } + + /* + * general case + */ + for( i = A->n - 1, y = 0; i >= 0; i-- ) + { + x = A->p[i]; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + + x <<= biH; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + } + + *r = y; + + return( 0 ); +} + +/* + * Fast Montgomery initialization (thanks to Tom St Denis) + */ +static void mpi_montg_init( t_int *mm, mpi *N ) +{ + t_int x, m0 = N->p[0]; + + x = m0; + x += ( ( m0 + 2 ) & 4 ) << 1; + x *= ( 2 - ( m0 * x ) ); + + if( biL >= 16 ) x *= ( 2 - ( m0 * x ) ); + if( biL >= 32 ) x *= ( 2 - ( m0 * x ) ); + if( biL >= 64 ) x *= ( 2 - ( m0 * x ) ); + + *mm = ~x + 1; +} + +/* + * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) + */ +static void mpi_montmul( mpi *A, mpi *B, mpi *N, t_int mm, mpi *T ) +{ + int i, n, m; + t_int u0, u1, *d; + + memset( T->p, 0, T->n * ciL ); + + d = T->p; + n = N->n; + m = ( B->n < n ) ? B->n : n; + + for( i = 0; i < n; i++ ) + { + /* + * T = (T + u0*B + u1*N) / 2^biL + */ + u0 = A->p[i]; + u1 = ( d[0] + u0 * B->p[0] ) * mm; + + mpi_mul_hlp( m, B->p, d, u0 ); + mpi_mul_hlp( n, N->p, d, u1 ); + + *d++ = u0; d[n + 1] = 0; + } + + memcpy( A->p, d, (n + 1) * ciL ); + + if( mpi_cmp_abs( A, N ) >= 0 ) + mpi_sub_hlp( n, N->p, A->p ); + else + /* prevent timing attacks */ + mpi_sub_hlp( n, A->p, T->p ); +} + +/* + * Montgomery reduction: A = A * R^-1 mod N + */ +static void mpi_montred( mpi *A, mpi *N, t_int mm, mpi *T ) +{ + t_int z = 1; + mpi U; + + U.n = U.s = z; + U.p = &z; + + mpi_montmul( A, &U, N, mm, T ); +} + +/* + * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) + */ +int mpi_exp_mod( mpi *X, mpi *A, mpi *E, mpi *N, mpi *_RR ) +{ + int ret, i, j, wsize, wbits; + int bufsize, nblimbs, nbits; + t_int ei, mm, state; + mpi RR, T, W[64]; + + if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) + return( XYSSL_ERR_MPI_BAD_INPUT_DATA ); + + /* + * Init temps and window size + */ + mpi_montg_init( &mm, N ); + mpi_init( &RR, &T, NULL ); + memset( W, 0, sizeof( W ) ); + + i = mpi_msb( E ); + + wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : + ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; + + j = N->n + 1; + MPI_CHK( mpi_grow( X, j ) ); + MPI_CHK( mpi_grow( &W[1], j ) ); + MPI_CHK( mpi_grow( &T, j * 2 ) ); + + /* + * If 1st call, pre-compute R^2 mod N + */ + if( _RR == NULL || _RR->p == NULL ) + { + MPI_CHK( mpi_lset( &RR, 1 ) ); + MPI_CHK( mpi_shift_l( &RR, N->n * 2 * biL ) ); + MPI_CHK( mpi_mod_mpi( &RR, &RR, N ) ); + + if( _RR != NULL ) + memcpy( _RR, &RR, sizeof( mpi ) ); + } + else + memcpy( &RR, _RR, sizeof( mpi ) ); + + /* + * W[1] = A * R^2 * R^-1 mod N = A * R mod N + */ + if( mpi_cmp_mpi( A, N ) >= 0 ) + mpi_mod_mpi( &W[1], A, N ); + else mpi_copy( &W[1], A ); + + mpi_montmul( &W[1], &RR, N, mm, &T ); + + /* + * X = R^2 * R^-1 mod N = R mod N + */ + MPI_CHK( mpi_copy( X, &RR ) ); + mpi_montred( X, N, mm, &T ); + + if( wsize > 1 ) + { + /* + * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) + */ + j = 1 << (wsize - 1); + + MPI_CHK( mpi_grow( &W[j], N->n + 1 ) ); + MPI_CHK( mpi_copy( &W[j], &W[1] ) ); + + for( i = 0; i < wsize - 1; i++ ) + mpi_montmul( &W[j], &W[j], N, mm, &T ); + + /* + * W[i] = W[i - 1] * W[1] + */ + for( i = j + 1; i < (1 << wsize); i++ ) + { + MPI_CHK( mpi_grow( &W[i], N->n + 1 ) ); + MPI_CHK( mpi_copy( &W[i], &W[i - 1] ) ); + + mpi_montmul( &W[i], &W[1], N, mm, &T ); + } + } + + nblimbs = E->n; + bufsize = 0; + nbits = 0; + wbits = 0; + state = 0; + + while( 1 ) + { + if( bufsize == 0 ) + { + if( nblimbs-- == 0 ) + break; + + bufsize = sizeof( t_int ) << 3; + } + + bufsize--; + + ei = (E->p[nblimbs] >> bufsize) & 1; + + /* + * skip leading 0s + */ + if( ei == 0 && state == 0 ) + continue; + + if( ei == 0 && state == 1 ) + { + /* + * out of window, square X + */ + mpi_montmul( X, X, N, mm, &T ); + continue; + } + + /* + * add ei to current window + */ + state = 2; + + nbits++; + wbits |= (ei << (wsize - nbits)); + + if( nbits == wsize ) + { + /* + * X = X^wsize R^-1 mod N + */ + for( i = 0; i < wsize; i++ ) + mpi_montmul( X, X, N, mm, &T ); + + /* + * X = X * W[wbits] R^-1 mod N + */ + mpi_montmul( X, &W[wbits], N, mm, &T ); + + state--; + nbits = 0; + wbits = 0; + } + } + + /* + * process the remaining bits + */ + for( i = 0; i < nbits; i++ ) + { + mpi_montmul( X, X, N, mm, &T ); + + wbits <<= 1; + + if( (wbits & (1 << wsize)) != 0 ) + mpi_montmul( X, &W[1], N, mm, &T ); + } + + /* + * X = A^E * R * R^-1 mod N = A^E mod N + */ + mpi_montred( X, N, mm, &T ); + +cleanup: + + for( i = (1 << (wsize - 1)); i < (1 << wsize); i++ ) + mpi_free( &W[i], NULL ); + + if( _RR != NULL ) + mpi_free( &W[1], &T, NULL ); + else mpi_free( &W[1], &T, &RR, NULL ); + + return( ret ); +} + +#if defined(XYSSL_GENPRIME) + +/* + * Greatest common divisor: G = gcd(A, B) (HAC 14.54) + */ +int mpi_gcd( mpi *G, mpi *A, mpi *B ) +{ + int ret; + mpi TG, TA, TB; + + mpi_init( &TG, &TA, &TB, NULL ); + + MPI_CHK( mpi_lset( &TG, 1 ) ); + MPI_CHK( mpi_copy( &TA, A ) ); + MPI_CHK( mpi_copy( &TB, B ) ); + + TA.s = TB.s = 1; + + while( mpi_cmp_int( &TA, 0 ) != 0 ) + { + while( ( TA.p[0] & 1 ) == 0 ) MPI_CHK( mpi_shift_r( &TA, 1 ) ); + while( ( TB.p[0] & 1 ) == 0 ) MPI_CHK( mpi_shift_r( &TB, 1 ) ); + + if( mpi_cmp_mpi( &TA, &TB ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( &TA, &TA, &TB ) ); + MPI_CHK( mpi_shift_r( &TA, 1 ) ); + } + else + { + MPI_CHK( mpi_sub_abs( &TB, &TB, &TA ) ); + MPI_CHK( mpi_shift_r( &TB, 1 ) ); + } + } + + MPI_CHK( mpi_mul_mpi( G, &TG, &TB ) ); + +cleanup: + + mpi_free( &TB, &TA, &TG, NULL ); + + return( ret ); +} + +/* + * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) + */ +int mpi_inv_mod( mpi *X, mpi *A, mpi *N ) +{ + int ret; + mpi G, TA, TU, U1, U2, TB, TV, V1, V2; + + if( mpi_cmp_int( N, 0 ) <= 0 ) + return( XYSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &TA, &TU, &U1, &U2, &G, + &TB, &TV, &V1, &V2, NULL ); + + MPI_CHK( mpi_gcd( &G, A, N ) ); + + if( mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = XYSSL_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + MPI_CHK( mpi_mod_mpi( &TA, A, N ) ); + MPI_CHK( mpi_copy( &TU, &TA ) ); + MPI_CHK( mpi_copy( &TB, N ) ); + MPI_CHK( mpi_copy( &TV, N ) ); + + MPI_CHK( mpi_lset( &U1, 1 ) ); + MPI_CHK( mpi_lset( &U2, 0 ) ); + MPI_CHK( mpi_lset( &V1, 0 ) ); + MPI_CHK( mpi_lset( &V2, 1 ) ); + + do + { + while( ( TU.p[0] & 1 ) == 0 ) + { + MPI_CHK( mpi_shift_r( &TU, 1 ) ); + + if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) + { + MPI_CHK( mpi_add_mpi( &U1, &U1, &TB ) ); + MPI_CHK( mpi_sub_mpi( &U2, &U2, &TA ) ); + } + + MPI_CHK( mpi_shift_r( &U1, 1 ) ); + MPI_CHK( mpi_shift_r( &U2, 1 ) ); + } + + while( ( TV.p[0] & 1 ) == 0 ) + { + MPI_CHK( mpi_shift_r( &TV, 1 ) ); + + if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) + { + MPI_CHK( mpi_add_mpi( &V1, &V1, &TB ) ); + MPI_CHK( mpi_sub_mpi( &V2, &V2, &TA ) ); + } + + MPI_CHK( mpi_shift_r( &V1, 1 ) ); + MPI_CHK( mpi_shift_r( &V2, 1 ) ); + } + + if( mpi_cmp_mpi( &TU, &TV ) >= 0 ) + { + MPI_CHK( mpi_sub_mpi( &TU, &TU, &TV ) ); + MPI_CHK( mpi_sub_mpi( &U1, &U1, &V1 ) ); + MPI_CHK( mpi_sub_mpi( &U2, &U2, &V2 ) ); + } + else + { + MPI_CHK( mpi_sub_mpi( &TV, &TV, &TU ) ); + MPI_CHK( mpi_sub_mpi( &V1, &V1, &U1 ) ); + MPI_CHK( mpi_sub_mpi( &V2, &V2, &U2 ) ); + } + } + while( mpi_cmp_int( &TU, 0 ) != 0 ); + + while( mpi_cmp_int( &V1, 0 ) < 0 ) + MPI_CHK( mpi_add_mpi( &V1, &V1, N ) ); + + while( mpi_cmp_mpi( &V1, N ) >= 0 ) + MPI_CHK( mpi_sub_mpi( &V1, &V1, N ) ); + + MPI_CHK( mpi_copy( X, &V1 ) ); + +cleanup: + + mpi_free( &V2, &V1, &TV, &TB, &G, + &U2, &U1, &TU, &TA, NULL ); + + return( ret ); +} + +static const int small_prime[] = +{ + 3, 5, 7, 11, 13, 17, 19, 23, + 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773, + 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, + 887, 907, 911, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997, -103 +}; + +/* + * Miller-Rabin primality test (HAC 4.24) + */ +int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng ) +{ + int ret, i, j, n, s, xs; + mpi W, R, T, A, RR; + unsigned char *p; + + if( mpi_cmp_int( X, 0 ) == 0 ) + return( 0 ); + + mpi_init( &W, &R, &T, &A, &RR, NULL ); + + xs = X->s; X->s = 1; + + /* + * test trivial factors first + */ + if( ( X->p[0] & 1 ) == 0 ) + return( XYSSL_ERR_MPI_NOT_ACCEPTABLE ); + + for( i = 0; small_prime[i] > 0; i++ ) + { + t_int r; + + if( mpi_cmp_int( X, small_prime[i] ) <= 0 ) + return( 0 ); + + MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) ); + + if( r == 0 ) + return( XYSSL_ERR_MPI_NOT_ACCEPTABLE ); + } + + /* + * W = |X| - 1 + * R = W >> lsb( W ) + */ + s = mpi_lsb( &W ); + MPI_CHK( mpi_sub_int( &W, X, 1 ) ); + MPI_CHK( mpi_copy( &R, &W ) ); + MPI_CHK( mpi_shift_r( &R, s ) ); + + i = mpi_msb( X ); + /* + * HAC, table 4.4 + */ + n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 : + ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 : + ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 ); + + for( i = 0; i < n; i++ ) + { + /* + * pick a random A, 1 < A < |X| - 1 + */ + MPI_CHK( mpi_grow( &A, X->n ) ); + + p = (unsigned char *) A.p; + for( j = 0; j < A.n * ciL; j++ ) + *p++ = (unsigned char) f_rng( p_rng ); + + j = mpi_msb( &A ) - mpi_msb( &W ); + MPI_CHK( mpi_shift_r( &A, j + 1 ) ); + A.p[0] |= 3; + + /* + * A = A^R mod |X| + */ + MPI_CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) ); + + if( mpi_cmp_mpi( &A, &W ) == 0 || + mpi_cmp_int( &A, 1 ) == 0 ) + continue; + + j = 1; + while( j < s && mpi_cmp_mpi( &A, &W ) != 0 ) + { + /* + * A = A * A mod |X| + */ + MPI_CHK( mpi_mul_mpi( &T, &A, &A ) ); + MPI_CHK( mpi_mod_mpi( &A, &T, X ) ); + + if( mpi_cmp_int( &A, 1 ) == 0 ) + break; + + j++; + } + + /* + * not prime if A != |X| - 1 or A == 1 + */ + if( mpi_cmp_mpi( &A, &W ) != 0 || + mpi_cmp_int( &A, 1 ) == 0 ) + { + ret = XYSSL_ERR_MPI_NOT_ACCEPTABLE; + break; + } + } + +cleanup: + + X->s = xs; + + mpi_free( &RR, &A, &T, &R, &W, NULL ); + + return( ret ); +} + +/* + * Prime number generation + */ +int mpi_gen_prime( mpi *X, int nbits, int dh_flag, + int (*f_rng)(void *), void *p_rng ) +{ + int ret, k, n; + unsigned char *p; + mpi Y; + + if( nbits < 3 ) + return( XYSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &Y, NULL ); + + n = BITS_TO_LIMBS( nbits ); + + MPI_CHK( mpi_grow( X, n ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + p = (unsigned char *) X->p; + for( k = 0; k < X->n * ciL; k++ ) + *p++ = (unsigned char) f_rng( p_rng ); + + k = mpi_msb( X ); + if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) ); + if( k > nbits ) MPI_CHK( mpi_shift_r( X, k - nbits ) ); + + X->p[0] |= 3; + + if( dh_flag == 0 ) + { + while( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) != 0 ) + { + if( ret != XYSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + MPI_CHK( mpi_add_int( X, X, 2 ) ); + } + } + else + { + MPI_CHK( mpi_sub_int( &Y, X, 1 ) ); + MPI_CHK( mpi_shift_r( &Y, 1 ) ); + + while( 1 ) + { + if( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) == 0 ) + { + if( ( ret = mpi_is_prime( &Y, f_rng, p_rng ) ) == 0 ) + break; + + if( ret != XYSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + } + + if( ret != XYSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + MPI_CHK( mpi_add_int( &Y, X, 1 ) ); + MPI_CHK( mpi_add_int( X, X, 2 ) ); + MPI_CHK( mpi_shift_r( &Y, 1 ) ); + } + } + +cleanup: + + mpi_free( &Y, NULL ); + + return( ret ); +} + +#endif + +#if defined(XYSSL_SELF_TEST) + +/* + * Checkup routine + */ +int mpi_self_test( int verbose ) +{ + int ret; + mpi A, E, N, X, Y, U, V; + + mpi_init( &A, &E, &N, &X, &Y, &U, &V, NULL ); + + MPI_CHK( mpi_read_string( &A, 16, + "EFE021C2645FD1DC586E69184AF4A31E" \ + "D5F53E93B5F123FA41680867BA110131" \ + "944FE7952E2517337780CB0DB80E61AA" \ + "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) ); + + MPI_CHK( mpi_read_string( &E, 16, + "B2E7EFD37075B9F03FF989C7C5051C20" \ + "34D2A323810251127E7BF8625A4F49A5" \ + "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ + "5B5C25763222FEFCCFC38B832366C29E" ) ); + + MPI_CHK( mpi_read_string( &N, 16, + "0066A198186C18C10B2F5ED9B522752A" \ + "9830B69916E535C8F047518A889A43A5" \ + "94B6BED27A168D31D4A52F88925AA8F5" ) ); + + MPI_CHK( mpi_mul_mpi( &X, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "602AB7ECA597A3D6B56FF9829A5E8B85" \ + "9E857EA95A03512E2BAE7391688D264A" \ + "A5663B0341DB9CCFD2C4C5F421FEC814" \ + "8001B72E848A38CAE1C65F78E56ABDEF" \ + "E12D3C039B8A02D6BE593F0BBBDA56F1" \ + "ECF677152EF804370C1A305CAF3B5BF1" \ + "30879B56C61DE584A0F53A2447A51E" ) ); + + if( verbose != 0 ) + printf( " MPI test #1 (mul_mpi): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + MPI_CHK( mpi_div_mpi( &X, &Y, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "256567336059E52CAE22925474705F39A94" ) ); + + MPI_CHK( mpi_read_string( &V, 16, + "6613F26162223DF488E9CD48CC132C7A" \ + "0AC93C701B001B092E4E5B9F73BCD27B" \ + "9EE50D0657C77F374E903CDFA4C642" ) ); + + if( verbose != 0 ) + printf( " MPI test #2 (div_mpi): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 || + mpi_cmp_mpi( &Y, &V ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + MPI_CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "36E139AEA55215609D2816998ED020BB" \ + "BD96C37890F65171D948E9BC7CBAA4D9" \ + "325D24D6A3C12710F10A09FA08AB87" ) ); + + if( verbose != 0 ) + printf( " MPI test #3 (exp_mod): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + MPI_CHK( mpi_inv_mod( &X, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ + "C3DBA76456363A10869622EAC2DD84EC" \ + "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) ); + + if( verbose != 0 ) + printf( " MPI test #4 (inv_mod): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + +cleanup: + + if( ret != 0 && verbose != 0 ) + printf( "Unexpected error, return code = %08X\n", ret ); + + mpi_free( &V, &U, &Y, &X, &N, &E, &A, NULL ); + + if( verbose != 0 ) + printf( "\n" ); + + return( ret ); +} + +#endif + +#endif diff --git a/library/certs.c b/library/certs.c new file mode 100644 index 000000000..8d0abb60c --- /dev/null +++ b/library/certs.c @@ -0,0 +1,211 @@ +/* + * X.509 test certificates + * + * Copyright (C) 2006-2007 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "xyssl/config.h" + +#if defined(XYSSL_CERTS_C) + +char test_ca_crt[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDpTCCAo2gAwIBAgIBADANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJGUjEO\r\n" +"MAwGA1UEBxMFUGFyaXMxDjAMBgNVBAoTBVh5U1NMMRYwFAYDVQQDEw1YeVNTTCBU\r\n" +"ZXN0IENBMB4XDTA3MDcwNzA1MDAxOFoXDTE3MDcwNzA1MDAxOFowRTELMAkGA1UE\r\n" +"BhMCRlIxDjAMBgNVBAcTBVBhcmlzMQ4wDAYDVQQKEwVYeVNTTDEWMBQGA1UEAxMN\r\n" +"WHlTU0wgVGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM+k\r\n" +"gt70fIPiYqmvXr+9uPmWoN405eoSzxdiRLLCHqL4V/Ts0E/H+JNfHS4DHlAgxrJu\r\n" +"+ZIadvSJuHkI6e1iMkAh5SU1DqaF3jrrFdJCooM6a077M4CRkE1tdAeZDf+BYp0q\r\n" +"BeMU9Y2+j7ibsQaPAizunbXLf4QdteExCwhYRJ8OVXSEaSNt339gJzTD6kOhES3b\r\n" +"lEN3qbx6lqFaJ5MLHTix5uNVc2rvbOizV5oLhJNqm52AKOp11tv6WTiI8loagvAc\r\n" +"jlhEZRNb9el5SL6Jai/uFcqXKzfXNKW3FYPQHFGobmiMfGt1lUSBJ3F2mrqEC7gC\r\n" +"wHy/FDvAI64/k5LZAFkCAwEAAaOBnzCBnDAMBgNVHRMEBTADAQH/MB0GA1UdDgQW\r\n" +"BBS87h+Y6Porg+SkfV7DdXKTMdkyZzBtBgNVHSMEZjBkgBS87h+Y6Porg+SkfV7D\r\n" +"dXKTMdkyZ6FJpEcwRTELMAkGA1UEBhMCRlIxDjAMBgNVBAcTBVBhcmlzMQ4wDAYD\r\n" +"VQQKEwVYeVNTTDEWMBQGA1UEAxMNWHlTU0wgVGVzdCBDQYIBADANBgkqhkiG9w0B\r\n" +"AQUFAAOCAQEAIHdoh0NCg6KAAhwDSmfEgSbKUI8/Zr/d56uw42HO0sj/uKPQzUco\r\n" +"3Mx2BYE1m1itg7q5OhrkB7J4ZB78EtNZM84nV+y6od3YpR0Z9VUxCx7948MozYRy\r\n" +"TKF5x/lKHRx1PJKfEO4clKdWTFAtWtGhewXrHJQ8C+ENh2Up2wTVh3Z+pEzuZNv3\r\n" +"u/JYu1H+vkt3l1WCy/9mxUnu+anW1DzxPWnjy4lx6Mi0BD2qfKBWLjVS+7v6ALcj\r\n" +"S2oRWWr4LUvXT7z9BBAvw2eJQD+a4uAya6EURG7AsAvr5MnWn/r0wLWmBJ6fB1Yp\r\n" +"F1kOmamOFvstLMf74rLX+LGKeJ/nwuI5FQ==\r\n" +"-----END CERTIFICATE-----\r\n"; + +char test_ca_key[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"Proc-Type: 4,ENCRYPTED\r\n" +"DEK-Info: DES-EDE3-CBC,7BDC280BA4C2F45C\r\n" +"\r\n" +"KI6rmwY0ChjF/0/Q7d1vE2jojZQTuF8j0wJUOf02PUUD4en8/FCLj69Pf3/lvOlu\r\n" +"F8hU4IuBHxN2+feuXp6xTmGd/VyKdWh4+NGtKr2V1gXfk2wqHk3/P/YuF7QhOQjZ\r\n" +"BlNF7n5o76Nufr3iwBbtIABCGQfNRUwGzrvmFXLIrSqns8ppv83qaD5jHVQQj5MM\r\n" +"cGIoidwmNORdVmBCVZ17dQ+lMPfqjhN27GBhzXbp9a2EP3w+IqrXOvcl4DqSY+DU\r\n" +"PIhS6KuQZ4iek4dI93wmw2D8Q67omcKYOX/BjCkZ/v6oq481qOej6MicIY/L9LxH\r\n" +"r91jqIYLJC+1w20YavB3kIkSe5zys30RzhPTOtG60j8kgiQ4Fh+L/nKBP5noOXGE\r\n" +"uzDBa051HCEYfufOVkXr6wBCFo9boqM1p/GI0Ze5gCsYY+Vzyu96gu+OGv55Jtyo\r\n" +"fY2yEwVKhfqNy+xJ+8dwf8dcc5vQLatXebDynuSPI2jbaos6MJT6n0LoY2TpAz47\r\n" +"vNE7UtEEdgZPPVwE4xO+dVa0kCqJxuG8b+ZZTHZidlQ6MBiebL4vXbeIFieQRzUM\r\n" +"06IQ7YqsiBVLYxicMlApdFpJ4QM2fFKlZRo+fHg8EN9HEbRpgxIf4IwAAFjOgsiO\r\n" +"ll7OmyzSF12NUIrRsIo02E4Y8X6xSFeYnOIiqZqdxG4xz/DZKoX6Js8WdYbtzrDv\r\n" +"7gYYEZy1cuR9PJzMDKXoLz/mjBqDsh11Vgm1nAHbhBqFaWSuueH/LV2rgRijUBKh\r\n" +"yMTnGXrz56DeJ85bYLjVEOM3xhvjsz6Fq5xLqXRTAzyQn7QuqRg2szLtCnN8olCh\r\n" +"rdS1Gd7EV5g24WnF9gTzYJ4lwO9oxOsPKKCD1Z77B+lbZLoxTu7+rakTtqLikWMv\r\n" +"7OILfR4iaIu1nKxhhXpwnze3u+1OWcuk0UnBjSnF519tlrgV3dmA0P2LHd6h6xru\r\n" +"vIgUFHbigCV0i55peEPxtcy9JGLGJ3WvHA3NGSsqkkB/ymdfEaMmEH7403UKqQqq\r\n" +"+K9Z1cYmeZlfoXClmdSjsxkYeN5raB0kOOSV/MEOySG+lztyLUGB4n46AZG2PgXN\r\n" +"A9g9tv2gqc51Vl+55qwTg5429DigjiByRkcmBU3A1aF8yzD1QerwobPmqeNZ0mWv\r\n" +"SllAvgVs2uy2Wf9/5gEWm+HjnJwS9VPNTocG/r+4BnDK8XG0Jy4oI+jSPxj/Y8Jt\r\n" +"0ejFPM5A7HGngiaPFYHxcwPwo4Aa4HZnk+keFrA+vF9eDd1IOj195a9TESL+IGt1\r\n" +"nuNmmuYjyJqM9Uvi1Mutv0UQ6Fl6yv4XxaUtMZKl4LtrAaMdW1T0PEgUG0tjSIxX\r\n" +"hBd1W+Ob4nmK29aa4iuXaOxeAA3QK7KCZo18CJFgnp1w97qohwlKf+4FuNXHL64Q\r\n" +"FgmpycV9nfP8G9aUYKAxs1+xutNv/B6opHmfLNL6d0cwi8dvGsrDdGlcyi8Dk/PF\r\n" +"GKSqlQTF5V7l4UOanefB51tuziEBY+LWcXP4XgqNGPQknPF90NnbH1EglQG2paqb\r\n" +"5bLyT8G6kfCSY4uHxs9lPuvfOjk9ptjy2FwfyBb3Sl4K+IFEE8XTNuNErh83AKh2\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; + +char test_ca_pwd[] = "test"; + +char test_srv_crt[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDPjCCAiagAwIBAgIBAjANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJGUjEO\r\n" +"MAwGA1UEBxMFUGFyaXMxDjAMBgNVBAoTBVh5U1NMMRYwFAYDVQQDEw1YeVNTTCBU\r\n" +"ZXN0IENBMB4XDTA3MDcwNzA1MDEyOVoXDTA4MDcwNjA1MDEyOVowMTELMAkGA1UE\r\n" +"BhMCRlIxDjAMBgNVBAoTBVh5U1NMMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0G\r\n" +"CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC40PDcGTgmHkt6noXDfkjVuymjiNYB\r\n" +"gjtiL7uA1Ke3tXStacEecQek/OJxYqYr7ffcWalS29LL6HbKpi0xLZKBbD9ACkDh\r\n" +"1Z/SvHlyQPILJdYb9DMw+kzZds5myXUjzn7Aem1YjoxMZUAMyc34i2900X2pL0v2\r\n" +"SfCeJ9Ym4MOnZxYl217+dX9ZbkgIgrT6uY2IYK4boDwxbTcyT8i/NPsVsiMwtWPM\r\n" +"rnQMr+XbgS98sUzcZE70Pe1TlV9Iy8j/8d2OiFo+qTyMu/6UpM2s3gdkQkMzx+Sm\r\n" +"4QitRUjzmEXeUePRUjEgHIv7vz069xuVBzrks36w5BXiVAhLke/OTKVPAgMBAAGj\r\n" +"TTBLMAkGA1UdEwQCMAAwHQYDVR0OBBYEFNkOyCTx64SDdPySGWl/tzD7/WMSMB8G\r\n" +"A1UdIwQYMBaAFLzuH5jo+iuD5KR9XsN1cpMx2TJnMA0GCSqGSIb3DQEBBQUAA4IB\r\n" +"AQBelJv5t+suaqy5Lo5bjNeHjNZfgg8EigDQ7NqaosvlQZAsh2N34Gg5YdkGyVdg\r\n" +"s32I/K5aaywyUbG9qVXQxCM2T95qBqyK56h9yJoZKWQD9H//+zB8kCK/16WvRfv3\r\n" +"VA7eSR19qOFWlHe+1qGh2YhxeDUfyi+fm4D36dGxqC2A34tZjo0QPHKtIeqM0kJy\r\n" +"zzL65TlbJQKkyTuRHofFv0jW9ZFG2wkGysVgCY5fjuLI1do/sWUaXd2987iNFa+K\r\n" +"FrHsTi6urSfZuGlZNxDXDHEE7Q2snAvvev+KR7DD9X4DJGcPX9gA4CGJj+9ZzyAA\r\n" +"ZTGpOzk1hIH44RFs2lJMZRlE\r\n" +"-----END CERTIFICATE-----\r\n"; + +char test_srv_key[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"MIIEowIBAAKCAQEAuNDw3Bk4Jh5Lep6Fw35I1bspo4jWAYI7Yi+7gNSnt7V0rWnB\r\n" +"HnEHpPzicWKmK+333FmpUtvSy+h2yqYtMS2SgWw/QApA4dWf0rx5ckDyCyXWG/Qz\r\n" +"MPpM2XbOZsl1I85+wHptWI6MTGVADMnN+ItvdNF9qS9L9knwnifWJuDDp2cWJdte\r\n" +"/nV/WW5ICIK0+rmNiGCuG6A8MW03Mk/IvzT7FbIjMLVjzK50DK/l24EvfLFM3GRO\r\n" +"9D3tU5VfSMvI//HdjohaPqk8jLv+lKTNrN4HZEJDM8fkpuEIrUVI85hF3lHj0VIx\r\n" +"IByL+789OvcblQc65LN+sOQV4lQIS5HvzkylTwIDAQABAoIBABeah8h0aBlmMRmd\r\n" +"+VN4Y3D4kF7UcRCMQ21Mz1Oq1Si/QgGLyiBLK0DFE16LzNE7eTZpNRjh/lAQhmtn\r\n" +"QcpQGa/x1TomlRbCo8DUVWZkKQWHdYroa0lMDliPtdimzhEepE2M1T5EJmLzY3S+\r\n" +"qVGe7UMsJjJfWgJAezyXteANQK+2YSt+CjPIqIHch1KexUnvdN9++1oEx6AbuZ8T\r\n" +"4avhFYZQP15tZNGsk2LfQlYS/NfbowkCsd0/TVubJBmDGUML/E5MbxjxLzlaNB2M\r\n" +"V59cBNgsgA35CODAUF4xOyoSfZGqG1Rb9qQrv1E6Jz56dG8SsKF3HqnDjxiPOVBN\r\n" +"FBnVJ+ECgYEA29MhAsKMm4XqBUKp6pIMFTgm/s1E5vxig70vqIiL+guvBhhQ7zs1\r\n" +"8UMTNXZoMELNoB/ev9fN0Cjc1Vr46b/x/yDw7wMb96i+vzENOzu4RHWi3OWpCPbp\r\n" +"qBKEi3hzN8M+BulPX8CDQx3aLRrfxw51J5EuA0NeybngbItgxTi0u6kCgYEA1zr0\r\n" +"6P5YdOhYHtSWDlkeD49MApcVuzaHnsHZVAhUqu3Rwiy9LRaJLZfr7fQDb9DYJbZp\r\n" +"sxTRLG6LSAcsR7mw+m+GvNqGt/9pSqbtW+L/VwVWSyF+YYklxZUD3UAAyrDVcDEC\r\n" +"a5S+jad4Csi/lVHt5ulWIckWL1fJvadn5ubKNDcCgYA+71xVGPP+lsFgTiytfrC8\r\n" +"5n2rl4MxinJ9+w0I+EbzCKNMYGvTgiU4dJasSMEdiBKs1FMGo7dF8F0BLHF1IsIa\r\n" +"5Ah2tXItXn9154o9OiTQXMmK6qmRaneM6fhOoeaCwYAhpGxYIpqx/Xr4TOhiag46\r\n" +"jMMaphAeOvw4t1K2RDziOQKBgQCyPCCU0gxuw/o1jda2CxbZy9EmU/erEX09+0n+\r\n" +"TOfQpSEPq/z9WaxAFY9LfsdZ0ZktoeHma1bNdL3i6A3DWAM3YSQzQMRPmzOWnqXx\r\n" +"cgoCBmlvzkzaeLjO5phMoLQHJmmafvuCG6uxov3F8Hi3LyHUF2c8k0nL6ucmJ3vj\r\n" +"uzu4AQKBgBSASMAJS63M9UJB1Eazy2v2NWw04CmzNxUfWrHuKpd/C2ik4QKu0sRO\r\n" +"r9KnkDgxxEhjDm7lXhlW12PU42yORst5I3Eaa1Cfi4KPFn/ozt+iNBYrzd8Tyvnb\r\n" +"qkdECl0+G2Fo/ER4NRCv7a24WNEsOMGzGRqw5cnSJrjbZLYMaIyK\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; + +char test_cli_crt[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDPTCCAiWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJGUjEO\r\n" +"MAwGA1UEBxMFUGFyaXMxDjAMBgNVBAoTBVh5U1NMMRYwFAYDVQQDEw1YeVNTTCBU\r\n" +"ZXN0IENBMB4XDTA3MDcwNzA1MDEyMFoXDTA4MDcwNjA1MDEyMFowMDELMAkGA1UE\r\n" +"BhMCRlIxDjAMBgNVBAoTBVh5U1NMMREwDwYDVQQDEwhKb2UgVXNlcjCCASIwDQYJ\r\n" +"KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKZkg8ANl6kGmLGqKc6KUHb9IsZwb2+K\r\n" +"jBw83Qb0KuvPVnu3MzEcXFvOZ83g0PL/z8ob5PKr8HP6bVYzhsD65imcCDEEVPk2\r\n" +"9r0XGTggGjB601Fd8aTShUWE4NLrKw6YNXTXgTNdvhHNxXwqmdNVLkmZjj3ZwYUc\r\n" +"cEE8eE5jHs8cMDXJLMCwgKIM7Sax22OhSHQHKwifVO4/Fdw5G+Suys8PhMX2jDXM\r\n" +"ICFwq8ld+bZGoNUtgp48FWhAMfJyTEaHh9LC46KkqGSDRIzx7/4cPB6QqrpzJN0o\r\n" +"Kr8kH7vdRDTFDmO23D4C5l0Bw/2aC76DhEJpB2bGA4iIszJs+F/PIL8CAwEAAaNN\r\n" +"MEswCQYDVR0TBAIwADAdBgNVHQ4EFgQUiWX1IvjRdYGt0zz5Sq16x01k0o4wHwYD\r\n" +"VR0jBBgwFoAUvO4fmOj6K4PkpH1ew3VykzHZMmcwDQYJKoZIhvcNAQEFBQADggEB\r\n" +"AGdqD7VThJmC+oeeMUHk2TQX2wZNU+GsC+RLjtlenckny95KnljGvMtCznyLkS5D\r\n" +"fAjLKfR1No8pk5gRdscqgyIuQx5WnHNv4QBZmMsmvDICxzRQaxuPFHbS4aLXldeL\r\n" +"yOWm5Z4qkMHpCKvA86blYsEkksGDV47fF9ZkOQ8nkh7Z4eY4/5TwqTY72ww5g4NL\r\n" +"6DZtWpcpGbX99NRaNVzcq9D+ElxkgHnH4YWafOKBclSgqrutbRLi2uZx/QpvuF+i\r\n" +"sUbe+HFPMWwU5lBv/oOhQkz0VD+HusYtXWS2lG88cT40aNly2CkYUugdTR/b9Uea\r\n" +"p/i862sL/lO40qlQ0xV5N7U=\r\n" +"-----END CERTIFICATE-----\r\n"; + +char test_cli_key[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"MIIEowIBAAKCAQEApmSDwA2XqQaYsaopzopQdv0ixnBvb4qMHDzdBvQq689We7cz\r\n" +"MRxcW85nzeDQ8v/Pyhvk8qvwc/ptVjOGwPrmKZwIMQRU+Tb2vRcZOCAaMHrTUV3x\r\n" +"pNKFRYTg0usrDpg1dNeBM12+Ec3FfCqZ01UuSZmOPdnBhRxwQTx4TmMezxwwNcks\r\n" +"wLCAogztJrHbY6FIdAcrCJ9U7j8V3Dkb5K7Kzw+ExfaMNcwgIXCryV35tkag1S2C\r\n" +"njwVaEAx8nJMRoeH0sLjoqSoZINEjPHv/hw8HpCqunMk3SgqvyQfu91ENMUOY7bc\r\n" +"PgLmXQHD/ZoLvoOEQmkHZsYDiIizMmz4X88gvwIDAQABAoIBAE0nBkAjDVN+j4ax\r\n" +"1DjEwZKqxVkmAUXDBDyDrCjxRoWY2gz7YW1ALUMUbeV0fO5v1zVrwbkUKKZeVBxI\r\n" +"QA9zRw28H8A6tfvolHgRIcx4dixMh3ePC+DVDJ6zglvKV2ipAwBufKYIrX0r4Io2\r\n" +"ZqUrNg9CeEYNlkHWceaN12rhYwO82pgHxnB1p5pI42pY7lzyLgSddf5n+M5UBOJI\r\n" +"gsNCkvbGdv7WQPVFTRDiRgEnCJ3rI8oPSK6MOUWJw3rh2hbkx+ex8NPvEKbzEXiU\r\n" +"p5j1AlbHIWP5sYBbA1YviFtryAV4fyfLcWPfoqa33Oozofjlwoj0Aixz+6rerLjZ\r\n" +"cpTSrAECgYEA2oCffUo6HH3Lq9oeWhFCoOyG3YjZmFrJaJwjHnvroX9/pXHqYKog\r\n" +"TehcjUJBtFZw0klcetYbZCFqT8v9nf0uPlgaiVGCtXf1MSbFXDUFKkYBiFwzdWMT\r\n" +"Ysmvhff82jMWZ8ecsXTyDRl858SR5WPZ52qEsCc5X2un7QENm6FtVT8CgYEAwvKS\r\n" +"zQNzuoJETqZX7AalmK3JM8Fdam+Qm5LNMcbvhbKwI8HKMS1VMuqaR0XdAX/iMXAx\r\n" +"P1VhSsmoSDbsMpxBEZIptpCen/GcqctITxANTakrBHxqb2aQ5EEu7SzgfHZWse3/\r\n" +"vQEyfcFTBlPIdcZUDzk4/w7WmyivpYtCWoAh1IECgYEA0UYZ+1UJfVpapRj+swMP\r\n" +"DrQbo7i7t7lUaFYLKNpFX2OPLTWC5txqnlOruTu5VHDqE+5hneDNUUTT3uOg4B2q\r\n" +"mdmmaNjh2M6wz0e0BVFexhNQynqMaqTe32IOM8DFs3L0xacgg7JfVn6P7CeQGOVe\r\n" +"wc96kICw6ZxhtJSqpOGipt8CgYBI/0Pw+IXxJK4nNSpe+u4vCYP5mUI9hKEFYCbt\r\n" +"qKwvyAUknn/zgiIQ+r/iSErFMPmlwXjvWi0gL/qPb+Fp4hCLX8u2zNhY08Px4Gin\r\n" +"Ej+pANtWxq+kHyfKEI5dyRwV/snfvlqwjy404JsSF3VMhIMdYDPzbb72Qnni5w5l\r\n" +"jO0eAQKBgBqt9jJMd1JdpemC2dm0BuuDIz2h3/MH+CMjfaDLenVpKykn17B6N92h\r\n" +"klMesqK3RQzDGwauDw431LQw0R69onn9fCM3wJw2yEC6wC9sF8I8hsNZbt64yZhZ\r\n" +"4Bi2YRTiHhpEuBqKlhHLDFHneo3SMYh8PU/PDQQcyWGHHUi9z1RE\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; + +char xyssl_ca_crt[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh\r\n" +"MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE\r\n" +"YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3\r\n" +"MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo\r\n" +"ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg\r\n" +"MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN\r\n" +"ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA\r\n" +"PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w\r\n" +"wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi\r\n" +"EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY\r\n" +"avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+\r\n" +"YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE\r\n" +"sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h\r\n" +"/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5\r\n" +"IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj\r\n" +"YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD\r\n" +"ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy\r\n" +"OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P\r\n" +"TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ\r\n" +"HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER\r\n" +"dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf\r\n" +"ReYNnyicsbkqWletNw+vHX/bvZ8=\r\n" +"-----END CERTIFICATE-----\r\n"; + +#endif diff --git a/library/debug.c b/library/debug.c new file mode 100644 index 000000000..4862fc46e --- /dev/null +++ b/library/debug.c @@ -0,0 +1,202 @@ +/* + * Debugging routines + * + * Copyright (C) 2006-2007 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "xyssl/config.h" + +#if defined(XYSSL_DEBUG_C) + +#include "xyssl/debug.h" + +#include +#include + +#if defined _MSC_VER && !defined snprintf +#define snprintf _snprintf +#endif + +#if defined _MSC_VER && !defined vsnprintf +#define vsnprintf _vsnprintf +#endif + +char *debug_fmt( const char *format, ... ) +{ + va_list argp; + static char str[512]; + int maxlen = sizeof( str ) - 1; + + va_start( argp, format ); + vsnprintf( str, maxlen, format, argp ); + va_end( argp ); + + str[maxlen] = '\0'; + return( str ); +} + +void debug_print_msg( ssl_context *ssl, int level, + char *file, int line, char *text ) +{ + char str[512]; + int maxlen = sizeof( str ) - 1; + + if( ssl->f_dbg == NULL ) + return; + + snprintf( str, maxlen, "%s(%04d): %s\n", file, line, text ); + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); +} + +void debug_print_ret( ssl_context *ssl, int level, + char *file, int line, char *text, int ret ) +{ + char str[512]; + int maxlen = sizeof( str ) - 1; + + if( ssl->f_dbg == NULL ) + return; + + snprintf( str, maxlen, "%s(%04d): %s() returned %d (0x%x)\n", + file, line, text, ret, ret ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); +} + +void debug_print_buf( ssl_context *ssl, int level, + char *file, int line, char *text, + unsigned char *buf, int len ) +{ + char str[512]; + int i, maxlen = sizeof( str ) - 1; + + if( ssl->f_dbg == NULL || len < 0 ) + return; + + snprintf( str, maxlen, "%s(%04d): dumping '%s' (%d bytes)\n", + file, line, text, len ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + + for( i = 0; i < len; i++ ) + { + if( i >= 4096 ) + break; + + if( i % 16 == 0 ) + { + if( i > 0 ) + ssl->f_dbg( ssl->p_dbg, level, "\n" ); + + snprintf( str, maxlen, "%s(%04d): %04x: ", file, line, i ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + } + + snprintf( str, maxlen, " %02x", (unsigned int) buf[i] ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + } + + if( len > 0 ) + ssl->f_dbg( ssl->p_dbg, level, "\n" ); +} + +void debug_print_mpi( ssl_context *ssl, int level, + char *file, int line, char *text, mpi *X ) +{ + char str[512]; + int i, j, k, n, maxlen = sizeof( str ) - 1; + + if( ssl->f_dbg == NULL || X == NULL ) + return; + + for( n = X->n - 1; n >= 0; n-- ) + if( X->p[n] != 0 ) + break; + + snprintf( str, maxlen, "%s(%04d): value of '%s' (%d bits) is:\n", + file, line, text, ((n + 1) * sizeof( t_int )) << 3 ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + + for( i = n, j = 0; i >= 0; i--, j++ ) + { + if( j % ( 16 / sizeof( t_int ) ) == 0 ) + { + if( j > 0 ) + ssl->f_dbg( ssl->p_dbg, level, "\n" ); + + snprintf( str, maxlen, "%s(%04d): ", file, line ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + } + + for( k = sizeof( t_int ) - 1; k >= 0; k-- ) + { + snprintf( str, maxlen, " %02x", (unsigned int) + ( X->p[i] >> (k << 3) ) & 0xFF ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + } + } + + ssl->f_dbg( ssl->p_dbg, level, "\n" ); +} + +void debug_print_crt( ssl_context *ssl, int level, + char *file, int line, char *text, x509_cert *crt ) +{ + char str[512], prefix[64], *p; + int i = 0, maxlen = sizeof( prefix ) - 1; + + if( ssl->f_dbg == NULL || crt == NULL ) + return; + + snprintf( prefix, maxlen, "%s(%04d): ", file, line ); + prefix[maxlen] = '\0'; + maxlen = sizeof( str ) - 1; + + while( crt != NULL && crt->next != NULL ) + { + p = x509parse_cert_info( prefix, crt ); + + snprintf( str, maxlen, "%s(%04d): %s #%d:\n%s", + file, line, text, ++i, p ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + + debug_print_mpi( ssl, level, file, line, + "crt->rsa.N", &crt->rsa.N ); + + debug_print_mpi( ssl, level, file, line, + "crt->rsa.E", &crt->rsa.E ); + + crt = crt->next; + } +} + +#endif diff --git a/library/des.c b/library/des.c new file mode 100644 index 000000000..aec027da9 --- /dev/null +++ b/library/des.c @@ -0,0 +1,876 @@ +/* + * FIPS-46-3 compliant Triple-DES implementation + * + * Copyright (C) 2006-2007 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * DES, on which TDES is based, was originally designed by Horst Feistel + * at IBM in 1974, and was adopted as a standard by NIST (formerly NBS). + * + * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf + */ + +#include "xyssl/config.h" + +#if defined(XYSSL_DES_C) + +#include "xyssl/des.h" + +#include + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_ULONG_BE +#define GET_ULONG_BE(n,b,i) \ +{ \ + (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ + | ( (unsigned long) (b)[(i) + 1] << 16 ) \ + | ( (unsigned long) (b)[(i) + 2] << 8 ) \ + | ( (unsigned long) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_ULONG_BE +#define PUT_ULONG_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * Expanded DES S-boxes + */ +static const unsigned long SB1[64] = +{ + 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 +}; + +static const unsigned long SB2[64] = +{ + 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 +}; + +static const unsigned long SB3[64] = +{ + 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 +}; + +static const unsigned long SB4[64] = +{ + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 +}; + +static const unsigned long SB5[64] = +{ + 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 +}; + +static const unsigned long SB6[64] = +{ + 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 +}; + +static const unsigned long SB7[64] = +{ + 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 +}; + +static const unsigned long SB8[64] = +{ + 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 +}; + +/* + * PC1: left and right halves bit-swap + */ +static const unsigned long LHs[16] = +{ + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static const unsigned long RHs[16] = +{ + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100, + 0x00000001, 0x01000001, 0x00010001, 0x01010001, + 0x00000101, 0x01000101, 0x00010101, 0x01010101, +}; + +/* + * Initial Permutation macro + */ +#define DES_IP(X,Y) \ +{ \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ + X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ +} + +/* + * Final Permutation macro + */ +#define DES_FP(X,Y) \ +{ \ + X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ + Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ +} + +/* + * DES round macro + */ +#define DES_ROUND(X,Y) \ +{ \ + T = *SK++ ^ X; \ + Y ^= SB8[ (T ) & 0x3F ] ^ \ + SB6[ (T >> 8) & 0x3F ] ^ \ + SB4[ (T >> 16) & 0x3F ] ^ \ + SB2[ (T >> 24) & 0x3F ]; \ + \ + T = *SK++ ^ ((X << 28) | (X >> 4)); \ + Y ^= SB7[ (T ) & 0x3F ] ^ \ + SB5[ (T >> 8) & 0x3F ] ^ \ + SB3[ (T >> 16) & 0x3F ] ^ \ + SB1[ (T >> 24) & 0x3F ]; \ +} + +#define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; } + +static void des_setkey( unsigned long SK[32], unsigned char key[8] ) +{ + int i; + unsigned long X, Y, T; + + GET_ULONG_BE( X, key, 0 ); + GET_ULONG_BE( Y, key, 4 ); + + /* + * Permuted Choice 1 + */ + T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); + T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); + + X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) + | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) + | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) + | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); + + Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) + | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) + | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) + | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); + + X &= 0x0FFFFFFF; + Y &= 0x0FFFFFFF; + + /* + * calculate subkeys + */ + for( i = 0; i < 16; i++ ) + { + if( i < 2 || i == 8 || i == 15 ) + { + X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; + Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; + } + else + { + X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; + Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; + } + + *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) + | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) + | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) + | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) + | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) + | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) + | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) + | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) + | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) + | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) + | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); + + *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) + | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) + | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) + | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) + | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) + | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) + | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) + | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) + | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) + | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) + | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); + } +} + +/* + * DES key schedule (56-bit, encryption) + */ +void des_setkey_enc( des_context *ctx, unsigned char key[8] ) +{ + des_setkey( ctx->sk, key ); +} + +/* + * DES key schedule (56-bit, decryption) + */ +void des_setkey_dec( des_context *ctx, unsigned char key[8] ) +{ + int i; + + des_setkey( ctx->sk, key ); + + for( i = 0; i < 16; i += 2 ) + { + SWAP( ctx->sk[i ], ctx->sk[30 - i] ); + SWAP( ctx->sk[i + 1], ctx->sk[31 - i] ); + } +} + +static void des3_set2key( unsigned long esk[96], + unsigned long dsk[96], + unsigned char key[16] ) +{ + int i; + + des_setkey( esk, key ); + des_setkey( dsk + 32, key + 8 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[30 - i]; + dsk[i + 1] = esk[31 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + esk[i + 64] = esk[i ]; + esk[i + 65] = esk[i + 1]; + + dsk[i + 64] = dsk[i ]; + dsk[i + 65] = dsk[i + 1]; + } +} + +/* + * Triple-DES key schedule (112-bit, encryption) + */ +void des3_set2key_enc( des3_context *ctx, unsigned char key[16] ) +{ + unsigned long sk[96]; + + des3_set2key( ctx->sk, sk, key ); + memset( sk, 0, sizeof( sk ) ); +} + +/* + * Triple-DES key schedule (112-bit, decryption) + */ +void des3_set2key_dec( des3_context *ctx, unsigned char key[16] ) +{ + unsigned long sk[96]; + + des3_set2key( sk, ctx->sk, key ); + memset( sk, 0, sizeof( sk ) ); +} + +static void des3_set3key( unsigned long esk[96], + unsigned long dsk[96], + unsigned char key[24] ) +{ + int i; + + des_setkey( esk, key ); + des_setkey( dsk + 32, key + 8 ); + des_setkey( esk + 64, key + 16 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[94 - i]; + dsk[i + 1] = esk[95 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + dsk[i + 64] = esk[30 - i]; + dsk[i + 65] = esk[31 - i]; + } +} + +/* + * Triple-DES key schedule (168-bit, encryption) + */ +void des3_set3key_enc( des3_context *ctx, unsigned char key[24] ) +{ + unsigned long sk[96]; + + des3_set3key( ctx->sk, sk, key ); + memset( sk, 0, sizeof( sk ) ); +} + +/* + * Triple-DES key schedule (168-bit, decryption) + */ +void des3_set3key_dec( des3_context *ctx, unsigned char key[24] ) +{ + unsigned long sk[96]; + + des3_set3key( sk, ctx->sk, key ); + memset( sk, 0, sizeof( sk ) ); +} + +/* + * DES-ECB block encryption/decryption + */ +void des_crypt_ecb( des_context *ctx, + unsigned char input[8], + unsigned char output[8] ) +{ + int i; + unsigned long X, Y, T, *SK; + + SK = ctx->sk; + + GET_ULONG_BE( X, input, 0 ); + GET_ULONG_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_ULONG_BE( Y, output, 0 ); + PUT_ULONG_BE( X, output, 4 ); +} + +/* + * DES-CBC buffer encryption/decryption + */ +void des_crypt_cbc( des_context *ctx, + int mode, + int length, + unsigned char iv[8], + unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( mode == DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + des_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + des_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } +} + +/* + * 3DES-ECB block encryption/decryption + */ +void des3_crypt_ecb( des3_context *ctx, + unsigned char input[8], + unsigned char output[8] ) +{ + int i; + unsigned long X, Y, T, *SK; + + SK = ctx->sk; + + GET_ULONG_BE( X, input, 0 ); + GET_ULONG_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( X, Y ); + DES_ROUND( Y, X ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_ULONG_BE( Y, output, 0 ); + PUT_ULONG_BE( X, output, 4 ); +} + +/* + * 3DES-CBC buffer encryption/decryption + */ +void des3_crypt_cbc( des3_context *ctx, + int mode, + int length, + unsigned char iv[8], + unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( mode == DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + des3_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + des3_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } +} + +#if defined(XYSSL_SELF_TEST) + +#include + +/* + * DES and 3DES test vectors from: + * + * http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip + */ +static const unsigned char des3_test_keys[24] = +{ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, + 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23 +}; + +static const unsigned char des3_test_iv[8] = +{ + 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, +}; + +static const unsigned char des3_test_buf[8] = +{ + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74 +}; + +static const unsigned char des3_test_ecb_dec[3][8] = +{ + { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D }, + { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB }, + { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A } +}; + +static const unsigned char des3_test_ecb_enc[3][8] = +{ + { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B }, + { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 }, + { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 } +}; + +static const unsigned char des3_test_cbc_dec[3][8] = +{ + { 0x12, 0x9F, 0x40, 0xB9, 0xD2, 0x00, 0x56, 0xB3 }, + { 0x47, 0x0E, 0xFC, 0x9A, 0x6B, 0x8E, 0xE3, 0x93 }, + { 0xC5, 0xCE, 0xCF, 0x63, 0xEC, 0xEC, 0x51, 0x4C } +}; + +static const unsigned char des3_test_cbc_enc[3][8] = +{ + { 0x54, 0xF1, 0x5A, 0xF6, 0xEB, 0xE3, 0xA4, 0xB4 }, + { 0x35, 0x76, 0x11, 0x56, 0x5F, 0xA1, 0x8E, 0x4D }, + { 0xCB, 0x19, 0x1F, 0x85, 0xD1, 0xED, 0x84, 0x39 } +}; + +/* + * Checkup routine + */ +int des_self_test( int verbose ) +{ + int i, j, u, v; + des_context ctx; + des3_context ctx3; + unsigned char key[24]; + unsigned char buf[8]; + unsigned char prv[8]; + unsigned char iv[8]; + + memset( key, 0, 24 ); + + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " DES%c-ECB-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + des_setkey_dec( &ctx, (unsigned char *) des3_test_keys ); + break; + + case 1: + des_setkey_enc( &ctx, (unsigned char *) des3_test_keys ); + break; + + case 2: + des3_set2key_dec( &ctx3, (unsigned char *) des3_test_keys ); + break; + + case 3: + des3_set2key_enc( &ctx3, (unsigned char *) des3_test_keys ); + break; + + case 4: + des3_set3key_dec( &ctx3, (unsigned char *) des3_test_keys ); + break; + + case 5: + des3_set3key_enc( &ctx3, (unsigned char *) des3_test_keys ); + break; + + default: + return( 1 ); + } + + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + des_crypt_ecb( &ctx, buf, buf ); + else + des3_crypt_ecb( &ctx3, buf, buf ); + } + + if( ( v == DES_DECRYPT && + memcmp( buf, des3_test_ecb_dec[u], 8 ) != 0 ) || + ( v != DES_DECRYPT && + memcmp( buf, des3_test_ecb_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " DES%c-CBC-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, des3_test_iv, 8 ); + memcpy( prv, des3_test_iv, 8 ); + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + des_setkey_dec( &ctx, (unsigned char *) des3_test_keys ); + break; + + case 1: + des_setkey_enc( &ctx, (unsigned char *) des3_test_keys ); + break; + + case 2: + des3_set2key_dec( &ctx3, (unsigned char *) des3_test_keys ); + break; + + case 3: + des3_set2key_enc( &ctx3, (unsigned char *) des3_test_keys ); + break; + + case 4: + des3_set3key_dec( &ctx3, (unsigned char *) des3_test_keys ); + break; + + case 5: + des3_set3key_enc( &ctx3, (unsigned char *) des3_test_keys ); + break; + + default: + return( 1 ); + } + + if( v == DES_DECRYPT ) + { + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + } + } + else + { + for( j = 0; j < 10000; j++ ) + { + unsigned char tmp[8]; + + if( u == 0 ) + des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + + memcpy( tmp, prv, 8 ); + memcpy( prv, buf, 8 ); + memcpy( buf, tmp, 8 ); + } + + memcpy( buf, prv, 8 ); + } + + if( ( v == DES_DECRYPT && + memcmp( buf, des3_test_cbc_dec[u], 8 ) != 0 ) || + ( v != DES_DECRYPT && + memcmp( buf, des3_test_cbc_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/library/dhm.c b/library/dhm.c new file mode 100644 index 000000000..4fff26488 --- /dev/null +++ b/library/dhm.c @@ -0,0 +1,253 @@ +/* + * Diffie-Hellman-Merkle key exchange + * + * Copyright (C) 2006-2007 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * Reference: + * + * http://www.cacr.math.uwaterloo.ca/hac/ (chapter 12) + */ + +#include "xyssl/config.h" + +#if defined(XYSSL_DHM_C) + +#include "xyssl/dhm.h" + +#include + +/* + * helper to validate the mpi size and import it + */ +static int dhm_read_bignum( mpi *X, + unsigned char **p, + unsigned char *end ) +{ + int ret, n; + + if( end - *p < 2 ) + return( XYSSL_ERR_DHM_BAD_INPUT_DATA ); + + n = ( (*p)[0] << 8 ) | (*p)[1]; + (*p) += 2; + + if( (int)( end - *p ) < n ) + return( XYSSL_ERR_DHM_BAD_INPUT_DATA ); + + if( ( ret = mpi_read_binary( X, *p, n ) ) != 0 ) + return( XYSSL_ERR_DHM_READ_PARAMS_FAILED | ret ); + + (*p) += n; + + return( 0 ); +} + +/* + * Parse the ServerKeyExchange parameters + */ +int dhm_read_params( dhm_context *ctx, + unsigned char **p, + unsigned char *end ) +{ + int ret, n; + + memset( ctx, 0, sizeof( dhm_context ) ); + + if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 || + ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 || + ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 ) + return( ret ); + + ctx->len = mpi_size( &ctx->P ); + + if( end - *p < 2 ) + return( XYSSL_ERR_DHM_BAD_INPUT_DATA ); + + n = ( (*p)[0] << 8 ) | (*p)[1]; + (*p) += 2; + + if( end != *p + n ) + return( XYSSL_ERR_DHM_BAD_INPUT_DATA ); + + return( 0 ); +} + +/* + * Setup and write the ServerKeyExchange parameters + */ +int dhm_make_params( dhm_context *ctx, int x_size, + unsigned char *output, int *olen, + int (*f_rng)(void *), void *p_rng ) +{ + int i, ret, n, n1, n2, n3; + unsigned char *p; + + /* + * generate X and calculate GX = G^X mod P + */ + n = x_size / sizeof( t_int ); + MPI_CHK( mpi_grow( &ctx->X, n ) ); + MPI_CHK( mpi_lset( &ctx->X, 0 ) ); + + n = x_size >> 3; + p = (unsigned char *) ctx->X.p; + for( i = 0; i < n; i++ ) + *p++ = (unsigned char) f_rng( p_rng ); + + while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) + mpi_shift_r( &ctx->X, 1 ); + + MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, + &ctx->P , &ctx->RP ) ); + + /* + * export P, G, GX + */ +#define DHM_MPI_EXPORT(X,n) \ + MPI_CHK( mpi_write_binary( X, p + 2, n ) ); \ + *p++ = (unsigned char)( n >> 8 ); \ + *p++ = (unsigned char)( n ); p += n; + + n1 = mpi_size( &ctx->P ); + n2 = mpi_size( &ctx->G ); + n3 = mpi_size( &ctx->GX ); + + p = output; + DHM_MPI_EXPORT( &ctx->P , n1 ); + DHM_MPI_EXPORT( &ctx->G , n2 ); + DHM_MPI_EXPORT( &ctx->GX, n3 ); + + *olen = p - output; + + ctx->len = n1; + +cleanup: + + if( ret != 0 ) + return( ret | XYSSL_ERR_DHM_MAKE_PARAMS_FAILED ); + + return( 0 ); +} + +/* + * Import the peer's public value G^Y + */ +int dhm_read_public( dhm_context *ctx, + unsigned char *input, int ilen ) +{ + int ret; + + if( ctx == NULL || ilen < 1 || ilen > ctx->len ) + return( XYSSL_ERR_DHM_BAD_INPUT_DATA ); + + if( ( ret = mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 ) + return( XYSSL_ERR_DHM_READ_PUBLIC_FAILED | ret ); + + return( 0 ); +} + +/* + * Create own private value X and export G^X + */ +int dhm_make_public( dhm_context *ctx, int x_size, + unsigned char *output, int olen, + int (*f_rng)(void *), void *p_rng ) +{ + int ret, i, n; + unsigned char *p; + + if( ctx == NULL || olen < 1 || olen > ctx->len ) + return( XYSSL_ERR_DHM_BAD_INPUT_DATA ); + + /* + * generate X and calculate GX = G^X mod P + */ + n = x_size / sizeof( t_int ); + MPI_CHK( mpi_grow( &ctx->X, n ) ); + MPI_CHK( mpi_lset( &ctx->X, 0 ) ); + + n = x_size >> 3; + p = (unsigned char *) ctx->X.p; + for( i = 0; i < n; i++ ) + *p++ = (unsigned char) f_rng( p_rng ); + + while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) + mpi_shift_r( &ctx->X, 1 ); + + MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, + &ctx->P , &ctx->RP ) ); + + MPI_CHK( mpi_write_binary( &ctx->GX, output, olen ) ); + +cleanup: + + if( ret != 0 ) + return( XYSSL_ERR_DHM_MAKE_PUBLIC_FAILED | ret ); + + return( 0 ); +} + +/* + * Derive and export the shared secret (G^Y)^X mod P + */ +int dhm_calc_secret( dhm_context *ctx, + unsigned char *output, int *olen ) +{ + int ret; + + if( ctx == NULL || *olen < ctx->len ) + return( XYSSL_ERR_DHM_BAD_INPUT_DATA ); + + MPI_CHK( mpi_exp_mod( &ctx->K, &ctx->GY, &ctx->X, + &ctx->P, &ctx->RP ) ); + + *olen = mpi_size( &ctx->K ); + + MPI_CHK( mpi_write_binary( &ctx->K, output, *olen ) ); + +cleanup: + + if( ret != 0 ) + return( XYSSL_ERR_DHM_CALC_SECRET_FAILED | ret ); + + return( 0 ); +} + +/* + * Free the components of a DHM key + */ +void dhm_free( dhm_context *ctx ) +{ + mpi_free( &ctx->RP, &ctx->K, &ctx->GY, + &ctx->GX, &ctx->X, &ctx->G, + &ctx->P, NULL ); +} + +#if defined(XYSSL_SELF_TEST) + +/* + * Checkup routine + */ +int dhm_self_test( int verbose ) +{ + return( verbose++ ); +} + +#endif + +#endif diff --git a/library/havege.c b/library/havege.c new file mode 100644 index 000000000..48ae7e6a3 --- /dev/null +++ b/library/havege.c @@ -0,0 +1,261 @@ +/* + * HAVEGE: HArdware Volatile Entropy Gathering and Expansion + * + * Copyright (C) 2006-2007 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The HAVEGE RNG was designed by Andre Seznec in 2002. + * + * http://www.irisa.fr/caps/projects/hipsor/publi.php + * + * Contact: seznec(at)irisa_dot_fr - orocheco(at)irisa_dot_fr + */ + +#include +#include + +#include "xyssl/config.h" + +#if defined(XYSSL_HAVEGE_C) + +#include "xyssl/havege.h" +#include "xyssl/timing.h" + +/* ------------------------------------------------------------------------ + * On average, one iteration accesses two 8-word blocks in the havege WALK + * table, and generates 16 words in the RES array. + * + * The data read in the WALK table is updated and permuted after each use. + * The result of the hardware clock counter read is used for this update. + * + * 25 conditional tests are present. The conditional tests are grouped in + * two nested groups of 12 conditional tests and 1 test that controls the + * permutation; on average, there should be 6 tests executed and 3 of them + * should be mispredicted. + * ------------------------------------------------------------------------ + */ + +#define SWAP(X,Y) { int *T = X; X = Y; Y = T; } + +#define TST1_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1; +#define TST2_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1; + +#define TST1_LEAVE U1++; } +#define TST2_LEAVE U2++; } + +#define ONE_ITERATION \ + \ + PTEST = PT1 >> 20; \ + \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + \ + PTX = (PT1 >> 18) & 7; \ + PT1 &= 0x1FFF; \ + PT2 &= 0x1FFF; \ + CLK = (int) hardclock(); \ + \ + i = 0; \ + A = &WALK[PT1 ]; RES[i++] ^= *A; \ + B = &WALK[PT2 ]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 1]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 4]; RES[i++] ^= *D; \ + \ + IN = (*A >> (1)) ^ (*A << (31)) ^ CLK; \ + *A = (*B >> (2)) ^ (*B << (30)) ^ CLK; \ + *B = IN ^ U1; \ + *C = (*C >> (3)) ^ (*C << (29)) ^ CLK; \ + *D = (*D >> (4)) ^ (*D << (28)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 2]; RES[i++] ^= *A; \ + B = &WALK[PT2 ^ 2]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 3]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 6]; RES[i++] ^= *D; \ + \ + if( PTEST & 1 ) SWAP( A, C ); \ + \ + IN = (*A >> (5)) ^ (*A << (27)) ^ CLK; \ + *A = (*B >> (6)) ^ (*B << (26)) ^ CLK; \ + *B = IN; CLK = (int) hardclock(); \ + *C = (*C >> (7)) ^ (*C << (25)) ^ CLK; \ + *D = (*D >> (8)) ^ (*D << (24)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 4]; \ + B = &WALK[PT2 ^ 1]; \ + \ + PTEST = PT2 >> 1; \ + \ + PT2 = (RES[(i - 8) ^ PTY] ^ WALK[PT2 ^ PTY ^ 7]); \ + PT2 = ((PT2 & 0x1FFF) & (~8)) ^ ((PT1 ^ 8) & 0x8); \ + PTY = (PT2 >> 10) & 7; \ + \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + \ + C = &WALK[PT1 ^ 5]; \ + D = &WALK[PT2 ^ 5]; \ + \ + RES[i++] ^= *A; \ + RES[i++] ^= *B; \ + RES[i++] ^= *C; \ + RES[i++] ^= *D; \ + \ + IN = (*A >> ( 9)) ^ (*A << (23)) ^ CLK; \ + *A = (*B >> (10)) ^ (*B << (22)) ^ CLK; \ + *B = IN ^ U2; \ + *C = (*C >> (11)) ^ (*C << (21)) ^ CLK; \ + *D = (*D >> (12)) ^ (*D << (20)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 6]; RES[i++] ^= *A; \ + B = &WALK[PT2 ^ 3]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 7]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 7]; RES[i++] ^= *D; \ + \ + IN = (*A >> (13)) ^ (*A << (19)) ^ CLK; \ + *A = (*B >> (14)) ^ (*B << (18)) ^ CLK; \ + *B = IN; \ + *C = (*C >> (15)) ^ (*C << (17)) ^ CLK; \ + *D = (*D >> (16)) ^ (*D << (16)) ^ CLK; \ + \ + PT1 = ( RES[(i - 8) ^ PTX] ^ \ + WALK[PT1 ^ PTX ^ 7] ) & (~1); \ + PT1 ^= (PT2 ^ 0x10) & 0x10; \ + \ + for( n++, i = 0; i < 16; i++ ) \ + hs->pool[n % COLLECT_SIZE] ^= RES[i]; + +/* + * Entropy gathering function + */ +static void havege_fill( havege_state *hs ) +{ + int i, n = 0; + int U1, U2, *A, *B, *C, *D; + int PT1, PT2, *WALK, RES[16]; + int PTX, PTY, CLK, PTEST, IN; + + WALK = hs->WALK; + PT1 = hs->PT1; + PT2 = hs->PT2; + + PTX = U1 = 0; + PTY = U2 = 0; + + memset( RES, 0, sizeof( RES ) ); + + while( n < COLLECT_SIZE * 4 ) + { + ONE_ITERATION + ONE_ITERATION + ONE_ITERATION + ONE_ITERATION + } + + hs->PT1 = PT1; + hs->PT2 = PT2; + + hs->offset[0] = 0; + hs->offset[1] = COLLECT_SIZE / 2; +} + +/* + * HAVEGE initialization + */ +void havege_init( havege_state *hs ) +{ + memset( hs, 0, sizeof( havege_state ) ); + + havege_fill( hs ); +} + +/* + * HAVEGE rand function + */ +int havege_rand( void *p_rng ) +{ + int ret; + havege_state *hs = (havege_state *) p_rng; + + if( hs->offset[1] >= COLLECT_SIZE ) + havege_fill( hs ); + + ret = hs->pool[hs->offset[0]++]; + ret ^= hs->pool[hs->offset[1]++]; + + return( ret ); +} + +#if defined(XYSSL_RAND_TEST) + +#include + +int main( int argc, char *argv[] ) +{ + FILE *f; + time_t t; + int i, j, k; + havege_state hs; + unsigned char buf[1024]; + + if( argc < 2 ) + { + fprintf( stderr, "usage: %s