java SM4 加密报错 No such algorithm: SM4/ECB/PKCS7Padding 解决记录
问题描述
使用 SM4 加密算法运行一直报错 No such algorithm: SM4/ECB/PKCS7Padding
。
本次加密用到的组件是 bouncycastle,该组件是由 bcprov-jdkxx 提供。
网上有各种解决办法,有修改 jre 下文件 java.security
的。
但本次问题较简单,解决相关 jar 包问题即可。
问题探索并解决
经查发现加密用的 jar 包是 org.bouncycastle:bcprov-jdk16:1.64
:
而配置的依赖明明是 org.bouncycastle:bcprov-jdk15on:1.60
:
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.60</version></dependency>
是不是这个原因?新建一个项目直接添加 bcprov-jdk15on:1.60
依赖,运行后加密成功,那应该就是这个版本问题。
pom 文件中并没有显示添加 bcprov-jdk16:1.64
这个依赖,那应该是其它的组件里的,经查发现是公司的一个加密组件 com.xx.xx
里的,尴尬。。。将这个版本排除掉,使用 bcprov-jdk15on:1.60
依赖:
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.60</version> </dependency> <dependency> <groupId>com.xx.xx</groupId> <artifactId>security</artifactId> <version>1.0.5-RELEASE</version> <exclusions> <exclusion> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk16</artifactId> </exclusion> </exclusions> </dependency>
经测试公司的加密组件功能不受影响。
SM4 加解密工具
package com.vcredit.creditreport.cdsxreport.util;import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;import lombok.extern.slf4j.Slf4j;import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;import javax.crypto.Cipher;import javax.crypto.KeyGenerator;import javax.crypto.spec.SecretKeySpec;import java.nio.charset.StandardCharsets;import java.security.Key;import java.security.SecureRandom;import java.security.Security;import java.util.Arrays;/** * SM4加密 * @author wankun * @date 2021/10/29. */@Slf4j@EnableApolloConfigpublic class SM4Utils { private static final String ENCODING = StandardCharsets.UTF_8.toString(); public static final String ALGORIGTHM_NAME = "SM4"; public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS7Padding"; public static final int DEFAULT_KEY_SIZE = 128; public SM4Utils() { } static { Security.addProvider(new BouncyCastleProvider()); } /** * 生成ecb暗号 * @param algorithmName * @param mode * @param key * @return ecb暗号 * @throws Exception */ 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, ALGORIGTHM_NAME); cipher.init(mode, sm4Key); return cipher; } /** * 自动生成密钥 * @return 密钥 * @throws Exception */ public static byte[] generateKey() throws Exception { return generateKey(DEFAULT_KEY_SIZE); } /** * 自动生成密钥 * @param keySize * @return 密钥 * @throws Exception */ public static byte[] generateKey(int keySize) throws Exception { KeyGenerator kg = KeyGenerator.getInstance(ALGORIGTHM_NAME, BouncyCastleProvider.PROVIDER_NAME); kg.init(keySize, new SecureRandom()); return kg.generateKey().getEncoded(); } /** * 加密 * @param hexKey 私钥 * @param paramStr 明文 * @return 密文 * @throws Exception */ public static String encrypt(String hexKey, String paramStr) throws Exception{ return encryptEcb(hexKey,paramStr,ENCODING); } /** * 加密 * @param hexKey 私钥 * @param paramStr 明文 * @param charset 编码 * @return 密文 * @throws Exception */ public static String encryptEcb(String hexKey, String paramStr, String charset) throws Exception { String cipherText = ""; if (null != paramStr && !"".equals(paramStr)) { byte[] keyData = ByteUtils.fromHexString(hexKey); charset = charset.trim(); if (charset.length() <= 0) { charset = ENCODING; } byte[] srcData = paramStr.getBytes(charset); byte[] cipherArray = encrypt_Ecb_Padding(keyData, srcData); 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); return cipher.doFinal(data); } /** * 解密 * @param hexKey 私钥 * @param cipherText 密文 * @param charset 编码 * @return 明文 * @throws Exception */ public static String decryptEcb(String hexKey, String cipherText, String charset) throws Exception { String decryptStr = ""; byte[] keyData = ByteUtils.fromHexString(hexKey); byte[] cipherData = ByteUtils.fromHexString(cipherText); byte[] srcData = decrypt_Ecb_Padding(keyData, cipherData); charset = charset.trim(); if (charset.length() <= 0) { charset = ENCODING; } decryptStr = new String(srcData, charset); return decryptStr; } /** * 解密 * @param key * @param cipherText * @return * @throws Exception */ public static byte[] decrypt_Ecb_Padding(byte[] key, byte[] cipherText) throws Exception { Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key); return cipher.doFinal(cipherText); } /** * 密码校验 * @param hexKey 私钥 * @param cipherText 密文 * @param paramStr 明文 * @return 校验结果 * @throws Exception */ public static boolean verifyEcb(String hexKey,String cipherText,String paramStr) throws Exception { boolean flag = false; byte[] keyData = ByteUtils.fromHexString(hexKey); byte[] cipherData = ByteUtils.fromHexString(cipherText); byte[] decryptData = decrypt_Ecb_Padding(keyData,cipherData); byte[] srcData = paramStr.getBytes(ENCODING); flag = Arrays.equals(decryptData,srcData); return flag; }}
测试代码:
public static void main(String[] args) { try { String key = "564e351eae88ebbddc28c5709cd286a6"; String str= "110101197408070619";//密钥(564e351eae88ebbddc28c5709cd286a6) 加密(110101197408070619) => 9dd25f18ebef6938d4eaaf465a389836eb62ddb02ab6456aa0c3da3437f20532 String cipher = SM4Utils.encrypt(key, str); System.out.println(cipher); System.out.println(SM4Utils.verifyEcb(key, cipher, str)); str = SM4Utils.decryptEcb(key, cipher,ENCODING); System.out.println(str); } catch (Exception e) { e.printStackTrace(); }}
标签:
分类:
java
本文来自【坤哥网】,转载请带上原文链接:http://www.kungge.com/kwan/6103.html