1. 程式人生 > >Java實現國密演算法SM2,SM3,SM4,並且實現ECB和CBC模式

Java實現國密演算法SM2,SM3,SM4,並且實現ECB和CBC模式

程式碼中實現了電碼本ECB模式和密文分組連線CBC模式,SM3.java和SM4.java為演算法實現類,utils的都是根據實現類寫的工具,可以根據需要呼叫雜湊演算法SM3的雜湊功能獲得雜湊值。



SM4.java中

sm4_crypt_ecb(SM4_Context ctx, byte[] input)      ECB模式加解密方法,根據金鑰判斷加解密功能

sm4_crypt_cbc(SM4_Context ctx, byte[] iv, byte[] input)      CBC模式加解密方法,根據金鑰判斷加解密功能

加密解密通過如下方法:

sm4_setkey_enc(SM4_Context ctx, byte[] key)  設定加密金鑰呼叫上述方法,實現加密

sm4_setkey_dec(SM4_Context ctx, byte[] key)  設定解密金鑰呼叫上述方法,實現解密

需要匯入的包為bcprov-jdk16  我用的版本是bcprov-jdk16-1.46

maven中配置依賴:

<dependency>
	<groupId>org.bouncycastle</groupId>
	<artifactId></artifactId>
	<version>1.46</version>
</dependency>

package中class目錄如下:


chiper.java

import java.math.BigInteger;  
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;  
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;  
import org.bouncycastle.crypto.params.ECPublicKeyParameters;  
import org.bouncycastle.math.ec.ECPoint; 

public class Cipher {
	 private int ct;  
	    private ECPoint p2;  
	    private SM3Digest sm3keybase;  
	    private SM3Digest sm3c3;  
	    private byte key[];  
	    private byte keyOff;  
	  
	    public Cipher()   
	    {  
	        this.ct = 1;  
	        this.key = new byte[32];  
	        this.keyOff = 0;  
	    }  
	  
	    private void Reset()   
	    {  
	        this.sm3keybase = new SM3Digest();  
	        this.sm3c3 = new SM3Digest();  
	          
	        byte p[] = Util.byteConvert32Bytes(p2.getX().toBigInteger());  
	        this.sm3keybase.update(p, 0, p.length);  
	        this.sm3c3.update(p, 0, p.length);  
	          
	        p = Util.byteConvert32Bytes(p2.getY().toBigInteger());  
	        this.sm3keybase.update(p, 0, p.length);  
	        this.ct = 1;  
	        NextKey();  
	    }  
	  
	    private void NextKey()   
	    {  
	        SM3Digest sm3keycur = new SM3Digest(this.sm3keybase);  
	        sm3keycur.update((byte) (ct >> 24 & 0xff));  
	        sm3keycur.update((byte) (ct >> 16 & 0xff));  
	        sm3keycur.update((byte) (ct >> 8 & 0xff));  
	        sm3keycur.update((byte) (ct & 0xff));  
	        sm3keycur.doFinal(key, 0);  
	        this.keyOff = 0;  
	        this.ct++;  
	    }  
	  
	    public ECPoint Init_enc(SM2 sm2, ECPoint userKey)   
	    {  
	        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();  
	        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();  
	        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();  
	        BigInteger k = ecpriv.getD();  
	        ECPoint c1 = ecpub.getQ();  
	        this.p2 = userKey.multiply(k);  
	        Reset();  
	        return c1;  
	    }  
	  
	    public void Encrypt(byte data[])   
	    {  
	        this.sm3c3.update(data, 0, data.length);  
	        for (int i = 0; i < data.length; i++)   
	        {  
	            if (keyOff == key.length)  
	            {  
	                NextKey();  
	            }  
	            data[i] ^= key[keyOff++];  
	        }  
	    }  
	  
	    public void Init_dec(BigInteger userD, ECPoint c1)  
	    {  
	        this.p2 = c1.multiply(userD);  
	        Reset();  
	    }  
	  
	    public void Decrypt(byte data[])   
	    {  
	        for (int i = 0; i < data.length; i++)  
	        {  
	            if (keyOff == key.length)  
	            {  
	                NextKey();  
	            }  
	            data[i] ^= key[keyOff++];  
	        }  
	  
	        this.sm3c3.update(data, 0, data.length);  
	    }  
	  
	    public void Dofinal(byte c3[])   
	    {  
	        byte p[] = Util.byteConvert32Bytes(p2.getY().toBigInteger());  
	        this.sm3c3.update(p, 0, p.length);  
	        this.sm3c3.doFinal(c3, 0);  
	        Reset();  
	    }  
}
SM2.java
import java.math.BigInteger;  
import java.security.SecureRandom;  
  
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;  
import org.bouncycastle.crypto.params.ECDomainParameters;  
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;  
import org.bouncycastle.math.ec.ECCurve;  
import org.bouncycastle.math.ec.ECFieldElement;  
import org.bouncycastle.math.ec.ECPoint;  
import org.bouncycastle.math.ec.ECFieldElement.Fp;  

public class SM2 {
	 //測試引數  
//  public static final String[] ecc_param = {  
//      "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",   
//      "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",   
//      "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",   
//      "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",   
//      "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",   
//      "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2"   
//  };  
      
    //正式引數  
    public static String[] ecc_param = {   
        "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",  
        "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",  
        "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",  
        "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",  
        "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",  
        "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"  
    };  
  
    public static SM2 Instance()   
    {  
        return new SM2();  
    }  
  
    public final BigInteger ecc_p;  
    public final BigInteger ecc_a;  
    public final BigInteger ecc_b;  
    public final BigInteger ecc_n;  
    public final BigInteger ecc_gx;  
    public final BigInteger ecc_gy;  
    public final ECCurve ecc_curve;  
    public final ECPoint ecc_point_g;  
    public final ECDomainParameters ecc_bc_spec;  
    public final ECKeyPairGenerator ecc_key_pair_generator;  
    public final ECFieldElement ecc_gx_fieldelement;  
    public final ECFieldElement ecc_gy_fieldelement;  
  
    public SM2()   
    {  
        this.ecc_p = new BigInteger(ecc_param[0], 16);  
        this.ecc_a = new BigInteger(ecc_param[1], 16);  
        this.ecc_b = new BigInteger(ecc_param[2], 16);  
        this.ecc_n = new BigInteger(ecc_param[3], 16);  
        this.ecc_gx = new BigInteger(ecc_param[4], 16);  
        this.ecc_gy = new BigInteger(ecc_param[5], 16);  
  
        this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx);  
        this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy);  
  
        this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b);  
        this.ecc_point_g = new ECPoint.Fp(this.ecc_curve, this.ecc_gx_fieldelement, this.ecc_gy_fieldelement);  
  
        this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.ecc_n);  
  
        ECKeyGenerationParameters ecc_ecgenparam;  
        ecc_ecgenparam = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom());  
  
        this.ecc_key_pair_generator = new ECKeyPairGenerator();  
        this.ecc_key_pair_generator.init(ecc_ecgenparam);  
    }  
}

SM2Utils.java

import java.io.IOException;  
import java.math.BigInteger;  
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;  
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;  
import org.bouncycastle.crypto.params.ECPublicKeyParameters;  
import org.bouncycastle.math.ec.ECPoint; 

public class SM2Utils {
	  //生成隨機祕鑰對  
    public static void generateKeyPair(){  
        SM2 sm2 = SM2.Instance();  
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();  
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();  
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();  
        BigInteger privateKey = ecpriv.getD();  
        ECPoint publicKey = ecpub.getQ();  
          
        System.out.println("公鑰: " + Util.byteToHex(publicKey.getEncoded()));  
        System.out.println("私鑰: " + Util.byteToHex(privateKey.toByteArray()));  
    }  
      
    //資料加密  
    public static String encrypt(byte[] publicKey, byte[] data) throws IOException  
    {  
        if (publicKey == null || publicKey.length == 0)  
        {  
            return null;  
        }  
          
        if (data == null || data.length == 0)  
        {  
            return null;  
        }  
          
        byte[] source = new byte[data.length];  
        System.arraycopy(data, 0, source, 0, data.length);  
          
        Cipher cipher = new Cipher();  
        SM2 sm2 = SM2.Instance();  
        ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);  
          
        ECPoint c1 = cipher.Init_enc(sm2, userKey);  
        cipher.Encrypt(source);  
        byte[] c3 = new byte[32];  
        cipher.Dofinal(c3);  
          
//      System.out.println("C1 " + Util.byteToHex(c1.getEncoded()));  
//      System.out.println("C2 " + Util.byteToHex(source));  
//      System.out.println("C3 " + Util.byteToHex(c3));  
        //C1 C2 C3拼裝成加密字串  
        return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(source) + Util.byteToHex(c3);  
          
    }  
      
    //資料解密  
    public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException  
    {  
        if (privateKey == null || privateKey.length == 0)  
        {  
            return null;  
        }  
          
        if (encryptedData == null || encryptedData.length == 0)  
        {  
            return null;  
        }  
        //加密位元組陣列轉換為十六進位制的字串 長度變為encryptedData.length * 2  
        String data = Util.byteToHex(encryptedData);  
        /***分解加密字串 
         * (C1 = C1標誌位2位 + C1實體部分128位 = 130) 
         * (C3 = C3實體部分64位  = 64) 
         * (C2 = encryptedData.length * 2 - C1長度  - C2長度) 
         */  
        byte[] c1Bytes = Util.hexToByte(data.substring(0,130));  
        int c2Len = encryptedData.length - 97;  
        byte[] c2 = Util.hexToByte(data.substring(130,130 + 2 * c2Len));  
        byte[] c3 = Util.hexToByte(data.substring(130 + 2 * c2Len,194 + 2 * c2Len));  
          
        SM2 sm2 = SM2.Instance();  
        BigInteger userD = new BigInteger(1, privateKey);  
          
        //通過C1實體位元組來生成ECPoint  
        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);  
        Cipher cipher = new Cipher();  
        cipher.Init_dec(userD, c1);  
        cipher.Decrypt(c2);  
        cipher.Dofinal(c3);  
          
        //返回解密結果  
        return c2;  
    }  
      
    public static void main(String[] args) throws Exception   
    {  
        //生成金鑰對  
        generateKeyPair();  
          
        String plainText = "ererfeiisgod";  
        byte[] sourceData = plainText.getBytes();  
          
        //下面的祕鑰可以使用generateKeyPair()生成的祕鑰內容  
        // 國密規範正式私鑰  
        String prik = "3690655E33D5EA3D9A4AE1A1ADD766FDEA045CDEAA43A9206FB8C430CEFE0D94";  
        // 國密規範正式公鑰  
        String pubk = "04F6E0C3345AE42B51E06BF50B98834988D54EBC7460FE135A48171BC0629EAE205EEDE253A530608178A98F1E19BB737302813BA39ED3FA3C51639D7A20C7391A";  
          
        System.out.println("加密: ");  
        String cipherText = SM2Utils.encrypt(Util.hexToByte(pubk), sourceData);  
        System.out.println(cipherText);  
        System.out.println("解密: ");  
        plainText = new String(SM2Utils.decrypt(Util.hexToByte(prik), Util.hexToByte(cipherText)));  
        System.out.println(plainText);  
          
    }  
}

SM3.java

public class SM3 {
	 public static final byte[] iv = { 0x73, (byte) 0x80, 0x16, 0x6f, 0x49,  
		        0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24, 0x42, (byte) 0xd7,  
		        (byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30,  
		        (byte) 0xbc, (byte) 0x16, 0x31, 0x38, (byte) 0xaa, (byte) 0xe3,  
		        (byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte) 0xfb, 0x0e,  
		        0x4e };  
		      
		    public static int[] Tj = new int[64];  
		      
		    static   
		    {  
		        for (int i = 0; i < 16; i++)   
		        {  
		            Tj[i] = 0x79cc4519;  
		        }  
		      
		        for (int i = 16; i < 64; i++)   
		        {  
		            Tj[i] = 0x7a879d8a;  
		        }  
		    }  
		  
		    public static byte[] CF(byte[] V, byte[] B)   
		    {  
		        int[] v, b;  
		        v = convert(V);  
		        b = convert(B);  
		        return convert(CF(v, b));  
		    }  
		  
		    private static int[] convert(byte[] arr)  
		    {  
		        int[] out = new int[arr.length / 4];  
		        byte[] tmp = new byte[4];  
		        for (int i = 0; i < arr.length; i += 4)   
		        {  
		            System.arraycopy(arr, i, tmp, 0, 4);  
		            out[i / 4] = bigEndianByteToInt(tmp);  
		        }  
		        return out;  
		    }  
		  
		    private static byte[] convert(int[] arr)   
		    {  
		        byte[] out = new byte[arr.length * 4];  
		        byte[] tmp = null;  
		        for (int i = 0; i < arr.length; i++)   
		        {  
		            tmp = bigEndianIntToByte(arr[i]);  
		            System.arraycopy(tmp, 0, out, i * 4, 4);  
		        }  
		        return out;  
		    }  
		  
		    public static int[] CF(int[] V, int[] B)   
		    {  
		        int a, b, c, d, e, f, g, h;  
		        int ss1, ss2, tt1, tt2;  
		        a = V[0];  
		        b = V[1];  
		        c = V[2];  
		        d = V[3];  
		        e = V[4];  
		        f = V[5];  
		        g = V[6];  
		        h = V[7];  
		          
		        int[][] arr = expand(B);  
		        int[] w = arr[0];  
		        int[] w1 = arr[1];  
		          
		        for (int j = 0; j < 64; j++)  
		        {  
		            ss1 = (bitCycleLeft(a, 12) + e + bitCycleLeft(Tj[j], j));  
		            ss1 = bitCycleLeft(ss1, 7);  
		            ss2 = ss1 ^ bitCycleLeft(a, 12);  
		            tt1 = FFj(a, b, c, j) + d + ss2 + w1[j];  
		            tt2 = GGj(e, f, g, j) + h + ss1 + w[j];  
		            d = c;  
		            c = bitCycleLeft(b, 9);  
		            b = a;  
		            a = tt1;  
		            h = g;  
		            g = bitCycleLeft(f, 19);  
		            f = e;  
		            e = P0(tt2);  
		  
		            /*System.out.print(j+" "); 
		            System.out.print(Integer.toHexString(a)+" "); 
		            System.out.print(Integer.toHexString(b)+" "); 
		            System.out.print(Integer.toHexString(c)+" "); 
		            System.out.print(Integer.toHexString(d)+" "); 
		            System.out.print(Integer.toHexString(e)+" "); 
		            System.out.print(Integer.toHexString(f)+" "); 
		            System.out.print(Integer.toHexString(g)+" "); 
		            System.out.print(Integer.toHexString(h)+" "); 
		            System.out.println("");*/  
		        }  
//		      System.out.println("");  
		  
		        int[] out = new int[8];  
		        out[0] = a ^ V[0];  
		        out[1] = b ^ V[1];  
		        out[2] = c ^ V[2];  
		        out[3] = d ^ V[3];  
		        out[4] = e ^ V[4];  
		        out[5] = f ^ V[5];  
		        out[6] = g ^ V[6];  
		        out[7] = h ^ V[7];  
		  
		        return out;  
		    }  
		  
		    private static int[][] expand(int[] B)   
		    {  
		        int W[] = new int[68];  
		        int W1[] = new int[64];  
		        for (int i = 0; i < B.length; i++)  
		        {  
		            W[i] = B[i];  
		        }  
		  
		        for (int i = 16; i < 68; i++)   
		        {  
		            W[i] = P1(W[i - 16] ^ W[i - 9] ^ bitCycleLeft(W[i - 3], 15))  
		                    ^ bitCycleLeft(W[i - 13], 7) ^ W[i - 6];  
		        }  
		  
		        for (int i = 0; i < 64; i++)   
		        {  
		            W1[i] = W[i] ^ W[i + 4];  
		        }  
		  
		        int arr[][] = new int[][] { W, W1 };  
		        return arr;  
		    }  
		  
		    private static byte[] bigEndianIntToByte(int num)   
		    {  
		        return back(Util.intToBytes(num));  
		    }  
		  
		    private static int bigEndianByteToInt(byte[] bytes)  
		    {  
		        return Util.byteToInt(back(bytes));  
		    }  
		  
		    private static int FFj(int X, int Y, int Z, int j)   
		    {  
		        if (j >= 0 && j <= 15)   
		        {  
		            return FF1j(X, Y, Z);  
		        }  
		        else   
		        {  
		            return FF2j(X, Y, Z);  
		        }  
		    }  
		  
		    private static int GGj(int X, int Y, int Z, int j)   
		    {  
		        if (j >= 0 && j <= 15)   
		        {  
		            return GG1j(X, Y, Z);  
		        }  
		        else  
		        {  
		            return GG2j(X, Y, Z);  
		        }  
		    }  
		  
		    // 邏輯位運算函式  
		    private static int FF1j(int X, int Y, int Z)  
		    {  
		        int tmp = X ^ Y ^ Z;  
		        return tmp;  
		    }  
		  
		    private static int FF2j(int X, int Y, int Z)  
		    {  
		        int tmp = ((X & Y) | (X & Z) | (Y & Z));  
		        return tmp;  
		    }  
		  
		    private static int GG1j(int X, int Y, int Z)   
		    {  
		        int tmp = X ^ Y ^ Z;  
		        return tmp;  
		    }  
		  
		    private static int GG2j(int X, int Y, int Z)   
		    {  
		        int tmp = (X & Y) | (~X & Z);  
		        return tmp;  
		    }  
		  
		    private static int P0(int X)   
		    {  
		        int y = rotateLeft(X, 9);  
		        y = bitCycleLeft(X, 9);  
		        int z = rotateLeft(X, 17);  
		        z = bitCycleLeft(X, 17);  
		        int t = X ^ y ^ z;  
		        return t;  
		    }  
		  
		    private static int P1(int X)   
		    {  
		        int t = X ^ bitCycleLeft(X, 15) ^ bitCycleLeft(X, 23);  
		        return t;  
		    }  
		  
		    /** 
		     * 對最後一個分組位元組資料padding 
		     *  
		     * @param in 
		     * @param bLen 
		     *            分組個數 
		     * @return 
		     */  
		    public static byte[] padding(byte[] in, int bLen)  
		    {  
		        int k = 448 - (8 * in.length + 1) % 512;  
		        if (k < 0)   
		        {  
		            k = 960 - (8 * in.length + 1) % 512;  
		        }  
		        k += 1;  
		        byte[] padd = new byte[k / 8];  
		        padd[0] = (byte) 0x80;  
		        long n = in.length * 8 + bLen * 512;  
		        byte[] out = new byte[in.length + k / 8 + 64 / 8];  
		        int pos = 0;  
		        System.arraycopy(in, 0, out, 0, in.length);  
		        pos += in.length;  
		        System.arraycopy(padd, 0, out, pos, padd.length);  
		        pos += padd.length;  
		        byte[] tmp = back(Util.longToBytes(n));  
		        System.arraycopy(tmp, 0, out, pos, tmp.length);  
		        return out;  
		    }  
		  
		    /** 
		     * 位元組陣列逆序 
		     *  
		     * @param in 
		     * @return 
		     */  
		    private static byte[] back(byte[] in)   
		    {  
		        byte[] out = new byte[in.length];  
		        for (int i = 0; i < out.length; i++)   
		        {  
		            out[i] = in[out.length - i - 1];  
		        }  
		  
		        return out;  
		    }  
		  
		    public static int rotateLeft(int x, int n)   
		    {  
		        return (x << n) | (x >> (32 - n));  
		    }  
		  
		    private static int bitCycleLeft(int n, int bitLen)   
		    {  
		        bitLen %= 32;  
		        byte[] tmp = bigEndianIntToByte(n);  
		        int byteLen = bitLen / 8;  
		        int len = bitLen % 8;  
		        if (byteLen > 0)  
		        {  
		            tmp = byteCycleLeft(tmp, byteLen);  
		        }  
		  
		        if (len > 0)   
		        {  
		            tmp = bitSmall8CycleLeft(tmp, len);  
		        }  
		  
		        return bigEndianByteToInt(tmp);  
		    }  
		  
		    private static byte[] bitSmall8CycleLeft(byte[] in, int len)   
		    {  
		        byte[] tmp = new byte[in.length];  
		        int t1, t2, t3;  
		        for (int i = 0; i < tmp.length; i++)  
		        {  
		            t1 = (byte) ((in[i] & 0x000000ff) << len);  
		            t2 = (byte) ((in[(i + 1) % tmp.length] & 0x000000ff) >> (8 - len));  
		            t3 = (byte) (t1 | t2);  
		            tmp[i] = (byte) t3;  
		        }  
		  
		        return tmp;  
		    }  
		  
		    private static byte[] byteCycleLeft(byte[] in, int byteLen)   
		    {  
		        byte[] tmp = new byte[in.length];  
		        System.arraycopy(in, byteLen, tmp, 0, in.length - byteLen);  
		        System.arraycopy(in, 0, tmp, in.length - byteLen, byteLen);  
		        return tmp;  
		    }  
}

SM3Digest.java

import org.bouncycastle.util.encoders.Hex;  

public class SM3Digest {
	 /** SM3值的長度 */  
    private static final int BYTE_LENGTH = 32;  
      
    /** SM3分組長度 */  
    private static final int BLOCK_LENGTH = 64;  
      
    /** 緩衝區長度 */  
    private static final int BUFFER_LENGTH = BLOCK_LENGTH * 1;  
      
    /** 緩衝區 */  
    private byte[] xBuf = new byte[BUFFER_LENGTH];  
      
    /** 緩衝區偏移量 */  
    private int xBufOff;  
      
    /** 初始向量 */  
    private byte[] V = SM3.iv.clone();  
      
    private int cntBlock = 0;  
  
    public SM3Digest() {  
    }  
  
    public SM3Digest(SM3Digest t)  
    {  
        System.arraycopy(t.xBuf, 0, this.xBuf, 0, t.xBuf.length);  
        this.xBufOff = t.xBufOff;  
        System.arraycopy(t.V, 0, this.V, 0, t.V.length);  
    }  
      
    /** 
     * SM3結果輸出 
     *  
     * @param out 儲存SM3結構的緩衝區 
     * @param outOff 緩衝區偏移量 
     * @return 
     */  
    public int doFinal(byte[] out, int outOff)   
    {  
        byte[] tmp = doFinal();  
        System.arraycopy(tmp, 0, out, 0, tmp.length);  
        return BYTE_LENGTH;  
    }  
  
    public void reset()   
    {  
        xBufOff = 0;  
        cntBlock = 0;  
        V = SM3.iv.clone();  
    }  
  
    /** 
     * 明文輸入 
     *  
     * @param in 
     *            明文輸入緩衝區 
     * @param inOff 
     *            緩衝區偏移量 
     * @param len 
     *            明文長度 
     */  
    public void update(byte[] in, int inOff, int len)  
    {  
        int partLen = BUFFER_LENGTH - xBufOff;  
        int inputLen = len;  
        int dPos = inOff;  
        if (partLen < inputLen)   
        {  
            System.arraycopy(in, dPos, xBuf, xBufOff, partLen);  
            inputLen -= partLen;  
            dPos += partLen;  
            doUpdate();  
            while (inputLen > BUFFER_LENGTH)   
            {  
                System.arraycopy(in, dPos, xBuf, 0, BUFFER_LENGTH);  
                inputLen -= BUFFER_LENGTH;  
                dPos += BUFFER_LENGTH;  
                doUpdate();  
            }  
        }  
  
        System.arraycopy(in, dPos, xBuf, xBufOff, inputLen);  
        xBufOff += inputLen;  
    }  
  
    private void doUpdate()   
    {  
        byte[] B = new byte[BLOCK_LENGTH];  
        for (int i = 0; i < BUFFER_LENGTH; i += BLOCK_LENGTH)   
        {  
            System.arraycopy(xBuf, i, B, 0, B.length);  
            doHash(B);  
        }  
        xBufOff = 0;  
    }  
  
    private void doHash(byte[] B)  
    {  
        byte[] tmp = SM3.CF(V, B);  
        System.arraycopy(tmp, 0, V, 0, V.length);  
        cntBlock++;  
    }  
  
    private byte[] doFinal()   
    {  
        byte[] B = new byte[BLOCK_LENGTH];  
        byte[] buffer = new byte[xBufOff];  
        System.arraycopy(xBuf, 0, buffer, 0, buffer.length);  
        byte[] tmp = SM3.padding(buffer, cntBlock);  
        for (int i = 0; i < tmp.length; i += BLOCK_LENGTH)  
        {  
            System.arraycopy(tmp, i, B, 0, B.length);  
            doHash(B);  
        }  
        return V;  
    }  
  
    public void update(byte in)   
    {  
        byte[] buffer = new byte[] { in };  
        update(buffer, 0, 1);  
    }  
      
    public int getDigestSize()   
    {  
        return BYTE_LENGTH;  
    }  
      
    public static void main(String[] args)   
    {  
        byte[] md = new byte[32];  
        byte[] msg1 = "ererfeiisgod".getBytes();  
        SM3Digest sm3 = new SM3Digest();  
        sm3.update(msg1, 0, msg1.length);  
        sm3.doFinal(md, 0);  
        String s = new String(Hex.encode(md));  
        System.out.println(s.toUpperCase());  
    }  
}
SM4_Context.java

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];  
    }  
}

SM4.java

import java.io.ByteArrayInputStream;  
import java.io.ByteArrayOutputStream;  

public class SM4 {
	 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];  
	        for (; i < 32; i++)   
	        {  
	            k[(i + 4)] = (k[i] ^ sm4CalciRK(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^ (long) CK[i]));  
	            SK[i] = k[(i + 4)];  
	        }  
	    }  
	  
	    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;  
	    }  
}

SM4Utils.java

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

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

public class SM4Utils {
//	private String secretKey = "";  
//    private String iv = "";  
//    private boolean hexString = false;  
      
    public String secretKey = "";  
    private String iv = "";  
    public boolean hexString = false;  
    
    public SM4Utils()  
    {  
    }  
//      
//    public byte encryptData_ECB1(byte[] inputStream){
//        try   
//        {  
//            SM4_Context ctx = new SM4_Context();  
//            ctx.isPadding = true;  
//            ctx.mode = SM4.SM4_ENCRYPT;  
//              
//            byte[] keyBytes;  
//            if (hexString)  
//            {  
//                keyBytes = Util.hexStringToBytes(secretKey);  
//            }  
//            else  
//            {  
//                keyBytes = secretKey.getBytes();  
//            }  
//              
//            SM4 sm4 = new SM4();  
//            sm4.sm4_setkey_enc(ctx, keyBytes);   
//            String cipherText = new BASE64Encoder().encode(inputStream);  
//            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 (Byte) null;  
//        }  
//    }
    
    public String encryptData_ECB(String plainText)  
    {  
        try   
        {  
            SM4_Context ctx = new SM4_Context();  
            ctx.isPadding = true;  
            ctx.mode = SM4.SM4_ENCRYPT;  
              
            byte[] keyBytes;  
            if (hexString)  
            {  
                keyBytes = Util.hexStringToBytes(secretKey);  
            }  
            else  
            {  
                keyBytes = secretKey.getBytes();  
            }  
              
            SM4 sm4 = new SM4();  
            sm4.sm4_setkey_enc(ctx, keyBytes);  
            byte[] encrypted = sm4.sm4_crypt_ecb(ctx, plainText.getBytes("GBK"));  
            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;  
        }   
        catch (Exception e)   
        {  
            e.printStackTrace();  
            return null;  
        }  
    }  
      
    public String decryptData_ECB(String cipherText)  
    {  
        try   
        {  
            SM4_Context ctx = new SM4_Context();  
            ctx.isPadding = true;  
            ctx.mode = SM4.SM4_DECRYPT;  
              
            byte[] keyBytes;  
            if (hexString)  
            {  
                keyBytes = Util.hexStringToBytes(secretKey);  
            }  
            else  
            {  
                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, "GBK");  
        }   
        catch (Exception e)   
        {  
            e.printStackTrace();  
            return null;  
        }  
    }  
      
    public String encryptData_CBC(String plainText)  
    {  
        try   
        {  
            SM4_Context ctx = new SM4_Context();  
            ctx.isPadding = true;  
            ctx.mode = SM4.SM4_ENCRYPT;  
              
            byte[] keyBytes;  
            byte[] ivBytes;  
            if (hexString)  
            {  
                keyBytes = Util.hexStringToBytes(secretKey);  
                ivBytes = Util.hexStringToBytes(iv);  
            }  
            else  
            {  
                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("GBK"));  
            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;  
        }   
        catch (Exception e)   
        {  
            e.printStackTrace();  
            return null;  
        }  
    }  
      
    public String decryptData_CBC(String cipherText)  
    {  
        try   
        {  
            SM4_Context ctx = new SM4_Context();  
            ctx.isPadding = true;  
            ctx.mode = SM4.SM4_DECRYPT;  
              
            byte[] keyBytes;  
            byte[] ivBytes;  
            if (hexString)  
            {  
                keyBytes = Util.hexStringToBytes(secretKey);  
                ivBytes = Util.hexStringToBytes(iv);  
            }  
            else  
            {  
                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, "GBK");  
        }   
        catch (Exception e)  
        {  
            e.printStackTrace();  
            return null;  
        }  
    }  
      
    public static void main(String[] args) throws IOException   
    {  
        String plainText = "ererfeiisgod";  
          
        SM4Utils sm4 = new SM4Utils();  
        sm4.secretKey = "JeF8U9wHFOMfs2Y8";  
        sm4.hexString = false;  
          
        System.out.println("ECB模式加密");  
        String cipherText = sm4.encryptData_ECB(plainText);  
        System.out.println("密文: " + cipherText);  
        System.out.println("");  
          
        plainText = sm4.decryptData_ECB(cipherText);  
        System.out.println("明文: " + plainText);  
        System.out.println("");  
          
        System.out.println("CBC模式加密");  
        sm4.iv = "UISwD9fW6cFh9SNS";  
        cipherText = sm4.encryptData_CBC(plainText);  
        System.out.println("密文: " + cipherText);  
        System.out.println("");  
          
        plainText = sm4.decryptData_CBC(cipherText);  
        System.out.println("明文: " + plainText);  
        
        System.out.println("CBC模式解密"); 
        System.out.println("密文:4esGgDn/snKraRDe6uM0jQ==");
        String cipherText2 = "4esGgDn/snKraRDe6uM0jQ==";
        plainText = sm4.decryptData_CBC(cipherText2);
        System.out.println("明文: " + plainText);  
    }  
}

Utils.java

import java.math.BigInteger; 

public class Util {
	 /** 
     * 整形轉換成網路傳輸的位元組流(位元組陣列)型資料 
     *  
     * @param num 一個整型資料 
     * @return 4個位元組的自己陣列 
     */  
    public static byte[] intToBytes(int num)  
    {  
        byte[] bytes = new byte[4];  
        bytes[0] = (byte) (0xff & (num >> 0));  
        bytes[1] = (byte) (0xff & (num >> 8));  
        bytes[2] = (byte) (0xff & (num >> 16));  
        bytes[3] = (byte) (0xff & (num >> 24));  
        return bytes;  
    }  
  
    /** 
     * 四個位元組的位元組資料轉換成一個整形資料 
     *  
     * @param bytes 4個位元組的位元組陣列 
     * @return 一個整型資料 
     */  
    public static int byteToInt(byte[] bytes)   
    {  
        int num = 0;  
        int temp;  
        temp = (0x000000ff & (bytes[0])) << 0;  
        num = num | temp;  
        temp = (0x000000ff & (bytes[1])) << 8;  
        num = num | temp;  
        temp = (0x000000ff & (bytes[2])) << 16;  
        num = num | temp;  
        temp = (0x000000ff & (bytes[3])) << 24;  
        num = num | temp;  
        return num;  
    }  
  
    /** 
     * 長整形轉換成網路傳輸的位元組流(位元組陣列)型資料 
     *  
     * @param num 一個長整型資料 
     * @return 4個位元組的自己陣列 
     */  
    public static byte[] longToBytes(long num)   
    {  
        byte[] bytes = new byte[8];  
        for (int i = 0; i < 8; i++)   
        {  
            bytes[i] = (byte) (0xff & (num >> (i * 8)));  
        }  
  
        return bytes;  
    }  
  
    /** 
     * 大數字轉換位元組流(位元組陣列)型資料 
     *  
     * @param n 
     * @return 
     */  
    public static byte[] byteConvert32Bytes(BigInteger n)   
    {  
        byte tmpd[] = (byte[])null;  
        if(n == null)  
        {  
            return null;  
        }  
          
        if(n.toByteArray().length == 33)  
        {  
            tmpd = new byte[32];  
            System.arraycopy(n.toByteArray(), 1, tmpd, 0, 32);  
        }   
        else if(n.toByteArray().length == 32)  
        {  
            tmpd = n.toByteArray();  
        }   
        else  
        {  
            tmpd = new byte[32];  
            for(int i = 0; i < 32 - n.toByteArray().length; i++)  
            {  
                tmpd[i] = 0;  
            }  
            System.arraycopy(n.toByteArray(), 0, tmpd, 32 - n.toByteArray().length, n.toByteArray().length);  
        }  
        return tmpd;  
    }  
      
    /** 
     * 換位元組流(位元組陣列)型資料轉大數字 
     *  
     * @param b 
     * @return 
     */  
    public static BigInteger byteConvertInteger(byte[] b)  
    {  
        if (b[0] < 0)  
        {  
            byte[] temp = new byte[b.length + 1];  
            temp[0] = 0;  
            System.arraycopy(b, 0, temp, 1, b.length);  
            return new BigInteger(temp);  
        }  
        return new BigInteger(b);  
    }  
      
    /** 
     * 根據位元組陣列獲得值(十六進位制數字) 
     *  
     * @param bytes 
     * @return 
     */  
    public static String getHexString(byte[] bytes)   
    {  
        return getHexString(bytes, true);  
    }  
      
    /** 
     * 根據位元組陣列獲得值(十六進位制數字) 
     *  
     * @param bytes 
     * @param upperCase 
     * @return 
     */  
    public static String getHexString(byte[] bytes, boolean upperCase)   
    {  
        String ret = "";  
        for (int i = 0; i < bytes.length; i++)   
        {  
            ret += Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1);  
        }  
        return upperCase ? ret.toUpperCase() : ret;  
    }  
      
    /** 
     * 列印十六進位制字串 
     *  
     * @param bytes 
     */  
    public static void printHexString(byte[] bytes)   
    {  
        for (int i = 0; i < bytes.length; i++)   
        {  
            String hex = Integer.toHexString(bytes[i] & 0xFF);  
            if (hex.length() == 1)   
            {  
                hex = '0' + hex;  
            }  
            System.out.print("0x" + hex.toUpperCase() + ",");  
        }  
        System.out.println("");  
    }  
      
    /** 
     * Convert hex string to byte[] 
     *  
     * @param hexString 
     *            the hex string 
     * @return byte[] 
     */  
    public static byte[] hexStringToBytes(String hexString)   
    {  
        if (hexString == null || hexString.equals(""))   
        {  
            return null;  
        }  
          
        hexString = hexString.toUpperCase();  
        int length = hexString.length() / 2;  
        char[] hexChars = hexString.toCharArray();  
        byte[] d = new byte[length];  
        for (int i = 0; i < length; i++)   
        {  
            int pos = i * 2;  
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));  
        }  
        return d;  
    }  
      
    /** 
     * Convert char to byte 
     *  
     * @param c 
     *            char 
     * @return byte 
     */  
    public static byte charToByte(char c)   
    {  
        return (byte) "0123456789ABCDEF".indexOf(c);  
    }  
      
    /** 
     * 用於建立十六進位制字元的輸出的小寫字元陣列 
     */  
    private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5',  
            '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};  
   
    /** 
     * 用於建立十六進位制字元的輸出的大寫字元陣列 
     */  
    private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5',  
            '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};  
   
    /** 
     * 將位元組陣列轉換為十六進位制字元陣列 
     * 
     * @param data byte[] 
     * @return 十六進位制char[] 
     */  
    public static char[] encodeHex(byte[] data) {  
        return encodeHex(data, true);  
    }  
   
    /** 
     * 將位元組陣列轉換為十六進位制字元陣列 
     * 
     * @param data        byte[] 
     * @param toLowerCase <code>true</code> 傳換成小寫格式 , <code>false</code> 傳換成大寫格式 
     * @return 十六進位制char[] 
     */  
    public static char[] encodeHex(byte[] data, boolean toLowerCase) {  
        return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);  
    }  
   
    /** 
     * 將位元組陣列轉換為十六進位制字元陣列 
     * 
     * @param data     byte[] 
     * @param toDigits 用於控制輸出的char[] 
     * @return 十六進位制char[] 
     */  
    protected static char[] encodeHex(byte[] data, char[] toDigits) {  
        int l = data.length;  
        char[] out = new char[l << 1];  
        // two characters form the hex value.  
        for (int i = 0, j = 0; i < l; i++) {  
            out[j++] = toDigits[(0xF0 & data[i]) >>> 4];  
            out[j++] = toDigits[0x0F & data[i]];  
        }  
        return out;  
    }  
   
    /** 
     * 將位元組陣列轉換為十六進位制字串 
     * 
     * @param data byte[] 
     * @return 十六進位制String 
     */  
    public static String encodeHexString(byte[] data) {  
        return encodeHexString(data, true);  
    }  
   
    /** 
     * 將位元組陣列轉換為十六進位制字串 
     * 
     * @param data        byte[] 
     * @param toLowerCase <code>true</code> 傳換成小寫格式 , <code>false</code> 傳換成大寫格式 
     * @return 十六進位制String 
     */  
    public static String encodeHexString(byte[] data, boolean toLowerCase) {  
        return encodeHexString(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);  
    }  
   
    /** 
     * 將位元組陣列轉換為十六進位制字串 
     * 
     * @param data     byte[] 
     * @param toDigits 用於控制輸出的char[] 
     * @return 十六進位制String 
     */  
    protected static String encodeHexString(byte[] data, char[] toDigits) {  
        return new String(encodeHex(data, toDigits));  
    }  
   
    /** 
     * 將十六進位制字元陣列轉換為位元組陣列 
     * 
     * @param data 十六進位制char[] 
     * @return byte[] 
     * @throws RuntimeException 如果源十六進位制字元陣列是一個奇怪的長度,將丟擲執行時異常 
     */  
    public static byte[] decodeHex(char[] data) {  
        int len = data.length;  
   
        if ((len & 0x01) != 0) {  
            throw new RuntimeException("Odd number of characters.");  
        }  
   
        byte[] out = new byte[len >> 1];  
   
        // two characters form the hex value.  
        for (int i = 0, j = 0; j < len; i++) {  
            int f = toDigit(data[j], j) << 4;  
            j++;  
            f = f | toDigit(data[j], j);  
            j++;  
            out[i] = (byte) (f & 0xFF);  
        }  
   
        return out;  
    }  
   
    /** 
     * 將十六進位制字元轉換成一個整數 
     * 
     * @param ch    十六進位制char 
     * @param index 十六進位制字元在字元陣列中的位置 
     * @return 一個整數 
     * @throws RuntimeException 當ch不是一個合法的十六進位制字元時,丟擲執行時異常 
     */  
    protected static int toDigit(char ch, int index) {  
        int digit = Character.digit(ch, 16);  
        if (digit == -1) {  
            throw new RuntimeException("Illegal hexadecimal character " + ch  
                    + " at index " + index);  
        }  
        return digit;  
    }  
   
    /** 
     * 數字字串轉ASCII碼字串 
     *  
     * @param String 
     *            字串 
     * @return ASCII字串 
     */  
    public static String StringToAsciiString(String content) {  
        String result = "";  
        int max = content.length();  
        for (int i = 0; i < max; i++) {  
            char c = content.charAt(i);  
            String b = Integer.toHexString(c);  
            result = result + b;  
        }  
        return result;  
    }  
      
    /** 
     * 十六進位制轉字串 
     *  
     * @param hexString 
     *            十六進位制字串 
     * @param encodeType 
     *            編碼型別4:Unicode,2:普通編碼 
     * @return 字串 
     */  
    public static String hexStringToString(String hexString, int encodeType) {  
        String result = "";  
        int max = hexString.length() / encodeType;  
        for (int i = 0; i < max; i++) {  
            char c = (char) hexStringToAlgorism(hexString  
                    .substring(i * encodeType, (i + 1) * encodeType));  
            result += c;  
        }  
        return result;  
    }  
      
    /** 
     * 十六進位制字串裝十進位制 
     *  
     * @param hex 
     *            十六進位制字串 
     * @return 十進位制數值 
     */  
    public static int hexStringToAlgorism(String hex) {  
        hex = hex.toUpperCase();  
        int max = hex.length();  
        int result = 0;  
        for (int i = max; i > 0; i--) {  
            char c = hex.charAt(i - 1);  
            int algorism = 0;  
            if (c >= '0' && c <= '9') {  
                algorism = c - '0';  
            } else {  
                algorism = c - 55;  
            }  
            result += Math.pow(16, max - i) * algorism;  
        }  
        return result;  
    }  
      
    /** 
     * 十六轉二進位制 
     *  
     * @param hex 
     *            十六進位制字串 
     * @return 二進位制字串 
     */  
    public static String hexStringToBinary(String hex) {  
        hex = hex.toUpperCase();  
        String result = "";  
        int max = hex.length();  
        for (int i = 0; i < max; i++) {  
            char c = hex.charAt(i);  
            switch (c) {  
            case '0':  
                result += "0000";  
                break;  
            case '1':  
                result += "0001";  
                break;  
            case '2':  
                result += "0010";  
                break;  
            case '3':  
                result += "0011";  
                break;  
            case '4':  
                result += "0100";  
                break;  
            case '5':  
                result += "0101";  
                break;  
            case '6':  
                result += "0110";  
                break;  
            case '7':  
                result += "0111";  
                break;  
            case '8':  
                result += "1000";  
                break;  
            case '9':  
                result += "1001";  
                break;  
            case 'A':  
                result += "1010";  
                break;  
            case 'B':  
                result += "1011";  
                break;  
            case 'C':  
                result += "1100";  
                break;  
            case 'D':  
                result += "1101";  
                break;  
            case 'E':  
                result += "1110";  
                break;  
            case 'F':  
                result += "1111";  
                break;  
            }  
        }  
        return result;  
    }  
      
    /** 
     * ASCII碼字串轉數字字串 
     *  
     * @param String 
     *            ASCII字串 
     * @return 字串 
     */  
    public static String AsciiStringToString(String content) {  
        String result = "";  
        int length = content.length() / 2;  
        for (int i = 0; i < length; i++) {  
            String c = content.substring(i * 2, i * 2 + 2);  
            int a = hexStringToAlgorism(c);  
            char b = (char) a;  
            String d = String.valueOf(b);  
            result += d;  
        }  
        return result;  
    }  
      
    /** 
     * 將十進位制轉換為指定長度的十六進位制字串 
     *  
     * @param algorism 
     *            int 十進位制數字 
     * @param maxLength 
     *            int 轉換後的十六進位制字串長度 
     * @return String 轉換後的十六進位制字串 
     */  
    public static String algorismToHexString(int algorism, int maxLength) {  
        String result = "";  
        result = Integer.toHexString(algorism);  
  
        if (result.length() % 2 == 1) {  
            result = "0" + result;  
        }  
        return patchHexString(result.toUpperCase(), maxLength);  
    }  
      
    /** 
     * 位元組陣列轉為普通字串(ASCII對應的字元) 
     *  
     * @param bytearray 
     *            byte[] 
     * @return String 
     */  
    public static String byteToString(byte[] bytearray) {  
        String result = "";  
        char temp;  
  
        int length = bytearray.length;  
        for (int i = 0; i < length; i++) {  
            temp = (char) bytearray[i];  
            result += temp;  
        }  
        return result;  
    }  
      
    /** 
     * 二進位制字串轉十進位制 
     *  
     * @param binary 
     *            二進位制字串 
     * @return 十進位制數值 
     */  
    public static int binaryToAlgorism(String binary) {  
        int max = binary.length();  
        int result = 0;  
        for (int i = max; i > 0; i--) {  
            char c = binary.charAt(i - 1);  
            int algorism = c - '0';  
            result += Math.pow(2, max - i) * algorism;  
        }  
        return result;  
    }  
  
    /** 
     * 十進位制轉換為十六進位制字串 
     *  
     * @param algorism 
     *            int 十進位制的數字 
     * @return String 對應的十六進位制字串 
     */  
    public static String algorismToHEXString(int algorism) {  
        String result = "";  
        result = Integer.toHexString(algorism);  
  
        if (result.length() % 2 == 1) {  
            result = "0" + result;  
  
        }  
        result = result.toUpperCase();  
  
        return result;  
    }  
      
    /** 
     * HEX字串前補0,主要用於長度位數不足。 
     *  
     * @param str 
     *            String 需要補充長度的十六進位制字串 
     * @param maxLength 
     *            int 補充後十六進位制字串的長度 
     * @return 補充結果 
     */  
    static public String patchHexString(String str, int maxLength) {  
        String temp = "";  
        for (int i = 0; i < maxLength - str.length(); i++) {  
            temp = "0" + temp;  
        }  
        str = (temp + str).substring(0, maxLength);  
        return str;  
    }  
      
    /** 
     * 將一個字串轉換為int 
     *  
     * @param s 
     *            String 要轉換的字串 
     * @param defaultInt 
     *            int 如果出現異常,預設返回的數字 
     * @param radix 
     *            int 要轉換的字串是什麼進位制的,如16 8 10. 
     * @return int 轉換後的數字 
     */  
    public static int parseToInt(String s, int defaultInt, int radix) {  
        int i = 0;  
        try {  
            i = Integer.parseInt(s, radix);  
        } catch (NumberFormatException ex) {  
            i = defaultInt;  
        }  
        return i;  
    }  
      
    /** 
     * 將一個十進位制形式的數字字串轉換為int 
     *  
     * @param s 
     *            String 要轉換的字串 
     * @param defaultInt 
     *            int 如果出現異常,預設返回的數字 
     * @return int 轉換後的數字 
     */  
    public static int parseToInt(String s, int defaultInt) {  
        int i = 0;  
        try {  
            i = Integer.parseInt(s);  
        } catch (NumberFormatException ex) {  
            i = defaultInt;  
        }  
        return i;  
    }  
      
    /** 
     * 十六進位制串轉化為byte陣列 
     *  
     * @return the array of byte 
     */  
    public static byte[] hexToByte(String hex)  
            throws IllegalArgumentException {  
        if (hex.length() % 2 != 0) {  
            throw new IllegalArgumentException();  
        }  
        char[] arr = hex.toCharArray();  
        byte[] b = new byte[hex.length() / 2];  
        for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {  
            String swap = "" + arr[i++] + arr[i];  
            int byteint = Integer.parseInt(swap, 16) & 0xFF;  
            b[j] = new Integer(byteint).byteValue();  
        }  
        return b;  
    }  
      
    /** 
     * 位元組陣列轉換為十六進位制字串 
     *  
     * @param b 
     *            byte[] 需要轉換的位元組陣列 
     * @return String 十六進位制字串 
     */  
    public static String byteToHex(byte b[]) {  
        if (b == null) {  
            throw new IllegalArgumentExce