返回顶部
首页 > 资讯 > 后端开发 > Python >Java实现国产加密算法SM4的示例详解
  • 896
分享到

Java实现国产加密算法SM4的示例详解

Python 官方文档:入门教程 => 点击学习

摘要

目录国产SM4加密解密算法概念1.SM4/ECB/PKCS5Padding2.SM4/CBC/PKCS5Padding国产SM4加密解密算法概念 SMS4算法是在国内广泛使用的Wap

国产SM4加密解密算法概念

SMS4算法是在国内广泛使用的Wapi无线网络标准中使用的加密算法,是一种32轮的迭代非平衡Feistel结构的分组加密算法,其密钥长度和分组长度均为128。SMS4算法的加解密过程中使用的算法是完全相同的,唯一不同点在于该算法的解密密钥是由它的加密密钥进行逆序变换后得到的。

SMS4分组加密算法是中国无线标准中使用的分组加密算法,在2012年已经被国家商用密码管理局确定为国家密码行业标准,标准编号GM/T 0002-2012并且改名为SM4算法,与SM2椭圆曲线公钥密码算法,SM3密码杂凑算法共同作为国家密码的行业标准,在我国密码行业中有着极其重要的位置。

SMS4算法的分组长度为128bit,密钥长度也是128bit。加解密算法均采用32轮非平衡Feistel迭代结构,该结构最先出现在分组密码LOKI的密钥扩展算法中。

SMS4通过32轮非线性迭代后加上一个反序变换,这样只需要解密密钥是加密密钥的逆序,就能使得解密算法与加密算法保持一致。SMS4加解密算法的结构完全相同,只是在使用轮密钥时解密密钥是加密密钥的逆序。

S盒是一种利用非线性变换构造的分组密码的一个组件,主要是为了实现分组密码过程中的混淆的特性和设计的。SMS4算法中的S盒在设计之初完全按照欧美分组密码的设计标准进行,它采用的方法是能够很好抵抗差值攻击的仿射函数逆映射复合法。

1.SM4/ECB/PKCS5Padding

实现代码

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.bouncycastle.util.encoders.Hex;
 
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecreTKEySpec;
import java.security.Key;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Arrays;
 

public final class Sm4Utils {
 
    static {
        Security.addProvider(new BouncyCastleProvider());
    }
 
    private static final String ENcoding = "UTF-8";
    public static final String ALGoRITHM_NAME = "SM4";
    // 加密算法/分组加密模式/分组填充方式
    // PKCS5Padding-以8个字节为一组进行分组加密
    // 定义分组加密模式使用:PKCS5Padding
    public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding";
    // 128-32位16进制;256-64位16进制
    public static final int DEFAULT_KEY_SIZE = 128;
 
    
    public static String generateKey() throws Exception {
        return new String(Hex.encode(generateKey(DEFAULT_KEY_SIZE)));
    }
 
    
    public static byte[] generateKey(int keySize) throws Exception {
        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
        kg.init(keySize, new SecureRandom());
        return kg.generateKey().getEncoded();
    }
 
    
    private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception {
        Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
        Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
        cipher.init(mode, sm4Key);
        return cipher;
    }
 
    
    public static String encryptEcb(String hexKey, String paramStr) {
        try {
            String cipherText = "";
            // 16进制字符串-->byte[]
            byte[] keyData = ByteUtils.fromHexString(hexKey);
            // String-->byte[]
            byte[] srcData = paramStr.getBytes(ENCODING);
            // 加密后的数组
            byte[] cipherArray = encryptEcbPadding(keyData, srcData);
            // byte[]-->hexString
            cipherText = ByteUtils.toHexString(cipherArray);
            return cipherText;
        } catch (Exception e) {
            return paramStr;
        }
    }
 
    
    public static byte[] encryptEcbPadding(byte[] key, byte[] data) throws Exception {
        Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(data);
    }
 
    
    public static String decryptEcb(String hexKey, String cipherText) {
        // 用于接收解密后的字符串
        String decryptStr = "";
        // hexString-->byte[]
        byte[] keyData = ByteUtils.fromHexString(hexKey);
        // hexString-->byte[]
        byte[] cipherData = ByteUtils.fromHexString(cipherText);
        // 解密
        byte[] srcData = new byte[0];
        try {
            srcData = decryptEcbPadding(keyData, cipherData);
            // byte[]-->String
            decryptStr = new String(srcData, ENCODING);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return decryptStr;
    }
 
    
    public static byte[] decryptEcbPadding(byte[] key, byte[] cipherText) throws Exception {
        Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(cipherText);
    }
 
    
    public static boolean verifyEcb(String hexKey, String cipherText, String paramStr) throws Exception {
        // 用于接收校验结果
        boolean flag = false;
        // hexString-->byte[]
        byte[] keyData = ByteUtils.fromHexString(hexKey);
        // 将16进制字符串转换成数组
        byte[] cipherData = ByteUtils.fromHexString(cipherText);
        // 解密
        byte[] decryptData = decryptEcbPadding(keyData, cipherData);
        // 将原字符串转换成byte[]
        byte[] srcData = paramStr.getBytes(ENCODING);
        // 判断2个数组是否一致
        flag = Arrays.equals(decryptData, srcData);
        return flag;
    }
 
    public static void main(String[] args) {
        try {
            String paramStr = "Hello, world";
            System.out.println("==========加密前源数据==========");
            System.out.println(paramStr);
            // 生成32位16进制密钥
            String key = Sm4Utils.generateKey();
            System.out.println("==========生成key==========");
            System.out.println(key);
            String cipher = Sm4Utils.encryptEcb(key, paramStr);
            System.out.println("==========加密串==========");
            System.out.println(cipher);
            System.out.println("==========是否为同一数据==========");
            System.out.println(Sm4Utils.verifyEcb(key, cipher, paramStr));
            paramStr = Sm4Utils.decryptEcb(key, cipher);
            System.out.println("==========解密后数据==========");
            System.out.println(paramStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果如下:

2.SM4/CBC/PKCS5Padding

示例代码

<dependency>
   <groupId>org.bouncycastle</groupId>
   <artifactId>bcprov-jdk15to18</artifactId>
   <version>1.68</version>
</dependency>
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
 
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Arrays;
 

public final class Sm4Util {
 
    static {
        Security.addProvider(new BouncyCastleProvider());
    }
 
    private static final String ENCODING = "UTF-8";
 
    public static final String ALGORITHM_NAME = "SM4";
    // 加密算法/分组加密模式/分组填充方式
    // PKCS5Padding-以8个字节为一组进行分组加密
    // 定义分组加密模式使用:PKCS5Padding
 
    public static final String ALGORITHM_NAME_CBC_PADDING = "SM4/CBC/PKCS5Padding";
    // 128-32位16进制;256-64位16进制
    public static final int DEFAULT_KEY_SIZE = 128;
 
    
    public static byte[] generateKey() throws Exception {
        return generateKey(DEFAULT_KEY_SIZE);
    }
 
 
    
    public static String generateKeyString() throws Exception {
        return ByteUtils.toHexString(generateKey());
    }
 
    
    public static byte[] generateKey(int keySize) throws Exception {
        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
        kg.init(keySize, new SecureRandom());
        return kg.generateKey().getEncoded();
    }
 
    
    public static String encrypt(String hexKey, String paramStr) throws Exception {
        String result = "";
        // 16进制字符串-->byte[]
        byte[] keyData = ByteUtils.fromHexString(hexKey);
        // String-->byte[]
        byte[] srcData = paramStr.getBytes(ENCODING);
        // 加密后的数组
        byte[] cipherArray = encryptCbcPadding(keyData, srcData);
 
        // byte[]-->hexString
        result = ByteUtils.toHexString(cipherArray);
        return result;
    }
 
    
    public static byte[] encryptCbcPadding(byte[] key, byte[] data) throws Exception {
        Cipher cipher = generateCbcCipher(ALGORITHM_NAME_CBC_PADDING, Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(data);
    }
 
    
    private static Cipher generateCbcCipher(String algorithmName, int mode, byte[] key) throws Exception {
        Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
        Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
        cipher.init(mode, sm4Key, generateIV());
        return cipher;
    }
 
    
    public static AlgorithmParameters generateIV() throws Exception {
        //iv 为一个 16 字节的数组,这里采用和 iOS 端一样的构造方法,数据全为0
        byte[] iv = new byte[16];
        Arrays.fill(iv, (byte) 0x00);
        AlgorithmParameters params = AlgorithmParameters.getInstance(ALGORITHM_NAME);
        params.init(new IvParameterSpec(iv));
        return params;
    }
 
    
    public static String decrypt(String hexKey, String text) throws Exception {
        // 用于接收解密后的字符串
        String result = "";
        // hexString-->byte[]
        byte[] keyData = ByteUtils.fromHexString(hexKey);
        // hexString-->byte[]
        byte[] resultData = ByteUtils.fromHexString(text);
        // 解密
        byte[] srcData = decryptCbcPadding(keyData, resultData);
        // byte[]-->String
        result = new String(srcData, ENCODING);
        return result;
    }
 
    
    public static byte[] decryptCbcPadding(byte[] key, byte[] cipherText) throws Exception {
        Cipher cipher = generateCbcCipher(ALGORITHM_NAME_CBC_PADDING, Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(cipherText);
    }
 
    public static void main(String[] args) throws Exception {
 
        String str = "Hello, world" ;
        System.out.println("==========生成密钥==========");
        String generateKey = generateKeyString();
        System.out.println(generateKey);
        System.out.println("==========加密==========");
        String encrypt = encrypt(generateKey, str);
        System.out.println(encrypt);
        System.out.println("==========解密==========");
        String decrypt = decrypt(generateKey, encrypt);
        System.out.println(decrypt);
    }
}

结果如下

到此这篇关于Java实现国产加密算法SM4的示例详解的文章就介绍到这了,更多相关Java加密算法SM4内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java实现国产加密算法SM4的示例详解

本文链接: https://lsjlt.com/news/178819.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作