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

469 阅读3分钟

加密算法依赖了groupId:org.bouncycastle中的bcprov-jdk,Bouncy Castle (bcprov-jdk15to18)提供了JDK 1.5 to 11 可使用的大量标准加密算法实现,其中包含了SM2,SM3,SM4。在这个类库基础上实现了一个SM4Util加解密工具类。

  • SM4:对称加密算法,性能比SM2好
    • 可以用于一般数据的加密与解密,例如可以在需要网络传输的数据发送前进行加密,对方收到数据后使用相同密钥进行解密获得明文。
  • SM4分组密码算法是我国自主设计的分组对称密码算法,用于实现数据的加密/解密运算,以保证数据和信息的机密性。要保证一个对称密码算法的安全性的基本条件是其具备足够的密钥长度,SM4算法与AES算法具有相同的密钥长度分组长度128比特,因此在安全性上高于3DES算法。

pom.xml 增加依赖:

org.bouncycastle bcprov-jdk15on 1.70 compile

Java 代码:

import org.bouncycastle.crypto.engines.SM4Engine;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.encoders.Hex;

import java.io.UnsupportedEncodingException;

/**
 * @Auther: sea
 * @Description: SM4算法
 */
public class SM4Util {
    //加解密的字节快大小
    public static final int BLOCK_SIZE = 16;

    /**
     * SM4ECB加密算法
     * @param in            待加密内容
     * @param keyBytes      密钥
     * @return
     */
    public static byte[] encryptByEcb0(byte[] in, byte[] keyBytes) {
        SM4Engine sm4Engine = new SM4Engine();
        sm4Engine.init(true, new KeyParameter(keyBytes));
        int inLen = in.length;
        byte[] out = new byte[inLen];

        int times = inLen / BLOCK_SIZE;

        for (int i = 0; i < times; i++) {
            sm4Engine.processBlock(in, i * BLOCK_SIZE, out, i * BLOCK_SIZE);
        }

        return out;
    }

    /**
     * SM4ECB加密算法
     * @param in            待加密内容
     * @param keyBytes      密钥
     * @return
     */
    public static String encryptByEcb(byte[] in, byte[] keyBytes) {
        byte[] out = encryptByEcb0(in, keyBytes);
        String cipher = Hex.toHexString(out);
        return cipher;
    }

    /**
     * SM4的ECB加密算法
     * @param content   待加密内容
     * @param key       密钥
     * @return
     */
    public static String encryptByEcb(String content, String key) {
        byte[] in = Hex.decode(content);
        byte[] keyBytes = Hex.decode(key);

        String cipher = encryptByEcb(in, keyBytes);
        return cipher;
    }

    /**
     * SM4的ECB解密算法
     * @param in        密文内容
     * @param keyBytes  密钥
     * @return
     */
    public static byte[] decryptByEcb0(byte[] in, byte[] keyBytes) {
        SM4Engine sm4Engine = new SM4Engine();
        sm4Engine.init(false, new KeyParameter(keyBytes));
        int inLen = in.length;
        byte[] out = new byte[inLen];

        int times = inLen / BLOCK_SIZE;

        for (int i = 0; i < times; i++) {
            sm4Engine.processBlock(in, i * BLOCK_SIZE, out, i * BLOCK_SIZE);
        }

        return out;
    }

    /**
     * SM4的ECB解密算法
     * @param in        密文内容
     * @param keyBytes  密钥
     * @return
     */
    public static String decryptByEcb(byte[] in, byte[] keyBytes) {
        byte[] out = decryptByEcb0(in, keyBytes);
        String plain = Hex.toHexString(out);
        return plain;
    }

    /**
     * SM4的ECB解密算法
     * @param cipher    密文内容
     * @param key       密钥
     * @return
     */
    public static String decryptByEcb(String cipher, String key) {
        byte[] in = Hex.decode(cipher);
        byte[] keyBytes = Hex.decode(key);

        String plain = decryptByEcb(in, keyBytes);
        return plain;
    }


    /**
     * SM4的ECB加密算法(PKCS#7 填充)
     * @param content   待加密内容(普通字符串: 1234567812345678aa1100)
     * @param key       密钥(十六进制字符串 :B6D8C12920418AFEA57514132E16039A)
     * @return     返回十六进制字符串:
     * ebd4745c5cb68922bfb65af306363b42c8793f648dafdc218b6c06158dbeadec
     */
    public static String sm4EncryptByEcb(String content, String key) throws UnsupportedEncodingException {
        byte[] in = content.getBytes("UTF-8");
        String cipher = "";
        byte[] keyBytes = Hex.decode(key);
        // 待加密串字节长度不是16的倍数,则需填充成16的整数倍
        byte[] fillData = DataPadding.encodeWithPKCS5(in,BLOCK_SIZE);
        cipher = encryptByEcb(fillData, keyBytes);

        return cipher;
    }


    /**
     * SM4的ECB解密算法 (PKCS#7 填充)
     * @param cipher    密文内容 (十六进制字符串:
     *                 ebd4745c5cb68922bfb65af306363b42c8793f648dafdc218b6c06158dbeadec)
     * @param key       密钥 (十六进制字符串: B6D8C12920418AFEA57514132E16039A)
     * @return  返回普通字符串: 1234567812345678aa1100
     */
    public static String sm4decryptByEcb(String cipher, String key) {
        byte[] in = Hex.decode(cipher);
        byte[] keyBytes = Hex.decode(key);
        // 解密
        byte[] out = decryptByEcb0(in, keyBytes);
        // 去掉填充字符
        byte[]respMsg = DataPadding.decodeWithPKCS5(out);
        String plain = new String(respMsg);
        return plain;
    }