java中使用sm3算法获取文件hash值

需求背景

工作中需要使用国密算法获取文件hash值做安全校验。

依赖安装 

在pom中添加hutool依赖,注意,只有5.x版本才会有SM3算法支持。

 <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.8.16</version>
 </dependency>
 <!-- BouncyCastle 加密库 -->
 <dependency>
     <groupId>org.bouncycastle</groupId>
     <artifactId>bcpkix-jdk15on</artifactId>
     <version>1.70</version>
 </dependency>
 <dependency>
     <groupId>org.bouncycastle</groupId>
     <artifactId>bcprov-jdk15on</artifactId>
     <version>1.70</version>
 </dependency>

代码实现

下面代码是最终版可成功运行的,踩过的坑在下面会介绍,如果能给大家遇到问题时带来一些启发就更好了。

    // 静态方法进行手动注册
    static {
        // 注册BouncyCastle Provider以支持SM3算法
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
            Security.addProvider(new BouncyCastleProvider());
            log.info("BouncyCastle Provider已注册");
        }
    }


    /**
     * 使用SM3算法计算文件的hash值
     * @param filePath 文件路径
     * @return SM3 hash值(十六进制字符串)
     */
    public static String calculateSM3Hash(String filePath) {
        try {
            File file = new File(filePath);
            if (!file.exists() || !file.isFile()) {
                log.error("文件不存在或不是有效文件: {}", filePath);
                return null;
            }
            
            SM3 sm3 = new SM3();
            String hash = sm3.digestHex(file);
            log.info("文件 {} 的SM3 hash值: {}", filePath, hash);
            return hash;
        } catch (Exception e) {
            log.error("计算文件SM3 hash值失败: {}, 错误信息: {}", filePath, e.getMessage(), e);
            // 打印可用的Provider信息用于调试
            log.error("当前可用的Security Providers:");
            for (java.security.Provider provider : Security.getProviders()) {
                log.error("Provider: {} - {}", provider.getName(), provider.getVersion());
            }
            return null;
        }
    }

    /**
     * 使用SM3算法计算文件的hash值
     * @param file 文件对象
     * @return SM3 hash值(十六进制字符串)
     */
    public static String calculateSM3Hash(File file) {
        try {
            if (file == null || !file.exists() || !file.isFile()) {
                log.error("文件对象为null或文件不存在或不是有效文件");
                return null;
            }
            
            SM3 sm3 = new SM3();
            String hash = sm3.digestHex(file);
            log.info("文件 {} 的SM3 hash值: {}", file.getAbsolutePath(), hash);
            return hash;
        } catch (Exception e) {
            log.error("计算文件SM3 hash值失败, 错误信息: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 使用SM3算法计算输入流的hash值
     * @param inputStream 输入流
     * @return SM3 hash值(十六进制字符串)
     */
    public static String calculateSM3Hash(InputStream inputStream) {
        try {
            if (inputStream == null) {
                log.error("输入流为null");
                return null;
            }
            
            SM3 sm3 = new SM3();
            String hash = sm3.digestHex(inputStream);
            log.info("输入流的SM3 hash值: {}", hash);
            return hash;
        } catch (Exception e) {
            log.error("计算输入流SM3 hash值失败, 错误信息: {}", e.getMessage(), e);
            return null;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("关闭输入流失败: {}", e.getMessage(), e);
                }
            }
        }
    }

遇到问题

运行时首先遇到:No  SuchAlgorithemExcepetion: no such algorithm:  SM3 for provider BC

初步判断原因:项目中没有BouncyCastle依赖,需要添加。添加 BouncyCastle依赖,最开始只有hutool依赖,添加完BouncyCastle依赖后需要在static方法中对Provider进行手动注册,修改完后运行还是会报这个错。

百度问题的时候发现了一位前辈发的博文,写的特别清晰:no such algorithm:sm4 for provider BC报错解决方法_no such algorithm: sm4 for provider bc-优快云博客

参考前辈的问题排查方法,在calculateSM3Hash方法中打印了一下BouncyCastleProvider的版本,果然版本打印为1.38,并非我后面引入的高版本,然后排查项目依赖,发现有其它一个依赖中依赖了1.38的低版本,将低版本排除掉就OK了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值