sm4对称加密算法,java,Android,js,ios版多端实现

d_hero
发布于 2023-6-29 14:02
浏览
0收藏

java版

pom.xml

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15to18</artifactId>
    <version>1.71</version>
</dependency>

<dependency>
  <groupId>cn.hutool</groupId>
  <artifactId>hutool-all</artifactId>
  <version>5.0.3</version>
</dependency>

package com.sm.sm4;

import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.symmetric.SM4;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.sm.mysm4.SM4Utils;

/**
 * 描述: 国密SM4对称加密算法辅助类<br>
 * 时间: 2022-07-14 16:01  <br>
 * 作者:IT学习道场
 */
public class SM4PlusUtil {

    //key必须是16字节,即128位
    final static String key = "sm4demo123456789";
    //指明加密算法和秘钥
    static SymmetricCrypto sm4 = new SymmetricCrypto("SM4",key.getBytes());

    //加密为16进制,也可以加密成base64/字节数组
    public static String encrypt(String text) {
        return sm4.encryptBase64(text);
    }

    //解密
    public static String decrypt(String text) {
        return sm4.decryptStr(text);
    }

    public static void main(String[] args) {
        String str = "来完成";
        String encryptBase64 = sm4.encryptBase64(str);
        String decryptStr = sm4.decryptStr(encryptBase64);
        System.out.println("密文:" + encryptBase64);
        System.out.println("明文:" + decryptStr);

    }

}

Android版本

package com.sm.mysm4;

public class SM4_Context {
    public int mode;

    public long[] sk;

    public boolean isPadding;

    public SM4_Context() {
        this.mode = 1;
        this.isPadding = true;
        this.sk = new long[32];
    }
}

package com.sm.mysm4;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SM4 {

    private String secretKey = "";
    private String iv = "";
    public static final int SM4_ENCRYPT = 1;

    public static final int SM4_DECRYPT = 0;

    private long GET_ULONG_BE(byte[] b, int i) {
        long n = (long) (b[i] & 0xff) << 24 | (long) ((b[i + 1] & 0xff) << 16) | (long) ((b[i + 2] & 0xff) << 8)
                | (long) (b[i + 3] & 0xff) & 0xffffffffL;
        return n;
    }

    private void PUT_ULONG_BE(long n, byte[] b, int i) {
        b[i] = (byte) (int) (0xFF & n >> 24);
        b[i + 1] = (byte) (int) (0xFF & n >> 16);
        b[i + 2] = (byte) (int) (0xFF & n >> 8);
        b[i + 3] = (byte) (int) (0xFF & n);
    }

    private long SHL(long x, int n) {
        return (x & 0xFFFFFFFF) << n;
    }

    private long ROTL(long x, int n) {
        return SHL(x, n) | x >> (32 - n);
    }

    private void SWAP(long[] sk, int i) {
        long t = sk[i];
        sk[i] = sk[(31 - i)];
        sk[(31 - i)] = t;
    }

    public static final byte[] SboxTable = {(byte) 0xd6, (byte) 0x90, (byte) 0xe9, (byte) 0xfe, (byte) 0xcc,
            (byte) 0xe1, 0x3d, (byte) 0xb7, 0x16, (byte) 0xb6, 0x14, (byte) 0xc2, 0x28, (byte) 0xfb, 0x2c, 0x05, 0x2b,
            0x67, (byte) 0x9a, 0x76, 0x2a, (byte) 0xbe, 0x04, (byte) 0xc3, (byte) 0xaa, 0x44, 0x13, 0x26, 0x49,
            (byte) 0x86, 0x06, (byte) 0x99, (byte) 0x9c, 0x42, 0x50, (byte) 0xf4, (byte) 0x91, (byte) 0xef, (byte) 0x98,
            0x7a, 0x33, 0x54, 0x0b, 0x43, (byte) 0xed, (byte) 0xcf, (byte) 0xac, 0x62, (byte) 0xe4, (byte) 0xb3, 0x1c,
            (byte) 0xa9, (byte) 0xc9, 0x08, (byte) 0xe8, (byte) 0x95, (byte) 0x80, (byte) 0xdf, (byte) 0x94,
            (byte) 0xfa, 0x75, (byte) 0x8f, 0x3f, (byte) 0xa6, 0x47, 0x07, (byte) 0xa7, (byte) 0xfc, (byte) 0xf3, 0x73,
            0x17, (byte) 0xba, (byte) 0x83, 0x59, 0x3c, 0x19, (byte) 0xe6, (byte) 0x85, 0x4f, (byte) 0xa8, 0x68, 0x6b,
            (byte) 0x81, (byte) 0xb2, 0x71, 0x64, (byte) 0xda, (byte) 0x8b, (byte) 0xf8, (byte) 0xeb, 0x0f, 0x4b, 0x70,
            0x56, (byte) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (byte) 0xd1, (byte) 0xa2, 0x25, 0x22, 0x7c,
            0x3b, 0x01, 0x21, 0x78, (byte) 0x87, (byte) 0xd4, 0x00, 0x46, 0x57, (byte) 0x9f, (byte) 0xd3, 0x27, 0x52,
            0x4c, 0x36, 0x02, (byte) 0xe7, (byte) 0xa0, (byte) 0xc4, (byte) 0xc8, (byte) 0x9e, (byte) 0xea, (byte) 0xbf,
            (byte) 0x8a, (byte) 0xd2, 0x40, (byte) 0xc7, 0x38, (byte) 0xb5, (byte) 0xa3, (byte) 0xf7, (byte) 0xf2,
            (byte) 0xce, (byte) 0xf9, 0x61, 0x15, (byte) 0xa1, (byte) 0xe0, (byte) 0xae, 0x5d, (byte) 0xa4, (byte) 0x9b,
            0x34, 0x1a, 0x55, (byte) 0xad, (byte) 0x93, 0x32, 0x30, (byte) 0xf5, (byte) 0x8c, (byte) 0xb1, (byte) 0xe3,
            0x1d, (byte) 0xf6, (byte) 0xe2, 0x2e, (byte) 0x82, 0x66, (byte) 0xca, 0x60, (byte) 0xc0, 0x29, 0x23,
            (byte) 0xab, 0x0d, 0x53, 0x4e, 0x6f, (byte) 0xd5, (byte) 0xdb, 0x37, 0x45, (byte) 0xde, (byte) 0xfd,
            (byte) 0x8e, 0x2f, 0x03, (byte) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, (byte) 0x8d, 0x1b, (byte) 0xaf,
            (byte) 0x92, (byte) 0xbb, (byte) 0xdd, (byte) 0xbc, 0x7f, 0x11, (byte) 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a,
            (byte) 0xd8, 0x0a, (byte) 0xc1, 0x31, (byte) 0x88, (byte) 0xa5, (byte) 0xcd, 0x7b, (byte) 0xbd, 0x2d, 0x74,
            (byte) 0xd0, 0x12, (byte) 0xb8, (byte) 0xe5, (byte) 0xb4, (byte) 0xb0, (byte) 0x89, 0x69, (byte) 0x97, 0x4a,
            0x0c, (byte) 0x96, 0x77, 0x7e, 0x65, (byte) 0xb9, (byte) 0xf1, 0x09, (byte) 0xc5, 0x6e, (byte) 0xc6,
            (byte) 0x84, 0x18, (byte) 0xf0, 0x7d, (byte) 0xec, 0x3a, (byte) 0xdc, 0x4d, 0x20, 0x79, (byte) 0xee, 0x5f,
            0x3e, (byte) 0xd7, (byte) 0xcb, 0x39, 0x48};

    public static final int[] FK = {0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc};

    public static final int[] CK = {0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd,
            0xc4cbd2d9, 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
            0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, 0xa0a7aeb5,
            0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279};

    private byte sm4Sbox(byte inch) {
        int i = inch & 0xFF;
        byte retVal = SboxTable[i];
        return retVal;
    }

    private long sm4Lt(long ka) {
        long bb = 0L;
        long c = 0L;
        byte[] a = new byte[4];
        byte[] b = new byte[4];
        PUT_ULONG_BE(ka, a, 0);
        b[0] = sm4Sbox(a[0]);
        b[1] = sm4Sbox(a[1]);
        b[2] = sm4Sbox(a[2]);
        b[3] = sm4Sbox(a[3]);
        bb = GET_ULONG_BE(b, 0);
        c = bb ^ ROTL(bb, 2) ^ ROTL(bb, 10) ^ ROTL(bb, 18) ^ ROTL(bb, 24);
        return c;
    }

    private long sm4F(long x0, long x1, long x2, long x3, long rk) {
        return x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk);
    }

    private long sm4CalciRK(long ka) {
        long bb = 0L;
        long rk = 0L;
        byte[] a = new byte[4];
        byte[] b = new byte[4];
        PUT_ULONG_BE(ka, a, 0);
        b[0] = sm4Sbox(a[0]);
        b[1] = sm4Sbox(a[1]);
        b[2] = sm4Sbox(a[2]);
        b[3] = sm4Sbox(a[3]);
        bb = GET_ULONG_BE(b, 0);
        rk = bb ^ ROTL(bb, 13) ^ ROTL(bb, 23);
        return rk;
    }

    private void sm4_setkey(long[] SK, byte[] key) {
        long[] MK = new long[4];
        long[] k = new long[36];
        int i = 0;
        MK[0] = GET_ULONG_BE(key, 0);
        MK[1] = GET_ULONG_BE(key, 4);
        MK[2] = GET_ULONG_BE(key, 8);
        MK[3] = GET_ULONG_BE(key, 12);
        k[0] = MK[0] ^ (long) FK[0];
        k[1] = MK[1] ^ (long) FK[1];
        k[2] = MK[2] ^ (long) FK[2];
        k[3] = MK[3] ^ (long) FK[3];
        long item = k[1] ^ k[2] ^ k[3];
        for (; i < 32; i++) {
            k[(i + 4)] = (k[i] ^ sm4CalciRK(item ^ (long) CK[i]));
            SK[i] = k[(i + 4)];
            item ^= k[i + 4] ^ k[i + 1];
        }
    }

    private void sm4_one_round(long[] sk, byte[] input, byte[] output) {
        int i = 0;
        long[] ulbuf = new long[36];
        ulbuf[0] = GET_ULONG_BE(input, 0);
        ulbuf[1] = GET_ULONG_BE(input, 4);
        ulbuf[2] = GET_ULONG_BE(input, 8);
        ulbuf[3] = GET_ULONG_BE(input, 12);
        while (i < 32) {
            ulbuf[(i + 4)] = sm4F(ulbuf[i], ulbuf[(i + 1)], ulbuf[(i + 2)], ulbuf[(i + 3)], sk[i]);
            i++;
        }
        PUT_ULONG_BE(ulbuf[35], output, 0);
        PUT_ULONG_BE(ulbuf[34], output, 4);
        PUT_ULONG_BE(ulbuf[33], output, 8);
        PUT_ULONG_BE(ulbuf[32], output, 12);
    }

    private byte[] padding(byte[] input, int mode) {
        if (input == null) {
            return null;
        }

        byte[] ret = (byte[]) null;
        if (mode == SM4_ENCRYPT) {
            int p = 16 - input.length % 16;
            ret = new byte[input.length + p];
            System.arraycopy(input, 0, ret, 0, input.length);
            for (int i = 0; i < p; i++) {
                ret[input.length + i] = (byte) p;
            }
        } else {
            int p = input[input.length - 1];
            ret = new byte[input.length - p];
            System.arraycopy(input, 0, ret, 0, input.length - p);
        }
        return ret;
    }

    public void sm4_setkey_enc(SM4_Context ctx, byte[] key) throws Exception {
        if (ctx == null) {
            throw new Exception("ctx is null!");
        }

        if (key == null || key.length != 16) {
            throw new Exception("key error!");
        }

        ctx.mode = SM4_ENCRYPT;
        sm4_setkey(ctx.sk, key);
    }

    public void sm4_setkey_dec(SM4_Context ctx, byte[] key) throws Exception {
        if (ctx == null) {
            throw new Exception("ctx is null!");
        }

        if (key == null || key.length != 16) {
            throw new Exception("key error!");
        }

        int i = 0;
        ctx.mode = SM4_DECRYPT;
        sm4_setkey(ctx.sk, key);
        for (i = 0; i < 16; i++) {
            SWAP(ctx.sk, i);
        }
    }

    public byte[] sm4_crypt_ecb(SM4_Context ctx, byte[] input) throws Exception {
        if (input == null) {
            throw new Exception("input is null!");
        }

        if ((ctx.isPadding) && (ctx.mode == SM4_ENCRYPT)) {
            input = padding(input, SM4_ENCRYPT);
        }

        int length = input.length;
        ByteArrayInputStream bins = new ByteArrayInputStream(input);
        ByteArrayOutputStream bous = new ByteArrayOutputStream();
        for (; length > 0; length -= 16) {
            byte[] in = new byte[16];
            byte[] out = new byte[16];
            bins.read(in);
            sm4_one_round(ctx.sk, in, out);
            bous.write(out);
        }

        byte[] output = bous.toByteArray();
        if (ctx.isPadding && ctx.mode == SM4_DECRYPT) {
            output = padding(output, SM4_DECRYPT);
        }
        bins.close();
        bous.close();
        return output;
    }

    public byte[] sm4_crypt_cbc(SM4_Context ctx, byte[] iv, byte[] input) throws Exception {
        if (iv == null || iv.length != 16) {
            throw new Exception("iv error!");
        }

        if (input == null) {
            throw new Exception("input is null!");
        }

        if (ctx.isPadding && ctx.mode == SM4_ENCRYPT) {
            input = padding(input, SM4_ENCRYPT);
        }

        int i = 0;
        int length = input.length;
        ByteArrayInputStream bins = new ByteArrayInputStream(input);
        ByteArrayOutputStream bous = new ByteArrayOutputStream();
        if (ctx.mode == SM4_ENCRYPT) {
            for (; length > 0; length -= 16) {
                byte[] in = new byte[16];
                byte[] out = new byte[16];
                byte[] out1 = new byte[16];

                bins.read(in);
                for (i = 0; i < 16; i++) {
                    out[i] = ((byte) (in[i] ^ iv[i]));
                }
                sm4_one_round(ctx.sk, out, out1);
                System.arraycopy(out1, 0, iv, 0, 16);
                bous.write(out1);
            }
        } else {
            byte[] temp = new byte[16];
            for (; length > 0; length -= 16) {
                byte[] in = new byte[16];
                byte[] out = new byte[16];
                byte[] out1 = new byte[16];

                bins.read(in);
                System.arraycopy(in, 0, temp, 0, 16);
                sm4_one_round(ctx.sk, in, out);
                for (i = 0; i < 16; i++) {
                    out1[i] = ((byte) (out[i] ^ iv[i]));
                }
                System.arraycopy(temp, 0, iv, 0, 16);
                bous.write(out1);
            }
        }

        byte[] output = bous.toByteArray();
        if (ctx.isPadding && ctx.mode == SM4_DECRYPT) {
            output = padding(output, SM4_DECRYPT);
        }
        bins.close();
        bous.close();
        return output;
    }

    public static String hexStr2Str(String hexStr) {
        String str = "0123456789ABCDEF";
        char[] hexs = hexStr.toCharArray();
        byte[] bytes = new byte[hexStr.length() / 2];
        int n;
        for (int i = 0; i < bytes.length; i++) {
            n = str.indexOf(hexs[2 * i]) * 16;
            n += str.indexOf(hexs[2 * i + 1]);
            bytes[i] = (byte) (n & 0xff);
        }
        return new String(bytes);
    }

    public static String str2HexStr(String str) {
        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder sb = new StringBuilder("");
        byte[] bs = str.getBytes();
        int bit;
        for (int i = 0; i < bs.length; i++) {
            bit = (bs[i] & 0x0f0) >> 4;
            sb.append(chars[bit]);
            bit = bs[i] & 0x0f;
            sb.append(chars[bit]);
            // sb.append(' ');
        }
        return sb.toString().trim();
    }

    public String decryptDataToString_CBC(String cipherText) {
        return decryptDataToString_CBC(cipherText, "GBK");
    }

    public String decryptDataToString_CBC(String cipherText, String charset) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_DECRYPT;

            byte[] keyBytes;
            byte[] ivBytes;
            keyBytes = secretKey.getBytes();
            ivBytes = iv.getBytes();
            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            byte[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, Base64.getDecoder().decode(cipherText));
            return new String(decrypted, charset);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public byte[] decryptData_CBC(String cipherText) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_DECRYPT;

            byte[] keyBytes;
            byte[] ivBytes;
            keyBytes = secretKey.getBytes();
            ivBytes = iv.getBytes();
            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            return sm4.sm4_crypt_cbc(ctx, ivBytes, Base64.getDecoder().decode(cipherText));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public String decryptDataToString_CBC(byte[] bytes) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_DECRYPT;

            byte[] keyBytes;
            byte[] ivBytes;
            keyBytes = secretKey.getBytes();
            ivBytes = iv.getBytes();
            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            byte[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, bytes);
            return new String(decrypted, "GBK");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public byte[] decryptData_ECB(byte[] bytes) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_DECRYPT;

            byte[] keyBytes;
            keyBytes = secretKey.getBytes();
            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            return sm4.sm4_crypt_ecb(ctx, bytes);

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public byte[] decryptData_ECB(String cipherText) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_DECRYPT;

            byte[] keyBytes;
            keyBytes = secretKey.getBytes();
            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            return sm4.sm4_crypt_ecb(ctx, Base64.getDecoder().decode(cipherText));

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public String decryptDataToString_ECB(String cipherText) {
        return decryptDataToString_ECB(cipherText, "GBK");
    }

    public String decryptDataToString_ECB(String cipherText, String charset) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_DECRYPT;

            byte[] keyBytes;
            keyBytes = secretKey.getBytes();
            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            byte[] decrypted = sm4.sm4_crypt_ecb(ctx, Base64.getDecoder().decode(cipherText));
            return new String(decrypted, charset);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public String encryptDataToString_CBC(byte[] bytes) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_ENCRYPT;

            byte[] keyBytes;
            byte[] ivBytes;
            keyBytes = secretKey.getBytes();
            ivBytes = iv.getBytes();
            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, bytes);
            String cipherText = Base64.getEncoder().encodeToString(encrypted);
            if (cipherText != null && cipherText.trim().length() > 0) {
                Pattern p = Pattern.compile("\\s*|\t|\r|\n");
                Matcher m = p.matcher(cipherText);
                cipherText = m.replaceAll("");
            }
            return cipherText;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public String encryptDataToString_CBC(String plainText) {
        return encryptDataToString_CBC(plainText, "GBK");
    }

    public String encryptDataToString_CBC(String plainText, String charset) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_ENCRYPT;

            byte[] keyBytes;
            byte[] ivBytes;
            keyBytes = secretKey.getBytes();
            ivBytes = iv.getBytes();
            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, plainText.getBytes(charset));
            String cipherText = Base64.getEncoder().encodeToString(encrypted);
            if (cipherText != null && cipherText.trim().length() > 0) {
                Pattern p = Pattern.compile("\\s*|\t|\r|\n");
                Matcher m = p.matcher(cipherText);
                cipherText = m.replaceAll("");
            }
            return cipherText;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public byte[] encryptData_CBC(String plainText, String charset) {
        try {
            return encryptData_CBC(plainText.getBytes(charset));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public byte[] encryptData_CBC(byte[] bytes) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_ENCRYPT;

            byte[] keyBytes;
            byte[] ivBytes;
            keyBytes = secretKey.getBytes();
            ivBytes = iv.getBytes();
            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            return sm4.sm4_crypt_cbc(ctx, ivBytes, bytes);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public byte[] encryptData_ECB(byte[] bytes) {

        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_ENCRYPT;

            byte[] keyBytes;
            keyBytes = secretKey.getBytes();
            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            return sm4.sm4_crypt_ecb(ctx, bytes);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public byte[] encryptData_ECB(String plainText) {
        return encryptData_ECB(plainText, "GBK");
    }

    public byte[] encryptData_ECB(String plainText, String charset) {
        try {
            return encryptData_ECB(plainText.getBytes(charset));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public String encryptDataToString_ECB(String plainText) {
        return encryptDataToString_ECB(plainText, "GBK");
    }


    //传递字符串。不是传递16进制字符串
    public String encryptDataToString_ECB(String plainText, String charset) {
        try {
            SM4_Context ctx = new SM4_Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_ENCRYPT;
            byte[] keyBytes;
            keyBytes = secretKey.getBytes();
            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4_crypt_ecb(ctx, plainText.getBytes(charset));
            String cipherText = Base64.getEncoder().encodeToString(encrypted);
            if (cipherText != null && cipherText.trim().length() > 0) {
                Pattern p = Pattern.compile("\\s*|\t|\r|\n");
                Matcher m = p.matcher(cipherText);
                cipherText = m.replaceAll("");
            }
            return cipherText;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * @return the iv
     */
    public String getIv() {
        return iv;
    }

    /**
     * @return the secretKey
     */
    public String getSecretKey() {
        return secretKey;
    }

    /**
     * @param iv the iv to set
     */
    public void setIv(String iv) {
        this.iv = iv;
    }

    /**
     * @param secretKey the secretKey to set
     */
    public void setSecretKey(String secretKey) {
        this.secretKey = secretKey;
    }


}


package com.sm.mysm4;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SM4Utils {
    private String secretKey = "";
    private String iv = "";

    public SM4Utils(String secretKey, String iv) {
        this.secretKey = secretKey;
        this.iv = iv;
    }

    public SM4Utils() {
    }

    public String encryptData_ECB(String plainText) throws Exception {
        SM4_Context ctx = new SM4_Context();
        ctx.isPadding = true;
        ctx.mode = SM4.SM4_ENCRYPT;

        byte[] keyBytes;
        keyBytes = secretKey.getBytes();
        SM4 sm4 = new SM4();
        sm4.sm4_setkey_enc(ctx, keyBytes);
        byte[] encrypted = sm4.sm4_crypt_ecb(ctx, plainText.getBytes("UTF-8"));
        String cipherText = new BASE64Encoder().encode(encrypted);
        if (cipherText != null && cipherText.trim().length() > 0) {
            Pattern p = Pattern.compile("\\s*|\t|\r|\n");
            Matcher m = p.matcher(cipherText);
            cipherText = m.replaceAll("");
        }
        return cipherText;
    }

    public String decryptData_ECB(String cipherText) throws Exception {
        SM4_Context ctx = new SM4_Context();
        ctx.isPadding = true;
        ctx.mode = SM4.SM4_DECRYPT;

        byte[] keyBytes;
        keyBytes = secretKey.getBytes();
        SM4 sm4 = new SM4();
        sm4.sm4_setkey_dec(ctx, keyBytes);
        byte[] decrypted = sm4.sm4_crypt_ecb(ctx, new BASE64Decoder().decodeBuffer(cipherText));
        return new String(decrypted, "UTF-8");
    }

    public String encryptData_CBC(String plainText) throws Exception {
        SM4_Context ctx = new SM4_Context();
        ctx.isPadding = true;
        ctx.mode = SM4.SM4_ENCRYPT;

        byte[] keyBytes;
        byte[] ivBytes;

        keyBytes = secretKey.getBytes();
        ivBytes = iv.getBytes();

        SM4 sm4 = new SM4();
        sm4.sm4_setkey_enc(ctx, keyBytes);
        byte[] encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, plainText.getBytes("UTF-8"));
        String cipherText = new BASE64Encoder().encode(encrypted);
        if (cipherText != null && cipherText.trim().length() > 0) {
            Pattern p = Pattern.compile("\\s*|\t|\r|\n");
            Matcher m = p.matcher(cipherText);
            cipherText = m.replaceAll("");
        }
        return cipherText;
    }

    public String decryptData_CBC(String cipherText) throws Exception {
        SM4_Context ctx = new SM4_Context();
        ctx.isPadding = true;
        ctx.mode = SM4.SM4_DECRYPT;

        byte[] keyBytes;
        byte[] ivBytes;
        keyBytes = secretKey.getBytes();
        ivBytes = iv.getBytes();

        SM4 sm4 = new SM4();
        sm4.sm4_setkey_dec(ctx, keyBytes);
        byte[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, new BASE64Decoder().decodeBuffer(cipherText));
        return new String(decrypted, "UTF-8");
    }

}


package sun.misc;

import java.io.IOException;
import java.io.OutputStream;

public class BASE64Encoder extends CharacterEncoder {
    private static final char[] pem_array = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};

    public BASE64Encoder() {
    }

    protected int bytesPerAtom() {
        return 3;
    }

    protected int bytesPerLine() {
        return 57;
    }

    protected void encodeAtom(OutputStream var1, byte[] var2, int var3, int var4) throws IOException {
        byte var5;
        if (var4 == 1) {
            var5 = var2[var3];
            byte var6 = 0;
            boolean var7 = false;
            var1.write(pem_array[var5 >>> 2 & 63]);
            var1.write(pem_array[(var5 << 4 & 48) + (var6 >>> 4 & 15)]);
            var1.write(61);
            var1.write(61);
        } else {
            byte var8;
            if (var4 == 2) {
                var5 = var2[var3];
                var8 = var2[var3 + 1];
                byte var9 = 0;
                var1.write(pem_array[var5 >>> 2 & 63]);
                var1.write(pem_array[(var5 << 4 & 48) + (var8 >>> 4 & 15)]);
                var1.write(pem_array[(var8 << 2 & 60) + (var9 >>> 6 & 3)]);
                var1.write(61);
            } else {
                var5 = var2[var3];
                var8 = var2[var3 + 1];
                byte var10 = var2[var3 + 2];
                var1.write(pem_array[var5 >>> 2 & 63]);
                var1.write(pem_array[(var5 << 4 & 48) + (var8 >>> 4 & 15)]);
                var1.write(pem_array[(var8 << 2 & 60) + (var10 >>> 6 & 3)]);
                var1.write(pem_array[var10 & 63]);
            }
        }

    }
}


//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package sun.misc;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PushbackInputStream;

public class BASE64Decoder extends CharacterDecoder {
    private static final char[] pem_array = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
    private static final byte[] pem_convert_array = new byte[256];
    byte[] decode_buffer = new byte[4];

    public BASE64Decoder() {
    }

    protected int bytesPerAtom() {
        return 4;
    }

    protected int bytesPerLine() {
        return 72;
    }

    protected void decodeAtom(PushbackInputStream var1, OutputStream var2, int var3) throws IOException {
        byte var5 = -1;
        byte var6 = -1;
        byte var7 = -1;
        byte var8 = -1;
        if (var3 < 2) {
            throw new CEFormatException("BASE64Decoder: Not enough bytes for an atom.");
        } else {
            int var4;
            do {
                var4 = var1.read();
                if (var4 == -1) {
                    throw new CEStreamExhausted();
                }
            } while(var4 == 10 || var4 == 13);

            this.decode_buffer[0] = (byte)var4;
            var4 = this.readFully(var1, this.decode_buffer, 1, var3 - 1);
            if (var4 == -1) {
                throw new CEStreamExhausted();
            } else {
                if (var3 > 3 && this.decode_buffer[3] == 61) {
                    var3 = 3;
                }

                if (var3 > 2 && this.decode_buffer[2] == 61) {
                    var3 = 2;
                }

                switch(var3) {
                case 4:
                    var8 = pem_convert_array[this.decode_buffer[3] & 255];
                case 3:
                    var7 = pem_convert_array[this.decode_buffer[2] & 255];
                case 2:
                    var6 = pem_convert_array[this.decode_buffer[1] & 255];
                    var5 = pem_convert_array[this.decode_buffer[0] & 255];
                default:
                    switch(var3) {
                    case 2:
                        var2.write((byte)(var5 << 2 & 252 | var6 >>> 4 & 3));
                        break;
                    case 3:
                        var2.write((byte)(var5 << 2 & 252 | var6 >>> 4 & 3));
                        var2.write((byte)(var6 << 4 & 240 | var7 >>> 2 & 15));
                        break;
                    case 4:
                        var2.write((byte)(var5 << 2 & 252 | var6 >>> 4 & 3));
                        var2.write((byte)(var6 << 4 & 240 | var7 >>> 2 & 15));
                        var2.write((byte)(var7 << 6 & 192 | var8 & 63));
                    }

                }
            }
        }
    }

    static {
        int var0;
        for(var0 = 0; var0 < 255; ++var0) {
            pem_convert_array[var0] = -1;
        }

        for(var0 = 0; var0 < pem_array.length; ++var0) {
            pem_convert_array[pem_array[var0]] = (byte)var0;
        }

    }
}


package sun.misc;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PushbackInputStream;
import java.nio.ByteBuffer;

public abstract class CharacterDecoder {
    public CharacterDecoder() {
    }

    protected abstract int bytesPerAtom();

    protected abstract int bytesPerLine();

    protected void decodeBufferPrefix(PushbackInputStream var1, OutputStream var2) throws IOException {
    }

    protected void decodeBufferSuffix(PushbackInputStream var1, OutputStream var2) throws IOException {
    }

    protected int decodeLinePrefix(PushbackInputStream var1, OutputStream var2) throws IOException {
        return this.bytesPerLine();
    }

    protected void decodeLineSuffix(PushbackInputStream var1, OutputStream var2) throws IOException {
    }

    protected void decodeAtom(PushbackInputStream var1, OutputStream var2, int var3) throws IOException {
        throw new CEStreamExhausted();
    }

    protected int readFully(InputStream var1, byte[] var2, int var3, int var4) throws IOException {
        for(int var5 = 0; var5 < var4; ++var5) {
            int var6 = var1.read();
            if (var6 == -1) {
                return var5 == 0 ? -1 : var5;
            }

            var2[var5 + var3] = (byte)var6;
        }

        return var4;
    }

    public void decodeBuffer(InputStream var1, OutputStream var2) throws IOException {
        int var4 = 0;
        PushbackInputStream var5 = new PushbackInputStream(var1);
        this.decodeBufferPrefix(var5, var2);

        while(true) {
            try {
                int var6 = this.decodeLinePrefix(var5, var2);

                int var3;
                for(var3 = 0; var3 + this.bytesPerAtom() < var6; var3 += this.bytesPerAtom()) {
                    this.decodeAtom(var5, var2, this.bytesPerAtom());
                    var4 += this.bytesPerAtom();
                }

                if (var3 + this.bytesPerAtom() == var6) {
                    this.decodeAtom(var5, var2, this.bytesPerAtom());
                    var4 += this.bytesPerAtom();
                } else {
                    this.decodeAtom(var5, var2, var6 - var3);
                    var4 += var6 - var3;
                }

                this.decodeLineSuffix(var5, var2);
            } catch (CEStreamExhausted var8) {
                this.decodeBufferSuffix(var5, var2);
                return;
            }
        }
    }

    public byte[] decodeBuffer(String var1) throws IOException {
        byte[] var2 = new byte[var1.length()];
        var1.getBytes(0, var1.length(), var2, 0);
        ByteArrayInputStream var3 = new ByteArrayInputStream(var2);
        ByteArrayOutputStream var4 = new ByteArrayOutputStream();
        this.decodeBuffer(var3, var4);
        return var4.toByteArray();
    }

    public byte[] decodeBuffer(InputStream var1) throws IOException {
        ByteArrayOutputStream var2 = new ByteArrayOutputStream();
        this.decodeBuffer(var1, var2);
        return var2.toByteArray();
    }

    public ByteBuffer decodeBufferToByteBuffer(String var1) throws IOException {
        return ByteBuffer.wrap(this.decodeBuffer(var1));
    }

    public ByteBuffer decodeBufferToByteBuffer(InputStream var1) throws IOException {
        return ByteBuffer.wrap(this.decodeBuffer(var1));
    }
}


package sun.misc;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.nio.ByteBuffer;

public abstract class CharacterEncoder {
    protected PrintStream pStream;

    public CharacterEncoder() {
    }

    protected abstract int bytesPerAtom();

    protected abstract int bytesPerLine();

    protected void encodeBufferPrefix(OutputStream var1) throws IOException {
        this.pStream = new PrintStream(var1);
    }

    protected void encodeBufferSuffix(OutputStream var1) throws IOException {
    }

    protected void encodeLinePrefix(OutputStream var1, int var2) throws IOException {
    }

    protected void encodeLineSuffix(OutputStream var1) throws IOException {
        this.pStream.println();
    }

    protected abstract void encodeAtom(OutputStream var1, byte[] var2, int var3, int var4) throws IOException;

    protected int readFully(InputStream var1, byte[] var2) throws IOException {
        for(int var3 = 0; var3 < var2.length; ++var3) {
            int var4 = var1.read();
            if (var4 == -1) {
                return var3;
            }

            var2[var3] = (byte)var4;
        }

        return var2.length;
    }

    public void encode(InputStream var1, OutputStream var2) throws IOException {
        byte[] var5 = new byte[this.bytesPerLine()];
        this.encodeBufferPrefix(var2);

        while(true) {
            int var4 = this.readFully(var1, var5);
            if (var4 == 0) {
                break;
            }

            this.encodeLinePrefix(var2, var4);

            for(int var3 = 0; var3 < var4; var3 += this.bytesPerAtom()) {
                if (var3 + this.bytesPerAtom() <= var4) {
                    this.encodeAtom(var2, var5, var3, this.bytesPerAtom());
                } else {
                    this.encodeAtom(var2, var5, var3, var4 - var3);
                }
            }

            if (var4 < this.bytesPerLine()) {
                break;
            }

            this.encodeLineSuffix(var2);
        }

        this.encodeBufferSuffix(var2);
    }

    public void encode(byte[] var1, OutputStream var2) throws IOException {
        ByteArrayInputStream var3 = new ByteArrayInputStream(var1);
        this.encode((InputStream)var3, var2);
    }

    public String encode(byte[] var1) {
        ByteArrayOutputStream var2 = new ByteArrayOutputStream();
        ByteArrayInputStream var3 = new ByteArrayInputStream(var1);
        String var4 = null;

        try {
            this.encode((InputStream)var3, var2);
            var4 = var2.toString("8859_1");
            return var4;
        } catch (Exception var6) {
            throw new Error("CharacterEncoder.encode internal error");
        }
    }

    private byte[] getBytes(ByteBuffer var1) {
        byte[] var2 = null;
        if (var1.hasArray()) {
            byte[] var3 = var1.array();
            if (var3.length == var1.capacity() && var3.length == var1.remaining()) {
                var2 = var3;
                var1.position(var1.limit());
            }
        }

        if (var2 == null) {
            var2 = new byte[var1.remaining()];
            var1.get(var2);
        }

        return var2;
    }

    public void encode(ByteBuffer var1, OutputStream var2) throws IOException {
        byte[] var3 = this.getBytes(var1);
        this.encode(var3, var2);
    }

    public String encode(ByteBuffer var1) {
        byte[] var2 = this.getBytes(var1);
        return this.encode(var2);
    }

    public void encodeBuffer(InputStream var1, OutputStream var2) throws IOException {
        byte[] var5 = new byte[this.bytesPerLine()];
        this.encodeBufferPrefix(var2);

        int var4;
        do {
            var4 = this.readFully(var1, var5);
            if (var4 == 0) {
                break;
            }

            this.encodeLinePrefix(var2, var4);

            for(int var3 = 0; var3 < var4; var3 += this.bytesPerAtom()) {
                if (var3 + this.bytesPerAtom() <= var4) {
                    this.encodeAtom(var2, var5, var3, this.bytesPerAtom());
                } else {
                    this.encodeAtom(var2, var5, var3, var4 - var3);
                }
            }

            this.encodeLineSuffix(var2);
        } while(var4 >= this.bytesPerLine());

        this.encodeBufferSuffix(var2);
    }

    public void encodeBuffer(byte[] var1, OutputStream var2) throws IOException {
        ByteArrayInputStream var3 = new ByteArrayInputStream(var1);
        this.encodeBuffer((InputStream)var3, var2);
    }

    public String encodeBuffer(byte[] var1) {
        ByteArrayOutputStream var2 = new ByteArrayOutputStream();
        ByteArrayInputStream var3 = new ByteArrayInputStream(var1);

        try {
            this.encodeBuffer((InputStream)var3, var2);
        } catch (Exception var5) {
            throw new Error("CharacterEncoder.encodeBuffer internal error");
        }

        return var2.toString();
    }

    public void encodeBuffer(ByteBuffer var1, OutputStream var2) throws IOException {
        byte[] var3 = this.getBytes(var1);
        this.encodeBuffer(var3, var2);
    }

    public String encodeBuffer(ByteBuffer var1) {
        byte[] var2 = this.getBytes(var1);
        return this.encodeBuffer(var2);
    }
}

js版本

sm4.js

function SM4Util() {
    this.secretKey = "sm4demo123456789";
    this.iv = "";

    this.decryptData_ECB = function (data) {
        var byteEcb = base64js.toByteArray(data);
        // 字符串转换成byte
        var key = this.stringToByte(this.secretKey);
        var sm4 = new SM4();
        // 进行sm
        var plain = sm4.decrypt_ecb(key, byteEcb);

        // 这里可以不转字符串可以转16进制 方法为Hex.encode
        return Hex.bytesToUtf8Str(plain);
    }

// 返回字符串
    this.encryptData_ECB = function (data) {

        var inputBytes = this.stringToByte(data);
        var key = this.stringToByte(this.secretKey);
        var sm4 = new SM4();
        var cipher = sm4.encrypt_ecb(key, inputBytes);
        // byte流转base字符串。
        var cipherText = base64js.fromByteArray(cipher);
        if (cipherText != null && cipherText.trim().length > 0) {
            cipherText.replace(/(\s*|\t|\r|\n)/g, "");
        }
        return cipherText;
    }

// 返回字符串
    this.decryptData_CBC = function (data) {
        var inputBytes = base64js.toByteArray(data);
        var key = this.stringToByte(this.secretKey);
        var iv = this.stringToByte(this.iv);
        var sm4 = new SM4();
        var plain = sm4.decrypt_cbc(key, iv, inputBytes);
        // 这里可以不转字符串可以转16进制 方法为Hex.encode
        return Hex.bytesToUtf8Str(plain);
    }

// 返回字符串
    this.encryptData_CBC = function (data) {
        var inputBytes = this.stringToByte(data);
        var key = this.stringToByte(this.secretKey);
        var iv = this.stringToByte(this.iv);
        var sm4 = new SM4();
        var cipher = sm4.encrypt_cbc(key, iv, inputBytes);
        // byte流转base字符串。
        var cipherText = base64js.fromByteArray(cipher);
        if (cipherText != null && cipherText.trim().length > 0) {
            cipherText.replace(/(\s*|\t|\r|\n)/g, "");
        }
        return cipherText;
    }


    this.stringToByte = function (str) {
        var bytes = new Array();
        var len, c;
        len = str.length;
        for (var i = 0; i < len; i++) {
            c = str.charCodeAt(i);
            if (c >= 0x010000 && c <= 0x10FFFF) {
                bytes.push(((c >> 18) & 0x07) | 0xF0);
                bytes.push(((c >> 12) & 0x3F) | 0x80);
                bytes.push(((c >> 6) & 0x3F) | 0x80);
                bytes.push((c & 0x3F) | 0x80);
            } else if (c >= 0x000800 && c <= 0x00FFFF) {
                bytes.push(((c >> 12) & 0x0F) | 0xE0);
                bytes.push(((c >> 6) & 0x3F) | 0x80);
                bytes.push((c & 0x3F) | 0x80);
            } else if (c >= 0x000080 && c <= 0x0007FF) {
                bytes.push(((c >> 6) & 0x1F) | 0xC0);
                bytes.push((c & 0x3F) | 0x80);
            } else {
                bytes.push(c & 0xFF);
            }
        }
        return bytes;
    }

}

function SM4() {

    this.sbox = new Array(
        0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
        0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
        0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
        0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
        0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
        0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
        0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
        0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
        0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
        0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
        0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
        0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
        0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
        0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
        0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
        0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
    );

    this.fk = new Array(0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc);
    this.ck = new Array(
        0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
        0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
        0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
        0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
        0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
        0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
        0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
        0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
    );
}

SM4.prototype = {
    expandKey: function (key) {
        var k = new Array(36);
        var mk = byteArrayToIntArray(key);
        k[0] = mk[0] ^ this.fk[0];
        k[1] = mk[1] ^ this.fk[1];
        k[2] = mk[2] ^ this.fk[2];
        k[3] = mk[3] ^ this.fk[3];
        var rk = new Array(32);
        for (var i = 0; i < 32; i++) {
            k[(i + 4)] = (k[i] ^ this.T1(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^ this.ck[i]));
            rk[i] = k[(i + 4)];
        }
        return rk;
    },
    T1: function (ta) {
        var rk = 0;
        var b = new Array(4);
        var a = intToByte(ta);
        b[0] = this.sbox[a[0] & 0xFF];
        b[1] = this.sbox[a[1] & 0xFF];
        b[2] = this.sbox[a[2] & 0xFF];
        b[3] = this.sbox[a[3] & 0xFF];
        var bint = byteToInt(b, 0);
        var rk = bint ^ (bint << 13 | (bint >>> (32 - 13))) ^ (bint << 23 | (bint >>> (32 - 23)));
        return rk;
    },
    one_encrypt: function (rk, data) {
        var x = new Array(36);
        x[0] = byteToInt(data, 0);
        x[1] = byteToInt(data, 4);
        x[2] = byteToInt(data, 8);
        x[3] = byteToInt(data, 12);
        for (var i = 0; i < 32; i++) {
            x[(i + 4)] = x[i] ^ this.T0(x[(i + 1)] ^ x[(i + 2)] ^ x[(i + 3)] ^ rk[i]);
        }
        var tmpx = new Array(4);
        for (var i = 35; i >= 32; i--) {
            tmpx[35 - i] = x[i];
        }
        var xbyte = intArrayToByteArray(tmpx);

        return xbyte;
    },
    T0: function (ta) {
        var a = intToByte(ta);
        var b = new Array(4);
        b[0] = this.sbox[a[0] & 0xFF];
        b[1] = this.sbox[a[1] & 0xFF];
        b[2] = this.sbox[a[2] & 0xFF];
        b[3] = this.sbox[a[3] & 0xFF];
        var bint = byteToInt(b, 0);
        var c = bint ^ (bint << 2 | (bint >>> (32 - 2))) ^ (bint << 10 | (bint >>> (32 - 10))) ^ (bint << 18 | (bint >>> (32 - 18))) ^ (bint << 24 | (bint >>> (32 - 24)));
        return c;
    },
    pkcs7padding: function (input, mode) {
        if (input == null) {
            return null;
        }

        var ret = null;
        if (mode == 1)//填充
        {
            var p = 16 - input.length % 16;
            ret = new Array(input.length + p);
            arrayCopy(input, 0, ret, 0, input.length);
            for (var i = 0; i < p; i++) {
                ret[input.length + i] = p;
            }
        } else//去除填充
        {
            var p = input[input.length - 1];
            ret = new Array(input.length - p);
            arrayCopy(input, 0, ret, 0, input.length - p);
        }
        return ret;
    },
    encrypt_ecb: function (key, data) {
        if (key == undefined || key == null || key.length % 16 != 0) {
            return null;
        }
        if (data == undefined || data == null || data.length <= 0) {
            return null;
        }
        var rk = this.expandKey(key);
        var blockLen = 16;
        var loop = parseInt(data.length / blockLen);//注意不能整除会有小数,要取整
        var cipher = new Array((loop + 1) * blockLen);
        var tmp = new Array(blockLen);
        var oneCipher = null;

        for (var i = 0; i < loop; i++) {
            arrayCopy(data, i * blockLen, tmp, 0, blockLen);
            oneCipher = this.one_encrypt(rk, tmp);
            arrayCopy(oneCipher, 0, cipher, i * blockLen, blockLen);
        }

        var lessData = new Array(data.length % blockLen);
        if (lessData.length > 0) {
            arrayCopy(data, loop * blockLen, lessData, 0, data.length % blockLen);
        }
        var padding = this.pkcs7padding(lessData, 1);
        oneCipher = this.one_encrypt(rk, padding);
        arrayCopy(oneCipher, 0, cipher, loop * blockLen, blockLen);

        return cipher;
    },
    decrypt_ecb: function (key, data) {
        if (key == undefined || key == null || key.length % 16 != 0) {
            return null;
        }
        if (data == undefined || data == null || data.length % 16 != 0) {
            return null;
        }
        var rk = this.expandKey(key);
        var nrk = new Array(32);
        for (var i = 0; i < rk.length; i++) {
            nrk[i] = rk[32 - i - 1];
        }
        var blockLen = 16;
        var loop = data.length / blockLen - 1;
        var tmp = new Array(blockLen);
        var onePlain = null;
        var plain = null;
        //先解密最后一部分,确定数据长度
        arrayCopy(data, loop * blockLen, tmp, 0, blockLen);
        onePlain = this.one_encrypt(nrk, tmp);
        var lastPart = this.pkcs7padding(onePlain, 0);

        plain = new Array(loop * blockLen + lastPart.length);
        arrayCopy(lastPart, 0, plain, loop * blockLen, lastPart.length);

        //解密剩下部分数据
        for (var i = 0; i < loop; i++) {
            arrayCopy(data, i * blockLen, tmp, 0, blockLen);
            onePlain = this.one_encrypt(nrk, tmp);
            arrayCopy(onePlain, 0, plain, i * blockLen, blockLen);
        }

        return plain;
    },
    encrypt_cbc: function (key, iv, data) {
        if (key == undefined || key == null || key.length % 16 != 0) {
            return null;
        }
        if (data == undefined || data == null || data.length <= 0) {
            return null;
        }
        if (iv == undefined || iv == null || iv.length % 16 != 0) {
            return null;
        }
        var rk = this.expandKey(key);
        var blockLen = 16;
        var loop = parseInt(data.length / blockLen);//注意不能整除会有小数,要取整
        var cipher = new Array((loop + 1) * blockLen);
        var tmp = new Array(blockLen);

        for (var i = 0; i < loop; i++) {
            arrayCopy(data, i * blockLen, tmp, 0, blockLen);
            for (var j = 0; j < blockLen; j++) {
                tmp[j] = tmp[j] ^ iv[j];
            }
            iv = this.one_encrypt(rk, tmp);
            arrayCopy(iv, 0, cipher, i * blockLen, blockLen);
        }

        var lessData = new Array(data.length % blockLen);
        if (lessData.length > 0) {
            arrayCopy(data, loop * blockLen, lessData, 0, data.length % blockLen);
        }
        var padding = this.pkcs7padding(lessData, 1);
        for (var i = 0; i < blockLen; i++) {
            padding[i] = padding[i] ^ iv[i];
        }
        iv = this.one_encrypt(rk, padding);
        arrayCopy(iv, 0, cipher, loop * blockLen, blockLen);

        return cipher;
    },
    decrypt_cbc: function (key, iv, data) {
        if (key == undefined || key == null || key.length % 16 != 0) {
            return null;
        }
        if (data == undefined || data == null || data.length % 16 != 0) {
            return null;
        }
        if (iv == undefined || iv == null || iv.length % 16 != 0) {
            return null;
        }
        var rk = this.expandKey(key);
        var nrk = new Array(32);
        for (var i = 0; i < rk.length; i++) {
            nrk[i] = rk[32 - i - 1];
        }
        var blockLen = 16;
        var loop = data.length / blockLen;
        var tmp = new Array(blockLen);
        var onePlain = null;
        var plain = null;


        //解密
        plain = new Array(data.length);
        for (var i = 0; i < loop; i++) {
            arrayCopy(data, i * blockLen, tmp, 0, blockLen);
            onePlain = this.one_encrypt(nrk, tmp);
            for (var j = 0; j < blockLen; j++) {
                onePlain[j] = onePlain[j] ^ iv[j];
            }
            arrayCopy(tmp, 0, iv, 0, blockLen);
            arrayCopy(onePlain, 0, plain, i * blockLen, blockLen);
        }

        //去填充,确定数据长度
        var lastPart = this.pkcs7padding(onePlain, 0);

        var realPlain = new Array(plain.length - blockLen + lastPart.length);
        arrayCopy(plain, 0, realPlain, 0, plain.length - blockLen);
        arrayCopy(lastPart, 0, realPlain, plain.length - blockLen, lastPart.length);

        return realPlain;
    }
}

function Hex() {

}

Hex.encode = function (b, pos, len) {
    var hexCh = new Array(len * 2);
    var hexCode = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');

    for (var i = pos, j = 0; i < len + pos; i++, j++) {
        hexCh[j] = hexCode[(b[i] & 0xFF) >> 4];
        hexCh[++j] = hexCode[(b[i] & 0x0F)];
    }

    return hexCh.join('');
}

Hex.decode = function (hex) {

    if (hex == null || hex == '') {
        return null;
    }
    if (hex.length % 2 != 0) {
        return null;
    }

    var ascLen = hex.length / 2;
    var hexCh = this.toCharCodeArray(hex);
    var asc = new Array(ascLen);

    for (var i = 0; i < ascLen; i++) {

        if (hexCh[2 * i] >= 0x30 && hexCh[2 * i] <= 0x39) {
            asc[i] = ((hexCh[2 * i] - 0x30) << 4);
        } else if (hexCh[2 * i] >= 0x41 && hexCh[2 * i] <= 0x46) {//A-F : 0x41-0x46
            asc[i] = ((hexCh[2 * i] - 0x41 + 10) << 4);
        } else if (hexCh[2 * i] >= 0x61 && hexCh[2 * i] <= 0x66) {//a-f  : 0x61-0x66
            asc[i] = ((hexCh[2 * i] - 0x61 + 10) << 4);
        } else {
            return null;
        }

        if (hexCh[2 * i + 1] >= 0x30 && hexCh[2 * i + 1] <= 0x39) {
            asc[i] = (asc[i] | (hexCh[2 * i + 1] - 0x30));
        } else if (hexCh[2 * i + 1] >= 0x41 && hexCh[2 * i + 1] <= 0x46) {
            asc[i] = (asc[i] | (hexCh[2 * i + 1] - 0x41 + 10));
        } else if (hexCh[2 * i + 1] >= 0x61 && hexCh[2 * i + 1] <= 0x66) {
            asc[i] = (asc[i] | (hexCh[2 * i + 1] - 0x61 + 10));
        } else {
            return null;
        }
    }
    return asc;
}

Hex.utf8StrToHex = function (utf8Str) {
    var ens = encodeURIComponent(utf8Str);
    var es = unescape(ens);
    var esLen = es.length;

    // Convert
    var words = [];
    for (var i = 0; i < esLen; i++) {
        words[i] = (es.charCodeAt(i).toString(16));
    }
    return words.join('');
}

Hex.utf8StrToBytes = function (utf8Str) {
    var ens = encodeURIComponent(utf8Str);
    var es = unescape(ens);
    var esLen = es.length;

    // Convert
    var words = [];
    for (var i = 0; i < esLen; i++) {
        words[i] = es.charCodeAt(i);
    }
    return words;
}

Hex.hexToUtf8Str = function (utf8Str) {
    var utf8Byte = Hex.decode(utf8Str);
    var latin1Chars = [];
    for (var i = 0; i < utf8Byte.length; i++) {
        latin1Chars.push(String.fromCharCode(utf8Byte[i]));
    }
    return decodeURIComponent(escape(latin1Chars.join('')));
}

Hex.bytesToUtf8Str = function (bytesArray) {
    var utf8Byte = bytesArray;
    var latin1Chars = [];
    for (var i = 0; i < utf8Byte.length; i++) {
        latin1Chars.push(String.fromCharCode(utf8Byte[i]));
    }
    return decodeURIComponent(escape(latin1Chars.join('')));
}

Hex.toCharCodeArray = function (chs) {
    var chArr = new Array(chs.length);
    for (var i = 0; i < chs.length; i++) {
        chArr[i] = chs.charCodeAt(i);
    }
    return chArr;
}
/*
*
* 字节流转换工具js
*
*/

/*
 * 数组复制
 */
function arrayCopy(src, pos1, dest, pos2, len) {
    var realLen = len;
    if (pos1 + len > src.length && pos2 + len <= dest.length) {
        realLen = src.length - pos1;
    } else if (pos2 + len > dest.length && pos1 + len <= src.length) {
        realLen = dest.length - pos2;
    } else if (pos1 + len <= src.length && pos2 + len <= dest.length) {
        realLen = len;
    } else if (dest.length < src.length) {
        realLen = dest.length - pos2;
    } else {
        realLen = src.length - pos2;
    }

    for (var i = 0; i < realLen; i++) {
        dest[i + pos2] = src[i + pos1];
    }
}

/*
 * 长整型转成字节,一个长整型为8字节
 * 返回:字节数组
 */
function longToByte(num) {
    //TODO 这里目前只转换了低四字节,因为js没有长整型,得要封装
    return new Array(
        0,
        0,
        0,
        0,
        (num >> 24) & 0x000000FF,
        (num >> 16) & 0x000000FF,
        (num >> 8) & 0x000000FF,
        (num) & 0x000000FF
    );
}

/*
 * int数转成byte数组
 * 事实上只不过转成byte大小的数,实际占用空间还是4字节
 * 返回:字节数组
 */
function intToByte(num) {
    return new Array(
        (num >> 24) & 0x000000FF,
        (num >> 16) & 0x000000FF,
        (num >> 8) & 0x000000FF,
        (num) & 0x000000FF
    );
}

/*
 * int数组转成byte数组,一个int数值转成四个byte
 * 返回:byte数组
 */
function intArrayToByteArray(nums) {
    var b = new Array(nums.length * 4);

    for (var i = 0; i < nums.length; i++) {
        arrayCopy(intToByte(nums[i]), 0, b, i * 4, 4);
    }

    return b;
}

/*
 * byte数组转成int数值
 * 返回:int数值
 */
function byteToInt(b, pos) {
    if (pos + 3 < b.length) {
        return ((b[pos]) << 24) | ((b[pos + 1]) << 16) | ((b[pos + 2]) << 8) | ((b[pos + 3]));
    } else if (pos + 2 < b.length) {
        return ((b[pos + 1]) << 16) | ((b[pos + 2]) << 8) | ((b[pos + 3]));
    } else if (pos + 1 < b.length) {
        return ((b[pos]) << 8) | ((b[pos + 1]));
    } else {
        return ((b[pos]));
    }
}

/*
 * byte数组转成int数组,每四个字节转成一个int数值
 *
 */
function byteArrayToIntArray(b) {
    // var arrLen = b.length%4==0 ? b.length/4:b.length/4+1;
    var arrLen = Math.ceil(b.length / 4);//向上取整
    var out = new Array(arrLen);
    for (var i = 0; i < b.length; i++) {
        b[i] = b[i] & 0xFF;//避免负数造成影响
    }
    for (var i = 0; i < out.length; i++) {
        out[i] = byteToInt(b, i * 4);
    }
    return out;
}

(function (r) {
    if (typeof exports === "object" && typeof module !== "undefined") {
        module.exports = r()
    } else {
        if (typeof define ===
            "function" && define.amd) {
            define([], r)
        } else {
            var e;
            if (typeof window !== "undefined") {
                e = window
            } else {
                if (typeof global
                    !== "undefined") {
                    e = global
                } else {
                    if (typeof self !== "undefined") {
                        e = self
                    } else {
                        e = this
                    }
                }
            }
            e.base64js = r()
        }
    }
})(function () {
    var r, e, t;
    return function r(e, t, n) {
        function o(i, a) {
            if (!t[i]) {
                if (!e[i]) {
                    var u = typeof require == "function" && require;
                    if (!a && u) {
                        return u(i, !0)
                    }
                    if (f) {
                        return f(i, !0)
                    }
                    var d = new Error("Cannot find module '" + i + "'");
                    throw d.code = "MODULE_NOT_FOUND", d
                }
                var c = t[i] = {exports: {}};
                e[i][0].call(c.exports, function (r) {
                    var t = e[i][1][r];
                    return o(t ? t : r)
                }, c, c.exports, r, e, t, n)
            }
            return t[i].exports
        }

        var f = typeof require == "function" && require;
        for (var i = 0; i < n.length; i++) {
            o(n[i])
        }
        return o
    }({
        "/": [function (r, e, t) {
            t.byteLength = c;
            t.toByteArray = v;
            t.fromByteArray = s;
            var n = [];
            var o = [];
            var f = typeof Uint8Array !== "undefined" ? Uint8Array : Array;
            var i = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
            for (var a = 0, u = i.length; a < u; ++a) {
                n[a] = i[a];
                o[i.charCodeAt(a)] = a
            }
            o["-".charCodeAt(0)] = 62;
            o["_".charCodeAt(0)] = 63;

            function d(r) {
                var e = r.length;
                if (e % 4 > 0) {
                    throw new Error("Invalid string. Length must be a multiple of 4")
                }
                return r[e - 2] === "=" ? 2 : r[e - 1] === "=" ? 1 : 0
            }

            function c(r) {
                return r.length * 3 / 4 - d(r)
            }

            function v(r) {
                var e, t, n, i, a;
                var u = r.length;
                i = d(r);
                a = new f(u * 3 / 4 - i);
                t = i > 0 ? u - 4 : u;
                var c = 0;
                for (e = 0; e < t; e += 4) {
                    n = o[r.charCodeAt(e)] << 18 | o[r.charCodeAt(e + 1)] << 12 | o[r.charCodeAt(e + 2)] << 6 | o[r.charCodeAt(e + 3)];
                    a[c++] = n >> 16 & 255;
                    a[c++] = n >> 8 & 255;
                    a[c++] = n & 255
                }
                if (i === 2) {
                    n = o[r.charCodeAt(e)] << 2 | o[r.charCodeAt(e + 1)] >> 4;
                    a[c++] = n & 255
                } else {
                    if (i === 1) {
                        n = o[r.charCodeAt(e)] << 10 | o[r.charCodeAt(e + 1)] << 4 | o[r.charCodeAt(e + 2)] >> 2;
                        a[c++] = n >> 8 & 255;
                        a[c++] = n & 255
                    }
                }
                return a
            }

            function l(r) {
                return n[r >> 18 & 63] + n[r >> 12 & 63] + n[r >> 6 & 63] + n[r & 63]
            }

            function h(r, e, t) {
                var n;
                var o = [];
                for (var f = e; f < t; f += 3) {
                    n = (r[f] << 16) + (r[f + 1] << 8) + r[f + 2];
                    o.push(l(n))
                }
                return o.join("")
            }

            function s(r) {
                var e;
                var t = r.length;
                var o = t % 3;
                var f = "";
                var i = [];
                var a = 16383;
                for (var u = 0, d = t - o; u < d; u += a) {
                    i.push(h(r, u, u + a > d ? d : u + a))
                }
                if (o === 1) {
                    e = r[t - 1];
                    f += n[e >> 2];
                    f += n[e << 4 & 63];
                    f += "=="
                } else {
                    if (o === 2) {
                        e = (r[t - 2] << 8) + r[t - 1];
                        f += n[e >> 10];
                        f += n[e >> 4 & 63];
                        f += n[e << 2 & 63];
                        f += "="
                    }
                }
                i.push(f);
                return i.join("")
            }
        }, {}]
    }, {}, [])("/")
});

html的demo代码

<!DOCTYPE html<html>

<head>
    <meta charset="UTF-8">
    <title>SM4的加密解密</title>
</head>
<script type="text/javascript" src="./js/sm4.js"></script>

<body>
<script  type="text/javascript">

    let sm4 =new SM4Util();
    let text = "你好";
    let encryptDataECB = sm4.encryptData_ECB(text);
    console.log("encryptDataECB  = ", encryptDataECB);
    let decryptDataECB = sm4.decryptData_ECB(encryptDataECB);
    console.log("decryptDataECB  = ", decryptDataECB);
</script>
</body>
</body>
</html>

IOS版

下面是ios的实现。采用国密 国密的 Objective-C 封装

查看具体实现过程,请至开源项目地址https://github.com/muzipiao/GMObjC。

- (void)testSm4{
    NSString *sm4Key = [GMUtils stringToHex:@"sm4demo123456789"]; //  生成 32 字节 Hex 编码格式字符串密钥
    // ECB 加解密模式
    NSString *sm4EcbCipertext = [GMSm4Utils ecbEncryptText:self.gPwd key:sm4Key];
    NSData *hexDecode = [GMUtils hexToData:sm4EcbCipertext];
    NSString *base64 = [hexDecode base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    
    NSLog(@"base64密文:%@",base64);
    NSString *sm4EcbPlaintext = [GMSm4Utils ecbDecryptText:sm4EcbCipertext key:sm4Key];
    
    NSMutableString *mStr = [NSMutableString stringWithString:self.gTextView.text];
    [mStr appendString:@"\n-------SM4加解密-------"];
    [mStr appendFormat:@"\nSM4密钥:\n%@", sm4Key];
    [mStr appendFormat:@"\nECB 模式加密密文:\n%@", sm4EcbCipertext];
    [mStr appendFormat:@"\nECB模式解密结果:\n%@", sm4EcbPlaintext];
    
    // CBC 加解密模式
    NSString *ivec = [GMSm4Utils createSm4Key]; // 生成 32 字节初始化向量
    NSString *sm4CbcCipertext = [GMSm4Utils cbcEncryptText:self.gPwd key:sm4Key IV:ivec];
    NSString *sm4CbcPlaintext = [GMSm4Utils cbcDecryptText:sm4CbcCipertext key:sm4Key IV:ivec];
    
    [mStr appendFormat:@"\nCBC模式需要的16字节向量:\n%@", ivec];
    [mStr appendFormat:@"\nCBC模式加密密文:\n%@", sm4CbcCipertext];
    [mStr appendFormat:@"\nCBC模式解密结果:\n%@", sm4CbcPlaintext];
    self.gTextView.text = mStr;
    
    // 加解密文件,任意文件可读取为 NSData 格式
    NSString *txtPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"sm4TestFile.txt" ofType:nil];
    NSData *fileData = [NSData dataWithContentsOfFile:txtPath];
    // 读取的文本文件
    NSString *orginStr = [[NSString alloc] initWithData:fileData encoding:NSUTF8StringEncoding];
    NSLog(@"文本文件原文:\n%@", orginStr);
    
    // ECB 模式加解密
    NSData *ecbCipherData = [GMSm4Utils ecbEncryptData:fileData key:sm4Key];
    NSData *ecbDecryptData = [GMSm4Utils ecbDecryptData:ecbCipherData key:sm4Key];
    // CBC 模式加解密
    NSData *cbcCipherData = [GMSm4Utils cbcEncryptData:fileData key:sm4Key IV:ivec];
    NSData *cbcDecryptData = [GMSm4Utils cbcDecryptData:cbcCipherData key:sm4Key IV:ivec];
    // 加解密后台文本不变
    NSString *sm4EcbFileStr = [[NSString alloc] initWithData:ecbDecryptData encoding:NSUTF8StringEncoding];
    NSString *sm4CbcFileStr = [[NSString alloc] initWithData:cbcDecryptData encoding:NSUTF8StringEncoding];
    NSLog(@"SM4 ECB 模式加解密后文本:\n%@", sm4EcbFileStr);
    NSLog(@"SM4 CBC 模式加解密后文本:\n%@", sm4CbcFileStr);
}

自己去试试吧




文章转载自公众号:IT学习道场

分类
已于2023-6-29 14:02:19修改
收藏
回复
举报
回复
    相关推荐