Loading

bouncycastle 进行java的加密解密

摘自:https://www.cnblogs.com/1314xhuan/p/16947347.html

bouncy castle(轻量级密码术包)是一种用于 Java 平台的开放源码的轻量级密码术包;它支持大量的密码术算法,并提供JCE 1.2.1的实现。

2|0bouncycastle安装

2|1环境搭建

maven下载

在进行bouncycastle安装之前先搭建好maven项目环境为后续算法实现打好基础
在这里推荐一篇博客对maven安装提供参考

maven安装

我们选择apache-maven-3.8.6-bin.zip进行下载

将压缩包解压到自己预安装路径。

随后进行环境变量配置

环境变量配置

首先先新建一个MAVEN_HOME的系统变量

随后编辑PATH环境变量,添加%MAVEN_HOME%\bin

随后在cmd中即可查看自己是否配置成功啦,若mvn -version能识别即成功

配置本地仓库

在maven路径处配置本地仓库文件夹maven-repository

在maven路径下的conf中找到setting.xml,在文件中找到localRepository结点添加仓库路径。

添加字段为:
<localRepository>仓库地址</localRepository>

通过网上资料我也了解到

localRepository节点用于配置本地仓库,本地仓库其实起到了一个缓存的作用,它的默认地址是 C:\Users\用户名.m2。
当我们从maven中获取jar包的时候,maven首先会在本地仓库中查找,如果本地仓库有则返回;如果没有则从远程仓库中获取包,并在本地库中保存。
此外,我们在maven项目中运行mvn install,项目将会自动打包并安装到本地仓库中。

配置镜像

因为国外的服务器下载jar包很慢所以我们改为阿里云服务器

在setting.xml文件中找到mirrors节点

添加如下配置信息

<!-- 阿里云仓库 --> <mirror> <id>alimaven</id> <mirrorOf>central</mirrorOf> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/repositories/central/</url> </mirror>

在这里我们也不必担心mirror有多个,因为有一个是maven默认配置的镜像地址,我们不用删除,因为每次maven运行寻找的都是第一个mirror,只要我们把阿里云配置在第一个位置就行啦!

配置JDK

依然是在setting.xml文件中进行配置,找到profiles节点,添加以下配置信息

<!-- java版本 --> <profile> <id>jdk-1.8</id> <activation> <activeByDefault>true</activeByDefault> <jdk>1.8</jdk> </activation> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> </properties> </profile>

在配置完成之后我们就要见证一下成果啦

添加本地仓库配置

在cmd中运行mvn help:system进行配置本地仓库。

运行成功之后就可以看到仓库里面有了一些文件

2|2安装bouncycastle

网上的资料和博客说是去bouncycastle官网下载相关jar包
由于我们前面配置的JDK版本为1.8所以我们要下的jar包为:

bcprov-jdk15to18-169.jar
bcprov-ext-jdk15to18-169.jar

但是我发现我无法进入bouncycastle的官网,后面在一片博客中了解到直接在pom.xml中插入一条依赖即可以让idea自动导入jar包

3|0国密算法实现

sm2实现

代码

SM2_Util.java
package sm2; import org.bouncycastle.crypto.engines.SM2Engine; import org.bouncycastle.crypto.params.*; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; import org.bouncycastle.jce.spec.ECParameterSpec; import org.bouncycastle.util.encoders.Hex; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; public class SM2Util { /** * SM2加密算法 * @param publicKey 公钥 * @param data 明文数据 * @return */ public String encrypt(PublicKey publicKey, String data) { ECPublicKeyParameters ecPublicKeyParameters = null; if (publicKey instanceof BCECPublicKey) { BCECPublicKey bcecPublicKey = (BCECPublicKey) publicKey; ECParameterSpec ecParameterSpec = bcecPublicKey.getParameters(); ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN()); ecPublicKeyParameters = new ECPublicKeyParameters(bcecPublicKey.getQ(), ecDomainParameters); } SM2Engine sm2Engine = new SM2Engine(); sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom())); byte[] arrayOfBytes = null; try { byte[] in = data.getBytes("utf-8"); arrayOfBytes = sm2Engine.processBlock(in,0, in.length); } catch (Exception e) { System.out.println("SM2加密时出现异常:"); } return Hex.toHexString(arrayOfBytes); } /** * SM2解密算法 * @param privateKey 私钥 * @param cipherData 密文数据 * @return */ public String decrypt(PrivateKey privateKey, String cipherData) { byte[] cipherDataByte = Hex.decode(cipherData); BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) privateKey; ECParameterSpec ecParameterSpec = bcecPrivateKey.getParameters(); ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN()); ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(bcecPrivateKey.getD(), ecDomainParameters); SM2Engine sm2Engine = new SM2Engine(); sm2Engine.init(false, ecPrivateKeyParameters); String result = null; try { byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length); return new String(arrayOfBytes, "utf-8"); } catch (Exception e) { System.out.println("SM2解密时出现异常"); } return result; } }
sm2_demo.java
package sm2; import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.*; import java.security.spec.ECGenParameterSpec; public class sm2_demo { private static String M="20201325xjr"; public static void main(String[] args) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { SM2Util sm2 = new SM2Util(); final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1"); // 获取一个椭圆曲线类型的密钥对生成器 final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider()); // 使用SM2参数初始化生成器 kpg.initialize(sm2Spec); // 获取密钥对 KeyPair keyPair = kpg.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); String data = sm2.encrypt(publicKey,M); System.out.println("明文:"+M); System.out.println("密文:"+data); String text=sm2.decrypt(privateKey,data); System.out.println("解密结果"+text); } }

添加configuration

随后运行即可啦!

sm3算法实现

代码

sm3主类测试代码
package sm3; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; public class sm3_demo { private static String test="20201325xjr"; public static void main(String[] args) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { SM3Util sm3 = new SM3Util(); String data = sm3.plainEncrypt(test); System.out.println("明文:"+test); System.out.println("哈希值:"+data); } }
SM3Util
package sm3; import org.bouncycastle.crypto.digests.SM3Digest; import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.util.encoders.Hex; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; /** * @Author: dzy * @Date: 2018/10/19 16:36 * @Describe: SM3工具类(杂凑算法-hash算法) */ public class SM3Util { /** * 16进制字符串SM3生成HASH签名值算法 * @param hexString 16进制字符串 * @return */ public static String hexEncrypt(String hexString) { byte[] srcData = Hex.decode(hexString); byte[] encrypt = encrypt(srcData); String cipherStr = Hex.toHexString(encrypt); return cipherStr; } /** * 16进制字符串SM3生成HASH签名值算法 * @param hexKey 16进制密钥 * @param hexString 16进制字符串 * @return */ public static String hexEncrypt(String hexKey, String hexString) { byte[] key = Hex.decode(hexKey); byte[] srcData = Hex.decode(hexString); byte[] encrypt = encrypt(key, srcData); String cipherStr = Hex.toHexString(encrypt); return cipherStr; } /** * 普通文本SM3生成HASH签名算法 * @param plain 待签名数据 * @return */ public static String plainEncrypt(String plain) { // 将返回的hash值转换成16进制字符串 String cipherStr = null; try { //将字符串转换成byte数组 byte[] srcData = plain.getBytes(StandardCharsets.UTF_8); //调用encrypt计算hash byte[] encrypt = encrypt(srcData); //将返回的hash值转换成16进制字符串 cipherStr = Hex.toHexString(encrypt); } catch (Exception e) { //log.error("将字符串转换为字节时出现异常:", e); } return cipherStr; } /** * 普通文本SM3生成HASH签名算法 * @param hexKey 密钥 * @param plain 待签名数据 * @return */ public static String plainEncrypt(String hexKey, String plain) { // 将返回的hash值转换成16进制字符串 String cipherStr = null; try { //将字符串转换成byte数组 byte[] srcData = plain.getBytes(StandardCharsets.UTF_8); //密钥 byte[] key = Hex.decode(hexKey); //调用encrypt计算hash byte[] encrypt = encrypt(key, srcData); //将返回的hash值转换成16进制字符串 cipherStr = Hex.toHexString(encrypt); } catch (Exception e) { //log.error("将字符串转换为字节时出现异常:", e); } return cipherStr; } /** * SM3计算hashCode * @param srcData 待计算数据 * @return */ public static byte[] encrypt(byte[] srcData) { SM3Digest sm3Digest = new SM3Digest(); sm3Digest.update(srcData, 0, srcData.length); byte[] encrypt = new byte[sm3Digest.getDigestSize()]; sm3Digest.doFinal(encrypt, 0); return encrypt; } /** * 通过密钥进行加密 * @param key 密钥byte数组 * @param srcData 被加密的byte数组 * @return */ public static byte[] encrypt(byte[] key, byte[] srcData) { KeyParameter keyParameter = new KeyParameter(key); SM3Digest digest = new SM3Digest(); HMac mac = new HMac(digest); mac.init(keyParameter); mac.update(srcData, 0, srcData.length); byte[] result = new byte[mac.getMacSize()]; mac.doFinal(result, 0); return result; } /** * SM3计算hashCode * @param srcData 待计算数据 * @return * @throws Exception */ public static byte[] encrypt_0(byte[] srcData) throws Exception { MessageDigest messageDigest = MessageDigest.getInstance("SM3", "BC"); byte[] digest = messageDigest.digest(srcData); return digest; } }

运行结果

正确性验证

经过验证证明结果正确

sm4实现

代码

sm4主测试类代码
package sm4; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; public class sm4_demo { private static String test= "20201325xjr_sm4_"; private static String mykey= "6cef39eb85614df44f6b0f6babcd89b6"; public static void main(String[] args) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { SM4Util sm4 = new SM4Util(); //SM3Util sm3 = new SM3Util(); //String data_in = sm3.plainEncrypt(test); //String data = sm4.encryptByEcb(data_in,mykey); String x16 = sm4.strToHexadecimal(test); //System.out.println(x16); String data = sm4.encryptByEcb(x16,mykey); System.out.println("明文:"+test); //System.out.println("摘 要:"+data_in); System.out.println("密文:"+data); String text_16 = sm4.decryptByEcb(data,mykey); //System.out.println(text_16); //System.out.println(x16.equals(text_16.toUpperCase())); String text = sm4.hexadecimalToStr(text_16.toUpperCase()); System.out.println("解密结果:"+text); } }
SM4Util
package sm4; import org.bouncycastle.crypto.engines.SM4Engine; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.util.encoders.Hex; /** * @Author: dzy * @Date: 2018/10/9 16:41 * @Describe: SM4算法 */ public class SM4Util { //加解密的字节快大小 public static final int BLOCK_SIZE = 16; /** * SM4ECB加密算法 * @param in 待加密内容 * @param keyBytes 密钥 * @return */ public static byte[] encryptByEcb0(byte[] in, byte[] keyBytes) { SM4Engine sm4Engine = new SM4Engine(); sm4Engine.init(true, new KeyParameter(keyBytes)); int inLen = in.length; byte[] out = new byte[inLen]; int times = inLen / BLOCK_SIZE; for (int i = 0; i < times; i++) { sm4Engine.processBlock(in, i * BLOCK_SIZE, out, i * BLOCK_SIZE); } return out; } /** * SM4ECB加密算法 * @param in 待加密内容 * @param keyBytes 密钥 * @return */ public static String encryptByEcb(byte[] in, byte[] keyBytes) { byte[] out = encryptByEcb0(in, keyBytes); String cipher = Hex.toHexString(out); return cipher; } /** * SM4的ECB加密算法 * @param content 待加密内容 * @param key 密钥 * @return */ public static String encryptByEcb(String content, String key) { byte[] in = Hex.decode(content); byte[] keyBytes = Hex.decode(key); String cipher = encryptByEcb(in, keyBytes); return cipher; } /** * SM4的ECB解密算法 * @param in 密文内容 * @param keyBytes 密钥 * @return */ public static byte[] decryptByEcb0(byte[] in, byte[] keyBytes) { SM4Engine sm4Engine = new SM4Engine(); sm4Engine.init(false, new KeyParameter(keyBytes)); int inLen = in.length; byte[] out = new byte[inLen]; int times = inLen / BLOCK_SIZE; for (int i = 0; i < times; i++) { sm4Engine.processBlock(in, i * BLOCK_SIZE, out, i * BLOCK_SIZE); } return out; } /** * SM4的ECB解密算法 * @param in 密文内容 * @param keyBytes 密钥 * @return */ public static String decryptByEcb(byte[] in, byte[] keyBytes) { byte[] out = decryptByEcb0(in, keyBytes); String plain = Hex.toHexString(out); return plain; } /** * SM4的ECB解密算法 * @param cipher 密文内容 * @param key 密钥 * @return */ public static String decryptByEcb(String cipher, String key) { byte[] in = Hex.decode(cipher); byte[] keyBytes = Hex.decode(key); String plain = decryptByEcb(in, keyBytes); return plain; } public static String strToHexadecimal(String str) { char[] chars = "0123456789ABCDEF".toCharArray(); StringBuilder sb = new StringBuilder(""); byte[] bs = str.getBytes(); int bit; for (int i = 0; i < bs.length; i++) { bit = (bs[i] & 0x0f0) >> 4; sb.append(chars[bit]); bit = bs[i] & 0x0f; sb.append(chars[bit]); } return sb.toString().trim(); } public static String hexadecimalToStr(String hexStr) { String str = "0123456789ABCDEF"; char[] hexs = hexStr.toCharArray(); byte[] bytes = new byte[hexStr.length() / 2]; int n; for (int i = 0; i < bytes.length; i++) { n = str.indexOf(hexs[2 * i]) * 16; n += str.indexOf(hexs[2 * i + 1]); bytes[i] = (byte) (n & 0xff); } return new String(bytes); } }

运行结果:

3|1导出jar包

添加plugin依赖

在pom.xml中添加如下配置

sm2test org.apache.maven.plugins maven-assembly-plugin 2.5.5 sm2.sm2_demo jar-with-dependencies

这里采用的是maven-assembly-plugin工具进行导出

随后在terminal中运行mvn package指令

当看见BUILD SUCCESS的时候就代表jar构建成功啦

此时targe目录下也会出现jar包

接下来使用java -jar java -jar target\sm2test-jar-with-dependencies.jar指令执行jar包得到以下结果

3|2openEuler中运行jar包

将jar传入openEuler虚拟机中,并使用java -jar java -jar sm2test-jar-with-dependencies.jar指令执行即可

4|0方法二

在同学那里拷来bouncycastle的资源包后打算试试直接在linux系统命令行下编译运行实现

直接将包导入jdk下的ext拓展包文件夹,然后直接在命令行进行编译运行

创建项目文件夹

创建sm2文件夹,并编写代码文件,(这里以sm2为例):

编译文件

使用命令javac sm2/*.java进行编译两个文件生成两个class类

运行文件

使用命令java sm2/sm2_demo运行主类

至于sm3、sm4算法实现在这里不过多赘述。

4|1所遇问题及解决方法

  1. 在跟着网上教程构建maven环境时要导入bouncycastle的jar包,但是无法进入官网下载地址

后面在根据网上资料了解后发现,idea其实可以通过导入依赖的方法进行导入包,只需在pom.xml中添加项即可啦!

  1. 在sm4算法实现的时候发现了下面的问题

我发现密文全是0,跟我在python的snowland-smx库中所遇的问题类似,因为sm4分组长度为128bit,后面我尝试着将密文换成了十六位的数字和字母即可啦,这也让我对sm4算法有了更深的印象。

  1. 导出的包名字不对,后面发现时在pom.xml文件中写的finalName不对,写成了sm2test,随后改成自己预想的名字就像啦

  2. 我在导出包的时候发生了一个很严重的问题,发生了找不到主类的情况,但是我们从pom.xml依赖中明显可以看出我设置了mainclass为sm2.sm2_demo,随后我们用360压缩打开jar包看一下

我发现没有Main-Class字段,所以我就加上了 Main-Class: sm2.sm2_demo,但是还是不如意,它发生了如下报错

错误: 无法初始化主类 sm2.sm2_demo
原因: java.lang.NoClassDefFoundError: org/bouncycastle/jce/provider/BouncyCastleProvider

这到底是怎么回事?我在网上搜了这个报错原因,网上有人说是在Terminal端执行没有idea中导入的bouncycastle相关包,那么问题又回到了原点,我需要下载bouncycastle包,但是我进不去官方网站,并且我在jdk18的jre文件夹下找不到ext文件夹,这个文件夹是存放拓展包的,我没有就算下载下来也不知道放哪,这个问题牵涉着我要换jdk,要重新配idea,重新导出包,意味着从头再来。但是我没有放弃,在后面一篇博客中了解到mvn package执行完之后会生成两个jar包,如下:

而我只有一个sm2test.jar,那我就将问题的研究方向变为了怎么生成dependencies包,我也跟网上找了很多方法都没有作用,后面我决定换一个pom.xml文件,具体如下:

<build> <finalName>sm2test</finalName><!--修改编译出来的jar包名,仅为{artifactId}.jar--> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>2.5.5</version> <executions> <execution> <phase>package</phase> <goals> <goal>single</goal> </goals> <configuration> <archive> <manifest> <mainClass> sm2.sm2_demo </mainClass> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </execution> </executions> </plugin> </plugins> </build>

从这个pom.xml文件就可以看出来,我加了一项

<phase>package</phase> <goals> <goal>single</goal> </goals>

然后就成功生成了 jar-with-dependencies.jar

后面在网上也了解学习到了此插件的一些知识:

此插件使用内置的Assembly Descriptor
要使用maven-assembly-plugin,需要指定至少一个要使用的assembly descriptor 文件。默认情况下,maven-assembly-plugin内置了几个可以用的assembly descriptor:

bin : 类似于默认打包,会将bin目录下的文件打到包中;
jar-with-dependencies : 会将所有依赖都解压打包到生成物中;
src :只将源码目录下的文件打包;
project : 将整个project资源打包。

此外要想生成一个带有依赖的包就应该要执行mvn package assembly:single,但由于我没有执行,然后我们加上的那段配置代码中就是代替了这段代码的作用,其中大致是创建一个phase容器,但是这个容器必须要有内容呀,那就是goal对象了,也就是single。一个goal可以链接多个phase,也可以不链接,但是phase必须要链接才行。
具体关于maven-assembly-plugin插件的知识可以看看下面这个链接的资料进行学习

assembly学习

4|2反思

在这次库的搭建过程中,虽然有组员提前已经做出来了,但是我所遇到的问题与他们截然不同,都很奇怪,他们能执行的命令我不能执行,我只能用其他的方式来实现同一效果(就比如那个assembly:single我就识别不了),虽然花费了挺多时间但是我觉得还是有所收获的,不管是对于maven的学习还是对于maven-assembly-plugin插件的学习都更加深刻了,也对bouncycastle算法库有了一些了解。但是我觉得自己的自学能力还有待提高,自己应该去探索去提高自己的自学能力,也希望自己未来能在自学能力方面能得到更好的提高吧!


__EOF__

本文作者:userName
本文链接:https://www.cnblogs.com/1314xhuan/p/16947347.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐】一下。您的鼓励是博主的最大动力!
 
 
posted @ 2024-01-10 18:10  Sam Xiao  阅读(3795)  评论(0)    收藏  举报