JAVA集成国密SM4

这篇具有很好参考价值的文章主要介绍了JAVA集成国密SM4。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

国密算法概述: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、目录结构

java sm4,国密,SpringBoot,java,开发语言

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、测试

java sm4,国密,SpringBoot,java,开发语言
使用方法参考测试类即可。

三、遇到的坑

3.1、秘钥长度

使用KeyGenerator构建的秘钥长度太长无法使用,会提示:
java sm4,国密,SpringBoot,java,开发语言
秘钥取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)

java sm4,国密,SpringBoot,java,开发语言

解密报错如下:

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)

java sm4,国密,SpringBoot,java,开发语言

查阅了资料才发现,是转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文章来源地址https://www.toymoban.com/news/detail-690486.html

到了这里,关于JAVA集成国密SM4的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 国密算法SM2,SM3,SM4-java实现原理

    SM2是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法,基于ECC。其签名速度与秘钥生成速度都快于RSA,非对称加密,该算法已公开 SM3是中华人民共和国政府采用的一种密码散列函数标准,由国家密码管理局于2010年12月17日发布。SM3主要用数字签名及验证、消息认

    2024年02月13日
    浏览(40)
  • 国密算法概述、及算法的集成应用(sm2、sm3、sm4)

    由于项目的需求,需要集成国密加解密,于是对国密又温故知新了一遍。同时整理了一下国密的一些算法。 本文主要从国密相关算法的简介、应用系统的集成、工具类的封装等方面入手,对国密进行深入的学习。 为了保障商用密码的安全性,国家密码局制定了一系列密码标

    2024年02月14日
    浏览(72)
  • 使用 Java Bouncy Castle实现国密算法SM4、SM3以及SM2的加密

    国密算法的实现借助了Java库函数 Bouncy Castle,加密库安装使用教程请参考链接 SM4,又称为商密算法,是一种分组密码算法,于2012年由中国密码技术研究中心(中国密码学会成员)发布,目前已成为我国国家密码算法,并在多个领域得到了广泛的应用。SM4算法采用了32轮迭代结

    2024年02月16日
    浏览(68)
  • java运用SM4国密算法对文件的加密与解密的实现

    首先我们在idae开发工具导入导入pom.xml的两个必要依赖  jar包下载地址:百度网盘 请输入提取码   npn8  图上systemPath 为jar包的文件路径,我们需要使用以下的路径存储jar包。(也可以自己设置) java包的文件路径如图所示 然后创建所需要加密的文件 ,需要加密的文件内容,

    2024年03月27日
    浏览(54)
  • SpringBoot实现国密SM4加密、解密

    SM4.0(原名SMS4.0)是中华人民共和国政府采用的一种分组密码标准,由国家密码管理局于2012年3月21日发布。相关标准为“GM/T 0002-2012《SM4分组密码算法》(原SMS4分组密码算法)”。 在商用密码体系中,SM4主要用于数据加密,其算法公开,分组长度与密钥长度均为128bit,加密算

    2024年02月07日
    浏览(63)
  • 国密算法SM2/3/4简单比较,以及基于Java的SM4(ECB模式,CBC模式)对称加解密实现

    常用的国密算法包含SM2,SM3,SM4。以下针对每个算法使用场景进行说明以比较其差异 SM2:非对称加密算法,可以替代RSA 数字签名,SM2为非对称加密,加解密使用一对私钥和公钥,只有签名发行者拥有私钥,可用于加密,其他需要验证解密或验签者使用公钥进行。如果使用公

    2024年04月13日
    浏览(41)
  • Delphi SM2/SM4国密算法

        最近忙个医保平台的项目,涉及SM2/SM4的签名,验签,加密,解密的业务操作过程。毕竟现在用Delpih的人不是很多,懂这方面的技术的人也更少,能涉及密码算法的少之更少,网上也能搜到一些开源的代码,也由于使用的人少,未加通过业务系统来验证,所以存在不少Bu

    2024年02月11日
    浏览(50)
  • vue前端国密SM2, SM4 算法实现

    整体加密逻辑是,首先生成16位key值 用SM2 公钥加密该key值,后端用sm2私钥 解密出key值,然后采用sm4方法根据key值对返回值进行加密,前端采用sm4 对后端返回结果进行解密进行前端展示 目前主要常用的国密算法有sm-crypto,gm-crypto,gm-crypt(SM4) 1、安装 sm-crypto 2、包装加解密

    2024年02月12日
    浏览(48)
  • 前端使用国密sm2和sm4进行加解密

    国密SM:国密算法,即国家商用密码算法。是由国家密码管理局认定和公布的密码算法标准及其应用规范,其中部分密码算法已经成为国际标准。如SM系列密码,SM代表商密,即商业密码,是指用于商业的、不涉及国家秘密的密码技术。 安装SM加密依赖 SM2 封装 将sm2的加密解密

    2024年02月08日
    浏览(60)
  • Go实现国密算法SM2、SM3、SM4

    SM2椭圆曲线公钥密码算法 Public key cryptographic algorithm SM2 based on elliptic curves 遵循的SM2标准号为: GM/T 0003.1-2012、GM/T 0003.2-2012、GM/T 0003.3-2012、GM/T 0003.4-2012、GM/T 0003.5-2012、GM/T 0009-2012、GM/T 0010-2012 依赖包: github.com/tjfoc/gmsm/sm2 SM3密码杂凑算法 - SM3 cryptographic hash algorithm 遵循的SM

    2024年02月15日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包