文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

JAVA集成国密SM4

2023-09-29 06:21

关注

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、目录结构

在这里插入图片描述

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";        public static final byte[] SM4_KEY_IV = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31 };        public static final String ALGORITHM_ECB_PADDING = "SM4/ECB/PKCS5Padding";        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;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();    }        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()));    }        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()));    }        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);    }        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()));    }        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()));    }        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);    }        public static String encrypt(String plainText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {        return encryptECB(plainText, keyText);    }        public static String decrypt(String cipherText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {        return decryptECB(cipherText, keyText);    }        public static String encryptECB(String plainText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {        return SecretCommon.encryptECB(plainText, keyText);    }        public static String decryptECB(String cipherText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {        return SecretCommon.decryptECB(cipherText, keyText);    }        public static String encryptCBC(String plainText, String keyText) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {        return SecretCommon.encryptCBC(plainText, 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 corruptedat 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

来源地址:https://blog.csdn.net/qq_38254635/article/details/131810715

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯