From 55522347f1f84fb5c6c66c095931d262c8992212 Mon Sep 17 00:00:00 2001 From: zhuyinlong <1158756092@qq.com> Date: Thu, 2 Nov 2023 19:02:32 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=81=E7=A8=8B=E8=AE=BE=E8=AE=A1=E7=95=8C?= =?UTF-8?q?=E9=9D=A2=E9=BB=91=E8=89=B2=E8=83=8C=E6=99=AF=E5=9B=BE=E6=A0=87?= =?UTF-8?q?=E8=89=B2=E7=A0=81=E9=97=AE=E9=A2=98=EF=BC=9B=E9=83=A8=E5=88=86?= =?UTF-8?q?=E9=AB=98=E5=8D=B1=E7=89=88=E6=9C=ACjar=E5=8C=85=E6=9B=B4?= =?UTF-8?q?=E6=8D=A2=EF=BC=9BSM2,SM3,SM4=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../designer/editor-app/stencil-controller.js | 2 +- .../icons/activity/list/type.decision.png | Bin 299 -> 182 bytes .../bpmn2.0/icons/activity/list/type.http.png | Bin 1267 -> 424 bytes .../bpmn2.0/icons/endevent/cancel.png | Bin 910 -> 582 bytes .../bpmn2.0/icons/endevent/terminate.png | Bin 3166 -> 600 bytes .../bpmn2.0/icons/startevent/conditional.png | Bin 3134 -> 488 bytes .../bpmn2.0/icons/startevent/signal.png | Bin 3201 -> 508 bytes common/pom.xml | 16 + .../common/utils/sm/SM2EngineExtend.java | 282 ++++++++++++++++++ .../com/ruoyi/common/utils/sm/SM2Utils.java | 177 +++++++++++ .../com/ruoyi/common/utils/sm/SM2crypto.java | 9 + .../com/ruoyi/common/utils/sm/SM3Utils.java | 221 ++++++++++++++ .../com/ruoyi/common/utils/sm/SM3crypto.java | 71 +++++ .../com/ruoyi/common/utils/sm/SM4Utils.java | 178 +++++++++++ pom.xml | 17 +- 15 files changed, 970 insertions(+), 3 deletions(-) create mode 100644 common/src/main/java/com/ruoyi/common/utils/sm/SM2EngineExtend.java create mode 100644 common/src/main/java/com/ruoyi/common/utils/sm/SM2Utils.java create mode 100644 common/src/main/java/com/ruoyi/common/utils/sm/SM2crypto.java create mode 100644 common/src/main/java/com/ruoyi/common/utils/sm/SM3Utils.java create mode 100644 common/src/main/java/com/ruoyi/common/utils/sm/SM3crypto.java create mode 100644 common/src/main/java/com/ruoyi/common/utils/sm/SM4Utils.java diff --git a/admin/src/main/resources/static/designer/editor-app/stencil-controller.js b/admin/src/main/resources/static/designer/editor-app/stencil-controller.js index 5a1fdf9..bf16ded 100644 --- a/admin/src/main/resources/static/designer/editor-app/stencil-controller.js +++ b/admin/src/main/resources/static/designer/editor-app/stencil-controller.js @@ -85,7 +85,7 @@ angular.module('flowableModeler') } // Check all received items - debugger + //debugger for (var stencilIndex = 0; stencilIndex < data.stencils.length; stencilIndex++) { // Check if the root group is the 'diagram' group. If so, this item should not be shown. diff --git a/admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.decision.png b/admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.decision.png index 0351fee8a4a147e3e54c9ddbfcd9dddc25fe693d..fef769c81b55a9ea5f78cb654f65246d09e9e3d4 100644 GIT binary patch delta 154 zcmV;L0A>HH0=5B=B!2;OQb$4nuFf3k0001RNklV#K_2)OR8q5`dN$-5fT5%)C|@}H3J$~tXR>26dwB-7#NVnKyvjA3=EDSe?!%Q z#b7R=*Z{JF0qz1c6F|;wBu0#CUKkAnB10To%ut@0D9z3Q>l6EVr)-reC;$Ke07*qo IM6N<$f~Y|{NdN!< delta 272 zcmV+r0q_2{0jmO#B!32COGiWi{{a60|De66lK=n!;7LS5R5*>r(=kc|VH5=5PtnFg zh*rTymUx16Vqs_P0c>NgWNjxNz|umniWd+TD^sapVPixK--DM_E?YRT?9TAN*_nU$ zrzh6pzK0WR{Bdr98$74*fbWjitR{HHBi@6L@q(w|``FDPY=7ebJBmS5B3@xq_$0JM z6EjPltHA)nq76f9R@c@FoA@jd7x)Oi6)($*xpt|-s3f??wD4(YiBVQq*Au-f)J;4^ z8_yTG!)5R@9N|28Bfd&CXp6xc=7rBgYpozF-22^+ESt0(&jf1VO9>8$-fw?hn}I5JW9){0%|G#^Q>&_hf?yn%rFy-10H=?b{hv;Gah< z>Tfoi%cId~gPEOPuQ!+r;JWUT<2WrL#36u^y_A`EwAL>(0e?ia3!nwS1#k`E!~%>l zE57fCnSffYb|j^|Vdhn9Qc4NW^ZHQ~ZELNIb~XiQG#Z644A-QTMIl5#DI;cXYpqYG z07P^TV1Gui!EiV%2SM=l2S7x}0B*C)LWoahE-R&;W8L@(l}e?M&*vY65Sv*5X0B?j z{ok4~!1KHkGkRYE2%;!@l2W$gx?*vXIWa^#tk>&X#uyvmxO01Qxm>B+?Y>TKm|A1C zT0M|b-o*xEOu_g4kGTOvbOzx3$MC3>+DpnObps+A09Xfbp_IBz3pW*DbC6QLcRHQ7 f%xV|?jg$IsOs#zpNmLrD00000NkvXXu0mjf8-=Tl literal 1267 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0WW zg+Z8+Vb&Z81_tJ3nIRD+5xzcF$@#f@i7EL>sd^Q;1whpd3^o;3KxS@gNuokUZcbjY zRfVk*ScMgk4HDK@QUEI{$+lIB@C{IK&M!(;Fx4~BGf=YQQczH^DN0GR3UYCSY6tRc zl`=|73as??%gf94%8m8%i_-NCEiEne4UF`SjC6r2bc-wVN)jt{^NN)rhQQ2mNi9w; z$}A|!%+FH*nVXoDUs__Tqy(}E4xsMLEr45;R}A$P(0}?Bi3R$GdItK~G?iqgA)JSz z3nYV6TWUon4s9SAh&FIwK-_2p3{flJ{FKbJN|(fvR68RBLsMM?V_jpz5JL+q17j;g za~pj$H3%PqbvqZOCYIzEh2-bw*ac)(q~_#;xC+L4#t@yz@<>`izOeEy%1i|YFDMZ0 z3~lr=#L(3{=jRp_r4|>1)SE)pBa5M{4@xc0&nX2NADWk0VrK-^f+mcvD-t1ZXAaYY zEQqcl0-FY8K_m^JXs`l@Q-n)qZfYLbFNS6|`dB54=o-U3d7J^$R?dD?) z6mdQNSY1VG;tLTgUMa!OL-H$FT2~xle^KJ}I#|R@v|eH2i;g~lj}g{}CuP&rj0LSD zji1lke17h4iPOIVCkp%x++%sdiOtNQ*+J_;)Pc(hJ~AG%G3o)I1+J{v!59|9FJHRS z_rSeZjXxO6BMwgwO4)Kp>&rv7XPe$u_}Q`XsY>J?G^^ZuzT#8gx$g;53nEYF?=}_p z%!-eT5B{PY?6SNRln4WvVW_^4+wgGn%2?42r7v@UHx3vIVCg!0Kr9^jsO4v diff --git a/admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/cancel.png b/admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/cancel.png index a4302bf88bfe9f8471042ef3e37694970de9872e..af0982def20df00e095b5292d495c94d2ed1b052 100644 GIT binary patch delta 557 zcmV+|0@D4C2gU@DB!2;OQb$4nuFf3k00062NklcC_#yScrwD zP!!aNik0NBOCc$ah;X~J+*Ou>g;vJKT%}#W&Jud&N*#-{6R#of~=~u0H$l3s>WHCJqhwQpb_~yfNRYBteJ&#?goIH zHHe5#dG9}!fFw!o6VY`5e^j+?t^HjT#e(<#Zm_3mx@e4fE+YE@ye=aX-46B|@P&wu ztLi;#?PC#H1%Gf_Rj(RjLJ1E6Y(-HNi%1OM4uB12o~1NR&#LOjih9m_zv-M?s+^it zEHU%IITt3g5ey=7kb1q|jEHOn1v58$(u53{ImqaAI{R9!)~_mHI{>Cc_1da!gB!32COGiWi{{a60|De66lK=n!32;bRa{vGi!vFvd!vV){sAK>D z00(qQO+^Ra2M`V&6;-M#C;$Kh8%ab#R5;6JQ%^`EcNl#$^K%?#oIi#n%o=sVz@$dO z!a!K{kgRjiw&rGQicof4dJu0df=)@HyNidlHA-Qt2Zd#O=zp<2h`scnxVaSEL%alg zXo@YUD~?8_iId6nPz~ySr}sU+@9@3vJph0p2mpZf^>tX5MFU`FXJ^&L#l`Oy78V`@ zKwn=U$z(DV07#OAMllT2z`Cvn`}_M}c6D|60DJ&70CiCm{X`;hWLehu^(-L-06<+6 zEX#HhLN;r)ntvLNMmGgP_<4AEm_0f=^0v0N+N#y+ql1Hk5YO{3%H{Gj03;HL|CdeE zG#G~YQ&E&ZY}+0m9UbLxr)Fkm-b*HvD@{#JryR%S9LFI5Krb&Z%jf6kzsa)Pn#p87 z&gb*d-QC?h$8qY_E~RPO!;OuNA5~TTrMYzW!Xyrz90zuEXy8W;Wvt+JOF_1?(QeDEdSln(P5F!&d!elfk2(2s1pEi9OvtB zIP5r%vwv`LanVju6nLI5Mk0|%dwY8Y0HA65AHy&r&CSi-wClPTcLl3dDz|#y_u)9s zO^Wh757lb*5^Zg5xvLXG0O*#MmS=>J%PSrBIgUF9;By@JhUfVQ01%JIpNgVb3Wvi< zCY??Pc6N3?DV0j}(9qCnu~>XnE|(caQSyqSjDG>xt=H=xdY;#z>$*BOH@CmNz5QjS zQh96J_A9KctjLC8{1pfUPN$}(-cP5~U&Z6`9Z8ZJZ`5`Dp=p}GPfkvLplO<|s;Y0A z<~NOlZW<|@&5n$R4Ual(#gpQdB@5u%Wk@^8|mrkDY~xv{m94&cX)W{ z<#6-)sONc8rBaCqg7CvFE8h%LEEWrB+IftFfj0TaB%RQFwvgpK@>#* z!0PJiG0*dl3xxu)ZTsHR($Z2cm;3ze?2KX<=3X!u{OLN*wOS1T@E_i89`_W>qMHB! N002ovPDHLkV1jHHt7iZJ diff --git a/admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/terminate.png b/admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/terminate.png index 0d6f780d46a0b0aa61e30164b4b73ac57e7ec407..4165a1f2c30109f52b2459c3374cc823f2f79e4d 100644 GIT binary patch delta 575 zcmV-F0>J&=7}x}mB!2;OQb$4nuFf3k0006KNklS&bi-wLm2YJaeP))j{qnEC=gN0Ie+&)Ns`uJI}Ik{IKHc@ z7l(m~=%sV+VUi@Tdi8YxV~nmj_=|`ZRdp4>aRB4JnyOZkBzfZFKEN3B5x^k;KLMO$ z=I6$k@q9ktZZ?~%#+b_hW&rF?4-)OS)_zL?Q4}?Z=n{axsyY<}!KkX<0dO>HzU`cQ zL_}i%-etKf)_>ZYDZm)>1;9a7oy+BN_eJFU5Dk`!#p0=UyFClw8h~YHK1Q`#?SP1^ zWYm&#ZZ8o%-bBO;s`?qgqOXg{j&%TLCS%O?Y{CYHsxFL-jMO`w&Yx`Hln0E7$Zwy> z<#PMF-EO=E;1&^i^-~=H?CEK+>;+TRS?An?Fbux}*nc&!!b%v16%naq1Ad6eL<)%G z_`Is#^Y8u|)oOLpId=oViEP!UK@eOOk!=9Hi9CFUnHwpfTrQ6m3WZMqCbFq#nE8eG zfj1B{FJ<RTdu#>{U9`#1cJ!+=}m{sCJ-;g(Pzt%m>r N002ovPDHLkV1f_o58(g+ delta 3161 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 Y2mYACq!(8HV*mgE07*qoM6N<$f|{}6*8l(j delta 3196 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 + + + org.springframework.boot + spring-boot-starter-web + + org.apache.shiro @@ -105,6 +111,16 @@ hutool-all + + + org.jasig.cas.client + cas-client-core + + + org.apache.tomcat.embed + tomcat-embed-core + + \ No newline at end of file diff --git a/common/src/main/java/com/ruoyi/common/utils/sm/SM2EngineExtend.java b/common/src/main/java/com/ruoyi/common/utils/sm/SM2EngineExtend.java new file mode 100644 index 0000000..be4916e --- /dev/null +++ b/common/src/main/java/com/ruoyi/common/utils/sm/SM2EngineExtend.java @@ -0,0 +1,282 @@ +package com.ruoyi.common.utils.sm; + +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.digests.SM3Digest; +import org.bouncycastle.crypto.params.*; +import org.bouncycastle.math.ec.ECConstants; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.BigIntegers; + +import java.math.BigInteger; +import java.security.SecureRandom; + +public class SM2EngineExtend { + private final Digest digest; + + /**是否为加密模式*/ + private boolean forEncryption; + private ECKeyParameters ecKey; + private ECDomainParameters ecParams; + private int curveLength; + private SecureRandom random; + /**密文排序方式*/ + private int cipherMode; + + /**BC库默认排序方式-C1C2C3*/ + public static int CIPHERMODE_BC = 0; + /**国密标准排序方式-C1C3C2*/ + public static int CIPHERMODE_NORM = 1; + + public SM2EngineExtend() { + this(new SM3Digest()); + } + + public SM2EngineExtend(Digest digest) { + this.digest = digest; + } + + /** + * 设置密文排序方式 + * @param cipherMode + */ + public void setCipherMode(int cipherMode){ + this.cipherMode = cipherMode; + } + + /** + * 默认初始化方法,使用国密排序标准 + * @param forEncryption - 是否以加密模式初始化 + * @param param - 曲线参数 + */ + public void init(boolean forEncryption, CipherParameters param) { + init(forEncryption, CIPHERMODE_NORM, param); + } + + /** + * 默认初始化方法,使用国密排序标准 + * @param forEncryption 是否以加密模式初始化 + * @param cipherMode 加密数据排列模式:1-标准排序;0-BC默认排序 + * @param param 曲线参数 + */ + public void init(boolean forEncryption, int cipherMode, CipherParameters param) { + this.forEncryption = forEncryption; + this.cipherMode = cipherMode; + if (forEncryption) { + ParametersWithRandom rParam = (ParametersWithRandom) param; + + ecKey = (ECKeyParameters) rParam.getParameters(); + ecParams = ecKey.getParameters(); + + ECPoint s = ((ECPublicKeyParameters) ecKey).getQ().multiply(ecParams.getH()); + if (s.isInfinity()) { + throw new IllegalArgumentException("invalid key: [h]Q at infinity"); + } + + random = rParam.getRandom(); + } else { + ecKey = (ECKeyParameters) param; + ecParams = ecKey.getParameters(); + } + + curveLength = (ecParams.getCurve().getFieldSize() + 7) / 8; + } + + /** + * 加密或解密输入数据 + * @param in + * @param inOff + * @param inLen + * @return + * @throws InvalidCipherTextException + */ + public byte[] processBlock( byte[] in, int inOff, int inLen) throws InvalidCipherTextException { + if (forEncryption) { + // 加密 + return encrypt(in, inOff, inLen); + } else { + return decrypt(in, inOff, inLen); + } + } + + /** + * 加密实现,根据cipherMode输出指定排列的结果,默认按标准方式排列 + * @param in + * @param inOff + * @param inLen + * @return + * @throws InvalidCipherTextException + */ + private byte[] encrypt(byte[] in, int inOff, int inLen) + throws InvalidCipherTextException { + byte[] c2 = new byte[inLen]; + + System.arraycopy(in, inOff, c2, 0, c2.length); + + byte[] c1; + ECPoint kPB; + do { + BigInteger k = nextK(); + + ECPoint c1P = ecParams.getG().multiply(k).normalize(); + + c1 = c1P.getEncoded(false); + + kPB = ((ECPublicKeyParameters) ecKey).getQ().multiply(k).normalize(); + + kdf(digest, kPB, c2); + } + while (notEncrypted(c2, in, inOff)); + + byte[] c3 = new byte[digest.getDigestSize()]; + + addFieldElement(digest, kPB.getAffineXCoord()); + digest.update(in, inOff, inLen); + addFieldElement(digest, kPB.getAffineYCoord()); + + digest.doFinal(c3, 0); + if (cipherMode == CIPHERMODE_NORM){ + return Arrays.concatenate(c1, c3, c2); + } + return Arrays.concatenate(c1, c2, c3); + } + + /** + * 解密实现,默认按标准排列方式解密,解密时解出c2部分原文并校验c3部分 + * @param in + * @param inOff + * @param inLen + * @return + * @throws InvalidCipherTextException + */ + private byte[] decrypt(byte[] in, int inOff, int inLen) + throws InvalidCipherTextException { + byte[] c1 = new byte[curveLength * 2 + 1]; + + System.arraycopy(in, inOff, c1, 0, c1.length); + + ECPoint c1P = ecParams.getCurve().decodePoint(c1); + + ECPoint s = c1P.multiply(ecParams.getH()); + if (s.isInfinity()) { + throw new InvalidCipherTextException("[h]C1 at infinity"); + } + + c1P = c1P.multiply(((ECPrivateKeyParameters) ecKey).getD()).normalize(); + + byte[] c2 = new byte[inLen - c1.length - digest.getDigestSize()]; + if (cipherMode == CIPHERMODE_BC) { + System.arraycopy(in, inOff + c1.length, c2, 0, c2.length); + }else{ + // C1 C3 C2 + System.arraycopy(in, inOff + c1.length + digest.getDigestSize(), c2, 0, c2.length); + } + + kdf(digest, c1P, c2); + + byte[] c3 = new byte[digest.getDigestSize()]; + + addFieldElement(digest, c1P.getAffineXCoord()); + digest.update(c2, 0, c2.length); + addFieldElement(digest, c1P.getAffineYCoord()); + + digest.doFinal(c3, 0); + + int check = 0; + // 检查密文输入值C3部分和由摘要生成的C3是否一致 + if (cipherMode == CIPHERMODE_BC) { + for (int i = 0; i != c3.length; i++) { + check |= c3[i] ^ in[c1.length + c2.length + i]; + } + }else{ + for (int i = 0; i != c3.length; i++) { + check |= c3[i] ^ in[c1.length + i]; + } + } + + clearBlock(c1); + clearBlock(c3); + + if (check != 0) { + clearBlock(c2); + throw new InvalidCipherTextException("invalid cipher text"); + } + + return c2; + } + + private boolean notEncrypted(byte[] encData, byte[] in, int inOff) { + for (int i = 0; i != encData.length; i++) { + if (encData[i] != in[inOff]) { + return false; + } + } + + return true; + } + + private void kdf(Digest digest, ECPoint c1, byte[] encData) { + int ct = 1; + int v = digest.getDigestSize(); + + byte[] buf = new byte[digest.getDigestSize()]; + int off = 0; + + for (int i = 1; i <= ((encData.length + v - 1) / v); i++) { + addFieldElement(digest, c1.getAffineXCoord()); + addFieldElement(digest, c1.getAffineYCoord()); + digest.update((byte) (ct >> 24)); + digest.update((byte) (ct >> 16)); + digest.update((byte) (ct >> 8)); + digest.update((byte) ct); + + digest.doFinal(buf, 0); + + if (off + buf.length < encData.length) { + xor(encData, buf, off, buf.length); + } else { + xor(encData, buf, off, encData.length - off); + } + + off += buf.length; + ct++; + } + } + + private void xor(byte[] data, byte[] kdfOut, int dOff, int dRemaining) { + for (int i = 0; i != dRemaining; i++) { + data[dOff + i] ^= kdfOut[i]; + } + } + + private BigInteger nextK() { + int qBitLength = ecParams.getN().bitLength(); + + BigInteger k; + do { + k = new BigInteger(qBitLength, random); + } + while (k.equals(ECConstants.ZERO) || k.compareTo(ecParams.getN()) >= 0); + + return k; + } + + private void addFieldElement(Digest digest, ECFieldElement v) { + byte[] p = BigIntegers.asUnsignedByteArray(curveLength, v.toBigInteger()); + + digest.update(p, 0, p.length); + } + + /** + * clear possible sensitive data + */ + private void clearBlock( + byte[] block) { + for (int i = 0; i != block.length; i++) { + block[i] = 0; + } + } +} diff --git a/common/src/main/java/com/ruoyi/common/utils/sm/SM2Utils.java b/common/src/main/java/com/ruoyi/common/utils/sm/SM2Utils.java new file mode 100644 index 0000000..b2d844c --- /dev/null +++ b/common/src/main/java/com/ruoyi/common/utils/sm/SM2Utils.java @@ -0,0 +1,177 @@ +package com.ruoyi.common.utils.sm; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import org.apache.tomcat.util.codec.binary.Base64; +import org.bouncycastle.asn1.gm.GMNamedCurves; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import org.bouncycastle.crypto.params.*; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.encoders.Hex; + +import java.math.BigInteger; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +/** + * SM2 加解密攻击类 + * + * 注意:为了兼容前端js库(原文转base64后加密),后端使用加密方法请先转Base64字符, 否则解密会失败! + * @author ZYL + * + */ +@Slf4j +public class SM2Utils { + public static void main(String[] args) { +// SM2KeyPair sM2KeyPair = getSm2Keys(false); +// System.out.println(sM2KeyPair.getPubKey()); +// System.out.println(sM2KeyPair.getPriKey()); + + + String a = Base64.encodeBase64String("123".getBytes()); + System.out.println("文本="+a); + String aa = SM2Utils.encrypt(SM2crypto.pubKey, a, SM2EngineExtend.CIPHERMODE_BC); + System.out.println("密文="+aa); + String aaa = SM2Utils.decrypt(SM2crypto.priKey, aa, SM2EngineExtend.CIPHERMODE_BC); + System.out.println("解密后="+aaa); + } + + /** + * SM2加密算法 + * @param publicKey 公钥 + * @param data 待加密的数据 + * @return 密文,BC库产生的密文带由04标识符,与非BC库对接时需要去掉开头的04 + */ + public static String encrypt(String publicKey, String data){ + // 按国密排序标准加密 + return encrypt(publicKey, data, SM2EngineExtend.CIPHERMODE_NORM); + } + + /** + * SM2加密算法 + * @param publicKey 公钥 + * @param data 待加密的数据 + * @param cipherMode 密文排列方式0-C1C2C3;1-C1C3C2; + * @return 密文,BC库产生的密文带由04标识符,与非BC库对接时需要去掉开头的04 + */ + public static String encrypt(String publicKey, String data, int cipherMode){ + // 获取一条SM2曲线参数 + X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1"); + // 构造ECC算法参数,曲线方程、椭圆曲线G点、大整数N + ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); + //提取公钥点 + ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(publicKey)); + // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04 + ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters); + + SM2EngineExtend sm2Engine = new SM2EngineExtend(); + // 设置sm2为加密模式 + sm2Engine.init(true, cipherMode, new ParametersWithRandom(publicKeyParameters, new SecureRandom())); + + byte[] arrayOfBytes = null; + try { + byte[] in = data.getBytes(); + arrayOfBytes = sm2Engine.processBlock(in, 0, in.length); + } catch (Exception e) { + log.error("SM2加密时出现异常:{}", e.getMessage(), e); + } + return Hex.toHexString(arrayOfBytes); + } + + /** + * 获取sm2密钥对 + * BC库使用的公钥=64个字节+1个字节(04标志位),BC库使用的私钥=32个字节 + * SM2秘钥的组成部分有 私钥D 、公钥X 、 公钥Y , 他们都可以用长度为64的16进制的HEX串表示, + *
SM2公钥并不是直接由X+Y表示 , 而是额外添加了一个头,当启用压缩时:公钥=有头+公钥X ,即省略了公钥Y的部分 + * @param compressed 是否压缩公钥(加密解密都使用BC库才能使用压缩) + * @return + */ + public static SM2KeyPair getSm2Keys(boolean compressed){ + //获取一条SM2曲线参数 + X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1"); + //构造domain参数 + ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); + //1.创建密钥生成器 + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + //2.初始化生成器,带上随机数 + try { + keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG"))); + } catch (NoSuchAlgorithmException e) { + log.error("生成公私钥对时出现异常:", e); + } + //3.生成密钥对 + AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair(); + ECPublicKeyParameters publicKeyParameters = (ECPublicKeyParameters)asymmetricCipherKeyPair.getPublic(); + ECPoint ecPoint = publicKeyParameters.getQ(); + // 把公钥放入map中,默认压缩公钥 + // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04 + String publicKey = Hex.toHexString(ecPoint.getEncoded(compressed)); + ECPrivateKeyParameters privateKeyParameters = (ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate(); + BigInteger intPrivateKey = privateKeyParameters.getD(); + // 把私钥放入map中 + String privateKey = intPrivateKey.toString(16); + return new SM2KeyPair(publicKey, privateKey); + } + + /** + * SM2解密算法 + * @param privateKey 私钥 + * @param cipherData 密文数据 + * @return + */ + public static String decrypt(String privateKey, String cipherData) { + // // 按国密排序标准解密 + return decrypt(privateKey, cipherData, SM2EngineExtend.CIPHERMODE_NORM); + } + + /** + * SM2解密算法 + * @param privateKey 私钥 + * @param cipherData 密文数据 + * @param cipherMode 密文排列方式0-C1C2C3;1-C1C3C2; + * @return + */ + public static String decrypt(String privateKey, String cipherData, int cipherMode) { + // 使用BC库加解密时密文以04开头,传入的密文前面没有04则补上 + if (!cipherData.startsWith("04")){ + cipherData = "04" + cipherData; + } + byte[] cipherDataByte = Hex.decode(cipherData); + + //获取一条SM2曲线参数 + X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1"); + //构造domain参数 + ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); + + BigInteger privateKeyD = new BigInteger(privateKey, 16); + ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters); + + SM2EngineExtend sm2Engine = new SM2EngineExtend(); + // 设置sm2为解密模式 + sm2Engine.init(false, cipherMode, privateKeyParameters); + + String result = ""; + try { + //processBlock得到Base64格式,记得解码 + byte[] arrayOfBytes = Base64.decodeBase64(sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length)); + return new String(arrayOfBytes); + } catch (Exception e) { + log.error("SM2解密时出现异常:{}", e.getMessage(), e); + } + return result; + + } + + @Data + @AllArgsConstructor + @NoArgsConstructor + static class SM2KeyPair{ + private String pubKey; + private String priKey; + } +} diff --git a/common/src/main/java/com/ruoyi/common/utils/sm/SM2crypto.java b/common/src/main/java/com/ruoyi/common/utils/sm/SM2crypto.java new file mode 100644 index 0000000..63301d4 --- /dev/null +++ b/common/src/main/java/com/ruoyi/common/utils/sm/SM2crypto.java @@ -0,0 +1,9 @@ +package com.ruoyi.common.utils.sm; + +import org.springframework.stereotype.Component; + +@Component +public class SM2crypto { + public static String pubKey = "04ebe49444321237d1d2415427a78b73ab1661e11a511221ac635546f647e44347332857b37f59705c6b95dbd9fcf0188f830946ac156b64c0e30623c3a0500342"; + public static String priKey = "7a70604a24c35fbdd099a84307bff1196eb9955280cc98cadcd18442ba3e3a83"; +} diff --git a/common/src/main/java/com/ruoyi/common/utils/sm/SM3Utils.java b/common/src/main/java/com/ruoyi/common/utils/sm/SM3Utils.java new file mode 100644 index 0000000..8d0ad01 --- /dev/null +++ b/common/src/main/java/com/ruoyi/common/utils/sm/SM3Utils.java @@ -0,0 +1,221 @@ +package com.ruoyi.common.utils.sm; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; + +import lombok.extern.slf4j.Slf4j; + +/** + * 国密SM3,消息摘要(MD5) + */ +@Slf4j +public class SM3Utils { + private static char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + public static final byte[] IV = {0x73, (byte) 0x80, 0x16, 0x6f, 0x49, 0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24, 0x42, + (byte) 0xd7, (byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30, (byte) 0xbc, (byte) 0x16, 0x31, + 0x38, (byte) 0xaa, (byte) 0xe3, (byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte) 0xfb, 0x0e, 0x4e}; + private static final Integer TJ_15 = Integer.valueOf("79cc4519", 16); + private static final Integer TJ_63 = Integer.valueOf("7a879d8a", 16); + private static final byte[] FirstPadding = {(byte) 0x80}; + private static final byte[] ZeroPadding = {(byte) 0x00}; + + private static int T(int j) { + if (j >= 0 && j <= 15) { + return TJ_15.intValue(); + } else if (j >= 16 && j <= 63) { + return TJ_63.intValue(); + } else { + throw new RuntimeException("data invalid"); + } + } + + private static Integer FF(Integer x, Integer y, Integer z, int j) { + if (j >= 0 && j <= 15) { + return Integer.valueOf(x.intValue() ^ y.intValue() ^ z.intValue()); + } else if (j >= 16 && j <= 63) { + return Integer.valueOf( + (x.intValue() & y.intValue()) | (x.intValue() & z.intValue()) | (y.intValue() & z.intValue())); + } else { + throw new RuntimeException("data invalid"); + } + } + + private static Integer GG(Integer x, Integer y, Integer z, int j) { + if (j >= 0 && j <= 15) { + return Integer.valueOf(x.intValue() ^ y.intValue() ^ z.intValue()); + } else if (j >= 16 && j <= 63) { + return Integer.valueOf((x.intValue() & y.intValue()) | (~x.intValue() & z.intValue())); + } else { + throw new RuntimeException("data invalid"); + } + } + + private static Integer P0(Integer x) { + return Integer + .valueOf(x.intValue() ^ Integer.rotateLeft(x.intValue(), 9) ^ Integer.rotateLeft(x.intValue(), 17)); + } + + private static Integer P1(Integer x) { + return Integer.valueOf(x.intValue() ^ Integer.rotateLeft(x.intValue(), 15) ^ Integer.rotateLeft(x.intValue(), 23)); + } + + private static byte[] padding(byte[] source) throws IOException { + if (source.length >= 0x2000000000000000L) { + throw new RuntimeException("src data invalid."); + } + long l = source.length * 8; + long k = 448 - (l + 1) % 512; + if (k < 0) { + k = k + 512; + } + if (log.isDebugEnabled()) { + log.debug("k = " + k); + } + try (ByteArrayOutputStream baos = new ByteArrayOutputStream();) { + baos.write(source); + baos.write(FirstPadding); + long i = k - 7; + while (i > 0) { + baos.write(ZeroPadding); + i -= 8; + } + baos.write(long2bytes(l)); + if (log.isDebugEnabled()) { + log.debug("paded size = " + baos.size()); + } + return baos.toByteArray(); + } + } + + private static byte[] long2bytes(long l) { + byte[] bytes = new byte[8]; + for (int i = 0; i < 8; i++) { + bytes[i] = (byte) (l >>> ((7 - i) * 8)); + } + return bytes; + } + + public static String encodeSM3(String source) throws IOException { + byte[] b = encodeSM3(source.getBytes()); + return byteToHexString(b); + } + + public static byte[] encodeSM3(byte[] source) throws IOException { + byte[] m1 = padding(source); + int n = m1.length / (512 / 8); + if (log.isDebugEnabled()) { + log.debug("n = " + n); + } + byte[] b; + byte[] vi = IV.clone(); + byte[] vi1 = null; + for (int i = 0; i < n; i++) { + b = Arrays.copyOfRange(m1, i * 64, (i + 1) * 64); + vi1 = CF(vi, b); + vi = vi1; + } + return vi1; + } + + private static byte[] CF(byte[] vi, byte[] bi) throws IOException { + int a, b, c, d, e, f, g, h; + a = toInteger(vi, 0); + b = toInteger(vi, 1); + c = toInteger(vi, 2); + d = toInteger(vi, 3); + e = toInteger(vi, 4); + f = toInteger(vi, 5); + g = toInteger(vi, 6); + h = toInteger(vi, 7); + + int[] w = new int[68]; + int[] w1 = new int[64]; + for (int i = 0; i < 16; i++) { + w[i] = toInteger(bi, i); + } + for (int j = 16; j < 68; j++) { + w[j] = P1(w[j - 16] ^ w[j - 9] ^ Integer.rotateLeft(w[j - 3], 15)) ^ Integer.rotateLeft(w[j - 13], 7) + ^ w[j - 6]; + } + for (int j = 0; j < 64; j++) { + w1[j] = w[j] ^ w[j + 4]; + } + int ss1, ss2, tt1, tt2; + for (int j = 0; j < 64; j++) { + ss1 = Integer.rotateLeft(Integer.rotateLeft(a, 12) + e + Integer.rotateLeft(T(j), j), 7); + ss2 = ss1 ^ Integer.rotateLeft(a, 12); + tt1 = FF(a, b, c, j) + d + ss2 + w1[j]; + tt2 = GG(e, f, g, j) + h + ss1 + w[j]; + d = c; + c = Integer.rotateLeft(b, 9); + b = a; + a = tt1; + h = g; + g = Integer.rotateLeft(f, 19); + f = e; + e = P0(tt2); + } + byte[] v = toByteArray(a, b, c, d, e, f, g, h); + for (int i = 0; i < v.length; i++) { + v[i] = (byte) (v[i] ^ vi[i]); + } + return v; + } + + private static int toInteger(byte[] source, int index) { + StringBuilder valueStr = new StringBuilder(""); + for (int i = 0; i < 4; i++) { + valueStr.append(chars[(byte) ((source[index * 4 + i] & 0xF0) >> 4)]); + valueStr.append(chars[(byte) (source[index * 4 + i] & 0x0F)]); + } + return Long.valueOf(valueStr.toString(), 16).intValue(); + + } + + private static byte[] toByteArray(int a, int b, int c, int d, int e, int f, int g, int h) throws IOException { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(32);) { + baos.write(toByteArray(a)); + baos.write(toByteArray(b)); + baos.write(toByteArray(c)); + baos.write(toByteArray(d)); + baos.write(toByteArray(e)); + baos.write(toByteArray(f)); + baos.write(toByteArray(g)); + baos.write(toByteArray(h)); + return baos.toByteArray(); + } + } + + private static byte[] toByteArray(int i) { + byte[] byteArray = new byte[4]; + byteArray[0] = (byte) (i >>> 24); + byteArray[1] = (byte) ((i & 0xFFFFFF) >>> 16); + byteArray[2] = (byte) ((i & 0xFFFF) >>> 8); + byteArray[3] = (byte) (i & 0xFF); + return byteArray; + } + + private static String byteToHexString(byte[] bytes) + { + StringBuilder resultHexString = new StringBuilder(); + String tempStr; + for (byte b: bytes) { + //这里需要对b与0xff做位与运算, + //若b为负数,强制转换将高位位扩展,导致错误, + //故需要高位清零 + tempStr = Integer.toHexString(b & 0xff); + //若转换后的十六进制数字只有一位, + //则在前补"0" + if (tempStr.length() == 1) { + resultHexString.append(0).append(tempStr); + } else { + resultHexString.append(tempStr); + } + } + return resultHexString.toString(); + } + + private SM3Utils() { + } +} diff --git a/common/src/main/java/com/ruoyi/common/utils/sm/SM3crypto.java b/common/src/main/java/com/ruoyi/common/utils/sm/SM3crypto.java new file mode 100644 index 0000000..728a6ac --- /dev/null +++ b/common/src/main/java/com/ruoyi/common/utils/sm/SM3crypto.java @@ -0,0 +1,71 @@ +package com.ruoyi.common.utils.sm; + +import java.io.IOException; +import java.security.SecureRandom; + +import org.apache.tomcat.util.codec.binary.Base64; +import org.bouncycastle.crypto.digests.SM3Digest; + +/** + * SM3加密 + */ +public class SM3crypto { + public static String getSaltStr() { + return Base64.encodeBase64String(getSalt()); + } + public static byte[] getSalt() { + /* + * 随机生成128位的随机数 + */ + SecureRandom random = new SecureRandom(); + byte bytes1[] = new byte[16]; + random.nextBytes(bytes1); + return bytes1; + } + + public static String pwdSaltedHashValueStr(String salt, String passwdString) { + return Base64.encodeBase64String(pwdSaltedHashValue(Base64.decodeBase64(salt), passwdString)); + } + public static String pwdSaltedHashValueStr(byte[] salt, String passwdString) { + return Base64.encodeBase64String(pwdSaltedHashValue(salt, passwdString)); + } + public static byte[] pwdSaltedHashValue(byte[] bytes1, String passwdString) { + // sm3加密密码 + try { + passwdString = SM3Utils.encodeSM3(passwdString); + } catch (IOException e) { + e.printStackTrace(); + } + + /* + * 加盐:即随机数和口令组合 + */ + byte passwdbyte[] = arraycat(bytes1, passwdString.getBytes()); + // SM3计算 + SM3Digest mdDigest = new SM3Digest(); + mdDigest.update(passwdbyte, 0, passwdbyte.length); + byte[] result = new byte[mdDigest.getDigestSize()]; + mdDigest.doFinal(result, 0); + return result; + } + + /* + * 拼接buf1和buf2数组 + */ + public static byte[] arraycat(byte[] buf1, byte[] buf2) { + byte[] bufret = null; + int len1 = 0; + int len2 = 0; + if (buf1 != null) + len1 = buf1.length; + if (buf2 != null) + len2 = buf2.length; + if (len1 + len2 > 0) + bufret = new byte[len1 + len2]; + if (len1 > 0) + System.arraycopy(buf1, 0, bufret, 0, len1); + if (len2 > 0) + System.arraycopy(buf2, 0, bufret, len1, len2); + return bufret; + } +} diff --git a/common/src/main/java/com/ruoyi/common/utils/sm/SM4Utils.java b/common/src/main/java/com/ruoyi/common/utils/sm/SM4Utils.java new file mode 100644 index 0000000..2b70e26 --- /dev/null +++ b/common/src/main/java/com/ruoyi/common/utils/sm/SM4Utils.java @@ -0,0 +1,178 @@ +package com.ruoyi.common.utils.sm; + +import java.security.Key; +import java.security.Security; +import java.util.Arrays; +import java.util.Random; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; + +public class SM4Utils { + static { + Security.addProvider(new BouncyCastleProvider()); + } + + public static final String[] POOL = new String[]{"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}; + private static final String ENCODING = "UTF-8"; + public static final String ALGORITHM_NAME = "SM4"; + + // 加密算法/分组加密模式/分组填充方式 + // PKCS5Padding-以8个字节为一组进行分组加密 + // 定义分组加密模式使用:PKCS5Padding + public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding"; + + public static void main(String[] args) { + try { + System.out.println("开始测试SM4加密解密===================="); + String json = "18511921736"; + System.out.println("加密前:" + json); + //自定义的32位16进制秘钥 + String key = SM4Utils.generateKeyStr(); + //sm4加密 + String cipher = SM4Utils.encryptEcb(key, json); + System.out.println("加密后:" + cipher); + //校验加密前后是否为同一数据 + System.out.println("校验:" + SM4Utils.verifyEcb(key, cipher, json)); + //解密 + json = SM4Utils.decryptEcb(key, cipher); + System.out.println("解密后:" + json); + System.out.println("结束==================="); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 生成字符串 + * @return 生成的32位长度的16进制字符串 + */ + public static String generateKeyStr(){ + StringBuilder sb = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < 32; i++) { + sb.append(POOL[random.nextInt(POOL.length)]); + } + return sb.toString(); + } + + /** + * sm4加密 + * + * @param hexKey 16进制密钥(忽略大小写) + * @param paramStr 待加密字符串 + * @return 返回16进制的加密字符串 + * @throws Exception + * @explain 加密模式:ECB 密文长度不固定,会随着被加密字符串长度的变化而变化 + */ + public static String encryptEcb(String hexKey, String paramStr) throws Exception { + String cipherText = ""; + // 16进制字符串-->byte[] + byte[] keyData = ByteUtils.fromHexString(hexKey); + // String-->byte[] + byte[] srcData = paramStr.getBytes(ENCODING); + // 加密后的数组 + byte[] cipherArray = encrypt_Ecb_Padding(keyData, srcData); + // byte[]-->hexString + cipherText = ByteUtils.toHexString(cipherArray); + return cipherText; + } + + /** + * 加密模式之Ecb + * + * @param key + * @param data + * @return + * @throws Exception + */ + public static byte[] encrypt_Ecb_Padding(byte[] key, byte[] data) throws Exception { + Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key);//声称Ecb暗号,通过第二个参数判断加密还是解密 + return cipher.doFinal(data); + } + + /** + * 生成ECB暗号 + * + * @param algorithmName 算法名称 + * @param mode 模式 + * @param key + * @return + * @throws Exception + * @explain ECB模式(电子密码本模式:Electronic codebook) + */ + private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception { + Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME); + Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME); + cipher.init(mode, sm4Key); + return cipher; + } + + //解密**************************************** + + /** + * sm4解密 + * + * @param hexKey 16进制密钥 + * @param cipherText 16进制的加密字符串(忽略大小写) + * @return 解密后的字符串 + * @throws Exception + * @explain 解密模式:采用ECB + */ + public static String decryptEcb(String hexKey, String cipherText) throws Exception { + // 用于接收解密后的字符串 + String decryptStr = ""; + // hexString-->byte[] + byte[] keyData = ByteUtils.fromHexString(hexKey); + // hexString-->byte[] + byte[] cipherData = ByteUtils.fromHexString(cipherText); + // 解密 + byte[] srcData = decrypt_Ecb_Padding(keyData, cipherData); + // byte[]-->String + decryptStr = new String(srcData, ENCODING); + return decryptStr; + } + + /** + * 解密 + * + * @param key + * @param cipherText + * @return + * @throws Exception + * @explain + */ + public static byte[] decrypt_Ecb_Padding(byte[] key, byte[] cipherText) throws Exception { + Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key);//生成Ecb暗号,通过第二个参数判断加密还是解密 + return cipher.doFinal(cipherText); + } + + /** + * 校验加密前后的字符串是否为同一数据 + * + * @param hexKey 16进制密钥(忽略大小写) + * @param cipherText 16进制加密后的字符串 + * @param paramStr 加密前的字符串 + * @return 是否为同一数据 + * @throws Exception + * @explain + */ + public static boolean verifyEcb(String hexKey, String cipherText, String paramStr) throws Exception { + // 用于接收校验结果 + boolean flag = false; + // hexString-->byte[] + byte[] keyData = ByteUtils.fromHexString(hexKey); + // 将16进制字符串转换成数组 + byte[] cipherData = ByteUtils.fromHexString(cipherText); + // 解密 + byte[] decryptData = decrypt_Ecb_Padding(keyData, cipherData); + // 将原字符串转换成byte[] + byte[] srcData = paramStr.getBytes(ENCODING); + // 判断2个数组是否一致 + flag = Arrays.equals(decryptData, srcData); + return flag; + } +} diff --git a/pom.xml b/pom.xml index 121158a..5a56252 100644 --- a/pom.xml +++ b/pom.xml @@ -26,12 +26,13 @@ UTF-8 1.8 3.1.1 - 1.8.0 + 1.12.0 2.1.0 1.2.16 1.21 2.3.2 3.0.0 + 2.7.12 2.2.2 1.4.1 1.2.79 @@ -81,10 +82,15 @@ org.springframework.boot spring-boot-dependencies - 2.7.12 + ${springboot.version} pom import + + org.springframework.boot + spring-boot-starter-web + ${springboot.version} + @@ -236,6 +242,13 @@ hutool-all 5.8.17 + + + + org.jasig.cas.client + cas-client-core + 3.6.1 +