bouncycastle安装配置

bouncycastle简介

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

bouncycastle安装

环境搭建

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进行配置本地仓库。

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

安装bouncycastle

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

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

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

国密算法实现

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);
    }
}

运行结果:

导出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包得到以下结果

openEuler中运行jar包

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

方法二

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

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

创建项目文件夹

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

编译文件

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

运行文件

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

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

所遇问题及解决方法

  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学习

反思

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

posted @ 2022-12-03 21:35  20201325my  阅读(3070)  评论(0编辑  收藏  举报