国密算法SM2/3/4简单比较,以及基于Java的SM4(ECB模式,CBC模式)对称加解密实现

这篇具有很好参考价值的文章主要介绍了国密算法SM2/3/4简单比较,以及基于Java的SM4(ECB模式,CBC模式)对称加解密实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

常用的国密算法包含SM2,SM3,SM4。以下针对每个算法使用场景进行说明以比较其差异

  • SM2:非对称加密算法,可以替代RSA
    • 数字签名,SM2为非对称加密,加解密使用一对私钥和公钥,只有签名发行者拥有私钥,可用于加密,其他需要验证解密或验签者使用公钥进行。如果使用公钥可以成功解密,则可以确定数据、文档或其他数字资产的拥有者。
    • 因性能问题,根据实际需要常用于小体积数据加密,例如对密钥或SM3生成的hash进行加密。针对SM3生成的hash值进行加密也是一种常用的签名方式,一般先对需要签名的数据、文档或数字资产使用SM3生成hash再用SM2进行签名。

             注:

             如果用于加密,那么加密是用公钥进行的,解密是用私钥进行的。

             如果用于数字签名,那么签名是用私钥进行的,验证签名则使用公钥。

  • SM3:散列哈希算法
    • 数据库中用户密码的保存,获取用户输入明文密码后,进行SM3生成hash值,再与数据库中保存的已经过SM3计算后的密码值进行比对。
    • 数据完整性验证,针对数据、文件或数据资产进行SM3生成hash并保存,在需要验证数据是否被修改时重新生成hash并与之前保存的hash值进行比对,一旦文件有被修改则会生成不同的hash值。例如可以针对数据库中关键数据字段进行hash,并保存。然后可以通过遍历定期验证hash是否一致,来发现被篡改的数据。
  • SM4:对称加密算法,性能比SM2好
    • 可以用于一般数据的加密与解密,例如可以在需要网络传输的数据发送前进行加密,对方收到数据后使用相同密钥进行解密获得明文。

基于Java的SM4(ECB模式,CBC模式)对称加解密实现

简单说明:加密算法依赖了groupId:org.bouncycastle中的bcprov-jdk15to18,Bouncy Castle (bcprov-jdk15to18)提供了JDK 1.5 to 1.8可使用的大量标准加密算法实现,其中包含了SM2,SM3,SM4。在这个类库基础上实现了一个SM4Util加解密工具类。注意: 此版本我在JDK1.8环境下,不同版本JDK需要找到匹配的依赖版本1.8及以上可以使用bcprov-jdk18on。Bouncy Castle同时也提供了bcutil-jdk15to18可以实现SM4加解密。

方式一:依赖bcprov-jdk15to18(以ECB模式为例) 注如果用jdk1.8的话使用bcprov-jdk18on比bcprov-jdk15to18的加密性能要好。

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15to18</artifactId>
    <version>1.77</version>
</dependency>

字节数组处理工具类: 

public class ByteUtils {

    private static final char[] HEX_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e',
            'f' };

    private ByteUtils() {
        // Utility class
    }

    public static byte[] fromHexString(String s) {
        int len = s.length();
        //
        // // Data length must be even
        // if (len % 2 != 0) {
        // throw new IllegalArgumentException("Hex string has an odd number of
        // characters");
        // }

        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }



    public static String toHexString(byte[] input) {
        StringBuilder sb = new StringBuilder();
        for (byte b : input) {
            sb.append(HEX_CHARS[(b >>> 4) & 0x0f]);
            sb.append(HEX_CHARS[b & 0x0f]);
        }
        return sb.toString();
    }


    public static String toHexString(byte[] input, String prefix, String separator) {
        StringBuilder sb = new StringBuilder(prefix);
        for (int i = 0; i < input.length; i++) {
            sb.append(HEX_CHARS[(input[i] >>> 4) & 0x0f]);
            sb.append(HEX_CHARS[input[i] & 0x0f]);
            if (i < input.length - 1) {
                sb.append(separator);
            }
        }
        return sb.toString();
    }

}

 加解密工具类:

import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class Sm4Utils {
    static {
        Security.addProvider(new BouncyCastleProvider());
    }
    private static final String ENCODING = "UTF-8";
    public static final String ALGORIGTHM_NAME = "SM4";
    public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS7Padding";
    public static final int DEFAULT_KEY_SIZE = 128;

    private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception {
        Cipher cipher = Cipher.getInstance(algorithmName, "BC");
        Key sm4Key = new SecretKeySpec(key, ALGORIGTHM_NAME);
        cipher.init(mode, sm4Key);
        return cipher;
    }

    public static byte[] generateKey(String keyString) throws Exception {
        // Use SHA-256 to hash the string and then take first 128 bits (16 bytes)
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest(keyString.getBytes(StandardCharsets.UTF_8));
        byte[] key = new byte[16];
        System.arraycopy(hash, 0, key, 0, 16);
        return key;
    }

     public static String encryptEcb(String key, String paramStr, String charset) throws Exception {
        String cipherText = "";
        if (null != paramStr && !"".equals(paramStr)) {
            byte[] keyData = generateKey(key);
            charset = charset.trim();
            if (charset.length() <= 0) {
                charset = ENCODING;
            }
            byte[] srcData = paramStr.getBytes(charset);
            byte[] cipherArray = encryptEcbPadding(keyData, srcData);
            cipherText = ByteUtils.toHexString(cipherArray);
        }

        return cipherText;
    }

    public static byte[] encryptEcbPadding(byte[] key, byte[] data) throws Exception {
        Cipher cipher = generateEcbCipher("SM4/ECB/PKCS7Padding", Cipher.ENCRYPT_MODE, key);
        byte[] bs = cipher.doFinal(data);
        return bs;
    }

    public static String decryptEcb(String key, String cipherText, String charset) throws Exception {
        String decryptStr = "";
        byte[] keyData = generateKey(key);
        byte[] cipherData = ByteUtils.fromHexString(cipherText);
        byte[] srcData = decryptEcbPadding(keyData, cipherData);
        charset = charset.trim();
        if (charset.length() <= 0) {
            charset = ENCODING;
        }

        decryptStr = new String(srcData, charset);
        return decryptStr;
    }

    public static byte[] decryptEcbPadding(byte[] key, byte[] cipherText) throws Exception {
        Cipher cipher = generateEcbCipher("SM4/ECB/PKCS7Padding", Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(cipherText);
    }

    public static void main(String[] args) {
        try {
            String json = "311111190001010001";
            String key = "test";
            String cipher = encryptEcb(key, json, ENCODING);
            System.out.println(cipher);
            System.out.println(decryptEcb(key, cipher, ENCODING));
        } catch (Exception var5) {
            var5.printStackTrace();
        }

    }
}

方式二:依赖bcprov-jdk15to18(以CBC模式为例),代码根据GPT-4生成修改调试,可运行。文章来源地址https://www.toymoban.com/news/detail-849916.html

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15to18</artifactId>
    <version>1.77</version>
</dependency>

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.engines.SM4Engine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.modes.CBCModeCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.Security;
import java.util.Arrays;

public class SM4Example {
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static byte[] encrypt(byte[] key, byte[] iv, byte[] data) throws Exception {
        SM4Engine engine = new SM4Engine();
        CBCModeCipher cbcBlockCipher = CBCBlockCipher.newInstance(engine);
        PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(cbcBlockCipher);
        CipherParameters params = new ParametersWithIV(new KeyParameter(key), iv);
        cipher.init(true, params);

        byte[] temp = new byte[cipher.getOutputSize(data.length)];
        int len = cipher.processBytes(data, 0, data.length, temp, 0);
        len += cipher.doFinal(temp, len);

        byte[] out = new byte[len];
        System.arraycopy(temp, 0, out, 0, len);
        return out;
    }

    public static byte[] decrypt(byte[] key, byte[] iv, byte[] data) throws Exception {
        SM4Engine engine = new SM4Engine();
        CBCModeCipher cbcBlockCipher = CBCBlockCipher.newInstance(engine);
        PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(cbcBlockCipher);
        CipherParameters params = new ParametersWithIV(new KeyParameter(key), iv);
        cipher.init(false, params);

        byte[] temp = new byte[cipher.getOutputSize(data.length)];
        int len = cipher.processBytes(data, 0, data.length, temp, 0);
        len += cipher.doFinal(temp, len);

        byte[] out = new byte[len];
        System.arraycopy(temp, 0, out, 0, len);
        return out;
    }

    public static void main(String[] args) throws Exception {
        byte[] key = "0123456789abcdef".getBytes(); // 16-byte key for SM4
        byte[] iv = "abcdef9876543210".getBytes(); // 16-byte IV for CBC mode
        byte[] dataToEncrypt = "Hello, Bouncy Castle SM4!".getBytes();

        byte[] encryptedData = encrypt(key, iv, dataToEncrypt);
        System.out.println("Encrypted Data: " + java.util.Base64.getEncoder().encodeToString(encryptedData));

        byte[] decryptedData = decrypt(key, iv, encryptedData);
        System.out.println("Decrypted Data: " + new String(decryptedData));
    }
}

到了这里,关于国密算法SM2/3/4简单比较,以及基于Java的SM4(ECB模式,CBC模式)对称加解密实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Delphi SM2/SM4国密算法

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

    2024年02月11日
    浏览(35)
  • 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日
    浏览(31)
  • vue普通加密以及国密SM2、SM3、sm4的使用

    sm-crypto:https://www.npmjs.com/package/sm-crypto 1. SM2是非对称加密算法 它是基于椭圆曲线密码的公钥密码算法标准,其秘钥长度256bit,包含数字签名、密钥交换和公钥加密,用于替换RSA/DH/ECDSA/ECDH等国际算法。可以满足电子认证服务系统等应用需求,由国家密码管理局于2010年12月17号

    2023年04月09日
    浏览(22)
  • 国密算法概述、及算法的集成应用(sm2、sm3、sm4)

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

    2024年02月14日
    浏览(35)
  • 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日
    浏览(27)
  • vue中使用国密算法SM2、SM3、SM4

    gm-crypto相关文档:https://gitcode.net/mirrors/byte-fe/gm-crypto?utm_source=csdn_github_accelerator vue3+element ui例子:https://gitee.com/huanglgln/vue-sys-manage-el  vue3+view ui例子:https://gitee.com/huanglgln/vue-sys-manage  vue3+Ant Design Vue ui例子:https://gitee.com/huanglgln/vue-sys-manage-adv 

    2024年02月15日
    浏览(26)
  • Python实现国家商用密码算法sm2/sm3/sm4/sm9(国密)

    2010 年开始,我国国家密码管理局就已经开始陆续发布了一系列国产加密算法,这其中就包括 SM1、SM2、SM3 、SM4、SM7、SM9、ZUC(祖冲之加密算法)等,SM 代表商密,即商业密码,是指用于商业的、不涉及国家秘密的密码技术。SM1 和 SM7 的算法不公开,其余算法都已成为 ISO/IEC

    2024年02月15日
    浏览(23)
  • 新手入门 | 掌握国密算法:新手指南: SM2 / SM3 / SM4密码算法详解

    在密码学领域,有多种加密与签名算法,它们在信息安全领域发挥着举足轻重的作用。如今,随着互联网的快速发展,网络安全已经成为各类信息系统完整性、可用性、保密性的重要保障,越来越多的国产密码算法得到了广泛的应用与关注。在本文中,我们将重点介绍三个经

    2024年02月12日
    浏览(109)
  • java实现国密SM4的加密和解密方式(即时通讯的消息对话加密采用SM2还是SM4)

    1.对于即时通讯的消息对话加密采用SM2还是SM4更合适? 对于即时通讯的消息对话加密,建议采用SM4对称加密算法,而不是SM2非对称加密算法。 SM2主要用于数字签名和密钥交换,其加密速度比SM4慢,而且SM2不太适合对长消息进行加密,因为它只能对比较短的数据块进行加密,这

    2024年02月07日
    浏览(50)
  • react+vue 前端国密算法sm2、sm3 、sm4的js ts实现

    1. 简单介绍下SM2 和 SM3 SM2 算法:是一种公钥加密算法,它的密钥长度为 256 位,安全性较高。可用于数字签名、密钥协商等场景。 SM3 算法:是一种对称加密算法,用于消息摘要和数字签名等场景。它的密钥长度为 256 位,安全性较高。SM3 算法与 SM2 算法相互配合,提高了整体

    2024年01月19日
    浏览(28)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包