JAVA集成国密SM4

news2024/11/24 22:41:54

JAVA集成国密SM4加解密

  • 一、pom配置
  • 二、代码集成
    • 2.1、目录结构
    • 2.2、源码
    • 2.3、测试
  • 三、遇到的坑
    • 3.1、秘钥长度
    • 3.2、转码问题
  • 四、相关链接

国密算法概述:https://blog.csdn.net/qq_38254635/article/details/131801527

SM4对称算法
SM4 无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位

一、pom配置

<!-- 国密 -->
<dependency>
	<groupId>org.bouncycastle</groupId>
	<artifactId>bcprov-jdk15to18</artifactId>
	<version>1.66</version>
</dependency>

二、代码集成

2.1、目录结构

在这里插入图片描述

2.2、源码

ConfigBean.java

package com.secret.sm4;

public class ConfigBean {

    /**
     * 秘钥空间大小
     */
    public static final int SM4_KEY_SIZE = 128;

    /**
     * 算法编号
     */
    public static final String ALGORITHM_NAME  = "SM4";

    /**
     * 首次加密初始向量  01030507090B0D0F11131517191B1D1F
     */
    public static final byte[] SM4_KEY_IV = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31 };

    /**
     * ECB模式串
     */
    public static final String ALGORITHM_ECB_PADDING = "SM4/ECB/PKCS5Padding";
    /**
     * CBC模式串
     */
    public static final String ALGORITHM_CBC_PADDING = "SM4/CBC/PKCS5Padding";

}

ProviderSingleton.java

package com.secret.sm4;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class ProviderSingleton {

    private static BouncyCastleProvider instance = null;

    private ProviderSingleton() {
    }

    private static synchronized void syncInit() {
        if (instance == null) {
            instance = new BouncyCastleProvider();
        }
    }

    public static BouncyCastleProvider getInstance() {
        if (instance == null) {
            syncInit();
        }
        return instance;
    }

}

SecretCommon.java

package com.secret.sm4;

import org.apache.tomcat.util.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;

/**
 * SM4分组对称密码算法(对称算法)
 * SM4分组密码算法是我国自主设计的分组对称密码算法,用于实现数据的加密/解密运算,以保证数据和信息的机密性。
 * 要保证一个对称密码算法的安全性的基本条件是其具备足够的密钥长度,SM4算法与AES算法具有相同的密钥长度分组长度128比特,因此在安全性上高于3DES算法。
 */
public class SecretCommon {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 生成秘钥
     */
    public static String generateKey() throws NoSuchAlgorithmException {
        return ByteUtils.toHexString(generateKeyByte(ConfigBean.SM4_KEY_SIZE, ProviderSingleton.getInstance()));
    }

    /**
     * 生成秘钥
     */
    public static String generateKeyBC() throws NoSuchProviderException, NoSuchAlgorithmException {
        return ByteUtils.toHexString(generateKeyByte(ConfigBean.SM4_KEY_SIZE, BouncyCastleProvider.PROVIDER_NAME));
    }

    public static byte[] generateKeyByte(int keySize, String var) throws NoSuchAlgorithmException, NoSuchProviderException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(ConfigBean.ALGORITHM_NAME, var);
        keyGenerator.init(keySize, new SecureRandom());
        return keyGenerator.generateKey().getEncoded();
    }

    public static byte[] generateKeyByte(int keySize, BouncyCastleProvider var) throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(ConfigBean.ALGORITHM_NAME, var);
        keyGenerator.init(keySize, new SecureRandom());
        return keyGenerator.generateKey().getEncoded();
    }

    /**
     * ECB模式,加密
     * @param plainText 明文字符串
     * @param keyText 秘钥内容
     */
    public static String encryptECB(String plainText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        return Base64.encodeBase64String(cipherECB(Cipher.ENCRYPT_MODE, plainText.getBytes(StandardCharsets.UTF_8), keyText.getBytes()));
    }

    /**
     * ECB模式,解密
     * @param cipherText 密文字符串
     * @param keyText 秘钥内容
     */
    public static String decryptECB(String cipherText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        return new String(cipherECB(Cipher.DECRYPT_MODE, Base64.decodeBase64(cipherText), keyText.getBytes()));
    }

    /**
     * ECB模式,加解密算法基础方法
     * @param mode 加解密模式 Cipher.ENCRYPT_MODE 1:加密/ Cipher.DECRYPT_MODE 2:解密
     * @param plainByte 需加密明文内容/待解密密文内容
     * @param keyByte 秘钥内容
     */
    public static byte[] cipherECB(int mode, byte[] plainByte, byte[] keyByte) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        Cipher cipher = Cipher.getInstance(ConfigBean.ALGORITHM_ECB_PADDING, ProviderSingleton.getInstance());
        cipher.init(mode, new SecretKeySpec(keyByte, ConfigBean.ALGORITHM_NAME));
        return cipher.doFinal(plainByte);
    }

    /**
     * CBC模式,加密
     * @param plainText 明文字符串
     * @param keyText 秘钥内容
     */
    public static String encryptCBC(String plainText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        return Base64.encodeBase64String(cipherCBC(Cipher.ENCRYPT_MODE, plainText.getBytes(StandardCharsets.UTF_8), keyText.getBytes()));
    }

    /**
     * CBC模式,解密
     * @param cipherText 密文字符串
     * @param keyText 秘钥内容
     */
    public static String decryptCBC(String cipherText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        return new String(cipherCBC(Cipher.DECRYPT_MODE, Base64.decodeBase64(cipherText), keyText.getBytes()));
    }

    /**
     * CBC模式,加解密算法基础方法
     * @param mode 加解密模式 Cipher.ENCRYPT_MODE 1:加密/ Cipher.DECRYPT_MODE 2:解密
     * @param plainByte 需加密明文内容/待解密密文内容
     * @param keyByte 秘钥内容
     */
    public static byte[] cipherCBC(int mode, byte[] plainByte, byte[] keyByte) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        Cipher cipher = Cipher.getInstance(ConfigBean.ALGORITHM_CBC_PADDING, ProviderSingleton.getInstance());
        cipher.init(mode, new SecretKeySpec(keyByte, ConfigBean.ALGORITHM_NAME), new IvParameterSpec(ConfigBean.SM4_KEY_IV));
        return cipher.doFinal(plainByte);
    }

}

Utils.java

package com.secret.sm4;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class Utils {

    /**
     * 生成秘钥
     */
    public static String generateKey() throws NoSuchAlgorithmException {
        return SecretCommon.generateKey().substring(0, 16);
    }

    /**
     * 默认加密方法(ECB)
     */
    public static String encrypt(String plainText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        return encryptECB(plainText, keyText);
    }

    /**
     * 默认解密方法(ECB)
     */
    public static String decrypt(String cipherText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        return decryptECB(cipherText, keyText);
    }

    /**
     * ECB模式,加密
     * @param plainText 明文字符串
     * @param keyText 秘钥内容
     */
    public static String encryptECB(String plainText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        return SecretCommon.encryptECB(plainText, keyText);
    }

    /**
     * ECB模式,解密
     * @param cipherText 密文字符串
     * @param keyText 秘钥内容
     */
    public static String decryptECB(String cipherText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        return SecretCommon.decryptECB(cipherText, keyText);
    }

    /**
     * CBC模式,加密
     * @param plainText 明文字符串
     * @param keyText 秘钥内容
     */
    public static String encryptCBC(String plainText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        return SecretCommon.encryptCBC(plainText, keyText);
    }

    /**
     * CBC模式,解密
     * @param cipherText 密文字符串
     * @param keyText 秘钥内容
     */
    public static String decryptCBC(String cipherText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        return SecretCommon.decryptCBC(cipherText, keyText);
    }

}

测试类:Test.java

package com.secret.sm4;

public class Test {

    public static void main(String[] args) throws Exception{
        String key = Utils.generateKey();
        System.out.println("生成SM4秘钥:" + key);

        String plainText = "Believe in yourself, you are the best";
        String ECBText = Utils.encrypt(plainText, key);
        System.out.println("ECB默认加密后密文:" + ECBText);
        System.out.println("ECB默认解密后明文:" + Utils.decrypt(ECBText, key));

        String CBCText = Utils.encryptCBC(plainText, key);
        System.out.println("CBC加密后密文:" + CBCText);
        System.out.println("CBC解密后明文:" + Utils.decryptCBC(CBCText, key));
    }

}

2.3、测试

在这里插入图片描述
使用方法参考测试类即可。

三、遇到的坑

3.1、秘钥长度

使用KeyGenerator构建的秘钥长度太长无法使用,会提示:
在这里插入图片描述
秘钥取16位即可使用。

3.2、转码问题

在使用 ECB模式 时,加解密都会报错,头大。

加密报错如下:

Exception in thread "main" java.lang.IllegalArgumentException: Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible value. Expected the discarded bits to be zero.
	at org.apache.tomcat.util.codec.binary.Base64.validateCharacter(Base64.java:429)
	at org.apache.tomcat.util.codec.binary.Base64.decode(Base64.java:671)
	at org.apache.tomcat.util.codec.binary.BaseNCodec.decode(BaseNCodec.java:362)
	at org.apache.tomcat.util.codec.binary.BaseNCodec.decode(BaseNCodec.java:353)
	at org.apache.tomcat.util.codec.binary.BaseNCodec.decode(BaseNCodec.java:379)
	at org.apache.tomcat.util.codec.binary.Base64.decodeBase64(Base64.java:172)
	at com.secret.sm4.SecretCommon.encryptECB(SecretCommon.java:64)
	at com.secret.sm4.Utils.encryptECB(Utils.java:39)
	at com.secret.sm4.Utils.encrypt(Utils.java:23)
	at com.secret.sm4.Test.main(Test.java:10)

在这里插入图片描述

解密报错如下:

Exception in thread "main" javax.crypto.BadPaddingException: pad block corrupted
	at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$BufferedGenericBlockCipher.doFinal(Unknown Source)
	at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source)
	at javax.crypto.Cipher.doFinal(Cipher.java:2165)
	at com.secret.sm4.SecretCommon.cipherECB(SecretCommon.java:85)
	at com.secret.sm4.SecretCommon.decryptECB(SecretCommon.java:73)
	at com.secret.sm4.Utils.decryptECB(Utils.java:48)
	at com.secret.sm4.Utils.decrypt(Utils.java:30)
	at com.secret.sm4.Test.main(Test.java:12)

在这里插入图片描述

查阅了资料才发现,是转byte[]数组的问题。

String plainText = "Believe in yourself, you are the best";
byte[] byte1 = plainText.getBytes();
byte[] byte2 = plainText.getBytes(StandardCharsets.UTF_8);
byte[] byte3 = Base64.decodeBase64(plainText);
byte[] byte4 = Hex.decode(plainText);
Base64.encodeBase64String()
new String()

测试的时候发现,同样是转byte[],不同的方法,可能结果会不一样,可以自行尝试验证。

加密的时候:
入参直接使用 getBytes()获取byte数组,返回参数使用 Base64.encodeBase64String()即可。
解密的时候:
入参使用 Base64.decodeBase64()获取byte数组,返回参数直接new String() 即可。

四、相关链接

国密算法概述:https://blog.csdn.net/qq_38254635/article/details/131801527

JAVA集成国密SM2:https://blog.csdn.net/qq_38254635/article/details/131810661

JAVA集成国密SM3:https://blog.csdn.net/qq_38254635/article/details/131810696

单例模式及多线程并发在单例模式中的影响:https://blog.csdn.net/qq_38254635/article/details/119888843

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/771988.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

线性表的链式存储结构以及顺序表和链表的比较

2.2线性表的链式存储结构 **链式存储结构&#xff1a;**结点在存储器中的位置是任意的&#xff0c;即逻辑上相邻的数据元素在物理上不一定相邻。 线性表的链式表示又称为非顺序映像或链式映像 这组存储单元既可以是连续的&#xff0c;也可以是不连续的&#xff0c;甚至是零散…

C++基础算法前缀和和差分篇

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;C算法 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 主要讲解了前缀和和差分算法 文章目录 Ⅳ. 前缀和 和 差分Ⅵ .Ⅰ前缀和…

AtcoderABC244场

A - Last LetterA - Last Letter 题目大意 给定一个长度为N的字符串S&#xff0c;由小写英文字母组成&#xff0c;打印出S的最后一个字符。 思路分析 题目要求打印出字符串S的最后一个字符&#xff0c;可以直接通过访问S的最后一个元素来获取该字符。可以使用字符串的back()…

旅游卡小程序软件招商加盟代理

旅游卡小程序软件招商加盟代理 我国人民生活水平的提高&#xff0c;旅游业成为了人们生活中必不可少的一部分。旅游卡小程序软件作为旅游行业的重要组成部分&#xff0c;也日益受到人们的关注。如今&#xff0c;旅游卡小程序软件招商加盟代理已经成为了一个热门的投资创业项…

$.getScript()方法获取js文件

通过$.getScript(‘xxxx.js’)获取xxxx.js文件&#xff0c;这时的ajax是一个get请求的状态&#xff0c;如果进行了入参data的赋值那么他就会跟在url后面,同理获取json文件&#xff0c;css文件。 一开始没想起这茬。。。

使用PostgreSQL创建高级搜索引擎

​本文我们将探索PostgreSQL中的全文搜索功能&#xff0c;并研究我们能够复制多少典型搜索引擎功能。 如果您想跟随并尝试示例查询&#xff08;我们建议这样做&#xff0c;这样更有趣&#xff09;&#xff0c;可以使用来自Kaggle的Wikipedia电影情节数据集执行代码示例。要导入…

C++day4 (拷贝构造函数、拷贝赋值函数、匿名对象、友元函数、常成员函数、常对象、运算符重载)

#include <iostream> #include <cstring> using namespace std;class mystring { private:char *str; //记录C风格字符串int size; //记录字符串的实际长度public://无参构造mystring():size(10){strnew char[size];//构造出一个长度为10的字符串strcpy(str,&…

第七章嵌套矢量中断控制器(Cortex-M7 Processor)

目录 第七章嵌套矢量中断控制器 7.1关于NVIC 7.2NVIC功能描述 7.2.1低功耗模式 7.2.2电平与脉冲中断 7.3NVIC程序员模型 7.3.1中断控制器类型寄存器 第七章嵌套矢量中断控制器 本章描述了嵌套矢量中断控制器(NVIC)。它包含以下部分: 关于NVIC在7-2页。NVIC功能描述见第7-…

【软考】系统架构设计风格分类的个人理解

个人适当学习了软考系统架构设计师中关于系统架构设计相关的内容&#xff0c;梳理了一下相关信息。 常见架构类型和常见分类 常见的软考中出现的系统架构列举如下&#xff1a; 分层架构管道-过滤器架构客户端-服务器架构模型-视图-控制器架构&#xff0c;即MVC架构事件驱动架…

Meta 最新发布 LLaMA 2(允许商业化)

文章目录 Llama 2 模型介绍Llama 2的核心点Llama 2的测评结果Llama 2的预训练预处理数据预训练设置和模型架构 Llama-2-chat 模型介绍Llama-2-chat 模型在帮助性和安全性上的表现Llama-2-chat 模型的训练过程 Llama 2 模型介绍 2023年7月18日&#xff0c;Meta 发布了Llama 2&a…

字节跳动后端面试,笔试部分

背景 笔者在刷B站的时候&#xff0c;看到了一个关于面试的实录&#xff0c;前半段是八股文&#xff0c;后半段是笔试部分&#xff0c;感觉笔试部分的题目还是挺有意思的&#xff0c;特此记录一下。 笔试部分 问题1&#xff1a;SQL 这题考的是 union all 的用法&#xff0c;在…

流程工业停机的实际成本

流程制造工厂面临着避免停机的巨大压力&#xff0c;因为这可能会严重影响企业的整体生产力、盈利能力和声誉。企业对计划外停机的原因和成本了解得越多&#xff0c;就能做更多的事情来帮助降低停机的发生率&#xff0c;并在停机发生时更好地做好应对准备。 图.石油炼化工厂&…

在Redis主从系统中使用哨兵

一、什么是哨兵 Redis的哨兵&#xff08;Sentinel&#xff09;是Redis分布式系统中的一种特殊角色&#xff0c;用于监控和管理Redis主从复制架构中的主节点&#xff08;master&#xff09;和从节点&#xff08;slave&#xff09;。 哨兵的主要功能是确保Redis系统的高可用性。它…

学校教室巡课,为何你总是出错?

教育是社会进步和个人发展的重要基石&#xff0c;而教师的教学质量和专业能力直接关系着教育的成效和学生的学习成果。为了促进教师的专业发展和提高教学质量&#xff0c;在线巡课系统应运而生。 通过在线巡课系统&#xff0c;巡课者可以远程观察教师的授课过程&#xff0c;并提…

Hugging Face开源库accelerate详解

官网&#xff1a;https://huggingface.co/docs/accelerate/package_reference/accelerator Accelerate使用步骤 初始化accelerate对象accelerator Accelerator()调用prepare方法对model、dataloader、optimizer、lr_schedluer进行预处理删除掉代码中关于gpu的操作&#xff0…

使用Jmeter做性能测试的注意点

目录 一、性能测试注意点 二、性能指标分析 一、性能测试注意点 1. 用jmeter测试时使用BeanShell脚本获取随机参数值&#xff0c;会导致请求时间过长&#xff0c;TPS过低。应改为使用csv读取参数值&#xff0c;记录的TPS会更加准确。 注&#xff1a;进行性能测试时&#xff0…

EMC学习笔记(十七)PCB设计中的安规考虑

PCB设计中的安规考虑 1 概述2.安全标识2.1 对安全标示通用准则2.2 电击和能量的危险2.3 PCB上的熔断器2.4 可更换电池 3.爬电距离和电气间隙4.涂覆印制板4.1 PCB板的机械强度4.2 印制电路板的阻燃等级4.3 热循环试验与热老化试验4.4 抗电强度试验4.5 耐划痕试验 5.布线和供电 1…

C# 属性

文章目录 实例属性静态属性只读属性&#xff1a;内部只读属性&#xff1a;动态计算值的属性方式一&#xff1a;主动计算方式二&#xff1a;被动计算 快速生成属性的方法&#xff1a;输入propfull&#xff0c;按两下tab键&#xff0c;然后再按tab键一次修改有底纹的字段&#xf…

LeetCode141.环形链表

141.环形链表 目录 141.环形链表一、哈希表二、双指针 一、哈希表 最容易想到的方法就是遍历所有节点&#xff0c;每次遍历到一个节点的时候&#xff0c;判断该节点此前是否被访问过 我们可以使用哈希表来存储所有已经访问过的节点 每次到达一个节点&#xff0c;如果该节点已…

Cyber Triage 3.7 (Windows) - 数字取证和事件响应

Cyber Triage 3.7 (Windows) - 数字取证和事件响应 请访问原文链接&#xff1a;https://sysin.org/blog/cybertriage-3&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 唯一专门用于事件响应的数字取证工具 快速、准确和简单地…