国密算法工具-SmUtil

介绍

Hutool针对Bouncy Castle做了简化包装,用于实现国密算法中的SM2、SM3、SM4。

国密算法工具封装包括:

  • 非对称加密和签名:SM2
  • 摘要签名算法:SM3
  • 对称加密:SM4

国密算法需要引入Bouncy Castle库的依赖。

使用

引入Bouncy Castle依赖

  1. <dependency>
  2. <groupId>org.bouncycastle</groupId>
  3. <artifactId>bcprov-jdk15to18</artifactId>
  4. <version>1.66</version>
  5. </dependency>

说明 bcprov-jdk15to18的版本请前往Maven中央库搜索,查找对应JDK的最新版本。

非对称加密SM2

  1. 使用随机生成的密钥对加密或解密
  1. String text = "我是一段测试aaaa";
  2. SM2 sm2 = SmUtil.sm2();
  3. // 公钥加密,私钥解密
  4. String encryptStr = sm2.encryptBcd(text, KeyType.PublicKey);
  5. String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));
  1. 使用自定义密钥对加密或解密
  1. String text = "我是一段测试aaaa";
  2. KeyPair pair = SecureUtil.generateKeyPair("SM2");
  3. byte[] privateKey = pair.getPrivate().getEncoded();
  4. byte[] publicKey = pair.getPublic().getEncoded();
  5. SM2 sm2 = SmUtil.sm2(privateKey, publicKey);
  6. // 公钥加密,私钥解密
  7. String encryptStr = sm2.encryptBcd(text, KeyType.PublicKey);
  8. String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));
  1. SM2签名和验签
  1. String content = "我是Hanley.";
  2. final SM2 sm2 = SmUtil.sm2();
  3. String sign = sm2.signHex(HexUtil.encodeHexStr(content));
  4. // true
  5. boolean verify = sm2.verifyHex(HexUtil.encodeHexStr(content), sign);

当然,也可以自定义密钥对:

  1. String content = "我是Hanley.";
  2. KeyPair pair = SecureUtil.generateKeyPair("SM2");
  3. final SM2 sm2 = new SM2(pair.getPrivate(), pair.getPublic());
  4. byte[] sign = sm2.sign(content.getBytes());
  5. // true
  6. boolean verify = sm2.verify(content.getBytes(), sign);
  1. 使用SM2曲线点构建SM2

使用曲线点构建中的点生成和验证见:https://i.goto327.top/CryptTools/SM2.aspx?tdsourcetag=s_pctim_aiomsg

  1. String privateKeyHex = "FAB8BBE670FAE338C9E9382B9FB6485225C11A3ECB84C938F10F20A93B6215F0";
  2. String x = "9EF573019D9A03B16B0BE44FC8A5B4E8E098F56034C97B312282DD0B4810AFC3";
  3. String y = "CC759673ED0FC9B9DC7E6FA38F0E2B121E02654BF37EA6B63FAF2A0D6013EADF";
  4. // 数据和ID此处使用16进制表示
  5. String data = "434477813974bf58f94bcf760833c2b40f77a5fc360485b0b9ed1bd9682edb45";
  6. String id = "31323334353637383132333435363738";
  7. final SM2 sm2 = new SM2(privateKeyHex, x, y);
  8. // 生成的签名是64位
  9. sm2.usePlainEncoding();
  10. final String sign = sm2.signHex(data, id);
  11. // true
  12. boolean verify = sm2.verifyHex(data, sign)
  1. 使用私钥D值签名
  1. //需要签名的明文,得到明文对应的字节数组
  2. byte[] dataBytes = "我是一段测试aaaa".getBytes();
  3. //指定的私钥
  4. String privateKeyHex = "1ebf8b341c695ee456fd1a41b82645724bc25d79935437d30e7e4b0a554baa5e";
  5. // 此构造从5.5.9开始可使用
  6. final SM2 sm2 = new SM2(privateKeyHex, null, null);
  7. sm2.usePlainEncoding();
  8. byte[] sign = sm2.sign(dataBytes, null);
  1. 使用公钥Q值验证签名
  1. //指定的公钥
  2. String publicKeyHex ="04db9629dd33ba568e9507add5df6587a0998361a03d3321948b448c653c2c1b7056434884ab6f3d1c529501f166a336e86f045cea10dffe58aa82ea13d725363";
  3. //需要加密的明文,得到明文对应的字节数组
  4. byte[] dataBytes = "我是一段测试aaaa".getBytes();
  5. //签名值
  6. String signHex ="2881346e038d2ed706ccdd025f2b1dafa7377d5cf090134b98756fafe084dddbcdba0ab00b5348ed48025195af3f1dda29e819bb66aa9d4d088050ff148482a";
  7. final SM2 sm2 = new SM2(null, ECKeyUtil.toSm2PublicParams(publicKeyHex));
  8. sm2.usePlainEncoding();
  9. // true
  10. boolean verify = sm2.verify(dataBytes, HexUtil.decodeHex(signHex));

摘要加密算法SM3

  1. //结果为:136ce3c86e4ed909b76082055a61586af20b4dab674732ebd4b599eef080c9be
  2. String digestHex = SmUtil.sm3("aaaaa");

对称加密SM4

  1. String content = "test中文";
  2. SymmetricCrypto sm4 = SmUtil.sm4();
  3. String encryptHex = sm4.encryptHex(content);
  4. String decryptStr = sm4.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8);