java使用SM4加密报错 No such algorithm 解决记录
lipiwang 2024-11-04 14:33 13 浏览 0 评论
SM4是我们国家密码管理局发布的一种对称分组加密算法,也称为国密算法。与AES类似,都是基于分组的对称加密,但其结构和加密流程有自己独特的设计。
SM4算法在无线局域网设备的安全认证和数据加密中应用广泛,尤其适用于对数据安全性要求较高的应用场景。
这是之前在公司对接的一家资金方就是使用的SM4加密,但在开发demo时,加密时出现错误,随手记录了下来,现整理发出希望帮到更多的网友。
问题描述
使用 SM4 加密算法运行一直报错 No such algorithm: SM4/ECB/PKCS7Padding。
本次加密用到的第三方库是 Bouncy Castle,提供对 SM4 算法的支持,该组件是由 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 加密解密的工具类以及一个测试方法。
SM4 加解密工具
package com.vrgamehome.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
@EnableApolloConfig
public 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();
}
}
相关推荐
- 微软Office Open XML中的数字签名漏洞
-
MicrosoftOffice是最广泛使用的办公文档应用程序之一。对于重要文件,如合同和发票,可以对其内容进行签名,以确保其真实性和完整性。自2019年以来,安全研究人员发现了针对PDF和ODF等其...
- Javaweb知识 day12 XML(javaweb中xml作用)
-
一、XML:1.1概念:ExtensibleMarkupLanguage可扩展标记语言*可扩展:标签都是自定义的。<user><student>1.2功能:...
- 易筋洗髓功——内外同修方可致远(易筋洗髓功口诀)
-
达摩祖师所传易筋、洗髓两经,一分为二,二实为一,无非以方便法门接引众生,而归于慈悲清净之心地。修炼《易筋经》是为强身健体,修炼《洗髓经》是为修心养性,此二者相辅相成,内外兼修,缺一不可。这是一套传统中...
- 道家洗髓功修炼要义,洗髓功如何做到丹田聚气?
-
不管是道家洗髓功,还是洗髓经,其修炼的关键点就在于得气、行气、聚气...那么,作为洗髓功修炼者,具体该怎么做呢?在实际修炼中,就洗髓功的修炼方法来讲,我们可以简单的归纳为修炼三部曲,其具体表现如下:一...
- 「清风聊练功」师门传我易筋经:聊聊我的学习经历和正身图感受
-
一个人的眼界认识,是随着是自身的知识积累和水平不断成长的。开篇为什么要说这么一句呢?是从我的学习经历上感受明显的这句话:一处不到一处迷。我们学传统武术,内功功法,也是从小白到明白一步步走的,走的越远,...
- 内功外练功介绍(练内功 外功)
-
这里介绍我练习的两套动功心得体会。是老道长的八部金刚功、长寿功和增演易筋洗髓经。八部金刚功外练奇经八脉,练出健康强壮的好身体还是可以的,长寿功也是内练功法。这部功法很好的预防效果。这个大家都认同的。说...
- 《增演易筋洗髓内功图说》17卷(1930年(清)周述官撰 1
-
少林空悟老师珍藏
- 国术典籍:《增演易筋洗髓内功图说》【2024年8月编校】
-
《增演易筋洗髓内功图说》系养生气功著作,全书共十八卷。清周述官编撰于光绪二十一年(1895年)。清光绪十九年(1893年),僧人静一空悟将少林功法传授于周述官,并将《增益易筋洗髓内功图说》十二卷(按,...
- 小说:自媒体小白的修道之路-洗髓(自媒体小白运营技巧)
-
谁应了谁的劫,谁又变成了谁的执念。当沧海遗忘了桑田,这世间又多了一个不回家的人!异域空间中,知生缓缓起身,目光扫了一下小帝后,又转身看向画板上的那朵白色蒲公英,自言道:“白瑛,这一世我们莫要再辜负了!...
- 这才是少林洗髓经真相:它是静功和导引术与八段锦暗合
-
不少朋友误解易筋经和洗髓经,将其简单归为强力呼吸的吐纳功以及为了提升房中的关窍功。事实上易筋经和洗髓经是两部功法:易筋经主要为炼体,包含以膜论为核心的十二月怕打筋膜法,以及辅助的呼吸、导引功法;洗髓经...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- maven镜像 (69)
- undefined reference to (60)
- zip格式 (63)
- oracle over (62)
- date_format函数用法 (67)
- 在线代理服务器 (60)
- shell 字符串比较 (74)
- x509证书 (61)
- localhost (65)
- java.awt.headless (66)
- syn_sent (64)
- settings.xml (59)
- 弹出窗口 (56)
- applicationcontextaware (72)
- my.cnf (73)
- httpsession (62)
- pkcs7 (62)
- session cookie (63)
- java 生成uuid (58)
- could not initialize class (58)
- beanpropertyrowmapper (58)
- word空格下划线不显示 (73)
- jar文件 (60)
- jsp内置对象 (58)
- makefile编写规则 (58)