From daf85caf9e5198f0bc4bb29d852a9b3774e39f5c Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 28 Sep 2019 02:09:31 +0800 Subject: [PATCH] fid Idcard Code --- CHANGELOG.md | 1 + README.md | 19 +- .../main/java/cn/hutool/core/io/FileUtil.java | 59 +--- .../java/cn/hutool/core/util/IdcardUtil.java | 252 +++++++++--------- .../cn/hutool/core/util/IdcardUtilTest.java | 7 + .../main/java/cn/hutool/crypto/SmUtil.java | 47 ++-- .../asymmetric/AbstractAsymmetricCrypto.java | 113 ++++---- .../cn/hutool/crypto/digest/Digester.java | 4 +- .../java/cn/hutool/crypto/digest/HMac.java | 4 +- .../hutool/crypto/digest/HmacAlgorithm.java | 2 +- .../java/cn/hutool/crypto/digest/MD5.java | 1 + .../java/cn/hutool/crypto/digest/SM3.java | 63 +++++ .../java/cn/hutool/crypto/symmetric/AES.java | 25 +- .../java/cn/hutool/crypto/symmetric/DES.java | 25 +- .../cn/hutool/crypto/symmetric/DESede.java | 25 +- .../java/cn/hutool/crypto/symmetric/RC4.java | 11 +- .../java/cn/hutool/crypto/symmetric/SM4.java | 166 ++++++++++++ .../crypto/symmetric/SymmetricCrypto.java | 29 +- .../java/cn/hutool/crypto/test/SmTest.java | 42 ++- .../json/test/bean/report/EnvSettingInfo.java | 2 +- 20 files changed, 546 insertions(+), 351 deletions(-) create mode 100644 hutool-crypto/src/main/java/cn/hutool/crypto/digest/SM3.java create mode 100644 hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/SM4.java diff --git a/CHANGELOG.md b/CHANGELOG.md index e26626e94..903d4fc5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * 【core】 新增Convert.toMap方法(issue#I12ISI@Gitee) * 【aop 】 增加返回值获取支持,优化逻辑和接口(pr#561@Github) * 【aop 】 改进HtmlUtil.removeHtmlAttr(issue#556@Github) +* 【crypto】 增加SM3和SM4类 ### Bug修复 * 【extra】 修复Mail中sslEnable无效问题(pr#74@Gitee) diff --git a/README.md b/README.md index 2b946cbd9..3552a17a7 100644 --- a/README.md +++ b/README.md @@ -6,33 +6,34 @@

- + - + - + - + - + + - + - gitee star + gitee star - github star + github star - netlify + netlify

diff --git a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java index 339e6c4e7..998b8d13b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java @@ -1,35 +1,20 @@ package cn.hutool.core.io; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.RandomAccessFile; -import java.io.Reader; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.file.FileReader; +import cn.hutool.core.io.file.*; +import cn.hutool.core.io.file.FileWriter; +import cn.hutool.core.io.file.FileReader.ReaderHandler; +import cn.hutool.core.io.resource.ResourceUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.*; + +import java.io.*; import java.net.URI; import java.net.URL; import java.net.URLConnection; import java.nio.charset.Charset; -import java.nio.file.CopyOption; -import java.nio.file.DirectoryStream; -import java.nio.file.FileVisitOption; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.LinkOption; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.StandardCopyOption; +import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.text.DecimalFormat; import java.util.*; @@ -38,26 +23,6 @@ import java.util.regex.Pattern; import java.util.zip.CRC32; import java.util.zip.Checksum; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.io.file.FileCopier; -import cn.hutool.core.io.file.FileMode; -import cn.hutool.core.io.file.FileReader; -import cn.hutool.core.io.file.FileReader.ReaderHandler; -import cn.hutool.core.io.file.FileWriter; -import cn.hutool.core.io.file.LineSeparator; -import cn.hutool.core.io.file.Tailer; -import cn.hutool.core.io.resource.ResourceUtil; -import cn.hutool.core.lang.Assert; -import cn.hutool.core.lang.Console; -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.CharUtil; -import cn.hutool.core.util.CharsetUtil; -import cn.hutool.core.util.ClassUtil; -import cn.hutool.core.util.ReUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.core.util.URLUtil; -import cn.hutool.core.util.ZipUtil; - /** * 文件工具类 * @@ -1583,7 +1548,7 @@ public class FileUtil { // 去除file:前缀 pathToUse = StrUtil.removePrefixIgnoreCase(pathToUse, URLUtil.FILE_URL_PREFIX); // 统一使用斜杠 - pathToUse = pathToUse.replaceAll("[/\\\\]{1,}", StrUtil.SLASH).trim(); + pathToUse = pathToUse.replaceAll("[/\\\\]{2,}", StrUtil.SLASH).trim(); //兼容Windows下的共享目录路径(原始路径如果以\\开头,则保留这种路径) if(path.startsWith("\\\\")){ pathToUse = "\\" + pathToUse; diff --git a/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java index a1376ffd0..133a39baf 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java @@ -1,41 +1,53 @@ package cn.hutool.core.util; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Validator; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + /** * 身份证相关工具类
* see https://www.oschina.net/code/snippet_1611_2881 - * + * *

* 本工具并没有对行政区划代码做校验,如有需求,请参阅(2018年10月): * http://www.mca.gov.cn/article/sj/xzqh/2018/201804-12/20181011221630.html *

- * + * * @author Looly * @since 3.0.4 */ public class IdcardUtil { - /** 中国公民身份证号码最小长度。 */ + /** + * 中国公民身份证号码最小长度。 + */ private static final int CHINA_ID_MIN_LENGTH = 15; - /** 中国公民身份证号码最大长度。 */ + /** + * 中国公民身份证号码最大长度。 + */ private static final int CHINA_ID_MAX_LENGTH = 18; - /** 每位加权因子 */ - private static final int power[] = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 }; - /** 省市代码表 */ - private static Map cityCodes = new HashMap(); - /** 台湾身份首字母对应数字 */ - private static Map twFirstCode = new HashMap(); - /** 香港身份首字母对应数字 */ - private static Map hkFirstCode = new HashMap(); + /** + * 每位加权因子 + */ + private static final int[] power = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}; + /** + * 省市代码表 + */ + private static Map cityCodes = new HashMap<>(); + /** + * 台湾身份首字母对应数字 + */ + private static Map twFirstCode = new HashMap<>(); + /** + * 香港身份首字母对应数字 + */ + private static Map hkFirstCode = new HashMap<>(); static { cityCodes.put("11", "北京"); @@ -116,7 +128,7 @@ public class IdcardUtil { /** * 将15位身份证号码转换为18位 - * + * * @param idCard 15位身份编码 * @return 18位身份编码 */ @@ -135,7 +147,7 @@ public class IdcardUtil { // 2000年之后不存在15位身份证号,此处用于修复此问题的判断 sYear -= 100; } - idCard18 = StrUtil.builder().append(idCard.substring(0, 6)).append(sYear).append(idCard.substring(8)); + idCard18 = StrUtil.builder().append(idCard, 0, 6).append(sYear).append(idCard.substring(8)); // 获取校验位 char sVal = getCheckCode18(idCard18.toString()); idCard18.append(sVal); @@ -147,7 +159,7 @@ public class IdcardUtil { /** * 是否有效身份证号 - * + * * @param idCard 身份证号,支持18位、15位和港澳台的10位 * @return 是否有效 */ @@ -155,25 +167,20 @@ public class IdcardUtil { idCard = idCard.trim(); int length = idCard.length(); switch (length) { - case 18:// 18位身份证 - return isvalidCard18(idCard); - case 15:// 15位身份证 - return isvalidCard15(idCard); - case 10: {// 10位身份证,港澳台地区 - String[] cardval = isValidCard10(idCard); - if (null != cardval && cardval[2].equals("true")) { - return true; - } else { - return false; + case 18:// 18位身份证 + return isvalidCard18(idCard); + case 15:// 15位身份证 + return isvalidCard15(idCard); + case 10: {// 10位身份证,港澳台地区 + String[] cardval = isValidCard10(idCard); + return null != cardval && cardval[2].equals("true"); } - } - default: - return false; + default: + return false; } } /** - * *

* 判断18位身份证的合法性 *

@@ -200,7 +207,7 @@ public class IdcardUtil { *
  • 余数只可能有0 1 2 3 4 5 6 7 8 9 10这11个数字。其分别对应的最后一位身份证的号码为1 0 X 9 8 7 6 5 4 3 2
  • *
  • 通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10,身份证的最后一位号码就是2
  • * - * + * * @param idCard 待验证的身份证 * @return 是否有效的18位身份证 */ @@ -208,9 +215,9 @@ public class IdcardUtil { if (CHINA_ID_MAX_LENGTH != idCard.length()) { return false; } - + //校验生日 - if(false == Validator.isBirthday(idCard.substring(6, 14))) { + if (false == Validator.isBirthday(idCard.substring(6, 14))) { return false; } @@ -221,16 +228,14 @@ public class IdcardUtil { if (Validator.isNumber(code17)) { // 获取校验位 char val = getCheckCode18(code17); - if (val == code18) { - return true; - } + return val == code18; } return false; } /** * 验证15位身份编码是否合法 - * + * * @param idCard 身份编码 * @return 是否合法 */ @@ -246,30 +251,27 @@ public class IdcardUtil { } //校验生日(两位年份,补充为19XX) - if(false == Validator.isBirthday("19" + idCard.substring(6, 12))) { - return false; - } + return false != Validator.isBirthday("19" + idCard.substring(6, 12)); } else { return false; } - return true; } /** * 验证10位身份编码是否合法 - * + * * @param idCard 身份编码 * @return 身份证信息数组 - *

    - * [0] - 台湾、澳门、香港 [1] - 性别(男M,女F,未知N) [2] - 是否合法(合法true,不合法false) 若不是身份证件号码则返回null - *

    + *

    + * [0] - 台湾、澳门、香港 [1] - 性别(男M,女F,未知N) [2] - 是否合法(合法true,不合法false) 若不是身份证件号码则返回null + *

    */ public static String[] isValidCard10(String idCard) { - if(StrUtil.isBlank(idCard)) { + if (StrUtil.isBlank(idCard)) { return null; } String[] info = new String[3]; - String card = idCard.replaceAll("[\\(|\\)]", ""); + String card = idCard.replaceAll("[()]", ""); if (card.length() != 8 && card.length() != 9 && idCard.length() != 10) { return null; } @@ -286,7 +288,7 @@ public class IdcardUtil { return info; } info[2] = isValidTWCard(idCard) ? "true" : "false"; - } else if (idCard.matches("^[1|5|7][0-9]{6}\\(?[0-9A-Z]\\)?$")) { // 澳门 + } else if (idCard.matches("^[157][0-9]{6}\\(?[0-9A-Z]\\)?$")) { // 澳门 info[0] = "澳门"; info[1] = "N"; } else if (idCard.matches("^[A-Z]{1,2}[0-9]{6}\\(?[0-9A]\\)?$")) { // 香港 @@ -301,29 +303,29 @@ public class IdcardUtil { /** * 验证台湾身份证号码 - * + * * @param idCard 身份证号码 * @return 验证码是否符合 */ public static boolean isValidTWCard(String idCard) { - if(StrUtil.isEmpty(idCard)) { + if (StrUtil.isEmpty(idCard)) { return false; } String start = idCard.substring(0, 1); - String mid = idCard.substring(1, 9); - String end = idCard.substring(9, 10); Integer iStart = twFirstCode.get(start); - if(null == iStart) { + if (null == iStart) { return false; } + String mid = idCard.substring(1, 9); + String end = idCard.substring(9, 10); int sum = iStart / 10 + (iStart % 10) * 9; final char[] chars = mid.toCharArray(); - Integer iflag = 8; + int iflag = 8; for (char c : chars) { sum += Integer.valueOf(String.valueOf(c)) * iflag; iflag--; } - return (sum % 10 == 0 ? 0 : (10 - sum % 10)) == Integer.valueOf(end) ? true : false; + return (sum % 10 == 0 ? 0 : (10 - sum % 10)) == Integer.valueOf(end); } /** @@ -334,23 +336,28 @@ public class IdcardUtil { *

    * 将身份证号码全部转换为数字,分别对应乘9-1相加的总和,整除11则证件号码有效 *

    - * + * * @param idCard 身份证号码 * @return 验证码是否符合 */ public static boolean isValidHKCard(String idCard) { - String card = idCard.replaceAll("[\\(|\\)]", ""); - Integer sum = 0; + String card = idCard.replaceAll("[()]", ""); + int sum; if (card.length() == 9) { - sum = (Integer.valueOf(card.substring(0, 1).toUpperCase().toCharArray()[0]) - 55) * 9 + (Integer.valueOf(card.substring(1, 2).toUpperCase().toCharArray()[0]) - 55) * 8; + sum = (Character.toUpperCase(card.charAt(0)) - 55) * 9 + (Character.toUpperCase(card.charAt(1)) - 55) * 8; card = card.substring(1, 9); } else { - sum = 522 + (Integer.valueOf(card.substring(0, 1).toUpperCase().toCharArray()[0]) - 55) * 8; + sum = 522 + (Character.toUpperCase(card.charAt(0)) - 55) * 8; + } + String start = idCard.substring(0, 1); + Integer iStart = hkFirstCode.get(start); + if (null == iStart) { + return false; } String mid = card.substring(1, 7); String end = card.substring(7, 8); char[] chars = mid.toCharArray(); - Integer iflag = 7; + int iflag = 7; for (char c : chars) { sum = sum + Integer.valueOf(String.valueOf(c)) * iflag; iflag--; @@ -358,14 +365,14 @@ public class IdcardUtil { if ("A".equals(end.toUpperCase())) { sum += 10; } else { - sum += Integer.valueOf(end); + sum += Integer.parseInt(end); } - return (sum % 11 == 0) ? true : false; + return sum % 11 == 0; } /** * 根据身份编号获取生日,只支持15或18位身份证号码 - * + * * @param idCard 身份编号 * @return 生日(yyyyMMdd) * @see #getBirth(String) @@ -376,12 +383,12 @@ public class IdcardUtil { /** * 根据身份编号获取生日,只支持15或18位身份证号码 - * + * * @param idCard 身份编号 * @return 生日(yyyyMMdd) */ public static String getBirth(String idCard) { - final Integer len = idCard.length(); + final int len = idCard.length(); if (len < CHINA_ID_MIN_LENGTH) { return null; } else if (len == CHINA_ID_MIN_LENGTH) { @@ -392,7 +399,7 @@ public class IdcardUtil { /** * 从身份证号码中获取生日日期,只支持15或18位身份证号码 - * + * * @param idCard 身份证号码 * @return 日期 */ @@ -403,7 +410,7 @@ public class IdcardUtil { /** * 根据身份编号获取年龄,只支持15或18位身份证号码 - * + * * @param idCard 身份编号 * @return 年龄 */ @@ -413,8 +420,8 @@ public class IdcardUtil { /** * 根据身份编号获取指定日期当时的年龄年龄,只支持15或18位身份证号码 - * - * @param idCard 身份编号 + * + * @param idCard 身份编号 * @param dateToCompare 以此日期为界,计算年龄。 * @return 年龄 */ @@ -425,12 +432,12 @@ public class IdcardUtil { /** * 根据身份编号获取生日年,只支持15或18位身份证号码 - * + * * @param idCard 身份编号 * @return 生日(yyyy) */ public static Short getYearByIdCard(String idCard) { - Integer len = idCard.length(); + final int len = idCard.length(); if (len < CHINA_ID_MIN_LENGTH) { return null; } else if (len == CHINA_ID_MIN_LENGTH) { @@ -441,12 +448,12 @@ public class IdcardUtil { /** * 根据身份编号获取生日月,只支持15或18位身份证号码 - * + * * @param idCard 身份编号 * @return 生日(MM) */ public static Short getMonthByIdCard(String idCard) { - Integer len = idCard.length(); + final int len = idCard.length(); if (len < CHINA_ID_MIN_LENGTH) { return null; } else if (len == CHINA_ID_MIN_LENGTH) { @@ -457,12 +464,12 @@ public class IdcardUtil { /** * 根据身份编号获取生日天,只支持15或18位身份证号码 - * + * * @param idCard 身份编号 * @return 生日(dd) */ public static Short getDayByIdCard(String idCard) { - Integer len = idCard.length(); + final int len = idCard.length(); if (len < CHINA_ID_MIN_LENGTH) { return null; } else if (len == CHINA_ID_MIN_LENGTH) { @@ -473,33 +480,27 @@ public class IdcardUtil { /** * 根据身份编号获取性别,只支持15或18位身份证号码 - * + * * @param idCard 身份编号 - * @return 性别(1: 男,0: 女) + * @return 性别(1 : 男 , 0 : 女) */ public static int getGenderByIdCard(String idCard) { Assert.notBlank(idCard); final int len = idCard.length(); - if(len < CHINA_ID_MIN_LENGTH) { + if (len < CHINA_ID_MIN_LENGTH) { throw new IllegalArgumentException("ID Card length must be 15 or 18"); } - + if (len == CHINA_ID_MIN_LENGTH) { idCard = convert15To18(idCard); } char sCardChar = idCard.charAt(16); - int gender = -1; - if (Integer.parseInt(String.valueOf(sCardChar)) % 2 != 0) { - gender = 1; - } else { - gender = 0; - } - return gender; + return (sCardChar % 2 != 0) ? 1 : 0; } /** * 根据身份编号获取户籍省份,只支持15或18位身份证号码 - * + * * @param idCard 身份编码 * @return 省级编码。 */ @@ -514,22 +515,23 @@ public class IdcardUtil { /** * 隐藏指定位置的几个身份证号数字为“*” - * - * @param idCard 身份证号 + * + * @param idCard 身份证号 * @param startInclude 开始位置(包含) - * @param endExclude 结束位置(不包含) + * @param endExclude 结束位置(不包含) * @return 隐藏后的身份证号码 - * @since 3.2.2 * @see StrUtil#hide(CharSequence, int, int) + * @since 3.2.2 */ public static String hide(String idCard, int startInclude, int endExclude) { return StrUtil.hide(idCard, startInclude, endExclude); } // ----------------------------------------------------------------------------------- Private method start + /** * 获得18位身份证校验码 - * + * * @param code17 18位身份证号中的前17位 * @return 第18位 */ @@ -540,44 +542,44 @@ public class IdcardUtil { /** * 将power和值与11取模获得余数进行校验码判断 - * - * @param iSum + * + * @param iSum 加权和 * @return 校验位 */ private static char getCheckCode18(int iSum) { switch (iSum % 11) { - case 10: - return '2'; - case 9: - return '3'; - case 8: - return '4'; - case 7: - return '5'; - case 6: - return '6'; - case 5: - return '7'; - case 4: - return '8'; - case 3: - return '9'; - case 2: - return 'x'; - case 1: - return '0'; - case 0: - return '1'; - default: - return StrUtil.C_SPACE; + case 10: + return '2'; + case 9: + return '3'; + case 8: + return '4'; + case 7: + return '5'; + case 6: + return '6'; + case 5: + return '7'; + case 4: + return '8'; + case 3: + return '9'; + case 2: + return 'x'; + case 1: + return '0'; + case 0: + return '1'; + default: + return StrUtil.C_SPACE; } } /** * 将身份证的每位和对应位的加权因子相乘之后,再得到和值 - * - * @param iArr - * @return 身份证编码。 + * + * @param iArr 身份证号码的数组 + * @return 身份证编码 */ private static int getPowerSum(char[] iArr) { int iSum = 0; diff --git a/hutool-core/src/test/java/cn/hutool/core/util/IdcardUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/IdcardUtilTest.java index aa95d068f..159f34cbb 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/IdcardUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/IdcardUtilTest.java @@ -1,5 +1,6 @@ package cn.hutool.core.util; +import cn.hutool.core.lang.Console; import org.junit.Assert; import org.junit.Test; @@ -66,4 +67,10 @@ public class IdcardUtilTest { Assert.assertEquals(province2, "内蒙古"); } + @Test + public void getGenderByIdCardTest() { + int gender = IdcardUtil.getGenderByIdCard(ID_18); + Assert.assertEquals(1, gender); + } + } diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/SmUtil.java b/hutool-crypto/src/main/java/cn/hutool/crypto/SmUtil.java index 09307e0db..09c960f49 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/SmUtil.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/SmUtil.java @@ -1,10 +1,14 @@ package cn.hutool.crypto; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; - +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.crypto.asymmetric.SM2; +import cn.hutool.crypto.digest.HMac; +import cn.hutool.crypto.digest.HmacAlgorithm; +import cn.hutool.crypto.digest.SM3; +import cn.hutool.crypto.digest.mac.BCHMacEngine; +import cn.hutool.crypto.digest.mac.MacEngine; +import cn.hutool.crypto.symmetric.SM4; +import cn.hutool.crypto.symmetric.SymmetricCrypto; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Sequence; @@ -14,14 +18,10 @@ import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; -import cn.hutool.core.io.IORuntimeException; -import cn.hutool.crypto.asymmetric.SM2; -import cn.hutool.crypto.digest.Digester; -import cn.hutool.crypto.digest.HMac; -import cn.hutool.crypto.digest.HmacAlgorithm; -import cn.hutool.crypto.digest.mac.BCHMacEngine; -import cn.hutool.crypto.digest.mac.MacEngine; -import cn.hutool.crypto.symmetric.SymmetricCrypto; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; /** * SM国密算法工具类
    @@ -34,9 +34,6 @@ public class SmUtil { private final static int RS_LEN = 32; - private static String SM3 = "SM3"; - private static String SM4 = "SM4"; - /** * 创建SM2算法对象
    * 生成新的私钥公钥对 @@ -79,10 +76,10 @@ public class SmUtil { * SM3加密:sm3().digest(data)
    * SM3加密并转为16进制字符串:sm3().digestHex(data)
    * - * @return {@link Digester} + * @return {@link SM3} */ - public static Digester sm3() { - return new Digester(SM3); + public static SM3 sm3() { + return new SM3(); } /** @@ -92,7 +89,7 @@ public class SmUtil { * @return SM3字符串 */ public static String sm3(String data) { - return new Digester(SM3).digestHex(data); + return sm3().digestHex(data); } /** @@ -102,7 +99,7 @@ public class SmUtil { * @return SM3字符串 */ public static String sm3(InputStream data) { - return new Digester(SM3).digestHex(data); + return sm3().digestHex(data); } /** @@ -112,7 +109,7 @@ public class SmUtil { * @return SM3字符串 */ public static String sm3(File dataFile) { - return new Digester(SM3).digestHex(dataFile); + return sm3().digestHex(dataFile); } /** @@ -126,8 +123,8 @@ public class SmUtil { * * @return {@link SymmetricCrypto} */ - public static SymmetricCrypto sm4() { - return new SymmetricCrypto(SM4); + public static SM4 sm4() { + return new SM4(); } /** @@ -143,7 +140,7 @@ public class SmUtil { * @return {@link SymmetricCrypto} */ public static SymmetricCrypto sm4(byte[] key) { - return new SymmetricCrypto(SM4, key); + return new SM4(key); } /** diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AbstractAsymmetricCrypto.java b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AbstractAsymmetricCrypto.java index df850ec5c..c3070b98d 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AbstractAsymmetricCrypto.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AbstractAsymmetricCrypto.java @@ -15,17 +15,24 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.CryptoException; import cn.hutool.crypto.SecureUtil; +/** + * 抽象的非对称加密对象,包装了加密和解密为Hex和Base64的封装 + * + * @param 返回自身类型 + * @author Looly + */ public abstract class AbstractAsymmetricCrypto> extends BaseAsymmetric { // ------------------------------------------------------------------ Constructor start + /** * 构造 - * + *

    * 私钥和公钥同时为空时生成一对新的私钥和公钥
    * 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密 - * - * @param algorithm 算法 + * + * @param algorithm 算法 * @param privateKey 私钥 - * @param publicKey 公钥 + * @param publicKey 公钥 * @since 3.1.1 */ public AbstractAsymmetricCrypto(String algorithm, PrivateKey privateKey, PublicKey publicKey) { @@ -34,10 +41,11 @@ public abstract class AbstractAsymmetricCryptonull自动生成一个key - * @return {@link SymmetricCrypto} + * @return {@link SymmetricCrypto}的子对象,既子对象自身 */ public SymmetricCrypto init(String algorithm, SecretKey key) { Assert.notBlank(algorithm, "'algorithm' must be not blank !"); @@ -163,6 +166,28 @@ public class SymmetricCrypto { return this; } + /** + * 设置偏移向量 + * + * @param iv {@link IvParameterSpec}偏移向量 + * @return 自身 + */ + public SymmetricCrypto setIv(IvParameterSpec iv) { + setParams(iv); + return this; + } + + /** + * 设置偏移向量 + * + * @param iv 偏移向量,加盐 + * @return 自身 + */ + public SymmetricCrypto setIv(byte[] iv) { + setIv(new IvParameterSpec(iv)); + return this; + } + // --------------------------------------------------------------------------------- Encrypt /** diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/SmTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/test/SmTest.java index 340e7377e..73e9ff0d5 100644 --- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/SmTest.java +++ b/hutool-crypto/src/test/java/cn/hutool/crypto/test/SmTest.java @@ -1,12 +1,19 @@ package cn.hutool.crypto.test; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.date.TimeInterval; +import cn.hutool.core.lang.Console; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.crypto.KeyUtil; +import cn.hutool.crypto.Mode; +import cn.hutool.crypto.Padding; +import cn.hutool.crypto.SmUtil; +import cn.hutool.crypto.digest.HMac; +import cn.hutool.crypto.symmetric.SM4; import org.junit.Assert; import org.junit.Test; -import cn.hutool.core.util.CharsetUtil; -import cn.hutool.crypto.SmUtil; -import cn.hutool.crypto.digest.HMac; -import cn.hutool.crypto.symmetric.SymmetricCrypto; +import javax.crypto.SecretKey; /** * SM单元测试 @@ -25,17 +32,34 @@ public class SmTest { @Test public void sm4Test() { String content = "test中文"; - SymmetricCrypto sm4 = SmUtil.sm4(); - + SM4 sm4 = SmUtil.sm4(); + + String encryptHex = sm4.encryptHex(content); + String decryptStr = sm4.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8); + + Assert.assertEquals(content, decryptStr); + } + + @Test + public void sm4ECBPKCS5PaddingTest2() { + String content = "test中文"; + SM4 sm4 = new SM4(Mode.ECB, Padding.PKCS5Padding); + Assert.assertEquals("SM4/ECB/PKCS5Padding", sm4.getCipher().getAlgorithm()); + String encryptHex = sm4.encryptHex(content); String decryptStr = sm4.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8); Assert.assertEquals(content, decryptStr); } + @Test - public void sm4Test2() { + public void sm4TestWithCustomKeyTest() { String content = "test中文"; - SymmetricCrypto sm4 = new SymmetricCrypto("SM4/ECB/PKCS5Padding"); - + + SecretKey key = KeyUtil.generateKey(SM4.ALGORITHM_NAME); + + SM4 sm4 = new SM4(Mode.ECB, Padding.PKCS5Padding, key); + Assert.assertEquals("SM4/ECB/PKCS5Padding", sm4.getCipher().getAlgorithm()); + String encryptHex = sm4.encryptHex(content); String decryptStr = sm4.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8); Assert.assertEquals(content, decryptStr); diff --git a/hutool-json/src/test/java/cn/hutool/json/test/bean/report/EnvSettingInfo.java b/hutool-json/src/test/java/cn/hutool/json/test/bean/report/EnvSettingInfo.java index 5136a20b8..c315d1450 100644 --- a/hutool-json/src/test/java/cn/hutool/json/test/bean/report/EnvSettingInfo.java +++ b/hutool-json/src/test/java/cn/hutool/json/test/bean/report/EnvSettingInfo.java @@ -18,7 +18,7 @@ public class EnvSettingInfo { private String reportFolder = "/report"; private String screenshotFolder = "/screenshot";; - + private String elementFolder = "/config/element/"; private String suiteFolder = "/config/suite/";