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); |