3 DES暗号解読方法

20376 ワード

データセキュリティから
 
    ネットバンクを使うとき、銀行カードが盗まれるのではないかと心配していますか?
    友达とQQでチャットする时、あなたのプライバシーが漏れることを心配していますか?
    開発者として、安全なコードを書くことは優雅なコードを書くよりも重要です.安全はすべての応用の根本だからです.データが侵されないことを確保するために、データ暗号化/復号技術が運用される.    ——『Java暗号解読の芸術』より抜粋
 
    したがって、データ転送とデータストレージのセキュリティを確保するために、特定のアルゴリズムによって、データ明文を複雑な暗号化することができます.
    多くの暗号化手段は、単項暗号化と双方向暗号化に大きく分けることができる.単項暗号化とは、データを要約計算することによって暗号文を生成し、暗号文はbase 64、MD 5、SHAなどの可逆的に復元されないことを指す.双方向暗号化とは逆に,暗号文を逆プッシュして明文に復元できることを指し,そのうち双方向暗号化は対称暗号化と非対称暗号化に分けられる.対称暗号化とは、データ使用者が同じ鍵を持っていなければ暗号解読できないことを意味し、暗号のセットを約束したように、対称暗号化の手段にはDES、3 DES、AES、IDEA、RC 4、RC 5などがある.対称暗号化ではなく、対称暗号化ではなく、同じ鍵のセットを持つ必要はありません.これは「情報公開鍵交換プロトコル」です.非対称暗号化には公開鍵と秘密鍵の2組の鍵が必要であり、公開鍵と秘密鍵はペアリングされ、すなわち公開鍵を用いてデータ暗号化され、対応する秘密鍵のみが復号される.このような暗号化手段としては,RSA,DSAなどがある.
                                                                                            
【暗号学常用用語】
    明文:暗号化されていないデータ
    暗号:暗号化されたデータ
    暗号化:明文を暗号化に変換するプロセス
    復号:暗号を明文に変換するプロセス    
    暗号化アルゴリズム:明文を密文に変換する変換アルゴリズム        
    復号アルゴリズム:暗号文を明文に変換する変換アルゴリズム
    ≪暗号化キー|Encryption Key|oem_src≫:アルゴリズムを暗号化するためのキー
    ≪復号鍵|Decrypte Keys|emdw≫:復号アルゴリズムによる復号操作に使用される鍵
    
 
 
初識3 DES
    3 DESは、3 DESedeまたはTripleDESとも呼ばれ、三重データ暗号化であり、逆プッシュ可能なアルゴリズムスキームである.
    1975年に米IBM社がDES暗号化アルゴリズムの研究と発表に成功したが、DES暗号長は暴力的に解読されやすく、DESアルゴリズムを改良することで、データブロックごとに3回のDES暗号化、すなわち3 DES暗号化アルゴリズムを行った.
    しかし、3 DESのアルゴリズムは公開されているため、アルゴリズム自体には秘密はなく、主に唯一の鍵に頼ってデータ暗号化復号の安全を確保している.
    3 DESはいったい安全なのかと聞かれるかもしれません.これまで3 DESを解読できる人はいなかったので、それを解読できれば、情報セキュリティ界全体を驚かせるのに十分でした......
 
【Java 3 DES暗号解読の流れ】
    ①共通に約束された鍵(keyBytes)およびアルゴリズム(Algorithm)を入力し、SecretKey鍵オブジェクトを構築する
        SecretKey deskey = new SecretKeySpec(keyBytes, Algorithm);    
    ②アルゴリズムに基づいてCipherオブジェクトをインスタンス化する.暗号化/復号化を担当します
        Cipher c1 = Cipher.getInstance(Algorithm);    
    ③暗号化/復号モードおよびSecretKeyキーオブジェクトへの入力、Cipherオブジェクトのインスタンス化
        c1.init(Cipher.ENCRYPT_MODE, deskey);    
    ④バイト配列を入力し、Cipher.doFinal()メソッドを呼び出し、暗号化/復号化を実現し、byteバイト配列を返す
        c1.doFinal(src);
3 DESケース
 
-SecretUtils.java(3 DES暗号解読ツールクラス)—
1 package my3des;
 2  
 3 import java.io.UnsupportedEncodingException;
 4  
 5 import javax.crypto.Cipher;
 6 import javax.crypto.SecretKey;
 7 import javax.crypto.spec.SecretKeySpec;
 8  
 9  
10 /**
11  * SecretUtils {3DES         }
12  * @author liuyinfei
13  * @date 2018-08-19
14  */
15 public class SecretUtils {
16  
17     //      , DES、DESede( 3DES)、Blowfish
18     private static final String Algorithm = "DESede";    
19     private static final String PASSWORD_CRYPT_KEY = "2012PinganVitality075522628888ForShenZhenBelter075561869839";
20     
21     
22     /**
23      *     
24      * @param src         
25      * @return 
26      */
27     public static byte[] encryptMode(byte[] src) {
28         try {
29              SecretKey deskey = new SecretKeySpec(build3DesKey(PASSWORD_CRYPT_KEY), Algorithm);    //    
30              Cipher c1 = Cipher.getInstance(Algorithm);    //       /   Cipher   
31              c1.init(Cipher.ENCRYPT_MODE, deskey);    //        
32              return c1.doFinal(src);
33          } catch (java.security.NoSuchAlgorithmException e1) {
34              e1.printStackTrace();
35          } catch (javax.crypto.NoSuchPaddingException e2) {
36              e2.printStackTrace();
37          } catch (java.lang.Exception e3) {
38              e3.printStackTrace();
39          }
40          return null;
41      }
42     
43     
44     /**
45      *     
46      * @param src        
47      * @return
48      */
49     public static byte[] decryptMode(byte[] src) {      
50         try {
51             SecretKey deskey = new SecretKeySpec(build3DesKey(PASSWORD_CRYPT_KEY), Algorithm);
52             Cipher c1 = Cipher.getInstance(Algorithm);
53             c1.init(Cipher.DECRYPT_MODE, deskey);    //        
54             return c1.doFinal(src);
55         } catch (java.security.NoSuchAlgorithmException e1) {
56             e1.printStackTrace();
57         } catch (javax.crypto.NoSuchPaddingException e2) {
58             e2.printStackTrace();
59         } catch (java.lang.Exception e3) {
60             e3.printStackTrace();
61         }
62         return null;
63      }
64     
65     
66     /*
67      *               
68      * @param keyStr      
69      * @return 
70      * @throws UnsupportedEncodingException
71      */
72     public static byte[] build3DesKey(String keyStr) throws UnsupportedEncodingException{
73         byte[] key = new byte[24];    //    24      ,      0
74         byte[] temp = keyStr.getBytes("UTF-8");    //          
75         
76         /*
77          *       
78          * System.arraycopy(   ,          ,    ,     )
79          */
80         if(key.length > temp.length){
81             //  temp  24 ,   temp          key   
82             System.arraycopy(temp, 0, key, 0, temp.length);
83         }else{
84             //  temp  24 ,   temp  24       key   
85             System.arraycopy(temp, 0, key, 0, key.length);
86         }
87         return key;
88     } 
89 }

-Main.java(テストクラス)-
1 package my3des;
 2  
 3 public class Main {
 4  
 5     /**
 6      * @param args
 7      */
 8     public static void main(String[] args) {
 9         String msg = "3DES      ";
10         System.out.println("【   】:" + msg);
11         
12         //  
13         byte[] secretArr = SecretUtils.encryptMode(msg.getBytes());    
14         System.out.println("【   】:" + new String(secretArr));
15         
16         //  
17         byte[] myMsgArr = SecretUtils.decryptMode(secretArr);  
18         System.out.println("【   】:" + new String(myMsgArr));
19     }
20 }

 
 
補足説明
・3 DESの鍵は24ビットのbyte配列でなければならない
    String.getBytes()を勝手に1つ持ってはいけません.次のエラーが表示されます.
        java.security.InvalidKeyException: Invalid key length: 59 bytes
    解決策はたくさんあります.1鍵の固定長で文字列を再定義します.②文字列をBase 64またはMD 5で暗号化し、固定長の文字を切り取ってbyte配列に変換する.③文字列をByte配列に変換し、その配列を修正し、長さが長すぎると一部のみ切り取り、長さが足りない場合はゼロを補う
 
・暗号化結果の符号化方式が一致すること
    byte配列から文字列に変換するには、base 64処理と16進数処理の2つの方法が一般的である.
    
・参考資料
    3 DESオンラインテストツール:http://tool.chacuo.net/crypt3des
 
 
 
3DES
package test;
 
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
 
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
 
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
public class ThreeDESUtil {
	 //      
    public static final String KEY_ALGORITHM = "desede";
    //     /    /     
    public static final String CIPHER_ALGORITHM = "desede/CBC/NoPadding";
 
    /** 
     * CBC   
     * @param key    
     * @param keyiv IV 
     * @param data    
     * @return Base64      
     * @throws Exception 
     */
    public static byte[] des3EncodeCBC(byte[] key, byte[] keyiv, byte[] data) throws Exception {
        Security.addProvider(new BouncyCastleProvider()); 
        Key deskey = keyGenerator(new String(key));
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        IvParameterSpec ips = new IvParameterSpec(keyiv);
        cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);
        byte[] bOut = cipher.doFinal(data);
        for (int k = 0; k < bOut.length; k++) {
            //System.out.print(bOut[k] + " ");
        }
        //System.out.println("");
        return bOut;
    }
 
    /** 
     *   
     *     key   
     * @param KeyStr       
     * @return      
     * @throws InvalidKeyException   
     * @throws NoSuchAlgorithmException   
     * @throws InvalidKeySpecException   
     * @throws Exception 
     */
    private static Key keyGenerator(String keyStr) throws Exception {
        byte input[] = HexString2Bytes(keyStr);
        DESedeKeySpec KeySpec = new DESedeKeySpec(input);
        SecretKeyFactory KeyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
        return ((Key) (KeyFactory.generateSecret(((java.security.spec.KeySpec) (KeySpec)))));
    }
 
    private static int parse(char c) {
        if (c >= 'a') return (c - 'a' + 10) & 0x0f;
        if (c >= 'A') return (c - 'A' + 10) & 0x0f;
        return (c - '0') & 0x0f;
    }
 
    //                 
    public static byte[] HexString2Bytes(String hexstr) {
        byte[] b = new byte[hexstr.length() / 2];
        int j = 0;
        for (int i = 0; i < b.length; i++) {
            char c0 = hexstr.charAt(j++);
            char c1 = hexstr.charAt(j++);
            b[i] = (byte) ((parse(c0) << 4) | parse(c1));
        }
        return b;
    }
 
    /** 
     * CBC   
     * @param key    
     * @param keyiv IV 
     * @param data Base64      
     * @return    
     * @throws Exception 
     */
    public static byte[] des3DecodeCBC(byte[] key, byte[] keyiv, byte[] data) throws Exception {
        Key deskey = keyGenerator(new String(key));
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        IvParameterSpec ips = new IvParameterSpec(keyiv);
        cipher.init(Cipher.DECRYPT_MODE, deskey, ips);
        byte[] bOut = cipher.doFinal(data);
        return bOut;
    }
 
    public static void main(String[] args) throws Exception {
        byte[] key = "6C4E60E55552386C759569836DC0F83869836DC0F838C0F7".getBytes();
        byte[] keyiv = { 1, 2, 3, 4, 5, 6, 7, 8};
        byte[] data = "aaaaaaaa".getBytes("UTF-8");
        System.out.println("data.length=" + data.length);
        System.out.println("CBC    ");
        byte[] str5 = des3EncodeCBC(key, keyiv, data);
       // System.out.println(new sun.misc.BASE64Encoder().encode(str5));
        System.out.println(new Base64().encodeToString(str5));
 
        byte[] str6 = des3DecodeCBC(key, keyiv, str5);
        System.out.println(new String(str6, "UTF-8"));
    }
}

DES:
package test;
 
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
 
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
 
import org.apache.commons.codec.binary.Base64;
 
public class DESUtil {
 
	 //     
    public static final String KEY_ALGORITHM = "DES";
    //    /    /     
    //DES        -->>ECB:       、CBC:        、CFB:      、OFB:      
    public static final String CIPHER_ALGORITHM = "DES/ECB/NoPadding";
 
    /**
     *   
     *     key  
     * @param KeyStr       
     * @return      
     * @throws InvalidKeyException   
     * @throws NoSuchAlgorithmException   
     * @throws InvalidKeySpecException   
     * @throws Exception 
     */
    private static SecretKey keyGenerator(String keyStr) throws Exception {
        byte input[] = HexString2Bytes(keyStr);
        DESKeySpec desKey = new DESKeySpec(input);
        //        ,     DESKeySpec   
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey securekey = keyFactory.generateSecret(desKey);
        return securekey;
    }
 
    private static int parse(char c) {
        if (c >= 'a') return (c - 'a' + 10) & 0x0f;
        if (c >= 'A') return (c - 'A' + 10) & 0x0f;
        return (c - '0') & 0x0f;
    }
 
    //                 
    public static byte[] HexString2Bytes(String hexstr) {
        byte[] b = new byte[hexstr.length() / 2];
        int j = 0;
        for (int i = 0; i < b.length; i++) {
            char c0 = hexstr.charAt(j++);
            char c1 = hexstr.charAt(j++);
            b[i] = (byte) ((parse(c0) << 4) | parse(c1));
        }
        return b;
    }
 
    /** 
     *     
     * @param data      
     * @param key   
     * @return        
     */
    public static String encrypt(String data, String key) throws Exception {
        Key deskey = keyGenerator(key);
        //    Cipher  ,            
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        SecureRandom random = new SecureRandom();
        //    Cipher  ,       
        cipher.init(Cipher.ENCRYPT_MODE, deskey, random);
        byte[] results = cipher.doFinal(data.getBytes());
        //                 (http://tripledes.online-domain-tools.com/)           
        for (int i = 0; i < results.length; i++) {
            System.out.print(results[i] + " ");
        }
        System.out.println();
        //       。           Base64       
        return Base64.encodeBase64String(results);
    }
 
    /** 
     *      
     * @param data       
     * @param key    
     * @return        
     */
    public static String decrypt(String data, String key) throws Exception {
        Key deskey = keyGenerator(key);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        //   Cipher  ,       
        cipher.init(Cipher.DECRYPT_MODE, deskey);
        //       
        return new String(cipher.doFinal(Base64.decodeBase64(data)));
    }
 
    public static void main(String[] args) throws Exception {
        String source = "amigoxie";
        System.out.println("  : " + source);
        String key = "A1B2C3D4E5F60708";
        String encryptData = encrypt(source, key);
        System.out.println("   : " + encryptData);
        String decryptData = decrypt(encryptData, key);
        System.out.println("   : " + decryptData);
    }
}

国密MS 4:
package test;
 
import java.util.Arrays;
 
public class SMS4 {
	
	private static final int ENCRYPT=1;
	private static final int DECRYPT=0;
	public static final int ROUND=32;
	private static final int BLOCK=16;
	
	private byte[] Sbox={
			(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
	};
	
	private 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 int Rotl(int x,int y)
	{
		return x<>>(32-y);
	}
	
	private int ByteSub(int A)
	{
		return (Sbox[A>>>24&0xFF]&0xFF)<<24|(Sbox[A>>>16&0xFF]&0xFF)<<16|(Sbox[A>>>8&0xFF]&0xFF)<<8|(Sbox[A&0xFF]&0xFF);
	}
 
	private int L1(int B)
	{
		return B^Rotl(B,2)^Rotl(B,10)^Rotl(B,18)^Rotl(B,24);
	//	return B^(B<<2|B>>>30)^(B<<10|B>>>22)^(B<<18|B>>>14)^(B<<24|B>>>8);
	}
	
	private int L2(int B)
	{
		return B^Rotl(B,13)^Rotl(B,23);
	//	return B^(B<<13|B>>>19)^(B<<23|B>>>9);
	}
	
	
	void SMS4Crypt(byte[] Input,byte[] Output,int[] rk)
	{
		int r,mid,x0,x1,x2,x3;
		int[] x= new int[4];
		int[] tmp = new int[4];
		for(int i=0;i<4;i++)
		{
			tmp[0]=Input[0+4*i]&0xff;
			tmp[1]=Input[1+4*i]&0xff;
			tmp[2]=Input[2+4*i]&0xff;
			tmp[3]=Input[3+4*i]&0xff;
			x[i]=tmp[0]<<24|tmp[1]<<16|tmp[2]<<8|tmp[3];
		//	x[i]=(Input[0+4*i]<<24|Input[1+4*i]<<16|Input[2+4*i]<<8|Input[3+4*i]);
		}
		for(r=0;r<32;r+=4)
		{
			mid=x[1]^x[2]^x[3]^rk[r+0];
			mid=ByteSub(mid);
			x[0]=x[0]^L1(mid);   //x4
			
			mid=x[2]^x[3]^x[0]^rk[r+1];
			mid=ByteSub(mid);
			x[1]=x[1]^L1(mid);	//x5
			
			mid=x[3]^x[0]^x[1]^rk[r+2];
			mid=ByteSub(mid);
			x[2]=x[2]^L1(mid);	//x6
			
			mid=x[0]^x[1]^x[2]^rk[r+3];
			mid=ByteSub(mid);
			x[3]=x[3]^L1(mid);	//x7
		}
		
		//Reverse
		for(int j=0;j<16;j+=4)
		{
			Output[j]  =(byte) (x[3-j/4]>>>24&0xFF);
			Output[j+1]=(byte) (x[3-j/4]>>>16&0xFF);
			Output[j+2]=(byte) (x[3-j/4]>>>8&0xFF);
			Output[j+3]=(byte) (x[3-j/4]&0xFF);
		}
	}
	
	private void SMS4KeyExt(byte[] Key,int[] rk,int CryptFlag)
	{
		int r,mid;
		int[] x= new int[4];
		int[] tmp =new int[4];
		for(int i=0;i<4;i++)
		{
			tmp[0]=Key[0+4*i]&0xFF;
			tmp[1]=Key[1+4*i]&0xff;
			tmp[2]=Key[2+4*i]&0xff;
			tmp[3]=Key[3+4*i]&0xff;
			x[i]=tmp[0]<<24|tmp[1]<<16|tmp[2]<<8|tmp[3];
		//	x[i]=Key[0+4*i]<<24|Key[1+4*i]<<16|Key[2+4*i]<<8|Key[3+4*i];
		}
		x[0]^=0xa3b1bac6;
		x[1]^=0x56aa3350;
		x[2]^=0x677d9197;
		x[3]^=0xb27022dc;
		for(r=0;r<32;r+=4)
		{
			mid=x[1]^x[2]^x[3]^CK[r+0];
			mid=ByteSub(mid);
			rk[r+0]=x[0]^=L2(mid);		//rk0=K4
			
			mid=x[2]^x[3]^x[0]^CK[r+1];
			mid=ByteSub(mid);
			rk[r+1]=x[1]^=L2(mid);		//rk1=K5
			
			mid=x[3]^x[0]^x[1]^CK[r+2];
			mid=ByteSub(mid);
			rk[r+2]=x[2]^=L2(mid);		//rk2=K6
			
			mid=x[0]^x[1]^x[2]^CK[r+3];
			mid=ByteSub(mid);
			rk[r+3]=x[3]^=L2(mid);		//rk3=K7
		}
		
		//rk31,rk30,...,rk0
		if(CryptFlag==DECRYPT)
		{
			for(r=0;r<16;r++)
			{
				mid=rk[r];
				rk[r]=rk[31-r];
				rk[31-r]=mid;
			}
		}
	}
	
	public int sms4(byte[] in,int inLen,byte[] key,byte[] out,int CryptFlag)
	{
		int point=0;
		int[] round_key=new int[ROUND]; 
		//int[] round_key={0};
		SMS4KeyExt(key,round_key,CryptFlag);
		byte[] input = new byte[16];
		byte[] output = new byte[16];
		
		while(inLen>=BLOCK)
		{
			input=Arrays.copyOfRange(in, point, point+16);
		//	output=Arrays.copyOfRange(out, point, point+16);
			SMS4Crypt(input,output,round_key);
			System.arraycopy(output, 0, out, point, BLOCK);
			inLen-=BLOCK;
			point+=BLOCK;
		}
		
		return 0;
	}
}