亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java實現(xiàn)國產(chǎn)加密算法SM4的示例詳解

 更新時間:2023年01月30日 15:38:47   作者:Ice_Blue_Bro  
這篇文章主要為大家詳細介紹了Java如何實現(xiàn)國產(chǎn)加密算法SM4(ECB和CBC兩種模式),文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下

國產(chǎn)SM4加密解密算法概念

SMS4算法是在國內(nèi)廣泛使用的WAPI無線網(wǎng)絡(luò)標準中使用的加密算法,是一種32輪的迭代非平衡Feistel結(jié)構(gòu)的分組加密算法,其密鑰長度和分組長度均為128。SMS4算法的加解密過程中使用的算法是完全相同的,唯一不同點在于該算法的解密密鑰是由它的加密密鑰進行逆序變換后得到的。

SMS4分組加密算法是中國無線標準中使用的分組加密算法,在2012年已經(jīng)被國家商用密碼管理局確定為國家密碼行業(yè)標準,標準編號GM/T 0002-2012并且改名為SM4算法,與SM2橢圓曲線公鑰密碼算法,SM3密碼雜湊算法共同作為國家密碼的行業(yè)標準,在我國密碼行業(yè)中有著極其重要的位置。

SMS4算法的分組長度為128bit,密鑰長度也是128bit。加解密算法均采用32輪非平衡Feistel迭代結(jié)構(gòu),該結(jié)構(gòu)最先出現(xiàn)在分組密碼LOKI的密鑰擴展算法中。

SMS4通過32輪非線性迭代后加上一個反序變換,這樣只需要解密密鑰是加密密鑰的逆序,就能使得解密算法與加密算法保持一致。SMS4加解密算法的結(jié)構(gòu)完全相同,只是在使用輪密鑰時解密密鑰是加密密鑰的逆序。

S盒是一種利用非線性變換構(gòu)造的分組密碼的一個組件,主要是為了實現(xiàn)分組密碼過程中的混淆的特性和設(shè)計的。SMS4算法中的S盒在設(shè)計之初完全按照歐美分組密碼的設(shè)計標準進行,它采用的方法是能夠很好抵抗差值攻擊的仿射函數(shù)逆映射復(fù)合法。

1.SM4/ECB/PKCS5Padding

實現(xiàn)代碼

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;
 
/**
 * Sm4 國密算法
 *
 */
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個字節(jié)為一組進行分組加密
    // 定義分組加密模式使用: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;
 
    /**
     * 自動生成密鑰
     *
     * @return
     * @explain
     */
    public static String generateKey() throws Exception {
        return new String(Hex.encode(generateKey(DEFAULT_KEY_SIZE)));
    }
 
    /**
     * @param keySize
     * @return
     * @throws Exception
     * @explain
     */
    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();
    }
 
    /**
     * 生成ECB暗號
     *
     * @param algorithmName 算法名稱
     * @param mode          模式
     * @param key
     * @return
     * @throws Exception
     * @explain ECB模式(電子密碼本模式:Electronic codebook)
     */
    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;
    }
 
    /**
     * sm4加密
     *
     * @param hexKey   16進制密鑰(忽略大小寫)
     * @param paramStr 待加密字符串
     * @return 返回16進制的加密字符串
     * @explain 加密模式:ECB
     * 密文長度不固定,會隨著被加密字符串長度的變化而變化
     */
    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);
            // 加密后的數(shù)組
            byte[] cipherArray = encryptEcbPadding(keyData, srcData);
            // byte[]-->hexString
            cipherText = ByteUtils.toHexString(cipherArray);
            return cipherText;
        } catch (Exception e) {
            return paramStr;
        }
    }
 
    /**
     * 加密模式之Ecb
     *
     * @param key
     * @param data
     * @return
     * @throws Exception
     * @explain
     */
    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);
    }
 
    /**
     * sm4解密
     *
     * @param hexKey     16進制密鑰
     * @param cipherText 16進制的加密字符串(忽略大小寫)
     * @return 解密后的字符串
     * @throws Exception
     * @explain 解密模式:采用ECB
     */
    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;
    }
 
    /**
     * 解密
     *
     * @param key
     * @param cipherText
     * @return
     * @throws Exception
     * @explain
     */
    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);
    }
 
    /**
     * 校驗加密前后的字符串是否為同一數(shù)據(jù)
     *
     * @param hexKey     16進制密鑰(忽略大小寫)
     * @param cipherText 16進制加密后的字符串
     * @param paramStr   加密前的字符串
     * @return 是否為同一數(shù)據(jù)
     * @throws Exception
     * @explain
     */
    public static boolean verifyEcb(String hexKey, String cipherText, String paramStr) throws Exception {
        // 用于接收校驗結(jié)果
        boolean flag = false;
        // hexString-->byte[]
        byte[] keyData = ByteUtils.fromHexString(hexKey);
        // 將16進制字符串轉(zhuǎn)換成數(shù)組
        byte[] cipherData = ByteUtils.fromHexString(cipherText);
        // 解密
        byte[] decryptData = decryptEcbPadding(keyData, cipherData);
        // 將原字符串轉(zhuǎn)換成byte[]
        byte[] srcData = paramStr.getBytes(ENCODING);
        // 判斷2個數(shù)組是否一致
        flag = Arrays.equals(decryptData, srcData);
        return flag;
    }
 
    public static void main(String[] args) {
        try {
            String paramStr = "Hello, world";
            System.out.println("==========加密前源數(shù)據(jù)==========");
            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("==========是否為同一數(shù)據(jù)==========");
            System.out.println(Sm4Utils.verifyEcb(key, cipher, paramStr));
            paramStr = Sm4Utils.decryptEcb(key, cipher);
            System.out.println("==========解密后數(shù)據(jù)==========");
            System.out.println(paramStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

結(jié)果如下:

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;
 
/**
 * Sm4 國密算法
 *
 */
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個字節(jié)為一組進行分組加密
    // 定義分組加密模式使用: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;
 
    /**
     * 自動生成密鑰
     *
     * @return
     * @explain
     */
    public static byte[] generateKey() throws Exception {
        return generateKey(DEFAULT_KEY_SIZE);
    }
 
 
    /**
     * 自動生成密鑰
     * @return
     * @throws Exception
     */
    public static String generateKeyString() throws Exception {
        return ByteUtils.toHexString(generateKey());
    }
 
    /**
     * @param keySize
     * @return
     * @throws Exception
     * @explain
     */
    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();
    }
 
    /**
     * sm4加密
     *
     * @param hexKey   16進制密鑰(忽略大小寫)
     * @param paramStr 待加密字符串
     * @return 返回16進制的加密字符串
     * @throws Exception
     * @explain 加密模式:CBC
     */
    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);
        // 加密后的數(shù)組
        byte[] cipherArray = encryptCbcPadding(keyData, srcData);
 
        // byte[]-->hexString
        result = ByteUtils.toHexString(cipherArray);
        return result;
    }
 
    /**
     * 加密模式之CBC
     *
     * @param key
     * @param data
     * @return
     * @throws Exception
     * @explain
     */
    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);
    }
 
    /**
     * 加密模式之CBC
     * @param algorithmName
     * @param mode
     * @param key
     * @return
     * @throws Exception
     */
    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;
    }
 
    /**
     * 生成iv
     * @return
     * @throws Exception
     */
    public static AlgorithmParameters generateIV() throws Exception {
        //iv 為一個 16 字節(jié)的數(shù)組,這里采用和 iOS 端一樣的構(gòu)造方法,數(shù)據(jù)全為0
        byte[] iv = new byte[16];
        Arrays.fill(iv, (byte) 0x00);
        AlgorithmParameters params = AlgorithmParameters.getInstance(ALGORITHM_NAME);
        params.init(new IvParameterSpec(iv));
        return params;
    }
 
    /**
     * sm4解密
     *
     * @param hexKey 16進制密鑰
     * @param text   16進制的加密字符串(忽略大小寫)
     * @return 解密后的字符串
     * @throws Exception
     * @explain 解密模式:采用CBC
     */
    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;
    }
 
    /**
     * 解密
     *
     * @param key
     * @param cipherText
     * @return
     * @throws Exception
     * @explain
     */
    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);
    }
}

結(jié)果如下

到此這篇關(guān)于Java實現(xiàn)國產(chǎn)加密算法SM4的示例詳解的文章就介紹到這了,更多相關(guān)Java加密算法SM4內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JVM內(nèi)存增強之逃逸分析

    JVM內(nèi)存增強之逃逸分析

    逃逸分析一種數(shù)據(jù)分析算法,基于此算法可以有效減少Java對象在堆內(nèi)存中的分配。本文將詳細講講逃逸分析的原理與實現(xiàn),需要的可以參考一下
    2022-09-09
  • 基于Spring Boot保護Web應(yīng)用程序

    基于Spring Boot保護Web應(yīng)用程序

    這篇文章主要介紹了基于Spring Boot保護Web應(yīng)用程序,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • 通過Class類獲取對象(實例講解)

    通過Class類獲取對象(實例講解)

    下面小編就為大家?guī)硪黄ㄟ^Class類獲取對象(實例講解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • Java保留兩位小數(shù)的實現(xiàn)方法

    Java保留兩位小數(shù)的實現(xiàn)方法

    這篇文章主要介紹了 Java保留兩位小數(shù)的實現(xiàn)方法的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • Java讀取txt文件中的數(shù)據(jù)賦給String變量方法

    Java讀取txt文件中的數(shù)據(jù)賦給String變量方法

    今天小編就為大家分享一篇Java讀取txt文件中的數(shù)據(jù)賦給String變量方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • SpringBoot中驗證用戶上傳的圖片資源的方法

    SpringBoot中驗證用戶上傳的圖片資源的方法

    這篇文章主要介紹了在SpringBoot中驗證用戶上傳的圖片資源,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • java循環(huán)練習(xí)的簡單代碼實例

    java循環(huán)練習(xí)的簡單代碼實例

    本篇文章介紹了,java中循環(huán)練習(xí)的一些簡單代碼實例。需要的朋友參考下
    2013-04-04
  • MyBatis-Plus框架整合詳細方法

    MyBatis-Plus框架整合詳細方法

    MyBatis-Plus是一個 MyBatis 的增強工具,在 MyBatis 的基礎(chǔ)上只做增強不做改變,為簡化開發(fā)、提高效率而生這篇文章主要介紹了MyBatis-Plus框架整合,需要的朋友可以參考下
    2022-04-04
  • SpringBoot創(chuàng)建線程池的六種方式小結(jié)

    SpringBoot創(chuàng)建線程池的六種方式小結(jié)

    本文主要介紹了SpringBoot創(chuàng)建線程池的六種方式小結(jié),包括自定義線程池,固定長度線程池,單一線程池,共享線程池,定時線程池,SpringBoot中注入異步線程池,感興趣的可以了解一下
    2023-11-11
  • Java編程實現(xiàn)游戲中的簡單碰撞檢測功能示例

    Java編程實現(xiàn)游戲中的簡單碰撞檢測功能示例

    這篇文章主要介紹了Java編程中的簡單碰撞檢測功能,涉及java針對坐標點的相關(guān)數(shù)學(xué)運算操作技巧,需要的朋友可以參考下
    2017-10-10

最新評論