Java implements national secret SM4/ECB/PKCS7Padding symmetric encryption and decryption

Java implements national secret SM4/ECB/PKCS7Padding symmetric encryption and decryption. For the convenience of demonstration, this question uses IntelliJ IDEA 2022.1 (Community Edition) to build the code.

1. Add the required jars to the pom.xml file

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>SM345</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!--sm3,sm4 encryption algorithm-->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.66</version>
        </dependency>
    </dependencies>
</project>

2. java code

import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
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;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.apache.commons.codec.binary.Base64;

/**
 * sm4 encryption algorithm tool class
 *
 * @author Marydon
 * @version 1.0
 * @explain sm4 encryption, decryption and encryption result verification
 * Reversible algorithm
 * @creationTime July 6, 2018 11:46:59 AM
 * @email [email protected]
 * @since
 */
public class Sm4Util {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    private static final String ENCODING = "UTF-8";
    public static final String ALGORITHM_NAME = "SM4";
    // Encryption algorithm/block encryption mode/block filling method
    // PKCS5Padding - group encryption in groups of 8 bytes
    // Define the group encryption mode to use: PKCS5Padding
    public static final String ALGORITHM_NAME_ECB_PADDING7 = "SM4/ECB/PKCS5Padding";
    public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS7Padding";
    // 64-16 digits hexadecimal; 128-32 digits hexadecimal; 256-64 digits hexadecimal
    public static final int DEFAULT_KEY_SIZE = 128;

    /**
     * Generate ECB password
     *
     * @param algorithmName algorithm name
     * @param mode mode
     * @param key
     * @return
     * @throwsException
     * @explain ECB mode (Electronic codebook mode: 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;
    }

    //generate key

    /**
     * Automatically generate keys
     *
     * @return
     * @throws NoSuchAlgorithmException
     * @throws NoSuchProviderException
     * @explain
     */
    public static byte[] generateKey() throws Exception {
        return generateKey(DEFAULT_KEY_SIZE);
    }

    /**
     * @param keySize
     * @return
     * @throwsException
     * @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 encryption
     *
     * @param hexKey hexadecimal key (ignoring case)
     * @param paramStr String to be encrypted
     * @return Returns the hexadecimal encrypted string
     * @throwsException
     * @explain encryption mode: ECB
     * The length of the ciphertext is not fixed and will change as the length of the encrypted string changes.
     */
    public static String encryptEcb(String hexKey, String paramStr) throws Exception {
        String cipherText = "";
        // Hexadecimal string -->byte[]
        //byte[] keyData = ByteUtils.fromHexString(hexKey);
        byte[] keyData = hexKey.getBytes(ENCODING);
        // String-->byte[]
        byte[] srcData = paramStr.getBytes(ENCODING);
        //Encrypted array
        byte[] cipherArray = encrypt_Ecb_Padding(keyData, srcData);
        // byte[]-->hexString
        //cipherText = ByteUtils.toHexString(cipherArray);
        cipherText = Base64.encodeBase64String(cipherArray);
        return cipherText;
    }

    /**
     * Encryption mode Ecb
     *
     * @param key
     * @param data
     * @return
     * @throwsException
     * @explain
     */
    public static byte[] encrypt_Ecb_Padding(byte[] key, byte[] data) throws Exception {
        Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(data);
    }

    /**
     * sm4 decryption
     *
     * @param hexKey hexadecimal key
     * @param cipherText hexadecimal encrypted string (ignoring case)
     * @return decrypted string
     * @throwsException
     * @explain Decryption mode: using ECB
     */
    public static String decryptEcb(String hexKey, String cipherText) throws Exception {
        // Used to receive the decrypted string
        String decryptStr = "";
        // hexString-->byte[]
        //byte[] keyData = ByteUtils.fromHexString(hexKey);
        byte[] keyData = hexKey.getBytes(ENCODING);
        // hexString-->byte[]
        //byte[] cipherData = ByteUtils.fromHexString(cipherText);
        byte[] cipherData =Base64.decodeBase64(cipherText);
        // Decrypt
        byte[] srcData = decrypt_Ecb_Padding(keyData, cipherData);
        //byte[]-->String
        decryptStr = new String(srcData, ENCODING);
        return decryptStr;
    }

    /**
     * decrypt
     *
     * @param key
     * @param cipherText
     * @return
     * @throwsException
     * @explain
     */
    public static byte[] decrypt_Ecb_Padding(byte[] key, byte[] cipherText) throws Exception {
        Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(cipherText);
    }

    /**
     * Verify whether the string before and after encryption is the same data
     *
     * @param hexKey hexadecimal key (ignoring case)
     * @param cipherText hexadecimal encrypted string
     * @param paramStr String before encryption
     * @return whether it is the same data
     * @throwsException
     * @explain
     */
    public static boolean verifyEcb(String hexKey, String cipherText, String paramStr) throws Exception {
        // Used to receive verification results
        boolean flag = false;
        // hexString-->byte[]
        //byte[] keyData = ByteUtils.fromHexString(hexKey);
        byte[] keyData = hexKey.getBytes(ENCODING);
        // Convert hexadecimal string into array
        //byte[] cipherData = ByteUtils.fromHexString(cipherText);
        byte[] cipherData = Base64.decodeBase64(cipherText);
        // Decrypt
        byte[] decryptData = decrypt_Ecb_Padding(keyData, cipherData);
        //Convert the original string into byte[]
        byte[] srcData = paramStr.getBytes(ENCODING);
        // Determine whether the two arrays are consistent
        flag = Arrays.equals(decryptData, srcData);
        return flag;
    }
}

3. This article uses a Base64 jar package commons-codec-1.16.0.jar, import org.apache.commons.codec.binary.Base64; you need to download and add a reference.

Select File, Project Structure, Project Settings, Library, click + on the far right, select the downloaded commons-codec-1.16.0.jar and add the package.

4. Use code

import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
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;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
//import org.apache.commons.codec.binary.Hex;
//import org.apache.commons.codec.binary.Base64;

public class Longteng {

    public static void main(String[] args) {
        try {

            String json = "{"name":"Marydon","website":"http://www.cnblogs.com/ Marydon20170307"}";
            json = "1234567890abcdefghijklmnopqrstuvwxyz";
            System.out.println("National secret SM4 encryption and decryption:");
            // Customized 32-bit hexadecimal key
            // String key = "86C63180C2806ED1F47B859DE501215B";
            String key = "1234567890123456";
            String cipher = Sm4Util.encryptEcb(key, json);
            System.out.println("National secret SM4 encryption and decryption: \r\\
Key: " + key + " \\
Encrypted content: " + json + " \\
After encryption v\ " + cipher);

            //System.out.println(cipher);
            //Compare encryption and decryption information
            System.out.println(Sm4Util.verifyEcb(key, cipher, json));// true
            json = Sm4Util.decryptEcb(key, cipher);
            System.out.println("National secret SM4 encryption and decryption: \\
Key: " + key + " \\
Encrypted content: " + cipher + " \\
After decryption: " + json );

            //System.out.println(json);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}