この記事は機械翻訳のミラー記事です。元の記事にジャンプするにはこちらをクリックしてください。

眺める: 16332|答える: 4

[アルゴリズム] SMS4アルゴリズムは対称ブロック暗号アルゴリズムです

[リンクをコピー]
掲載地 2015/12/08 21:49:35 | | |
これはブロック暗号アルゴリズムですが、彼は多くのものを使っています。今ではインターネット上に特定のソースコードがありますが、このコードには研究価値があります。もし興味があれば、一緒にコミュニケーションを取り学びながら参加できます。 実際、完全なコードを提供する意味はありませんが、それでも http://www.2cto.com/kf/201501/369374.html に完全なコードアドレスを添付しています
また、その中にはSボックスも含まれており、これはDESアルゴリズムで使われる非常に重要な要素です。ですので、同僚からの提案は、DESアルゴリズムのSボックスを明確に理解することで、このSMS4アルゴリズムの仕様が何を指しているのかを知ることです。 仕様書は添付されていません。





先の:この場所は長い間更新されておらず、今後毎日C言語を更新するつもりです。
次に:C言語、フルバージョン動画
掲載地 2015/12/08 22:19:05 |

SMS4はじめに:

このアルゴリズムはグループ化アルゴリズムです。 このアルゴリズムのパケット長は128ビット、鍵長は128ビット、つまり16バイトです。 暗号化アルゴリズムも鍵展開アルゴリズムも32ラウンドの非線形反復構造を採用しています。 復号アルゴリズムは暗号化アルゴリズムと同じ構造を持ちますが、ラウンドキーの使用順序が逆で、復号ホイールキーは暗号ホイールキーの逆順です。 SMS4のすべてのベースクラスでは、暗号化と復号の基本機能は同じですが、暗号化か復号かを判別するためにint型フラグビットが必要です。

SMS4暗号化アルゴリズムの基本:



パブリッククラスSMS4 {

    プライベート静的最終整数 ENCRYPT = 1;
    プライベート静的最終 int DECRYPT = 0;
    公開静的最終 int ラウンド = 32;
    プライベート静的最終 int BLOCK = 16;

    プライベートバイト[] Sbox = { (byte) 0xd6, (byte) 0x90, (byte) 0xe9, (byte) 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 };

    プライベート 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) {
        返す x << y | x の >>> (32 - y);
    }

    private int ByteSub(int A) {
        リターン(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) {
        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) {
        B ^ Rotl(B, 13) ^ Rotl(B, 23);
        返す B^(B<<13|B>>>19)^(B<<23|B>>>9);
    }

    void SMS4Crypt(byte[] Input, byte[] Output, int[] rk) {
        INTはR、ミッド、X0、x1、X2、X3;
        int[] x = 新しいint[4];
        int[] tmp = 新しいint[4];
        (int i = 0; 私は4<; i++) {
            tmp[0] = 入力[0 + 4 * i] & 0xff;
            tmp[1] = 入力[1 + 4 * i] & 0xff;
            tmp[2] = 入力[2 + 4 * i] & 0xff;
            tmp[3] = 入力[3 + 4 * i] & 0xff;
            x= TMP[0] << 24 | TMP[1] << 16 | TMP[2] << 8 | tmp[3];
            x=(Input[0+4*i]<<24|Input[1+4*i]<<16|Input[2+4*i]<<8|Input[3+4*i]);
        }
        (r = 0; R < 32; r += 4) {
            ミッド = x[1] ^ x[2] ^ x[3] ^ rk[r + 0];
            mid = ByteSub(mid);
            x[0] = x[0] ^ L1(中段); x4

            ミッド = x[2] ^ x[3] ^ x[0] ^ rk[r + 1];
            mid = ByteSub(mid);
            x[1] = x[1] ^ L1(ミッド); x5

            ミッド = x[3] ^ x[0] ^ x[1] ^ rk[r + 2];
            mid = ByteSub(mid);
            x[2] = x[2] ^ L1(中段); x6

            ミッド = x[0] ^ x[1] ^ x[2] ^ rk[r + 3];
            mid = ByteSub(mid);
            x[3] = x[3] ^ L1(ミッド); x7
        }

        裏面
        (int j = 0; j < 16; j += 4) {
            Output[j] = (バイト) (x[3 - j / 4] >>> 24 & 0xFF);
            出力[j + 1] = (バイト) (x[3 - j / 4] >>> 16 & 0xFF);
            出力[j + 2] = (バイト) (x[3 - j / 4] >>> 8 & 0xFF);
            Output[j + 3] = (バイト) (x[3 - j / 4] & 0xFF);
        }
    }

    private void SMS4KeyExt(byte[] キー, int[] rk, int CryptFlag) {
        インターン、右、ミッド;
        int[] x = 新しいint[4];
        int[] tmp = 新しいint[4];
        (int i = 0; 私は4<; i++) {
            tmp[0] = キー[0 + 4 * i] & 0xFF;
            tmp[1] = キー[1 + 4 * i] & 0xff;
            tmp[2] = キー[2 + 4 * i] & 0xff;
            tmp[3] = キー[3 + 4 * i] & 0xff;
            x= TMP[0] << 24 | TMP[1] << 16 | TMP[2] << 8 | tmp[3];
            x=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;
        (r = 0; R < 32; r += 4) {
            ミッド = x[1] ^ x[2] ^ x[3] ^ CK[R + 0];
            mid = ByteSub(mid);
            rk[r + 0] = x[0] ^= L2(ミッド); rk0=K4

            ミッド = x[2] ^ x[3] ^ x[0] ^ CK[R + 1];
            mid = ByteSub(mid);
            rk[r + 1] = x[1] ^= L2(ミッド); rk1=K5

            ミッド = x[3] ^ x[0] ^ x[1] ^ CK[R + 2];
            mid = ByteSub(mid);
            rk[r + 2] = x[2] ^= L2(中盤); rk2=K6

            ミッド = x[0] ^ x[1] ^ x[2] ^ CK[R + 3];
            mid = ByteSub(mid);
            rk[r + 3] = x[3] ^= L2(ミッド); rk3=K7
        }

        ホイールキーの順序を復号:rk31、rk30,...,rk0
        もし(CryptFlag == DECRYPT) {
            (r = 0; r < 16; r++) {
                ミッド = RK[r];
                rk[r] = rk[31 - r];
                RK[31 - R] = ミッド;
            }
        }
    }

    public int sms4(byte[] in, int inLen, byte[] key, byte[] out, int CryptFlag) {
        int point = 0;
        int[] round_key = 新しいint[ROUND];
        int[] round_key={0};
        SMS4KeyExt(key, round_key, CryptFlag);
        バイト[] 入力 = 新しいバイト[16];
        byte[] output = new byte[16];

        while (inLen >= ブロック) {
            input = Arrays.copyOfRange(in, point, point + 16);
            output=Arrays.copyOfRange(out, point, point+16);
            SMS4Crypt(入力、出力、round_key);
            System.arraycopy(output, 0, out, point, BLOCK);
            inLen -= ブロック;
            ポイント+=ブロック;
        }

        返す0;
    }
}

パッケージ化された外部インターフェース:

この基本クラスに基づく主なインターフェースは以下の通りです。



プライベート静的バイト[] encode16(byte[] plain, byte[] key);
プライベート静的バイト[] decode16(byte[] cipher, byte[] key);
プライベート静的バイト[] encode32(byte[] plain, byte[] key);
プライベート静的バイト[] decode32(byte[] cipher, byte[] key);
パブリック静的バイト[] encodeSMS4(byte[] plain, byte[] key);
公開静的バイト[] decodeSMS4(byte[] cipher, byte[] key);
公開静的文字列 decodeSMS4toString(byte[] cipher, byte[] key);

encode16(byte[], byte[])は、16ビット平文および16ビット鍵の暗号化インターフェースです。
プライベート静的バイト[] decode16(byte[] cipher, byte[] キー):16ビット暗号文と16ビット鍵を復号するためのインターフェースです。
プライベート静的バイト[] encode32(byte[] plain, byte[] key): これは32ビット平文と16ビット鍵を暗号化するインターフェースです。
プライベート静的バイト[] decode32(byte[] cipher, byte[] key): これは32ビット暗号文と16ビット鍵を復号するためのインターフェースです。
公開静的バイト[] encodeSMS4(byte[] plain, byte[] key): これは平文と16ビット鍵を無制限のバイト数で暗号化するインターフェースです。
公開静的バイト[] デコードSMS4(byte[] cipher, byte[] key): これは暗号文および16ビット鍵を無制限のバイト数で復号するためのインターフェースです。
公開静的文字列デコードSMS4toString(byte[] cipher, byte[] key):これは無制限バイトの暗号文と16ビット鍵を復号するためのインターフェースです。
インターフェースメソッドコード:



公開静的バイト[] encodeSMS4(文字列平文、バイト[]キー) {
        もし(平文 == null || plaintext.equals()) {
            nullを返します;
        }
        (int i = plaintext.getBytes().length % 16; 私は16<; i++) {
            平文 += '';
        }
        
        return SMS4.encodeSMS4(plaintext.getBytes(), key);
    }
   
    /**
     * SMS4暗号化(平文長無制限)
     *
     * @param 平文
     * @paramキー
     * @return
     */
    パブリック静的バイト[] encodeSMS4(byte[] plaintext, byte[] key) {
        byte[] 暗号文 = 新しいbyte[plaintext.length];
        
        int k = 0;
        int plainLen = plaintext.length;
        一方(k + 16 <= plainLen) {
            byte[] cellPlain = 新しいバイト[16];
            (int i = 0; 私は16<; i++) {
                cellPlain= 平文[k + i];
            }
            byte[] cellCipher = encode16(cellPlain、キー);
            (int i = 0; 私はcellCipher.length<; i++) {
                暗号文[k + i] = cellCipher;
            }
            
            k += 16;
        }

        暗号文を返す;
    }

    /**
     * 平文長に制限のないSMS4復号
     *
     * @param暗号文
     * @paramキー
     * @return
     */
    公開静的バイト[] decodeSMS4(byte[] 暗号文、バイト[] キー) {
        byte[] plaintext = 新しいbyte[ciphertext.length];
        
        int k = 0;
        int cipherLen = 暗号文.length;
        一方(k + 16 <= cipherLen) {
            byte[] cellCipher = 新しいバイト[16];
            (int i = 0; 私は16<; i++) {
                セルサイファー= 暗号文[k + i];
            }
            byte[] cellPlain = decode16(cellCipher、キー);
            (int i = 0; 私は<cellPlain.length; i++) {
                平文[k + i] = cellPlain;
            }
            
            k += 16;
        }
        
        平文を返す;
    }

    /**
     * 復号して平文文字列を取得する
     * @param暗号文
     * @paramキー
     * @return
     */
    public static string decodeSMS4toString(byte[] 暗号文、byte[] キー) {
        byte[] plaintext = 新しいbyte[ciphertext.length];
        平文 = decodeSMS4(暗号文、キー);
        return new String(plaintext);
    }

    /**
     * 暗号化されているのは16ビット平文のみ
     *
     * @param 平文
     * @paramキー
     * @return
     */
    プライベート静的バイト[] encode16(byte[] plaintext, byte[] key) {
        バイト[] 暗号 = 新しいバイト[16];
        SMS4 sm4 = 新しいSMS4();
        sm4.sms4(平文、16、鍵、暗号、ENCRYPT);

        リターン暗号;
    }

    /**
     * 復号されるのは16ビットの暗号文のみ
     *
     * @param 平文
     * @paramキー
     * @return
     */
    プライベート静的バイト[] decode16(byte[] 暗号文、バイト[] キー) {
        byte[] plain = 新しいバイト[16];
        SMS4 sm4 = 新しいSMS4();
        sm4.sms4(暗号文、16、鍵、平文、復号);

        返却は平地;
    }
ここでは32ビット平文暗号化のみを紹介しません。これは16ビット平文のみの方法と非常に似ています。


平文の長さを制限せずに暗号化と復号を行う基本的なアルゴリズムは、16ビットのみを暗号化・復号するというこの基礎に基づいています。 16ビットを超える平文の場合は、ここでパケット暗号化が用いられます。 例えば30ビットの平文が16で割り切れない場合、16で割り切れるように増やす方法もあります。 原則として、最小の数だけを16で割ることができます。もちろん、あなたが満足していれば、大きくしても問題ありません。なぜなら、それが最後の記号だからです。

パケット暗号化とは、16ビット平文を一度暗号化し、その後暗号化された16ビット暗号文を新しい暗号文に再構成することです。 復号の過程で、16ビットの単一のピースに分割され、これらの復号された平文のいくつかが新しい平文として再構成されます。



使用デモンストレーション:



キー
        バイト[] キー = { 0x01, 0x23, 0x45, 0x67, (バイト) 0x89, (バイト) 0xab,
                (バイト)0xcd、(バイト)0xef、(バイト)0xfe、(バイト)0xdc、
                (バイト)0xba、(バイト)0x98、0x76、0x54、0x32、0x10};

        文字列 newString = コーディング、こんにちは!; プレーンテキスト
        
        byte[] enOut = SMS4.encodeSMS4(newString, key);
        もし(enOut == null) {
            帰る;
        }
        
        System.out.println(encryption result:);
        printBit(enOut);

        byte[] deOut = SMS4.decodeSMS4(enOut, key);
        System.out.println(
復号結果(リターンバイト[]):);
        printBit(deOut);

        String deOutStr = SMS4.decodeSMS4toString(enOut, key);
        System.out.println(
結果を復号(Stringを返す):
+ deOutStr);
 地主| 掲載地 2015/12/08 22:25:41 |
シャオ・ジャザ 2015-12-8 22:19 投稿
SMS4はじめに:

このアルゴリズムはグループ化アルゴリズムです。 このアルゴリズムのパケット長は128ビット、鍵長は128ビット、つまり16バイトです。 ...

中の顔を真似してるの? このアルゴリズムは何度かコンピュータ上で実行しましたが、JavaのデバッグにおけるC#にはまだ慣れておらず、彼のすべてのステップを詳しく知っているわけではなく、彼の作業の原理もまだ理解していません。 Java、すべての変数のデバッグ方法を知っていますか?
掲載地 2015/12/08 22:40:48 |

ブレークポイントを設定すること、すす月食ブレークポイントのF5キーとF6キーはシングルステップデバッグ、F5はステップイン、つまり実行する行コードを入力する、F6はステップオーバー、つまり行コードを実行し、次の行にジャンプする
 地主| 掲載地 2015/12/08 23:07:37 |
2015年12月8日 22:40公開
ブレークポイントを設定すること、すす月食ブレークポイントのF5キーとF6キーはどちらもシングルステップデバッグで、F5はステップイン、つまりこの行のコードを入力して実行する...

確かに知っていますが、彼の具体的なプロセスは知らず、仕様のどの段階にいつどこで到達するかもわかりません。 理解してくれたら嬉しいのに
免責事項:
Code Farmer Networkが発行するすべてのソフトウェア、プログラミング資料、記事は学習および研究目的のみを目的としています。 上記の内容は商業的または違法な目的で使用されてはならず、そうでなければ利用者はすべての結果を負うことになります。 このサイトの情報はインターネットからのものであり、著作権紛争はこのサイトとは関係ありません。 ダウンロード後24時間以内に上記の内容を完全にパソコンから削除してください。 もしこのプログラムを気に入ったら、正規のソフトウェアを支持し、登録を購入し、より良い本物のサービスを受けてください。 もし侵害があれば、メールでご連絡ください。

Mail To:help@itsvse.com