From 9646804e7318ee1f384266545ebbe904a35fca5c Mon Sep 17 00:00:00 2001 From: timvansteenbergen Date: Mon, 14 Feb 2022 12:42:03 +0100 Subject: [PATCH 1/2] Changes to DS_CheckForSetup: - started with 7 decisions and 14 activities and 5 CW0040 warnings, ended with 4 decisions and 8 activities and 0 warnings - Fix a hazard: when Encryptionkey is empty, it only warned the user to first set a value to this constant. Now it gives that message in the snippet itself, preventing the user to still use this module and ignore the warning. - The above fix also removed one CW0040 warning. - removed 3 CW0040 warnings caused by unneccessary call-page-activity. Removed the 3 activities. - removed the last CW0040 warning caused by unneccessary call-page-activity. Removed the 3 activities. - improved the structure by creating EmailSettings_FetchOrCreate. Replaced DS_GetEmailSettings with this logic, only using DS_ when it was called as datasource, and calling the fetchorcreate in the other occurences. - reduced the two calls to CountNrOfTemplates to only one - removed superfluous decision at the end of the happy-flow - decision with message '>0' actually compared to >1; changed the message to 'EmailTemplateCount > 1' --- .../EmailModuleWithTemplates.mpr | Bin 10477568 -> 10481664 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/EmailModuleWithTemplates/EmailModuleWithTemplates.mpr b/src/EmailModuleWithTemplates/EmailModuleWithTemplates.mpr index d8403e87114c8186a2c70afeef456bb336f2a401..2b90de26165a099d2434d66eef63cc16171689c9 100644 GIT binary patch delta 12473 zcmeI22Ut|+w)bamW`F@}%lu&}LIauSoHNi=F=7d1zZF)A2iqEWePW=JBCd%v9Le&;^Vcfa^NKY?A|vfi@( zYrVVlL=U^Pvxi+Z+-M|=#qD9S^nYTpSR<5U+=!8FNt;LN8*x9v3*1}#2JtOPlKT;3 zQboA4_a)fLbae5Cbh)eQv$6XKdHG`d6^rc&ghX@@Ho`%45j{j7;UWfzAu&-ax zuDOmQX}Z!X>B;1T(9(6oR?25hh$NX6F+0o=3uFjli3~-CA;S?XWCUW3j70c|4KfOO z2eC!oMeLB#$QWcSVvjf=j>tH~2^o(F5FsK$#E3KEg191Xh&v)dCLkWjM8p&ELc9?l z#24{H{E+}85D7wpkx57h5{iT&;fNH8Kq8SSWHJ(s#2{0USR@Xaio_$+km<+_WG3<+ zl7J*4Nk}r1f}|p8hzv3>cp(#R=XZzC3pVe>C3#Z+0_-niaXa zL@6xVs)!@UNT6j&R@*R~YLV z2w1~N7K>vW5&)AoD=e6=7AWo#gfo~dB!`khA#;AA!jOcf%4$<+p2aqV)q5)-&t(}i>lNp6e60yb4D z#u4#wzEUxd*b0+YVreeWy|H$zVPcR>o|+Mv@1HLN?=J?w1Kx9Kb7=KlX9|X^6z{{g zPw=-}Pn3Fk>Ta?0e}ER>rqK{vL60ZrIYC7Q9cyIm#9~nbmJZ(65i;{v(>qBWS7#R} zolRR}BYoD=+x1+8E*>J03)q-c*?@_H{yQOt>k8Tyf*z4$7{@&NJb_JmGnXD};LKW2 z^jhe43vB@x3+Pok_&y}d>2AV>i7BM5NnMefi-(ICCQApK6Ryy-fS#ixc5#70#q=t| zjj1c9>qu*%<{1|j8IxHoW2t)}auImA3b38-tXha%OgBR7LIsC(MQbdk7pVvT8Eo4@ z?+5uoCB>vy(@6v=6az!kA<&h~nFjBb()UQAGX$2=Ngybv=fb&zdd6V8l>X2L&0f*l zau%hw)~=tntjKp%`86J0eVF3J?S{!oWI1)@yXl$km&0TnWcgTSa`d?O9zAS~dgL>mA+cUF9S{N9Ix4&H0C>rDV zHMH1r!Xe3z?fFMFxv{eQ)U?<)KCLI&&F^4%PvMZnlOJhoTB!Uiq{8b}$dOYi6W^(S zatOMs$Z=HNnMcX53uIxNGrX_$WQDwd?4b%B)Jz%Rdb+P6N+4aW~pJACCQZFlzfMCh8lNcG<{c2}X|3U?p) z7IL!1{aeM-5efR$w%fw$ix-A%U;A;X=|BJ7zQO2?su)m4tu^-j2(d5W-g<(w9oq zO9}s3p}LSG&k@uf+@F!hxMF`)uUh0a@&-X|!o|nAPmnJB`xpHA0QnAih*VebaL0IY*~CWQI)h+#UfYx7S`^_cwFX!REMC+ogEeuo3e7%0v1DwvGBga+>WAtn6@d76Y5_noG9#p^ z0TD%hMR~rniXAdS7DVMbq&bVFdD*e~!i<>lX=%AB1%hIsyR+vcrtM*klx;u;_6qC{E2nK9GmrADVm=NGsp$IC>sU9yvl3dHV${P?Ia zVPH<)v~-6lIVn=lhXzd8d{|DB-;}E^gcyYZkY!pKc*~A8SXNZM^3+t_5yECN2ghhC7p%=`AC?^gZe!5DSz)}f_ zVU#xnqez-Q>vh>MlsEL zD^9fE=kxgh{b0D~>woBG)Yi*mi%GCqY(Dc=|C3j<}6>4NlPw~WBK=|O38iUOkpQd~o)&Pkq}C-Kd2pY2c}b19l4%P8=)n#4R1 z)t@BDBg3?VjV??D_gl~x?wwe#^@Z>cNqv=$h*bgeC)6isJkCG|rBPx*frb$)8l8MA zLw~rm?I*h_8YKpgJnBtxIR3~BIsr|Sv_Z>fI$=!Yxu*R*VlTr! zp?+c?Brh>CV}`Ugea|EIgV2^co)I@Uo#PP)7 zJ4yZX5W|jA|2zz3PuGrR#&sz!@YGE?0&O?+hCo!eVi@DnsrZ6N9A((&6g@n{W5V!l ziQjjmE+ZOX?kJ-L%!(6=g*-O5W1|di#~XOSiARc|%=E6cAMi--@dIqd8~k|>%6=dv z@T*I&LWO`X-J1YvCml+-sr`E5ItA$u@*Swb1usc=wdG6+cbHm@rWBZP{NY74T@ELH z##{SUv?*WmKOwFKtQCFM&;W7WmjCC)^?7@<%7JsNJDhDs{kNs`K!HE^pwf&Qpq|TS zY*_kd)iX+T5uEeKVBilVw78$J{kKVIp>w~Q{%=WW4A1(;GygpaZ7RS}tZ%$GanJpI zw)UZ++tyq1j81j@gS4HpAWz1!#4T5vnVMfgHMUb5bdq#V$O}L?NZ*VZN+}-TYPk$8 z&0Hrf-aky7xsd7j@MEHYs80pL`5h#}NxZJD7RtC+62_`UiQImuT@KJQ&i`Q^9 zYu4L!T;7^rZa|wrXB<>bn`+EkW78E?en=465NVds@}dN6R+^z0C?<@-uAMgKO^xfg zym!pgke$n`7hTyk4U(@lO@xwmdI9{68)*Wq$2>y#xMAMxBY>*k#2q;0QX9Ef`1hHe z2j@XcVyrzRF#*Or;kDAz@uA{~vR^_2zM8><$r6)Z5oFq%i_p5R_)?yM$;h1nWt3!L zMc9xVS`qYpDlLW)+mvIdwr+)DX<=~aR!h^^(pC4yg73!liInq2ySPw)vGl+Vj_F6g zh|1vPt7<9ulo*LA_ZvYaQ$O&N?hbbCibz~@P9u^=>-gv9$YnWlR&AdJeQ@#8r)yW< z3R&LZxYX>{${)0{iQ6>Ku3+~$-=@zS4>#w&g4>LdMmCKfai@>FyzBP5dSa)M|DN^t zZfu#h4sPF^Z4JAZu&sC%kz@AR2$H6)NVJmPMsb^5%bjQ|!Iy(F^9$ts)ZFa6ESX%! zmuJZM1u}VI9zQo-^9R^GUuy|_?VQb^)G9etN6a#YV_TG$$Vmj$Y*of-o9 ze;O3#me&pqm5q;>9+DQC>pC?uFe;!hG%epU#nVDMnGOSVZ~ccs4VT*d>gP~ zEM4RgR0XAcv)SY!LyaS+o{t!xeCNuXN$b)Z_v{T6$+anmd$BpUg$5=*6{UKSZ@%ie zuZ__!w`T8>Ha+%Vy3?g6>rlS2Mv;krjvL+O6oz`LsxuB9h_ z9M*78GJfK!yXD#}&3fO@56Pye{Mu*!-Lbp8VXC%{of);N=bg2_m0#Q2bV^obtLq3E zvD09=Tdz^SP8(nZjZtGKXT}DF3kpP`;`v2$ilU@~=`NF8WQEaEfwQDA&^LNgnqN?E zusD2Pk>^hHe~(eK^!_uWs?$<`+~GfO)V^C`1?z9aE$%#wsJU|C)_JEly+-|clkw)3 z-KWAg?`kMFFr-tpsV_tGAD2b>UJE?1-R1NX_Umqq;1cz34-1z@U+2t@Q+{^m`J=#N zjy9L(?;89WXqwEX6hqUDkOHd|X{hKD+rLKqq zO_YJjoDJk>_S&56T>AkzSq|o8J%qp?Qe_GB0(!RYI9C@BHv#a9=@n?(=Wu@sEz{&f zb@7I)NB~qZ?G3dhbTGyrFJR>?ye+uF=5X8v9?k-IF^gUW4_fINx^DP9=4VX`$ibM4 zbvQ<6>4`O$dW*Pmj1ES-6&t)gulwf$K@-9>Ve01h@MPlR*oha;SqH7kIBiE3V#-{3 z%@lhOOE00eUT%)tef*WQb*b+)_mQ^7K+I$ZfKzj$6qP~I|52&3Nu){vC$l&&eXCYC!Q8j z>CR`|EBuv_LlalR9@^@H%iYbae;!$(e0e_rTm+HKXC1c$%VaZ}dMF9y2fa==Dc_Pi

Hogfo(){cokmAcQ+S>qKKn@Gzxnpbq@mIWS=vH2kBOwH>>qDjf9J=zu-#z?+Q++& zXww$b`U*xtRC6O2JVWZZ%=^>nSp*ek=hU?0=lQ;^A?4xE|0#JFl-)IB!Eq*SOuaYd z@v_i~36l=(bb0x>B>OvUDJQlyhBB9D()I*(I(~i3+4ChKYp$1;yxZb^8%);M1;ZCn zv>qfS&}C2>(5O2>fQflQpQO9sx1_sUA1Tm3&8eLNeWTdQwn3bqU+)Oo{EkCF<*@B7 ze-y>qUwLLNT^Ae<6yU3`ghE9*}ojm&4Y~>eg%e<^~ehn_kreonG}8 z(40b#Bi?~8Qs~`;4+!t5hBI}kv?+>V>3QsRswo=W*F=`=U<0;F|lP^%K00X!yr$y>$90nKCUN%A@>uw+Q(_hzX z3=Yyn9Q)|A#^Yvf+c0T=`Lr(!A{yTZ!mQC7K1`(JAm2&Xn)iBc#$BmhQ^>NDS4e); z2)O-&$__g3ZYY4}VR{@mms!Jh>pSeiU(Z@F8@attGx{Zlp=_kt5J;NJu{0fmZ4b;& z&di#Eoytm<%lu(>J{_%@SY|k}(6Vox=AdPSOF8D?6@wi(n;+u1_2Vf)$~lieQ5f%a z!i*Eg18&J_&bp74MzB4G9!ov@!m49+cXZI9+~jZXn)pw_{1|79jZn;*hxPux?ex#< zLs{nrZ%r39Lt7Ti8B93$J-#|ej8u;mo=Wv;U+=`n&||y$xG8Mdzz*U>kn_FxLTGEF zBQ*o=DgvSg_aWD%97@wSuw6oj{niydf9)$!dXqg0b}XSKm`&dE>om*r#QB=ImUiOv zu}=}X{9KJ(Np7`V^i z(xhgS0G$}J;20!-VrK8{iO)pKP!G%IY4!HoT~}-6%yfRHoS&8}E8yqk%K5VSnFVr3 zermo9=Nms0x|ix&4R;X~h943rbF0yR;lVoJ#Z}-TetQ{-ep^OZ0QU(9 z`MPG%F%@;t|JOPyIjTVdQQnQle~GF8NipU3Ux}%=Mb>zKoUM46%wqM=@oA5Q{ue}! zTYDqNh`%Doe_Q0J+)oTvCmp)s`JW2Bv zl_-0iU|)>Sqp;-#ZiU5*i%nQM{ZD{w&ptIRaAO5E>U3F?!hJ8bsb8W!HzauT)$rA- z`tAJk8F#gH9L?z7**VxtS~uvIjQZ=Q%e4po1G0_39r#lp8zx>3C`|V|Xt3Xl{kdZ~ z5R1q$Fn&k1<0vvBIa{Xwph+9-VjM5e%$Zg2_Q#l2Ys@Xc)ftQ_2`o=pb}uxjA}Tte zZpWBMFgadN0&DP=^{0K(DFbZN@*_CGV-GN*mbp^x3Zwgh>pPlv&2Qjeh3>D|)6}1N zj)GxLO3ZhzRqVKN?^58#mmLQmo-!>0VrSh{5L~9Y5LrnNr#zeYiLQBF^Qq?>EzAh` zc^Q~o(T}8-w+2tzd*Yn`7RgV>@9Dn^2b+@mQ+P-ol|>IzT`b46RKF2`^ZBF)hR%^+ z>09!}Ec}A&t*CoIa=2_$^u@HxC`we;N$ zhR|lxh+hP1vj-e-^8g`b_sI?ug|rRd)|9^yeXt2>c>~&_m78ag4z*k zy&Wx^RhX5W&rer>vdhoS?+sa<_;7MnqqUn5KR$fxOV?hZjo;*TV@Bxry*tIoT^ zbWAc)<6N9Zck*vVC}ub>kG^$dr#jv016Rf10C{uh(O}>TR@C|6%a4XOeh_kW?w%*s zGYopOr^OiM^Q5-ER%I{mgl_4MO3(f%3eKBWkG8?{7V|!XWc~0<-k$H%!&Z*^MZaWO zu%kB1*tL)z0bQeNje#bb2Ej2m2;!C4^0eV4ia1>VgI@Of0H6&?rnosH`r&hta z*~!Uf$WYhrFW23AFLLU-N$<^3S&m=6nJA*8_~NQVqi!(zyUS0M|QKsMw+F62Qz6u?p_gd!-05-5c-D2HXR z99FDZ4ke#EAcTOHDUZZAMc24;oit zcGs476(VW3z;$o=Tfs?tii;@7PTE^=Eim1~fd|ywB=Z-7D@>gViS%c6dNHLPWyh1p z6j7+~n%1;dA(K8_-q)tdcD{qIc~L*wxN=KhA*RW65-0y6a4n|4vGYja+RZx*LqT=c zPQvxSHhPJ;$3cxh(b7(DC!>>pY#b;oR%x89*&t!%V2wz`Mv}t{k*g>uSTOi# zY(=D8A#xK1g;2*(%^W(l(aE0Tf9C8&L7@~rO!FpHT$Bu??miMZJshT4U^ARqidiV} zo)kk*95v2VBI&QxPpVlgEb89qE@g+(SwGEWTKrHarvd(&EV^diGx%%9 z(*2vdel+11-EG7`oktxJOQ5jw*NyQKj$x#~QJQUU$A*KOJxFz^!G^we)0`7HR`XEa z)}*mga(5W!4%xJ5uDHYm`cG@|*wnOUD^oezX4o)KsoMVaV+r(Qi^j))X-R2#V0d`? z^oXPx!!t^kmgN^E1SBj=SQ4F-pBSG!aq`6Iu%NQM!jj1N(aj0uaC75jq0d3hH}>Wj z{-|!(w6$v`T{3nt!!8zki@jSNl2Tc&`h;Jlu%x+eueIQQ)pXm+T={WzOI>x#rs@`5 zTT8uFAQ#Wr#vgW=nJN=hTK0QZe$TT~{VcjQm+UCz`+6V088h?4W<{6AE{>a?m%e;x zaQ4y=b!NfR;Ns|6>RC&phfhz7UN$8+FQjb3^wCkm&hP8vIgxC9b$5MR_hylHwRs_A z+^|M=Ks&U+0XPV)a0m`V8whX&j>0iG4kzF}I0>iVOSlSO!PoE&T!ZUy!`vab-h5a9 zX$-Ev5Ic(?1JYqJs38+x1@q#)1hOFqa=|=s@*p1ypa=?~1d5++OR+77Ww0Dp!U|Xg zuK_O2RG5F(Kqb5mYoQ9Np$68$8}KHqhmBAR8$bhfpoLAKgL>Eu4M3m=9t_WH!PW>S z*b1u~@zV@%!8X_qZ^JvV1Kx$5unTs>9@q=}U_T&53{u7*Weieg`5P%?kR}ExV~{e- zK2pXU2c(NR2}l`p%G?R<*g@`@)9?Yj48SxC3|LJNOyChx_mY z{0KimH}t>*cnH71Z}12n!>>>OW^J(j1O9}+;BRyOpD+xI4T~RE1Y+Po0#;xRQjh@} zVC}&E8Aogtpaci#1--#s?gY-@0)4<0+`t|BLO<~Fz>g=Wpg(xQ0PqGM7zBf1h~SXc zFxRe4+rV{Mix8&u9m}iBFRYMvn(j#KTkI=~WlvYG>r1G;n0)*b#>IsdOwJC9OUfzB zoE0)50B&O9@qpL{(B6o1}45Uf6E` zVX0rAsmHGlSf7;{6jm z_5QOg@#c6wPIEusYt?55k5d0)u2S(s|Iq&RRdZubu{*!r_=*=L-{Mr16e*D_8SjX7 zXUpwkYnT-a3eJ`OLx9zIGBSx7S#ethaZy&RbUGuQE;zLNPLbA3|Cog7 zAM0B(twoiLsFJg!r%c4H`8{>5P!r7G<|t4qaiPc6jY=8*6JpE7fA!JoXYB5_Uix2Q$j zIGR?E;I-^<;aIZf4VDcPVp25gST>x_zoJ=4U1{QRG`|ULc7#j(Y43E6Miud2fy9UH z8t3jNo1i^7_3oFoV~#!zB!9YQv~p1Rn{%3z+oDdbdNgfY>bh`q433y8vOlV$__ip6 zxJ7&*UXN0*FskSf_oH=p3^%Ahd4RpQ| zEmtg1$jP`CEw{%Z2<=_XvzDi(Hp&D=l_AxNeV1NckE*AZv2qHpMb)Osil^}k&9#P^ zBCH0o*2JT}56`JC|4s*f)Oe7G#&CK%PL-7@M38g<(%VBQ&+8APNUBAQLLZkcIet~d@ssMs9Qk_U$KJ5 zUEsekhkRJKCe@h&F7lUX^DNh3TBsBE6H;3Eg(5bd4jtsjvy150gM2p48{;6SrLBB9 zd2DEq(U|Y+WP;TpUTVd53W{TVBFm1X1;_bB(Z_DYo@L$WljD3EJDP@_;CEBS5<5BF zKEX#(=LlPlR1fN(rcy|JkMA-s=dv~mIK^KkRYss%$Zq04kedqy>Uq>>JssQ6$C2qL ztxT}j@?Hw_kt4KpLtkG~{nC%4d5!#bQvU7swy>*$ud7;O)Oi_&CMCbfmi7KlaD(YFM4x_HH(1y` zSAULW_fq+M{rgy`P7r&hk2lR0pUHj5FG|0GRnqY&{md8hCL~1bTUkX==8Nrm zk#fAgM=4$WV&QLUa){A)h(5@m0y`f!;l~)gf>m5hez8uwU>Bz!YtGly33^MulBc=5 zkuX7@#*QM_iTd5t^)@E;rxW#2RQgw)ix4_V-`5HcT-kdMDd=B)MpA8}zL;8OXXG3% zpe{?lo}^}LS3$6i(#2X5bc%W^Jbg%8$p_J{MBNOEI-m6~y1tfI3SS56O69owcDlJD zc0W0L^K!vKr5kHGuY=Nt@$TfgO{=680lF&c){fdv#~o3pO{t5tMwYr=bpKD5++B6U z&9CXQ)0E_?YvGPoT{KeiA2tTk_{#boKB?Ph^)yqF53x~G{UWalqT^)$<_3?OD|fU*>w1^DVS6dlBq(H z$`o(unXf1ByGHNkn`V<^ozX`K&>CwvwuOXx<7D;gBw3s@)aiQlok4KG- zFn^%2$C`DgBtPRpHj~8u##mZ%u5N%(>TfJIuU`0?$Ws};gP!69s!$;3~}9djeO0tst)0`ecDf)=hP7;?TnpTh1!j9{gv*fGQ8Df8xxc z)Kb~YnoNg!DTTO-hLZ|`>uUT{(WYwTwBn(vAi9|+c31Wq^r_vhjt!Ic*Z#aI-YtDM z-R#uqDapx7A`T54Ne3?1JF~&G#I|vcRb=S!k-@=~*2y{9gfSh@UYMxa*yv1Y1FTk3 zlbf}~Dk3D%TubGk^`ckvo#e{0Ee-R|MBR$l?3&$o{^7rN5SuI+*^q7G$bp<)<*NRp zRhTrz%T#H387fN|)oPpuDg6!l-z2vB=(X>))eg>Hevy*ntbJ7Bman(xZ>CHl>EH_5@$O7rSm}!7cy0v%;v(MH8WlWKQDY|Gb^d-i3vIFV7vf&XAgM zV=MEMWm0(DdNxmSVos?sFDZAWhTBgE>f%$XsdDOq{>HUSl)H>DF@YM+K9T#*x4@bF`qsI7u zdQ@GgQmYG#id7kE)nK}~udWZNE}3jbsa08d=Ca)U40R4FW#s3ZYv!qna?~Zo>Ks*R zTAnH>OqHEhn3i3P7R>dF)vD5xoE&mrDq3$DQ4({ehEv-5Mi*6}D#&8azCJf^(!xq8IlbxPZ(0Rhg@!65sjq z)-J>+&%d0WNk;0JZ$AFW#r&2@}`#Z#`ESrw31-zBIpAj zU^a(Pmu+JXb!OFb<{LpT)$|VuWj=qYL&nG)nEpE7Nwv0q<43V7)zgt`{!)M5`H!_s z)wcT7sH5S(FB;nwGKJXQMrXR5EgkPM`=yF!2S&EM|0HZu?RoVs?RSnPq)m`IdrwrS zWiX Date: Mon, 14 Feb 2022 17:36:51 +0100 Subject: [PATCH 2/2] Added attribute EncryptionKeyIsOk to prevent having to make the encryptionkey constant publicly visible, which is a bad idea. --- .../EmailModuleWithTemplates.mpr | Bin 10481664 -> 10481664 bytes .../encryption/actions/DecryptString.java | 111 +- .../encryption/actions/EncryptString.java | 24 +- .../actions/PGPDecryptDocument.java | 4 +- .../actions/PGPEncryptDocument.java | 17 +- .../encryption/pgp/PGPFileProcessor.java | 476 ++++---- .../javasource/encryption/pgp/PGPUtils.java | 1034 ++++++++--------- .../system/UserActionsRegistrar.java | 10 +- 8 files changed, 859 insertions(+), 817 deletions(-) diff --git a/src/EmailModuleWithTemplates/EmailModuleWithTemplates.mpr b/src/EmailModuleWithTemplates/EmailModuleWithTemplates.mpr index 2b90de26165a099d2434d66eef63cc16171689c9..3d67a2bf469c5ff7de1e5b0fa5dea10f0d9c7cfc 100644 GIT binary patch delta 70776 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 delta 73972 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

YU-Ql6mTE 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 TZxn~Lm6k>+)wY>hJ;?kQny8Sw diff --git a/src/EmailModuleWithTemplates/javasource/encryption/actions/DecryptString.java b/src/EmailModuleWithTemplates/javasource/encryption/actions/DecryptString.java index d4331b2..c754450 100644 --- a/src/EmailModuleWithTemplates/javasource/encryption/actions/DecryptString.java +++ b/src/EmailModuleWithTemplates/javasource/encryption/actions/DecryptString.java @@ -16,6 +16,8 @@ import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +import java.util.regex.Pattern; +import java.util.regex.Matcher; import com.mendix.systemwideinterfaces.MendixRuntimeException; import com.mendix.systemwideinterfaces.core.IContext; import com.mendix.webui.CustomJavaAction; @@ -25,38 +27,36 @@ public class DecryptString extends CustomJavaAction private java.lang.String value; private java.lang.String key; private java.lang.String prefix; + private java.lang.String legacyKey; - public DecryptString(IContext context, java.lang.String value, java.lang.String key, java.lang.String prefix) + public DecryptString(IContext context, java.lang.String value, java.lang.String key, java.lang.String prefix, java.lang.String legacyKey) { super(context); this.value = value; this.key = key; this.prefix = prefix; + this.legacyKey = legacyKey; } @java.lang.Override public java.lang.String executeAction() throws Exception { // BEGIN USER CODE - if (this.value == null || !isStartsWithRightPrefix()) - return null; - if (this.prefix == null || this.prefix.isEmpty()) - throw new MendixRuntimeException("Prefix should not be empty"); - if (this.key == null || this.key.isEmpty()) - throw new MendixRuntimeException("Key should not be empty"); - if (this.key.length() != 16) - throw new MendixRuntimeException("Key length should be 16"); - - String decryptedText = null; + if (this.prefix != null) + throw new MendixRuntimeException("Prefix should be null when passed to DecryptString, this parameter will be deprecated"); + if (this.value == null) + return this.value; - if (isEncryptedWithLegacyAlgorithm(this.value)) { - decryptedText = decryptUsingLegacyAlgorithm(); - } - else { - decryptedText = decryptUsingGcm(); + String textPrefix = getPrefix(this.value); + if (textPrefix == null) + throw new MendixRuntimeException("Encrypted string does not have a valid prefix."); + switch (textPrefix) { + case "AES": return decryptUsingLegacyAlgorithm(); + case "AES2": return decryptUsingGcm(); + case "AES3": return decryptUsingNewAlgorithm(); + default: + throw new MendixRuntimeException("Invalid prefix encountered when trying to decrypt string: {" + textPrefix + "}"); } - - return decryptedText; // END USER CODE } @@ -70,18 +70,54 @@ public java.lang.String toString() } // BEGIN EXTRA CODE - private final int GCM_TAG_LENGTH = 16; // in bytes - private final String LEGACY_PREFIX = "{AES}"; - private final String WRONG_KEY_ERROR_MESSAGE = "Cannot decrypt the text because it was either NOT encrypted with a key of length 16 or they key is different"; + private static final int GCM_TAG_LENGTH = 16; // in bytes + private static final String LEGACY_PREFIX = "{AES}"; + private static final String LEGACY_PREFIX2 = "{AES2}"; + private static final String NEW_PREFIX = "{AES3}"; + private static final Pattern PREFIX_REGEX = Pattern.compile("^\\{([a-zA-Z0-9]*)\\}.*$"); + private static final String WRONG_KEY_ERROR_MESSAGE = "Cannot decrypt the text because it was either NOT encrypted with a key of length 16 or the key is different"; + + private String decryptUsingNewAlgorithm() throws Exception { + if (this.key == null || this.key.isEmpty()) + throw new MendixRuntimeException("Key should not be empty"); + if (this.key.length() != 32) + throw new MendixRuntimeException("Key length should be 32"); + + String[] s = this.value.substring(NEW_PREFIX.length()).split(";"); + + if (s.length < 2) + throw new MendixRuntimeException("Unexpected prefix when trying to decrypt string."); + + Cipher c = Cipher.getInstance("AES/GCM/NoPadding"); + SecretKeySpec k = new SecretKeySpec(this.key.getBytes(), "AES"); + + byte[] iv = Base64.getDecoder().decode(s[0].getBytes()); + byte[] encryptedData = Base64.getDecoder().decode(s[1].getBytes()); + + try { + GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv); + c.init(Cipher.DECRYPT_MODE, k, spec); + return new String(c.doFinal(encryptedData)); + } catch (InvalidAlgorithmParameterException | BadPaddingException ex) { + if (isEncryptedWithWrongKey(ex.getMessage())) + throw new MendixRuntimeException(WRONG_KEY_ERROR_MESSAGE); + else throw ex; + } + } private String decryptUsingGcm() throws Exception { - String[] s = this.value.substring(this.prefix.length()).split(";"); + if (this.legacyKey == null || this.legacyKey.isEmpty()) + throw new MendixRuntimeException("Legacy key should not be empty"); + if (this.legacyKey.length() != 16) + throw new MendixRuntimeException("Legacy key length should be 16"); - if (s.length < 2) //Not an encrypted string, just return the original value. - return this.value; + String[] s = this.value.substring(LEGACY_PREFIX2.length()).split(";"); + + if (s.length < 2) + throw new MendixRuntimeException("Unexpected prefix when trying to decrypt string using legacy algorithm."); Cipher c = Cipher.getInstance("AES/GCM/PKCS5PADDING"); - SecretKeySpec k = new SecretKeySpec(this.key.getBytes(), "AES"); + SecretKeySpec k = new SecretKeySpec(this.legacyKey.getBytes(), "AES"); byte[] iv = Base64.getDecoder().decode(s[0].getBytes()); byte[] encryptedData = Base64.getDecoder().decode(s[1].getBytes()); @@ -98,19 +134,23 @@ private String decryptUsingGcm() throws Exception { } private boolean isEncryptedWithWrongKey(String message) { - return - message.equals( "Wrong IV length: must be 16 bytes long") || + return message.equals("Wrong IV length: must be 16 bytes long") || message.equals("Given final block not properly padded"); } private String decryptUsingLegacyAlgorithm() throws Exception { + if (this.legacyKey == null || this.legacyKey.isEmpty()) + throw new MendixRuntimeException("Legacy key should not be empty"); + if (this.legacyKey.length() != 16) + throw new MendixRuntimeException("Legacy key length should be 16"); + String[] s = this.value.substring(LEGACY_PREFIX.length()).split(";"); - if (s.length < 2) //Not an encrypted string, just return the original value. - return this.value; + if (s.length < 2) + throw new MendixRuntimeException("Unexpected prefix when trying to decrypt string using legacy algorithm."); Cipher c = Cipher.getInstance("AES/CBC/PKCS5PADDING"); - SecretKeySpec k = new SecretKeySpec(this.key.getBytes(), "AES"); + SecretKeySpec k = new SecretKeySpec(this.legacyKey.getBytes(), "AES"); byte[] iv = Base64.getDecoder().decode(s[0].getBytes()); byte[] encryptedData = Base64.getDecoder().decode(s[1].getBytes()); @@ -125,12 +165,11 @@ private String decryptUsingLegacyAlgorithm() throws Exception { } } - private boolean isEncryptedWithLegacyAlgorithm(String text) { - return text.startsWith(LEGACY_PREFIX); - } - - private boolean isStartsWithRightPrefix() { - return this.value.startsWith(this.value) || isEncryptedWithLegacyAlgorithm(this.value); + // try to extract the prefix of an encrypted string + // returns null if no prefix is found + private String getPrefix(String text) { + Matcher m = PREFIX_REGEX.matcher(text); + return m.find() ? m.group(1) : null; } // END EXTRA CODE } diff --git a/src/EmailModuleWithTemplates/javasource/encryption/actions/EncryptString.java b/src/EmailModuleWithTemplates/javasource/encryption/actions/EncryptString.java index 7d87c70..3a0af2c 100644 --- a/src/EmailModuleWithTemplates/javasource/encryption/actions/EncryptString.java +++ b/src/EmailModuleWithTemplates/javasource/encryption/actions/EncryptString.java @@ -38,20 +38,27 @@ public java.lang.String executeAction() throws Exception return null; if (this.prefix == null || this.prefix.isEmpty()) throw new MendixRuntimeException("Prefix should not be empty"); + if(isLegacyAlgorithm(this.prefix)) + throw new MendixRuntimeException(String.format( + "The used prefix is no longer supported for encryption. Please use '%s'.", NEW_PREFIX)); + if (!hasValidPrefix(this.prefix)) + throw new MendixRuntimeException(String.format("Invalid prefix used. Please use '%s'.", NEW_PREFIX)); if (this.key == null || this.key.isEmpty()) throw new MendixRuntimeException("Key should not be empty"); - if (this.key.length() != 16) - throw new MendixRuntimeException("Key length should be 16"); - Cipher c = Cipher.getInstance("AES/GCM/PKCS5PADDING"); + if (this.key.length() != 32) + throw new MendixRuntimeException("Key length should be 32"); + Cipher c = Cipher.getInstance("AES/GCM/NoPadding"); SecretKeySpec k = new SecretKeySpec(this.key.getBytes(), "AES"); c.init(Cipher.ENCRYPT_MODE, k); byte[] encryptedData = c.doFinal(this.value.getBytes()); byte[] iv = c.getIV(); - return new StringBuilder(this.prefix + - new String(Base64.getEncoder().encode(iv))).append(";").append( - new String(Base64.getEncoder().encode(encryptedData))).toString(); + StringBuilder sb = new StringBuilder(this.prefix); + sb.append(new String(Base64.getEncoder().encode(iv))); + sb.append(';'); + sb.append(new String(Base64.getEncoder().encode(encryptedData))); + return sb.toString(); // END USER CODE } @@ -65,5 +72,10 @@ public java.lang.String toString() } // BEGIN EXTRA CODE + private static final String NEW_PREFIX = "{AES3}"; + private static final String LEGACY_PREFIX_REGEX = "^\\{AES2?}$"; + + private boolean hasValidPrefix(String text) { return text.equals(NEW_PREFIX); } + private boolean isLegacyAlgorithm(String text) { return text.matches(LEGACY_PREFIX_REGEX); } // END EXTRA CODE } diff --git a/src/EmailModuleWithTemplates/javasource/encryption/actions/PGPDecryptDocument.java b/src/EmailModuleWithTemplates/javasource/encryption/actions/PGPDecryptDocument.java index def193d..58f45e7 100644 --- a/src/EmailModuleWithTemplates/javasource/encryption/actions/PGPDecryptDocument.java +++ b/src/EmailModuleWithTemplates/javasource/encryption/actions/PGPDecryptDocument.java @@ -16,8 +16,8 @@ import encryption.proxies.microflows.Microflows; /** - * Encrypt the FileDocument using PGP encryption. - * This is allowed to be the same FileDocument instance and the action will just store th decrypted file in the entity. + * Encrypt the FileDocument using PGP encryption. + * This is allowed to be the same FileDocument instance and the action will just store the decrypted file in the entity. * * The certificate must be a File containing a valid PGP key ring (matching the document) and the certificate must have a passphrase entered in the attribute * diff --git a/src/EmailModuleWithTemplates/javasource/encryption/actions/PGPEncryptDocument.java b/src/EmailModuleWithTemplates/javasource/encryption/actions/PGPEncryptDocument.java index 1935423..4979bf7 100644 --- a/src/EmailModuleWithTemplates/javasource/encryption/actions/PGPEncryptDocument.java +++ b/src/EmailModuleWithTemplates/javasource/encryption/actions/PGPEncryptDocument.java @@ -15,11 +15,10 @@ import encryption.pgp.PGPFileProcessor; /** - * Encrypt the FileDocument using PGP encryption. - * This is allowed to be the same FileDocument instance and the action will just store the encrypted file in the provided entity. + * Encrypt the FileDocument using PGP encryption. + * This is allowed to be the same FileDocument instance and the action will just store the encrypted file in the provided entity. * - * The certificate must be a valid public PGP key provided by the external party. If you want to sign the document you can optionally provide the private key to used for signing. - * The external party would have to validate the signature against the pub key from signature key. + * The certificate must be a valid public PGP key provided by the external party. * * This action will either return true or an exception */ @@ -31,16 +30,13 @@ public class PGPEncryptDocument extends CustomJavaAction private system.proxies.FileDocument DocumentToEncrypt; private IMendixObject __OutputDocument; private system.proxies.FileDocument OutputDocument; - private IMendixObject __SigningCertificate; - private encryption.proxies.PGPCertificate SigningCertificate; - public PGPEncryptDocument(IContext context, IMendixObject ExternalPublicKey, IMendixObject DocumentToEncrypt, IMendixObject OutputDocument, IMendixObject SigningCertificate) + public PGPEncryptDocument(IContext context, IMendixObject ExternalPublicKey, IMendixObject DocumentToEncrypt, IMendixObject OutputDocument) { super(context); this.__ExternalPublicKey = ExternalPublicKey; this.__DocumentToEncrypt = DocumentToEncrypt; this.__OutputDocument = OutputDocument; - this.__SigningCertificate = SigningCertificate; } @java.lang.Override @@ -52,8 +48,6 @@ public java.lang.Boolean executeAction() throws Exception this.OutputDocument = __OutputDocument == null ? null : system.proxies.FileDocument.initialize(getContext(), __OutputDocument); - this.SigningCertificate = __SigningCertificate == null ? null : encryption.proxies.PGPCertificate.initialize(getContext(), __SigningCertificate); - // BEGIN USER CODE PGPFileProcessor p = new PGPFileProcessor(); @@ -62,9 +56,6 @@ public java.lang.Boolean executeAction() throws Exception p.setAsciiArmored(true); p.setPublicKeyFileName(this.ExternalPublicKey.getMendixObject()); - // If we are going to validate the signature we also need the private key and passphrase - // p.setPassphrase( Microflows.decrypt(getContext(), this.SigningCertificate.getPassPhrase_Encrypted()) ); - return p.encrypt(getContext()); // END USER CODE } diff --git a/src/EmailModuleWithTemplates/javasource/encryption/pgp/PGPFileProcessor.java b/src/EmailModuleWithTemplates/javasource/encryption/pgp/PGPFileProcessor.java index 513a2ab..18a7687 100644 --- a/src/EmailModuleWithTemplates/javasource/encryption/pgp/PGPFileProcessor.java +++ b/src/EmailModuleWithTemplates/javasource/encryption/pgp/PGPFileProcessor.java @@ -1,239 +1,239 @@ -package encryption.pgp; - - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.UUID; - -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPSecretKey; - -import com.mendix.core.Core; -import com.mendix.core.CoreException; -import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.systemwideinterfaces.core.IMendixObject; - -public class PGPFileProcessor { - - private String passphrase; - private IMendixObject publicKeyFileDocument; - private IMendixObject secretKeyFileDocument; - private IMendixObject inputFileDocument; - private IMendixObject outputFileDocument; - private boolean asciiArmored = false; - private boolean integrityCheck = true; - - /** - * Encrypt the InputDocument - * - * This function requires the publicKey, OutputFile and InputFile to be specified - * - * @param context - * @return true or exception - * @throws Exception - */ - public boolean encrypt( IContext context ) throws Exception { - - if ( this.publicKeyFileDocument == null ) - throw new CoreException("Please provide a public key document"); - if ( this.outputFileDocument == null ) - throw new CoreException("Please provide an output document"); - - InputStream publicKeyIn = Core.getFileDocumentContent(context, this.publicKeyFileDocument); - - String tempOutputFile = getNewTempFile("out"); - FileOutputStream out = new FileOutputStream(tempOutputFile); - - - File tmpIn = writeInputDocumentToTempFile(context); - - PGPUtils.encryptFile(out, tmpIn.getAbsolutePath(), PGPUtils.readPublicKey(publicKeyIn), this.isAsciiArmored(), this.isIntegrityCheck()); - out.close(); - publicKeyIn.close(); - tmpIn.delete(); - - storeOutput(context, tempOutputFile); - - return true; - } - - - /** - * Encrypt and sign the InputDocument - * - * This function requires the publicKey, privateKey (for signing), OutputFile and InputFile to be specified - * - * @param context - * @return true or exception - * @throws Exception - */ - public boolean signEncrypt( IContext context ) throws Exception { - - if ( this.publicKeyFileDocument == null ) - throw new CoreException("Please provide a public key document"); - if ( this.secretKeyFileDocument == null ) - throw new CoreException("Please provide a secret key document"); - if ( this.passphrase == null ) - throw new CoreException("Please provide a pass phrase"); - if ( this.outputFileDocument == null ) - throw new CoreException("Please provide an output document"); - - - String tempOutputFile = getNewTempFile("out"); - try { - FileOutputStream out = new FileOutputStream(tempOutputFile); - - InputStream publicKeyIn = Core.getFileDocumentContent(context, this.publicKeyFileDocument); - InputStream secretKeyIn = Core.getFileDocumentContent(context, this.secretKeyFileDocument); - - PGPPublicKey publicKey = PGPUtils.readPublicKey(publicKeyIn); - PGPSecretKey secretKey = PGPUtils.readSecretKey(secretKeyIn); - - File tmpIn = writeInputDocumentToTempFile(context); - - PGPUtils.signEncryptFile( - out, - tmpIn.getAbsolutePath(), - publicKey, - secretKey, - this.getPassphrase(), - this.isAsciiArmored(), - this.isIntegrityCheck()); - - out.close(); - publicKeyIn.close(); - secretKeyIn.close(); - tmpIn.delete(); - - storeOutput(context, tempOutputFile); - } - finally { - (new File(tempOutputFile)).delete(); - } - - return true; - } - - public boolean decrypt( IContext context ) throws Exception { - InputStream in = Core.getFileDocumentContent(context, this.inputFileDocument); - InputStream keyIn = Core.getFileDocumentContent(context, this.secretKeyFileDocument); - - String tempOutputFile = getNewTempFile("out"); - try { - FileOutputStream out = new FileOutputStream(tempOutputFile); - PGPUtils.decryptFile(in, out, keyIn, this.passphrase.toCharArray()); - in.close(); - out.close(); - keyIn.close(); - - storeOutput(context, tempOutputFile); - } - finally { - (new File(tempOutputFile)).delete(); - } - - return true; - } - - - /** - * Generate a new random file name in the Mx Temp folder - * - * @param suffix - * @return full path to a file in deployment/data/tmp/ - */ - public static String getNewTempFile( String suffix ) { - return Core.getConfiguration().getTempPath().getAbsolutePath() + "/" + UUID.randomUUID().toString() + "-" + suffix + ".pgp"; - } - - /** - * Evaluate and store the content of the output file in the output file document (with the same name as input file) - * - * @param context - * @param tempOutputFile - * @throws IOException - */ - private void storeOutput( IContext context, String tempOutputFile ) throws IOException { - FileInputStream in = new FileInputStream(tempOutputFile); - Core.storeFileDocumentContent(context, this.outputFileDocument, (String) this.inputFileDocument.getValue(context, "Name"), in); - in.close(); - } - - private File writeInputDocumentToTempFile( IContext context ) throws IOException - { - File tmpFile = new File(getNewTempFile("in")); - FileOutputStream outStream = new FileOutputStream(tmpFile); - - InputStream inStream = Core.getFileDocumentContent(context, this.inputFileDocument); - - int content; - while( (content = inStream.read()) != -1 ) - { - outStream.write(content); - } - outStream.close(); - inStream.close(); - - return tmpFile; - } - - /** - * Should we use ASCII encoded output for the encryption or decryption action - * @param asciiArmored - */ - public boolean isAsciiArmored() { - return this.asciiArmored; - } - - /** - * Should we use ASCII encoded output for the encryption or decryption action - * @param asciiArmored - */ - public void setAsciiArmored( boolean asciiArmored ) { - this.asciiArmored = asciiArmored; - } - - public boolean isIntegrityCheck() { - return this.integrityCheck; - } - - public void setIntegrityCheck( boolean integrityCheck ) { - this.integrityCheck = integrityCheck; - } - - public String getPassphrase() { - return this.passphrase; - } - - public void setPassphrase( String passphrase ) { - this.passphrase = passphrase; - } - - public IMendixObject getPublicKeyFileName() { - return this.publicKeyFileDocument; - } - - public void setPublicKeyFileName( IMendixObject publicKeyFileDocument ) { - this.publicKeyFileDocument = publicKeyFileDocument; - } - - public IMendixObject getSecretKeyFileName() { - return this.secretKeyFileDocument; - } - - public void setSecretKeyFileName( IMendixObject secretKeyFileDocument ) { - this.secretKeyFileDocument = secretKeyFileDocument; - } - - - public void setInputFileDocument( IMendixObject inputFileDocument ) { - this.inputFileDocument = inputFileDocument; - } - - public void setOutputFileDocument( IMendixObject outputFileDocument ) { - this.outputFileDocument = outputFileDocument; - } +package encryption.pgp; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; + +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPSecretKey; + +import com.mendix.core.Core; +import com.mendix.core.CoreException; +import com.mendix.systemwideinterfaces.core.IContext; +import com.mendix.systemwideinterfaces.core.IMendixObject; + +public class PGPFileProcessor { + + private String passphrase; + private IMendixObject publicKeyFileDocument; + private IMendixObject secretKeyFileDocument; + private IMendixObject inputFileDocument; + private IMendixObject outputFileDocument; + private boolean asciiArmored = false; + private boolean integrityCheck = true; + + /** + * Encrypt the InputDocument + * + * This function requires the publicKey, OutputFile and InputFile to be specified + * + * @param context + * @return true or exception + * @throws Exception + */ + public boolean encrypt( IContext context ) throws Exception { + + if ( this.publicKeyFileDocument == null ) + throw new CoreException("Please provide a public key document"); + if ( this.outputFileDocument == null ) + throw new CoreException("Please provide an output document"); + + InputStream publicKeyIn = Core.getFileDocumentContent(context, this.publicKeyFileDocument); + + String tempOutputFile = getNewTempFile("out"); + FileOutputStream out = new FileOutputStream(tempOutputFile); + + + File tmpIn = writeInputDocumentToTempFile(context); + + PGPUtils.encryptFile(out, tmpIn.getAbsolutePath(), PGPUtils.readPublicKey(publicKeyIn), this.isAsciiArmored(), this.isIntegrityCheck()); + out.close(); + publicKeyIn.close(); + tmpIn.delete(); + + storeOutput(context, tempOutputFile); + + return true; + } + + + /** + * Encrypt and sign the InputDocument + * + * This function requires the publicKey, privateKey (for signing), OutputFile and InputFile to be specified + * + * @param context + * @return true or exception + * @throws Exception + */ + public boolean signEncrypt( IContext context ) throws Exception { + + if ( this.publicKeyFileDocument == null ) + throw new CoreException("Please provide a public key document"); + if ( this.secretKeyFileDocument == null ) + throw new CoreException("Please provide a secret key document"); + if ( this.passphrase == null ) + throw new CoreException("Please provide a pass phrase"); + if ( this.outputFileDocument == null ) + throw new CoreException("Please provide an output document"); + + + String tempOutputFile = getNewTempFile("out"); + try { + FileOutputStream out = new FileOutputStream(tempOutputFile); + + InputStream publicKeyIn = Core.getFileDocumentContent(context, this.publicKeyFileDocument); + InputStream secretKeyIn = Core.getFileDocumentContent(context, this.secretKeyFileDocument); + + PGPPublicKey publicKey = PGPUtils.readPublicKey(publicKeyIn); + PGPSecretKey secretKey = PGPUtils.readSecretKey(secretKeyIn); + + File tmpIn = writeInputDocumentToTempFile(context); + + PGPUtils.signEncryptFile( + out, + tmpIn.getAbsolutePath(), + publicKey, + secretKey, + this.getPassphrase(), + this.isAsciiArmored(), + this.isIntegrityCheck()); + + out.close(); + publicKeyIn.close(); + secretKeyIn.close(); + tmpIn.delete(); + + storeOutput(context, tempOutputFile); + } + finally { + (new File(tempOutputFile)).delete(); + } + + return true; + } + + public boolean decrypt( IContext context ) throws Exception { + InputStream in = Core.getFileDocumentContent(context, this.inputFileDocument); + InputStream keyIn = Core.getFileDocumentContent(context, this.secretKeyFileDocument); + + String tempOutputFile = getNewTempFile("out"); + try { + FileOutputStream out = new FileOutputStream(tempOutputFile); + PGPUtils.decryptFile(in, out, keyIn, this.passphrase.toCharArray()); + in.close(); + out.close(); + keyIn.close(); + + storeOutput(context, tempOutputFile); + } + finally { + (new File(tempOutputFile)).delete(); + } + + return true; + } + + + /** + * Generate a new random file name in the Mx Temp folder + * + * @param suffix + * @return full path to a file in deployment/data/tmp/ + */ + public static String getNewTempFile( String suffix ) { + return Core.getConfiguration().getTempPath().getAbsolutePath() + "/" + UUID.randomUUID().toString() + "-" + suffix + ".pgp"; + } + + /** + * Evaluate and store the content of the output file in the output file document (with the same name as input file) + * + * @param context + * @param tempOutputFile + * @throws IOException + */ + private void storeOutput( IContext context, String tempOutputFile ) throws IOException { + FileInputStream in = new FileInputStream(tempOutputFile); + Core.storeFileDocumentContent(context, this.outputFileDocument, (String) this.inputFileDocument.getValue(context, "Name"), in); + in.close(); + } + + private File writeInputDocumentToTempFile( IContext context ) throws IOException + { + File tmpFile = new File(getNewTempFile("in")); + FileOutputStream outStream = new FileOutputStream(tmpFile); + + InputStream inStream = Core.getFileDocumentContent(context, this.inputFileDocument); + + int content; + while( (content = inStream.read()) != -1 ) + { + outStream.write(content); + } + outStream.close(); + inStream.close(); + + return tmpFile; + } + + /** + * Should we use ASCII encoded output for the encryption or decryption action + * @param asciiArmored + */ + public boolean isAsciiArmored() { + return this.asciiArmored; + } + + /** + * Should we use ASCII encoded output for the encryption or decryption action + * @param asciiArmored + */ + public void setAsciiArmored( boolean asciiArmored ) { + this.asciiArmored = asciiArmored; + } + + public boolean isIntegrityCheck() { + return this.integrityCheck; + } + + public void setIntegrityCheck( boolean integrityCheck ) { + this.integrityCheck = integrityCheck; + } + + public String getPassphrase() { + return this.passphrase; + } + + public void setPassphrase( String passphrase ) { + this.passphrase = passphrase; + } + + public IMendixObject getPublicKeyFileName() { + return this.publicKeyFileDocument; + } + + public void setPublicKeyFileName( IMendixObject publicKeyFileDocument ) { + this.publicKeyFileDocument = publicKeyFileDocument; + } + + public IMendixObject getSecretKeyFileName() { + return this.secretKeyFileDocument; + } + + public void setSecretKeyFileName( IMendixObject secretKeyFileDocument ) { + this.secretKeyFileDocument = secretKeyFileDocument; + } + + + public void setInputFileDocument( IMendixObject inputFileDocument ) { + this.inputFileDocument = inputFileDocument; + } + + public void setOutputFileDocument( IMendixObject outputFileDocument ) { + this.outputFileDocument = outputFileDocument; + } } \ No newline at end of file diff --git a/src/EmailModuleWithTemplates/javasource/encryption/pgp/PGPUtils.java b/src/EmailModuleWithTemplates/javasource/encryption/pgp/PGPUtils.java index 1f132e8..21a2451 100644 --- a/src/EmailModuleWithTemplates/javasource/encryption/pgp/PGPUtils.java +++ b/src/EmailModuleWithTemplates/javasource/encryption/pgp/PGPUtils.java @@ -1,518 +1,518 @@ -package encryption.pgp; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.NoSuchProviderException; -import java.security.Provider; -import java.security.SecureRandom; -import java.security.Security; -import java.util.Date; -import java.util.Iterator; - -import org.apache.commons.io.IOUtils; -import org.bouncycastle.bcpg.ArmoredOutputStream; -import org.bouncycastle.bcpg.HashAlgorithmTags; -import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; -import org.bouncycastle.bcpg.sig.KeyFlags; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.openpgp.PGPCompressedData; -import org.bouncycastle.openpgp.PGPCompressedDataGenerator; -import org.bouncycastle.openpgp.PGPEncryptedData; -import org.bouncycastle.openpgp.PGPEncryptedDataGenerator; -import org.bouncycastle.openpgp.PGPEncryptedDataList; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPLiteralData; -import org.bouncycastle.openpgp.PGPLiteralDataGenerator; -import org.bouncycastle.openpgp.PGPObjectFactory; -import org.bouncycastle.openpgp.PGPOnePassSignature; -import org.bouncycastle.openpgp.PGPOnePassSignatureList; -import org.bouncycastle.openpgp.PGPPrivateKey; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.bouncycastle.openpgp.PGPSignature; -import org.bouncycastle.openpgp.PGPSignatureGenerator; -import org.bouncycastle.openpgp.PGPSignatureList; -import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; -import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; -import org.bouncycastle.openpgp.PGPUtil; -import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; -import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder; -import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder; -import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider; -import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder; -import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; -import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory; -import org.bouncycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator; -import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; - -public class PGPUtils { - - private static final int BUFFER_SIZE = 1 << 16; // should always be power of 2 - private static final int KEY_FLAGS = 27; - private static final int[] MASTER_KEY_CERTIFICATION_TYPES = new int[] { - PGPSignature.POSITIVE_CERTIFICATION, - PGPSignature.CASUAL_CERTIFICATION, - PGPSignature.NO_CERTIFICATION, - PGPSignature.DEFAULT_CERTIFICATION - }; - - @SuppressWarnings("unchecked") - public static PGPPublicKey readPublicKey( InputStream in ) - throws IOException, PGPException - { - - PGPPublicKeyRingCollection keyRingCollection = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(in), new BcKeyFingerprintCalculator()); - - // - // we just loop through the collection till we find a key suitable for encryption, in the real - // world you would probably want to be a bit smarter about this. - // - PGPPublicKey publicKey = null; - - // - // iterate through the key rings. - // - Iterator rIt = keyRingCollection.getKeyRings(); - - while( publicKey == null && rIt.hasNext() ) { - PGPPublicKeyRing kRing = rIt.next(); - Iterator kIt = kRing.getPublicKeys(); - while( publicKey == null && kIt.hasNext() ) { - PGPPublicKey key = kIt.next(); - if ( key.isEncryptionKey() ) { - publicKey = key; - } - } - } - - if ( publicKey == null ) { - throw new IllegalArgumentException("Can't find public key in the key ring."); - } - if ( !isForEncryption(publicKey) ) { - throw new IllegalArgumentException("KeyID " + publicKey.getKeyID() + " not flagged for encryption."); - } - - return publicKey; - } - - @SuppressWarnings("unchecked") - public static PGPSecretKey readSecretKey( InputStream in ) - throws IOException, PGPException - { - - PGPSecretKeyRingCollection keyRingCollection = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(in), new BcKeyFingerprintCalculator()); - - // - // We just loop through the collection till we find a key suitable for signing. - // In the real world you would probably want to be a bit smarter about this. - // - PGPSecretKey secretKey = null; - - Iterator rIt = keyRingCollection.getKeyRings(); - while( secretKey == null && rIt.hasNext() ) { - PGPSecretKeyRing keyRing = rIt.next(); - Iterator kIt = keyRing.getSecretKeys(); - while( secretKey == null && kIt.hasNext() ) { - PGPSecretKey key = kIt.next(); - if ( key.isSigningKey() ) { - secretKey = key; - } - } - } - - // Validate secret key - if ( secretKey == null ) { - throw new IllegalArgumentException("Can't find private key in the key ring."); - } - if ( !secretKey.isSigningKey() ) { - throw new IllegalArgumentException("Private key does not allow signing."); - } - if ( secretKey.getPublicKey().isRevoked() ) { - throw new IllegalArgumentException("Private key has been revoked."); - } - if ( !hasKeyFlags(secretKey.getPublicKey(), KeyFlags.SIGN_DATA) ) { - throw new IllegalArgumentException("Key cannot be used for signing."); - } - - return secretKey; - } - - /** - * Load a secret key ring collection from keyIn and find the private key corresponding to - * keyID if it exists. - * - * @param keyIn input stream representing a key ring collection. - * @param keyID keyID we want. - * @param pass passphrase to decrypt secret key with. - * @return - * @throws IOException - * @throws PGPException - * @throws NoSuchProviderException - */ - public static PGPPrivateKey findPrivateKey( InputStream keyIn, long keyID, char[] pass ) - throws IOException, PGPException, NoSuchProviderException - { - PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn), new BcKeyFingerprintCalculator()); - return findPrivateKey(pgpSec.getSecretKey(keyID), pass); - - } - - /** - * Load a secret key and find the private key in it - * - * @param pgpSecKey The secret key - * @param pass passphrase to decrypt secret key with - * @return - * @throws PGPException - */ - public static PGPPrivateKey findPrivateKey( PGPSecretKey pgpSecKey, char[] pass ) - throws PGPException - { - if ( pgpSecKey == null ) - return null; - - PBESecretKeyDecryptor decryptor = new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass); - return pgpSecKey.extractPrivateKey(decryptor); - } - - /** - * decrypt the passed in message stream - */ - @SuppressWarnings("unchecked") - public static void decryptFile( InputStream in, OutputStream out, InputStream keyIn, char[] passwd ) - throws Exception - { - Security.addProvider(new BouncyCastleProvider()); - - in = org.bouncycastle.openpgp.PGPUtil.getDecoderStream(in); - - PGPObjectFactory pgpF = new PGPObjectFactory(in, new BcKeyFingerprintCalculator()); - PGPEncryptedDataList enc; - - Object o = pgpF.nextObject(); - // - // the first object might be a PGP marker packet. - // - if ( o instanceof PGPEncryptedDataList ) { - enc = (PGPEncryptedDataList) o; - } - else { - enc = (PGPEncryptedDataList) pgpF.nextObject(); - } - - // - // find the secret key - // - Iterator it = enc.getEncryptedDataObjects(); - PGPPrivateKey sKey = null; - PGPPublicKeyEncryptedData pbe = null; - - while( sKey == null && it.hasNext() ) { - PGPEncryptedData data = it.next(); - if (data instanceof PGPPublicKeyEncryptedData) { - pbe = (PGPPublicKeyEncryptedData) data; - - sKey = findPrivateKey(keyIn, pbe.getKeyID(), passwd); - } - } - - if ( sKey == null ) { - throw new IllegalArgumentException("Secret key for message not found. (Looking for key:" + pbe.getKeyID() + ")"); - } - - InputStream clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey)); - - PGPObjectFactory plainFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator()); - - Object message = plainFact.nextObject(); - - if ( message instanceof PGPCompressedData ) { - PGPCompressedData cData = (PGPCompressedData) message; - PGPObjectFactory pgpFact = new PGPObjectFactory(cData.getDataStream(), new BcKeyFingerprintCalculator()); - - message = pgpFact.nextObject(); - } - - if ( message instanceof PGPLiteralData ) { - PGPLiteralData ld = (PGPLiteralData) message; - - InputStream unc = ld.getInputStream(); - int ch; - - while( (ch = unc.read()) >= 0 ) { - out.write(ch); - } - } - else if ( message instanceof PGPOnePassSignatureList ) { - throw new PGPException("Encrypted message contains a signed message - not literal data."); - } - else { - throw new PGPException("Message is not a simple encrypted file - type unknown."); - } - - if ( pbe.isIntegrityProtected() ) { - if ( !pbe.verify() ) { - throw new PGPException("Message failed integrity check"); - } - } - } - - public static void encryptFile( - OutputStream out, - String fileName, - PGPPublicKey encKey, - boolean armor, - boolean withIntegrityCheck ) - throws IOException, NoSuchProviderException, PGPException - { - Security.addProvider(new BouncyCastleProvider()); - - if ( armor ) { - out = new ArmoredOutputStream(out); - } - - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP); - - PGPUtil.writeFileToLiteralData( - comData.open(bOut), - PGPLiteralData.BINARY, - new File(fileName)); - - comData.close(); - - BcPGPDataEncryptorBuilder dataEncryptor = new BcPGPDataEncryptorBuilder(PGPEncryptedData.TRIPLE_DES); - dataEncryptor.setWithIntegrityPacket(withIntegrityCheck); - dataEncryptor.setSecureRandom(new SecureRandom()); - - PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(dataEncryptor); - encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(encKey)); - - byte[] bytes = bOut.toByteArray(); - OutputStream cOut = encryptedDataGenerator.open(out, bytes.length); - cOut.write(bytes); - cOut.close(); - - encryptedDataGenerator.close(); - bOut.close(); - - - if( armor ) { - out.close(); - } - } - - @SuppressWarnings("unchecked") - public static void signEncryptFile( - OutputStream out, - String fileName, - PGPPublicKey publicKey, - PGPSecretKey secretKey, - String password, - boolean armor, - boolean withIntegrityCheck ) - throws Exception - { - - // Initialize Bouncy Castle security provider - Provider provider = new BouncyCastleProvider(); - Security.addProvider(provider); - - if ( armor ) { - out = new ArmoredOutputStream(out); - } - - BcPGPDataEncryptorBuilder dataEncryptor = new BcPGPDataEncryptorBuilder(PGPEncryptedData.TRIPLE_DES); - dataEncryptor.setWithIntegrityPacket(withIntegrityCheck); - dataEncryptor.setSecureRandom(new SecureRandom()); - - PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(dataEncryptor); - encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(publicKey)); - - OutputStream encryptedOut = encryptedDataGenerator.open(out, new byte[PGPUtils.BUFFER_SIZE]); - - // Initialize compressed data generator - PGPCompressedDataGenerator compressedDataGenerator = new PGPCompressedDataGenerator(PGPCompressedData.ZIP); - OutputStream compressedOut = compressedDataGenerator.open(encryptedOut, new byte[PGPUtils.BUFFER_SIZE]); - - // Initialize signature generator - PGPPrivateKey privateKey = findPrivateKey(secretKey, password.toCharArray()); - - PGPContentSignerBuilder signerBuilder = new BcPGPContentSignerBuilder(secretKey.getPublicKey().getAlgorithm(), - HashAlgorithmTags.SHA1); - - PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(signerBuilder); - signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey); - - boolean firstTime = true; - Iterator it = secretKey.getPublicKey().getUserIDs(); - while( it.hasNext() && firstTime ) { - PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); - spGen.setSignerUserID(false, it.next()); - signatureGenerator.setHashedSubpackets(spGen.generate()); - // Exit the loop after the first iteration - firstTime = false; - } - signatureGenerator.generateOnePassVersion(false).encode(compressedOut); - - // Initialize literal data generator - PGPLiteralDataGenerator literalDataGenerator = new PGPLiteralDataGenerator(); - OutputStream literalOut = literalDataGenerator.open( - compressedOut, - PGPLiteralData.BINARY, - fileName, - new Date(), - new byte[PGPUtils.BUFFER_SIZE]); - - // Main loop - read the "in" stream, compress, encrypt and write to the "out" stream - FileInputStream in = new FileInputStream(fileName); - byte[] buf = new byte[PGPUtils.BUFFER_SIZE]; - int len; - while( (len = in.read(buf)) > 0 ) { - literalOut.write(buf, 0, len); - signatureGenerator.update(buf, 0, len); - } - - literalOut.close(); - in.close(); - literalDataGenerator.close(); - // Generate the signature, compress, encrypt and write to the "out" stream - signatureGenerator.generate().encode(compressedOut); - compressedDataGenerator.close(); - encryptedDataGenerator.close(); - if ( armor ) { - out.close(); - } - } - - public static boolean verifyFile( - InputStream in, - InputStream keyIn, - String extractContentFile ) - throws Exception - { - in = PGPUtil.getDecoderStream(in); - - PGPObjectFactory pgpFact = new PGPObjectFactory(in, new BcKeyFingerprintCalculator()); - PGPCompressedData c1 = (PGPCompressedData) pgpFact.nextObject(); - - pgpFact = new PGPObjectFactory(c1.getDataStream(), new BcKeyFingerprintCalculator()); - - PGPOnePassSignatureList p1 = (PGPOnePassSignatureList) pgpFact.nextObject(); - - PGPOnePassSignature ops = p1.get(0); - - PGPLiteralData p2 = (PGPLiteralData) pgpFact.nextObject(); - - InputStream dIn = p2.getInputStream(); - - IOUtils.copy(dIn, new FileOutputStream(extractContentFile)); - - int ch; - PGPPublicKeyRingCollection pgpRing = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(keyIn), new BcKeyFingerprintCalculator()); - - PGPPublicKey key = pgpRing.getPublicKey(ops.getKeyID()); - - FileOutputStream out = new FileOutputStream(p2.getFileName()); - - ops.init(new BcPGPContentVerifierBuilderProvider(), key); - - while( (ch = dIn.read()) >= 0 ) - { - ops.update((byte) ch); - out.write(ch); - } - - out.close(); - - PGPSignatureList p3 = (PGPSignatureList) pgpFact.nextObject(); - return ops.verify(p3.get(0)); - } - - /** - * From LockBox Lobs PGP Encryption tools. - * http://www.lockboxlabs.org/content/downloads - * - * I didn't think it was worth having to import a 4meg lib for three methods - * - * @param key - * @return - */ - public static boolean isForEncryption( PGPPublicKey key ) - { - if ( key.getAlgorithm() == PublicKeyAlgorithmTags.RSA_SIGN - || key.getAlgorithm() == PublicKeyAlgorithmTags.DSA - || key.getAlgorithm() == PublicKeyAlgorithmTags.EC - || key.getAlgorithm() == PublicKeyAlgorithmTags.ECDSA ) - { - return false; - } - - return hasKeyFlags(key, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE); - } - - /** - * From LockBox Lobs PGP Encryption tools. - * http://www.lockboxlabs.org/content/downloads - * - * I didn't think it was worth having to import a 4meg lib for three methods - * - * @param key - * @return - */ - @SuppressWarnings("unchecked") - private static boolean hasKeyFlags( PGPPublicKey encKey, int keyUsage ) { - if ( encKey.isMasterKey() ) { - for( int i = 0; i != PGPUtils.MASTER_KEY_CERTIFICATION_TYPES.length; i++ ) { - for( Iterator eIt = encKey.getSignaturesOfType(PGPUtils.MASTER_KEY_CERTIFICATION_TYPES[i]); eIt.hasNext(); ) { - PGPSignature sig = eIt.next(); - if ( !isMatchingUsage(sig, keyUsage) ) { - return false; - } - } - } - } - else { - for( Iterator eIt = encKey.getSignaturesOfType(PGPSignature.SUBKEY_BINDING); eIt.hasNext(); ) { - PGPSignature sig = eIt.next(); - if ( !isMatchingUsage(sig, keyUsage) ) { - return false; - } - } - } - return true; - } - - /** - * From LockBox Lobs PGP Encryption tools. - * http://www.lockboxlabs.org/content/downloads - * - * I didn't think it was worth having to import a 4meg lib for three methods - * - * @param key - * @return - */ - private static boolean isMatchingUsage( PGPSignature sig, int keyUsage ) { - if ( sig.hasSubpackets() ) { - PGPSignatureSubpacketVector sv = sig.getHashedSubPackets(); - if ( sv.hasSubpacket(PGPUtils.KEY_FLAGS) ) { - if ( (sv.getKeyFlags() == 0 && keyUsage == 0) ) { - return false; - } - } - } - return true; - } - +package encryption.pgp; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Date; +import java.util.Iterator; + +import org.apache.commons.io.IOUtils; +import org.bouncycastle.bcpg.ArmoredOutputStream; +import org.bouncycastle.bcpg.HashAlgorithmTags; +import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; +import org.bouncycastle.bcpg.sig.KeyFlags; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openpgp.PGPCompressedData; +import org.bouncycastle.openpgp.PGPCompressedDataGenerator; +import org.bouncycastle.openpgp.PGPEncryptedData; +import org.bouncycastle.openpgp.PGPEncryptedDataGenerator; +import org.bouncycastle.openpgp.PGPEncryptedDataList; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPLiteralData; +import org.bouncycastle.openpgp.PGPLiteralDataGenerator; +import org.bouncycastle.openpgp.PGPObjectFactory; +import org.bouncycastle.openpgp.PGPOnePassSignature; +import org.bouncycastle.openpgp.PGPOnePassSignatureList; +import org.bouncycastle.openpgp.PGPPrivateKey; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData; +import org.bouncycastle.openpgp.PGPPublicKeyRing; +import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; +import org.bouncycastle.openpgp.PGPSecretKey; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureGenerator; +import org.bouncycastle.openpgp.PGPSignatureList; +import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; +import org.bouncycastle.openpgp.PGPUtil; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; +import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder; +import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder; +import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider; +import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder; +import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; +import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory; +import org.bouncycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator; +import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; + +public class PGPUtils { + + private static final int BUFFER_SIZE = 1 << 16; // should always be power of 2 + private static final int KEY_FLAGS = 27; + private static final int[] MASTER_KEY_CERTIFICATION_TYPES = new int[] { + PGPSignature.POSITIVE_CERTIFICATION, + PGPSignature.CASUAL_CERTIFICATION, + PGPSignature.NO_CERTIFICATION, + PGPSignature.DEFAULT_CERTIFICATION + }; + + @SuppressWarnings("unchecked") + public static PGPPublicKey readPublicKey( InputStream in ) + throws IOException, PGPException + { + + PGPPublicKeyRingCollection keyRingCollection = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(in), new BcKeyFingerprintCalculator()); + + // + // we just loop through the collection till we find a key suitable for encryption, in the real + // world you would probably want to be a bit smarter about this. + // + PGPPublicKey publicKey = null; + + // + // iterate through the key rings. + // + Iterator rIt = keyRingCollection.getKeyRings(); + + while( publicKey == null && rIt.hasNext() ) { + PGPPublicKeyRing kRing = rIt.next(); + Iterator kIt = kRing.getPublicKeys(); + while( publicKey == null && kIt.hasNext() ) { + PGPPublicKey key = kIt.next(); + if ( key.isEncryptionKey() ) { + publicKey = key; + } + } + } + + if ( publicKey == null ) { + throw new IllegalArgumentException("Can't find public key in the key ring."); + } + if ( !isForEncryption(publicKey) ) { + throw new IllegalArgumentException("KeyID " + publicKey.getKeyID() + " not flagged for encryption."); + } + + return publicKey; + } + + @SuppressWarnings("unchecked") + public static PGPSecretKey readSecretKey( InputStream in ) + throws IOException, PGPException + { + + PGPSecretKeyRingCollection keyRingCollection = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(in), new BcKeyFingerprintCalculator()); + + // + // We just loop through the collection till we find a key suitable for signing. + // In the real world you would probably want to be a bit smarter about this. + // + PGPSecretKey secretKey = null; + + Iterator rIt = keyRingCollection.getKeyRings(); + while( secretKey == null && rIt.hasNext() ) { + PGPSecretKeyRing keyRing = rIt.next(); + Iterator kIt = keyRing.getSecretKeys(); + while( secretKey == null && kIt.hasNext() ) { + PGPSecretKey key = kIt.next(); + if ( key.isSigningKey() ) { + secretKey = key; + } + } + } + + // Validate secret key + if ( secretKey == null ) { + throw new IllegalArgumentException("Can't find private key in the key ring."); + } + if ( !secretKey.isSigningKey() ) { + throw new IllegalArgumentException("Private key does not allow signing."); + } + if ( secretKey.getPublicKey().hasRevocation() ) { + throw new IllegalArgumentException("Private key has been revoked."); + } + if ( !hasKeyFlags(secretKey.getPublicKey(), KeyFlags.SIGN_DATA) ) { + throw new IllegalArgumentException("Key cannot be used for signing."); + } + + return secretKey; + } + + /** + * Load a secret key ring collection from keyIn and find the private key corresponding to + * keyID if it exists. + * + * @param keyIn input stream representing a key ring collection. + * @param keyID keyID we want. + * @param pass passphrase to decrypt secret key with. + * @return + * @throws IOException + * @throws PGPException + * @throws NoSuchProviderException + */ + public static PGPPrivateKey findPrivateKey( InputStream keyIn, long keyID, char[] pass ) + throws IOException, PGPException, NoSuchProviderException + { + PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn), new BcKeyFingerprintCalculator()); + return findPrivateKey(pgpSec.getSecretKey(keyID), pass); + + } + + /** + * Load a secret key and find the private key in it + * + * @param pgpSecKey The secret key + * @param pass passphrase to decrypt secret key with + * @return + * @throws PGPException + */ + public static PGPPrivateKey findPrivateKey( PGPSecretKey pgpSecKey, char[] pass ) + throws PGPException + { + if ( pgpSecKey == null ) + return null; + + PBESecretKeyDecryptor decryptor = new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass); + return pgpSecKey.extractPrivateKey(decryptor); + } + + /** + * decrypt the passed in message stream + */ + @SuppressWarnings("unchecked") + public static void decryptFile( InputStream in, OutputStream out, InputStream keyIn, char[] passwd ) + throws Exception + { + Security.addProvider(new BouncyCastleProvider()); + + in = org.bouncycastle.openpgp.PGPUtil.getDecoderStream(in); + + PGPObjectFactory pgpF = new PGPObjectFactory(in, new BcKeyFingerprintCalculator()); + PGPEncryptedDataList enc; + + Object o = pgpF.nextObject(); + // + // the first object might be a PGP marker packet. + // + if ( o instanceof PGPEncryptedDataList ) { + enc = (PGPEncryptedDataList) o; + } + else { + enc = (PGPEncryptedDataList) pgpF.nextObject(); + } + + // + // find the secret key + // + Iterator it = enc.getEncryptedDataObjects(); + PGPPrivateKey sKey = null; + PGPPublicKeyEncryptedData pbe = null; + + while( sKey == null && it.hasNext() ) { + PGPEncryptedData data = it.next(); + if (data instanceof PGPPublicKeyEncryptedData) { + pbe = (PGPPublicKeyEncryptedData) data; + + sKey = findPrivateKey(keyIn, pbe.getKeyID(), passwd); + } + } + + if ( sKey == null ) { + throw new IllegalArgumentException("Secret key for message not found. (Looking for key:" + pbe.getKeyID() + ")"); + } + + InputStream clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey)); + + PGPObjectFactory plainFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator()); + + Object message = plainFact.nextObject(); + + if ( message instanceof PGPCompressedData ) { + PGPCompressedData cData = (PGPCompressedData) message; + PGPObjectFactory pgpFact = new PGPObjectFactory(cData.getDataStream(), new BcKeyFingerprintCalculator()); + + message = pgpFact.nextObject(); + } + + if ( message instanceof PGPLiteralData ) { + PGPLiteralData ld = (PGPLiteralData) message; + + InputStream unc = ld.getInputStream(); + int ch; + + while( (ch = unc.read()) >= 0 ) { + out.write(ch); + } + } + else if ( message instanceof PGPOnePassSignatureList ) { + throw new PGPException("Encrypted message contains a signed message - not literal data."); + } + else { + throw new PGPException("Message is not a simple encrypted file - type unknown."); + } + + if ( pbe.isIntegrityProtected() ) { + if ( !pbe.verify() ) { + throw new PGPException("Message failed integrity check"); + } + } + } + + public static void encryptFile( + OutputStream out, + String fileName, + PGPPublicKey encKey, + boolean armor, + boolean withIntegrityCheck ) + throws IOException, NoSuchProviderException, PGPException + { + Security.addProvider(new BouncyCastleProvider()); + + if ( armor ) { + out = new ArmoredOutputStream(out); + } + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP); + + PGPUtil.writeFileToLiteralData( + comData.open(bOut), + PGPLiteralData.BINARY, + new File(fileName)); + + comData.close(); + + BcPGPDataEncryptorBuilder dataEncryptor = new BcPGPDataEncryptorBuilder(PGPEncryptedData.TRIPLE_DES); + dataEncryptor.setWithIntegrityPacket(withIntegrityCheck); + dataEncryptor.setSecureRandom(new SecureRandom()); + + PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(dataEncryptor); + encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(encKey)); + + byte[] bytes = bOut.toByteArray(); + OutputStream cOut = encryptedDataGenerator.open(out, bytes.length); + cOut.write(bytes); + cOut.close(); + + encryptedDataGenerator.close(); + bOut.close(); + + + if( armor ) { + out.close(); + } + } + + @SuppressWarnings("unchecked") + public static void signEncryptFile( + OutputStream out, + String fileName, + PGPPublicKey publicKey, + PGPSecretKey secretKey, + String password, + boolean armor, + boolean withIntegrityCheck ) + throws Exception + { + + // Initialize Bouncy Castle security provider + Provider provider = new BouncyCastleProvider(); + Security.addProvider(provider); + + if ( armor ) { + out = new ArmoredOutputStream(out); + } + + BcPGPDataEncryptorBuilder dataEncryptor = new BcPGPDataEncryptorBuilder(PGPEncryptedData.TRIPLE_DES); + dataEncryptor.setWithIntegrityPacket(withIntegrityCheck); + dataEncryptor.setSecureRandom(new SecureRandom()); + + PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(dataEncryptor); + encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(publicKey)); + + OutputStream encryptedOut = encryptedDataGenerator.open(out, new byte[PGPUtils.BUFFER_SIZE]); + + // Initialize compressed data generator + PGPCompressedDataGenerator compressedDataGenerator = new PGPCompressedDataGenerator(PGPCompressedData.ZIP); + OutputStream compressedOut = compressedDataGenerator.open(encryptedOut, new byte[PGPUtils.BUFFER_SIZE]); + + // Initialize signature generator + PGPPrivateKey privateKey = findPrivateKey(secretKey, password.toCharArray()); + + PGPContentSignerBuilder signerBuilder = new BcPGPContentSignerBuilder(secretKey.getPublicKey().getAlgorithm(), + HashAlgorithmTags.SHA1); + + PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(signerBuilder); + signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey); + + boolean firstTime = true; + Iterator it = secretKey.getPublicKey().getUserIDs(); + while( it.hasNext() && firstTime ) { + PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); + spGen.addSignerUserID(false, it.next()); + signatureGenerator.setHashedSubpackets(spGen.generate()); + // Exit the loop after the first iteration + firstTime = false; + } + signatureGenerator.generateOnePassVersion(false).encode(compressedOut); + + // Initialize literal data generator + PGPLiteralDataGenerator literalDataGenerator = new PGPLiteralDataGenerator(); + OutputStream literalOut = literalDataGenerator.open( + compressedOut, + PGPLiteralData.BINARY, + fileName, + new Date(), + new byte[PGPUtils.BUFFER_SIZE]); + + // Main loop - read the "in" stream, compress, encrypt and write to the "out" stream + FileInputStream in = new FileInputStream(fileName); + byte[] buf = new byte[PGPUtils.BUFFER_SIZE]; + int len; + while( (len = in.read(buf)) > 0 ) { + literalOut.write(buf, 0, len); + signatureGenerator.update(buf, 0, len); + } + + literalOut.close(); + in.close(); + literalDataGenerator.close(); + // Generate the signature, compress, encrypt and write to the "out" stream + signatureGenerator.generate().encode(compressedOut); + compressedDataGenerator.close(); + encryptedDataGenerator.close(); + if ( armor ) { + out.close(); + } + } + + public static boolean verifyFile( + InputStream in, + InputStream keyIn, + String extractContentFile ) + throws Exception + { + in = PGPUtil.getDecoderStream(in); + + PGPObjectFactory pgpFact = new PGPObjectFactory(in, new BcKeyFingerprintCalculator()); + PGPCompressedData c1 = (PGPCompressedData) pgpFact.nextObject(); + + pgpFact = new PGPObjectFactory(c1.getDataStream(), new BcKeyFingerprintCalculator()); + + PGPOnePassSignatureList p1 = (PGPOnePassSignatureList) pgpFact.nextObject(); + + PGPOnePassSignature ops = p1.get(0); + + PGPLiteralData p2 = (PGPLiteralData) pgpFact.nextObject(); + + InputStream dIn = p2.getInputStream(); + + IOUtils.copy(dIn, new FileOutputStream(extractContentFile)); + + int ch; + PGPPublicKeyRingCollection pgpRing = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(keyIn), new BcKeyFingerprintCalculator()); + + PGPPublicKey key = pgpRing.getPublicKey(ops.getKeyID()); + + FileOutputStream out = new FileOutputStream(p2.getFileName()); + + ops.init(new BcPGPContentVerifierBuilderProvider(), key); + + while( (ch = dIn.read()) >= 0 ) + { + ops.update((byte) ch); + out.write(ch); + } + + out.close(); + + PGPSignatureList p3 = (PGPSignatureList) pgpFact.nextObject(); + return ops.verify(p3.get(0)); + } + + /** + * From LockBox Lobs PGP Encryption tools. + * http://www.lockboxlabs.org/content/downloads + * + * I didn't think it was worth having to import a 4meg lib for three methods + * + * @param key + * @return + */ + public static boolean isForEncryption( PGPPublicKey key ) + { + if ( key.getAlgorithm() == PublicKeyAlgorithmTags.RSA_SIGN + || key.getAlgorithm() == PublicKeyAlgorithmTags.DSA + || key.getAlgorithm() == PublicKeyAlgorithmTags.ECDH + || key.getAlgorithm() == PublicKeyAlgorithmTags.ECDSA ) + { + return false; + } + + return hasKeyFlags(key, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE); + } + + /** + * From LockBox Lobs PGP Encryption tools. + * http://www.lockboxlabs.org/content/downloads + * + * I didn't think it was worth having to import a 4meg lib for three methods + * + * @param key + * @return + */ + @SuppressWarnings("unchecked") + private static boolean hasKeyFlags( PGPPublicKey encKey, int keyUsage ) { + if ( encKey.isMasterKey() ) { + for( int i = 0; i != PGPUtils.MASTER_KEY_CERTIFICATION_TYPES.length; i++ ) { + for( Iterator eIt = encKey.getSignaturesOfType(PGPUtils.MASTER_KEY_CERTIFICATION_TYPES[i]); eIt.hasNext(); ) { + PGPSignature sig = eIt.next(); + if ( !isMatchingUsage(sig, keyUsage) ) { + return false; + } + } + } + } + else { + for( Iterator eIt = encKey.getSignaturesOfType(PGPSignature.SUBKEY_BINDING); eIt.hasNext(); ) { + PGPSignature sig = eIt.next(); + if ( !isMatchingUsage(sig, keyUsage) ) { + return false; + } + } + } + return true; + } + + /** + * From LockBox Lobs PGP Encryption tools. + * http://www.lockboxlabs.org/content/downloads + * + * I didn't think it was worth having to import a 4meg lib for three methods + * + * @param key + * @return + */ + private static boolean isMatchingUsage( PGPSignature sig, int keyUsage ) { + if ( sig.hasSubpackets() ) { + PGPSignatureSubpacketVector sv = sig.getHashedSubPackets(); + if ( sv.hasSubpacket(PGPUtils.KEY_FLAGS) ) { + if ( (sv.getKeyFlags() == 0 && keyUsage == 0) ) { + return false; + } + } + } + return true; + } + } \ No newline at end of file diff --git a/src/EmailModuleWithTemplates/javasource/system/UserActionsRegistrar.java b/src/EmailModuleWithTemplates/javasource/system/UserActionsRegistrar.java index ac5e80d..1745f06 100644 --- a/src/EmailModuleWithTemplates/javasource/system/UserActionsRegistrar.java +++ b/src/EmailModuleWithTemplates/javasource/system/UserActionsRegistrar.java @@ -7,11 +7,11 @@ public class UserActionsRegistrar public void registerActions(IActionRegistrator registrator) { registrator.bundleComponentLoaded(); - registrator.registerUserAction(emailtemplate.actions.ConvertHTMLBodyToPlainText.class); - registrator.registerUserAction(emailtemplate.actions.CopyAttachmentContent.class); - registrator.registerUserAction(emailtemplate.actions.ReplaceCustomToken.class); - registrator.registerUserAction(emailtemplate.actions.ReplaceEmailTemplateTokens.class); - registrator.registerUserAction(emailtemplate.actions.SendEmail.class); + registrator.registerUserAction(emailmodulewithtemplates.actions.ConvertHTMLBodyToPlainText.class); + registrator.registerUserAction(emailmodulewithtemplates.actions.CopyAttachmentContent.class); + registrator.registerUserAction(emailmodulewithtemplates.actions.ReplaceCustomToken.class); + registrator.registerUserAction(emailmodulewithtemplates.actions.ReplaceEmailTemplateTokens.class); + registrator.registerUserAction(emailmodulewithtemplates.actions.SendEmail.class); registrator.registerUserAction(encryption.actions.DecryptString.class); registrator.registerUserAction(encryption.actions.EncryptString.class); registrator.registerUserAction(encryption.actions.GeneratePGPKeyRing.class);