国密算法SM4的GCM模式加密解密实现

发布时间 2023-11-30 09:14:26作者: 锦缇千羽
import org.bouncycastle.util.encoders.Hex;

import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SM4Utils {
    /**
     * 默认 SECRET_KEY
     * secretKey 必须为16位,可包含字母、数字、标点
     */
	private static String SECRET_KEY =""
	/**
     * 默认 IV
     * 当时用CBC模式的时候,SECRET_KEY和IV都需要传值,解密要和加密的SECRET_KEY和IV一致,更加安全
     * iv 必须为 16 位,可包含字母、数字、标点
     */
    private static final String IV = "";
    
    private static final Pattern P = Pattern.compile("\\s*|\t|\r|\n");
    /**
     * GCM模式加密,默认密钥
     *
     * @param plainText 要加密的数据
     * @return String
     */
    public static String encryptData_GCM(String plainText) {
        if (plainText == null) {
            return null;
        }
        try {
            SM4 sm4 = new SM4();
            byte[] key;
            byte[] iv;
            byte[] data;

            key = SM4Utils.SECRET_KEY.getBytes();
            iv = SM4Utils.getIv().getBytes();
            data = plainText.getBytes();

            // 加密
            String cipherText = encrypt_crypt_gcm(key, iv, data);
            if (cipherText != null && cipherText.trim().length() > 0) {
                Matcher m = P.matcher(cipherText);
                cipherText = m.replaceAll("");
            }
            return cipherText;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
     /**
     * GCM模式加密, secertKey和iv需要自己传值, 加密解密一致
     * @param plainText plainText
     * @return String
     */
    public static String encryptData_GCM(String plainText, String secretKey, String ivString) {
        if (plainText == null) {
            return null;
        }
        try {
            SM4 sm4 = new SM4();
            byte[] key;
            byte[] iv;
            byte[] data;

            key = secretKey.getBytes();
            iv = ivString.getBytes();
            data = plainText.getBytes();

            // 加密
            String cipherText = encrypt_crypt_gcm(key, iv, data);
            if (cipherText != null && cipherText.trim().length() > 0) {
                Matcher m = P.matcher(cipherText);
                cipherText = m.replaceAll("");
            }
            return cipherText;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    public static String encrypt_crypt_gcm(byte[] key, byte[] iv, byte[] data) throws Exception {
        if (iv == null || iv.length != 16) {
            throw new Exception("iv error!");
        }

        if (data == null) {
            throw new Exception("input is null!");
        }
        SM4Engine engine = new SM4Engine();
        GCMBlockCipher cipher = new GCMBlockCipher(engine);
        KeyParameter keyParam = new KeyParameter(key);
        AEADParameters params = new AEADParameters(keyParam, 128, iv, null);
        cipher.init(true, params);
        byte[] ciphertext = new byte[cipher.getOutputSize(data.length)];
        int len = cipher.processBytes(data, 0, data.length, ciphertext, 0);
        cipher.doFinal(ciphertext, len);
        return Hex.toHexString(ciphertext);
    }
    
     /**
     * GCM模式解密,SECRET_KEY和IV都需要传值,解密要和加密的SECRET_KEY和IV一致,更加安全
     *
     * @param cipherText String
     * @param secretKey String
     * @param ivString String
     * @return String
     * @author yanXu
     */
    public static String decryptData_GCM(String cipherText, String secretKey, String ivString) {
        if (cipherText == null) {
            return null;
        }
        try {
            byte[] key;
            byte[] iv;
            byte[] data;

            key = secretKey.getBytes();
            iv = ivString.getBytes();
            data = Hex.decode(cipherText);

            return decrypt_crypt_gcm(key, iv, data);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * GCM模式解密,SECRET_KEY和IV为默认值
     *
     * @param cipherText String
     * @return String
     * @author yanXu
     */
    public static String decryptData_GCM(String cipherText) {
        if (cipherText == null) {
            return null;
        }
        try {
            byte[] key;
            byte[] iv;
            byte[] data;

            key = SECRET_KEY.getBytes();
            iv = IV.getBytes();
            data = Hex.decode(cipherText);

            return decrypt_crypt_gcm(key, iv, data);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    public static String decrypt_crypt_gcm(byte[] key, byte[] iv, byte[] input) throws Exception {
        if (input == null) {
            throw new Exception("input is null!");
        }
        SM4Engine engine = new SM4Engine();
        GCMBlockCipher cipher = new GCMBlockCipher(engine);
        KeyParameter keyParam = new KeyParameter(key);
        AEADParameters params = new AEADParameters(keyParam, 128, iv, null);

        cipher.init(false, params);
        byte[] decrypted = new byte[cipher.getOutputSize(input.length)];
        int len = cipher.processBytes(input, 0, input.length, decrypted, 0);
        cipher.doFinal(decrypted, len);
        return new String(decrypted);
    }